/** @file
* @brief Convex hull of a set of points
*//*
* Authors:
* Nathan Hurst <njh@mail.csse.monash.edu.au>
* Michael G. Sloan <mgsloan@gmail.com>
* Krzysztof KosiĆski <tweenk.pl@gmail.com>
* Copyright 2006-2015 Authors
*
* modify it either under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation
* (the "LGPL") or, at your option, under the terms of the Mozilla
* Public License Version 1.1 (the "MPL"). If you do not alter this
* notice, a recipient may use your version of this file under either
* the MPL or the LGPL.
*
* You should have received a copy of the LGPL along with this library
* in the file COPYING-LGPL-2.1; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* You should have received a copy of the MPL along with this library
* in the file COPYING-MPL-1.1
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
* OF ANY KIND, either express or implied. See the LGPL or the MPL for
* the specific language governing rights and limitations.
*
*/
#include <algorithm>
#include <map>
#include <iostream>
#include <cassert>
/** Todo:
+ modify graham scan to work top to bottom, rather than around angles
+ intersection
+ minimum distance between convex hulls
+ maximum distance between convex hulls
+ hausdorf metric?
+ check all degenerate cases carefully
+ check all algorithms meet all invariants
+ generalise rotating caliper algorithm (iterator/circulator?)
*/
namespace Geom {
: _boundary(2)
, _lower(0)
{
_boundary[0] = a;
_boundary[1] = b;
_construct();
}
: _boundary(3)
, _lower(0)
{
_boundary[0] = a;
_boundary[1] = b;
_boundary[2] = c;
_construct();
}
: _boundary(4)
, _lower(0)
{
_boundary[0] = a;
_boundary[1] = b;
_boundary[2] = c;
_boundary[3] = d;
_construct();
}
: _lower(0)
{
//if (pts.size() > 16) { // arbitrary threshold
// _prune(pts.begin(), pts.end(), _boundary);
//} else {
//}
_construct();
}
{
if (b == c) return false;
return cross(b-a, c-a) > 0;
}
{
// _boundary must already be sorted in LexLess<X> order
_lower = 0;
return;
}
_lower = 1;
return;
}
_lower = 2;
return;
}
--k;
}
}
_lower = k;
--k;
}
}
}
{
if (size() <= 2) return 0;
double a = 0;
}
return fabs(a * 0.5);
}
{
return ret;
}
{
if (ret[Y] >= i->y()) {
ret = *i;
} else {
break;
}
}
return ret;
}
{
if (ret[Y] <= j->y()) {
ret = *j;
} else {
break;
}
}
return ret;
}
{
if (f == last) return false;
if (f == first) {
if (p == *f) return true;
return false;
}
Point a = *(f-1), b = *f;
if (a[X] == b[X]) {
} else {
// TODO: maybe there is a more numerically stable method
if (above(p[Y], y)) return false;
}
return true;
}
{
if (_boundary[0] == p) return true;
return false;
}
// 1. verify that the point is in the relevant X range
// 2. check whether it is below the upper hull
// 3. check whether it is above the lower hull
return true;
}
{
for (unsigned i = 0; i < 4; ++i) {
}
return true;
}
{
// TODO: requires interiorContains.
// We have to check all points of ch, and each point takes logarithmic time.
// If there are more points in ch that here, it is faster to make the check
// the other way around.
/*if (ch.size() > size()) {
for (iterator i = begin(); i != end(); ++i) {
if (ch.interiorContains(*i)) return false;
}
return true;
}*/
if (!contains(*i)) return false;
}
return true;
}
{
}
{
_lower = 0;
_construct();
}
#if 0
/*** SignedTriangleArea
* returns the area of the triangle defined by p0, p1, p2. A clockwise triangle has positive area.
*/
double
}
class angle_cmp{
public:
Point o;
#if 0
bool
// not remove this check or std::sort could crash
if (a == b) return false;
#if 1
if(da[1] == 0)
return true; // infinite tangent
if(db[1] == 0)
return false; // infinite tangent
return true;
#else
//assert((ata > atb) == (aa < ab));
return true;
#endif
return false;
}
#else
{
// not remove this check or std::sort could generate
// a segmentation fault because it needs a strict '<'
// but due to round errors a == b doesn't mean dxy == dyx
if (a == b) return false;
}
#endif
};
//Mathematically incorrect mod, but more useful.
int mod(int i, int l) {
return i >= 0 ?
i % l : (i % l) + l;
}
//OPT: usages can often be replaced by conditions
/*** ConvexHull::add_point
* to add a point we need to find whether the new point extends the boundary, and if so, what it
* obscures. Tarjan? Jarvis?*/
void
if(len < 2) {
return;
}
bool pushed = false;
for(int i = 0; i < len; i++) {
if(pre) {
if(cur) {
if(!pushed) {
pushed = true;
}
continue;
}
else if(!pushed) {
pushed = true;
}
}
}
}
//OPT: quickly find an obscured point and find the bounds by extending from there. then push all points not within the bounds in order.
//OPT: use binary searches to find the actual starts/ends, use known rights as boundaries. may require cooperation of find_left algo.
/*** ConvexHull::is_clockwise
* We require that successive pairs of edges always turn right.
* We return false on collinear points
* proposed algorithm: walk successive edges and require triangle area is positive.
*/
bool
ConvexHull::is_clockwise() const {
if(is_degenerate())
return true;
it != e;) {
return false;
++it;
}
return true;
}
/*** ConvexHull::top_point_first
* We require that the first point in the convex hull has the least y coord, and that off all such points on the hull, it has the least x coord.
* proposed algorithm: track lexicographic minimum while walking the list.
*/
bool
ConvexHull::top_point_first() const {
if(size() <= 1) return true;
}
}
//OPT: since the Y values are orderly there should be something like a binary search to do this.
bool
ConvexHull::meets_invariants() const {
return is_clockwise() && top_point_first();
}
/*** ConvexHull::is_degenerate
* We allow three degenerate cases: empty, 1 point and 2 points. In many cases these should be handled explicitly.
*/
bool
ConvexHull::is_degenerate() const {
}
int sgn(double x) {
if(x == 0) return 0;
return (x<0)?-1:1;
}
int side = 0;
for(int i = 0; i < 4; i++) {
}
return true;
}
/** find bridging pairs between two convex hulls.
* this code is based on Hormoz Pirzadeh's masters thesis. There is room for optimisation:
* 1. reduce recomputation
* 2. use more efficient angle code
* 3. write as iterator
*/
// 1. find maximal points on a and b
// 2. find first copodal pair
// In the case of parallel support lines, we must consider all four pairs of copodal points
{
assert(0); // untested
}
ai++;
L[0] = a[ai];
bi++;
L[1] = b[bi];
ai++;
L[0] = a[ai];
} else {
bi++;
L[1] = b[bi];
}
}
return ret;
}
unsigned find_bottom_right(ConvexHull const &a) {
unsigned it = 1;
it++;
return it-1;
}
/*** ConvexHull sweepline_intersection(ConvexHull a, ConvexHull b);
* find the intersection between two convex hulls. The intersection is also a convex hull.
* (Proof: take any two points both in a and in b. Any point between them is in a by convexity,
* and in b by convexity, thus in both. Need to prove still finite bounds.)
* This algorithm works by sweeping a line down both convex hulls in parallel, working out the left and right edges of the new hull.
*/
unsigned al = 0;
unsigned bl = 0;
al++;
}
bl++;
}
// al and bl now point to the top of the first pair of edges that overlap in y value
//double sweep_y = std::min(a.boundary[al][Y],
// b.boundary[bl][Y]);
return ret;
}
/*** ConvexHull intersection(ConvexHull a, ConvexHull b);
* find the intersection between two convex hulls. The intersection is also a convex hull.
* (Proof: take any two points both in a and in b. Any point between them is in a by convexity,
* and in b by convexity, thus in both. Need to prove still finite bounds.)
*/
/*
int ai = 0, bi = 0;
int aj = a.boundary.size() - 1;
int bj = b.boundary.size() - 1;
*/
/*while (true) {
if(a[ai]
}*/
return ret;
}
template <typename T>
}
/*** ConvexHull merge(ConvexHull a, ConvexHull b);
* find the smallest convex hull that surrounds a and b.
*/
// Given our list of bridges {(pb1, qb1), ..., (pbk, qbk)}
// we start with the highest point in p0, q0, say it is p0.
// then the merged hull is p0, ..., pb1, qb1, ..., qb2, pb2, ...
// In other words, either of the two polygons vertices are added in order until the vertex coincides with a bridge point, at which point we swap.
unsigned state = (a[0][Y] < b[0][Y])?0:1;
unsigned idx = 0;
<< state
<< " \n";
}
}
}
return ret;
}
// we can avoid the find pivot step because of top_point_first
swap(a, b);
/** if we modified graham scan to work top to bottom as proposed in lect754.pdf we could replace the
angle sort with a simple merge sort type algorithm. furthermore, we could do the graham scan
online, avoiding a bunch of memory copies. That would probably be linear. -- njh*/
result.angle_sort();
return result;
}
// we can avoid the find pivot step because of top_point_first
swap(a, b);
/** if we modified graham scan to work top to bottom as proposed in lect754.pdf we could replace the
angle sort with a simple merge sort type algorithm. furthermore, we could do the graham scan
online, avoiding a bunch of memory copies. That would probably be linear. -- njh*/
return result;
}
//TODO: reinstate
/*ConvexCover::ConvexCover(Path const &sp) : path(&sp) {
cc.reserve(sp.size());
for(Geom::Path::const_iterator it(sp.begin()), end(sp.end()); it != end; ++it) {
cc.push_back(ConvexHull((*it).begin(), (*it).end()));
}
}*/
if (n < 2)
return 0;
if(n < 3) {
return 0;
}
double atmp = 0;
for (unsigned i = n-1, j = 0; j < n; i = j, j++) {
}
if (atmp != 0) {
}
return atmp / 2;
}
// n/2, n-1 construct a new point, say (n/2 + n)/2 throw away the furthest boundary point iterate
// until interval is a single value
if(d < dd) {
p = &boundary[i];
d = dd;
}
}
return p;
}
// returns (a, (b,c)), three points which define the narrowest diameter of the hull as the pair of
// lines going through b,c, and through a, parallel to b,c TODO: This can be made linear time by
// moving point tc incrementally from the previous value (it can only move in one direction). It
// is currently n*O(furthest)
if(td < d) {
a = ta;
b = tb;
c = tc;
d = td;
}
}
return d;
}
#endif
};
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :