path-intersection.cpp revision 07bda0b13ae048815f53f21ad1edbe3cc1b7e4e8
//for path_direction:
#ifdef HAVE_GSL
#include <gsl/gsl_vector.h>
#include <gsl/gsl_multiroots.h>
#endif
namespace Geom {
/**
* This function computes the winding of the path, given a reference point.
* Positive values correspond to counter-clockwise in the mathematical coordinate system,
* and clockwise in screen coordinates. This particular implementation casts a ray in
* the positive x direction. It iterates the path, checking for intersection with the
* used to derive a delta on the winding value. If the point is within the bounding box,
* the curve specific winding function is called.
*/
//start on a segment which is not a horizontal line with y = p[y]
}
int wind = 0;
unsigned cnt = 0;
bool starting = true;
{
cnt++;
starting = false;
Coord x = p[X], y = p[Y];
// if y is included, these will have opposite values, giving order.
// ray goes through bbox
// winding delta determined by position of endpoints
if(final_to_ray != EQUAL_TO) {
wind += int(c); // GT = counter-clockwise = 1; LT = clockwise = -1; EQ = not-included = 0
//std::cout << int(c) << " ";
goto cont;
}
} else {
//inside bbox, use custom per-curve winding thingie
//std::cout << "n" << delt << " ";
}
//Handling the special case of an endpoint on the ray:
if(final[Y] == y) {
//Traverse segments until it breaks away from y
//99.9% of the time this will happen the first go
next++;
for(; ; next++) {
//TODO: X considerations
//It has diverged
const double fudge = 0.01;
wind += int(c);
//std::cout << "!!!!!" << int(c) << " ";
}
} else {
//Is a continuation through the ray, so counts windingwise
wind += int(c);
//std::cout << "!!!!!" << int(c) << " ";
}
}
goto cont;
}
}
//Looks like it looped, which means everything's flat
return 0;
}
cont:(void)0;
}
return wind;
}
/**
* This function should only be applied to simple paths (regions), as otherwise
* a boolean winding direction is undefined. It returns true for fill, false for
* hole. Defaults to using the sign of area when it reaches funny cases.
*/
bool path_direction(Path const &p) {
if(p.empty()) return false;
//could probably be more efficient, but this is a quick job
double y = p.initialPoint()[Y];
double x = p.initialPoint()[X];
goto doh;
for(unsigned i = 1; i < p.size(); i++) {
// if y is included, these will have opposite values, giving order.
if(c != EQUAL_TO) {
if(nx > x) {
x = nx;
res = c;
}
}
}
return res < 0;
doh:
//Otherwise fallback on area
double area;
return area > 0;
}
//pair intersect code based on njh's pair-intersect
/** A little sugar for appending a list to another */
template<typename T>
void append(T &a, T const &b) {
}
/**
* Finds the intersection between the lines defined by A0 & A1, and B0 & B1.
* Returns through the last 3 parameters, returning the t-values on the lines
* and the cross-product of the deltas (a useful byproduct). The return value
* indicates if the time values are within their proper range on the line segments.
*/
bool
// kramers rule as cross products
return false;
else
{
}
}
#if 0
typedef union dbl_64{
long long i64;
double d64;
};
{
dbl_64 s;
if(s.i64 == 0)
{
s.i64++;
}
else if(s.i64-- < 0)
else
}
#endif
#ifdef HAVE_GSL
struct rparams {
Curve const &A;
Curve const &B;
};
static int
gsl_vector * f)
{
const double x0 = gsl_vector_get (x, 0);
gsl_vector_set (f, 0, dx[0]);
return GSL_SUCCESS;
}
#endif
static void
{
for(int i = 0; i < 4; i++) {
/**
we want to solve
J*(x1 - x0) = f(x0)
|dA(s)[0] -dB(t)[0]| (X1 - X0) = A(s) - B(t)
|dA(s)[1] -dB(t)[1]|
**/
// We're using the standard transformation matricies, which is numerically rather poor. Much better to solve the equation using elimination.
0, 0);
// At this point we could do a line search
break;
s = ns;
t = nt;
}
#ifdef HAVE_GSL
int status;
if(0) { // the GSL version is more accurate, but taints this with GPL
const size_t n = 2;
struct rparams p = {A, B};
gsl_multiroot_function f = {&intersect_polish_f, n, &p};
double x_init[2] = {s, t};
gsl_vector *x = gsl_vector_alloc (n);
gsl_vector_set (x, 0, x_init[0]);
gsl_multiroot_fsolver_set (sol, &f, x);
do
{
iter++;
if (status) /* check if solver is stuck */
break;
status =
}
s = gsl_vector_get (sol->x, 0);
gsl_vector_free (x);
}
#endif
}
/**
* This uses the local bounds functions of curves to generically intersect two.
* It passes in the curves, time intervals, and keeps track of depth, while
* returning the results through the Crossings parameter.
*/
// std::cout << depth << "(" << Al << ", " << Ah << ")\n";
if (!Ar) return;
if (!Br) return;
//Checks the general linearity of the function
//&& B.boundsLocal(Interval(Bl, Bh), 1).maxExtent() < 0.1)) {
B, tB);
if(depth % 2)
else
return;
}
}
if(depth > 12) return;
}
return ret;
}
/** A simple wrapper around pair_intersect */
return ret;
}
//same as below but curves not paths
//std::cout << " " << depth << "[" << Al << ", " << Ah << "]" << "[" << Bl << ", " << Bh << "]";
B, tB);
if(depth % 2)
else
return;
}
}
if(depth > 12) return;
}
return ret;
}
/**
* Takes two paths and time ranges on them, with the invariant that the
* paths are monotonic on the range. Splits A when the linear intersection
* doesn't exist or is inaccurate. Uses the fact that it is monotonic to
* do very fast local bounds.
*/
if(depth % 2)
else
return;
}
}
if(depth > 12) return;
}
/** This returns the times when the x or y derivative is 0 in the curve. */
delete deriv;
return rs;
}
/** Convenience function to add a value to each entry in a vector of doubles. */
for(unsigned i = 0; i < x.size(); i++) {
}
return ret;
}
/**
* Finds all the monotonic splits for a path. Only includes the split between
* curves if they switch derivative directions at that point.
*/
for(unsigned i = 0; i < p.size(); i++) {
//The direction changed, include the split time
}
}
return ret;
}
/**
* Applies path_mono_splits to multiple paths, and returns the results such that
* time-set i corresponds to Path i.
*/
return ret;
}
/**
* Processes the bounds for a list of paths and a list of splits on them, yielding a list of rects for each.
* Each entry i corresponds to path i of the input. The number of rects in each entry is guaranteed to be the
* number of splits for that path, subtracted by one.
*/
std::vector<std::vector<Rect> > split_bounds(std::vector<Path> const &p, std::vector<std::vector<double> > splits) {
for(unsigned i = 0; i < p.size(); i++) {
}
return ret;
}
/**
* This is the main routine of "MonoCrosser", and implements a monotonic strategy on multiple curves.
* Finds crossings between two sets of paths, yielding a CrossingSet. [0, a.size()) of the return correspond
* to the sorted crossings of a with paths of b. The rest of the return, [a.size(), a.size() + b.size()],
* corresponds to the sorted crossings of b with paths of a.
*
* This function does two sweeps, one on the bounds of each path, and after that cull, one on the curves within.
* This leads to a certain amount of code complexity, however, most of that is factored into the above functions
*/
std::vector<std::vector<Rect> > bounds_a = split_bounds(a, splits_a), bounds_b = split_bounds(b, splits_b);
Crossings n;
//Sweep of the monotonic portions
res, .1);
}
}
}
}
return results;
}
/* This function is similar codewise to the MonoCrosser, the main difference is that it deals with
* only one set of paths and includes self intersection
CrossingSet crossings_among(std::vector<Path> const &p) {
CrossingSet results(p.size(), Crossings());
if(p.empty()) return results;
std::vector<std::vector<double> > splits = paths_mono_splits(p);
std::vector<std::vector<Rect> > prs = split_bounds(p, splits);
std::vector<Rect> rs;
for(unsigned i = 0; i < prs.size(); i++) rs.push_back(union_list(prs[i]));
std::vector<std::vector<unsigned> > cull = sweep_bounds(rs);
//we actually want to do the self-intersections, so add em in:
for(unsigned i = 0; i < cull.size(); i++) cull[i].push_back(i);
for(unsigned i = 0; i < cull.size(); i++) {
for(unsigned jx = 0; jx < cull[i].size(); jx++) {
unsigned j = cull[i][jx];
Crossings res;
//Sweep of the monotonic portions
std::vector<std::vector<unsigned> > cull2 = sweep_bounds(prs[i], prs[j]);
for(unsigned k = 0; k < cull2.size(); k++) {
for(unsigned lx = 0; lx < cull2[k].size(); lx++) {
unsigned l = cull2[k][lx];
mono_pair(p[i], splits[i][k-1], splits[i][k],
p[j], splits[j][l-1], splits[j][l],
res, .1);
}
}
for(unsigned k = 0; k < res.size(); k++) { res[k].a = i; res[k].b = j; }
merge_crossings(results[i], res, i);
merge_crossings(results[j], res, j);
}
}
return results;
}
*/
return res;
}
/*
void mono_curve_intersect(Curve const & A, double Al, double Ah,
Curve const & B, double Bl, double Bh,
Crossings &ret, unsigned depth=0) {
// std::cout << depth << "(" << Al << ", " << Ah << ")\n";
Point A0 = A.pointAt(Al), A1 = A.pointAt(Ah),
B0 = B.pointAt(Bl), B1 = B.pointAt(Bh);
if(!Rect(A0, A1).intersects(Rect(B0, B1)) || A0 == A1 || B0 == B1) return;
//Checks the general linearity of the function
if((depth > 12) || (A.boundsLocal(Interval(Al, Ah), 1).maxExtent() < 0.1
&& B.boundsLocal(Interval(Bl, Bh), 1).maxExtent() < 0.1)) {
double tA, tB, c;
if(linear_intersect(A0, A1, B0, B1, tA, tB, c)) {
tA = tA * (Ah - Al) + Al;
tB = tB * (Bh - Bl) + Bl;
if(depth % 2)
ret.push_back(Crossing(tB, tA, c < 0));
else
ret.push_back(Crossing(tA, tB, c > 0));
return;
}
}
if(depth > 12) return;
double mid = (Bl + Bh)/2;
mono_curve_intersect(B, Bl, mid,
A, Al, Ah,
ret, depth+1);
mono_curve_intersect(B, mid, Bh,
A, Al, Ah,
ret, depth+1);
}
std::vector<std::vector<double> > curves_mono_splits(Path const &p) {
std::vector<std::vector<double> > ret;
for(unsigned i = 0; i <= p.size(); i++) {
std::vector<double> spl;
spl.push_back(0);
append(spl, curve_mono_splits(p[i]));
spl.push_back(1);
ret.push_back(spl);
}
}
std::vector<std::vector<Rect> > curves_split_bounds(Path const &p, std::vector<std::vector<double> > splits) {
std::vector<std::vector<Rect> > ret;
for(unsigned i = 0; i < splits.size(); i++) {
std::vector<Rect> res;
for(unsigned j = 1; j < splits[i].size(); j++)
res.push_back(Rect(p.pointAt(splits[i][j-1]+i), p.pointAt(splits[i][j]+i)));
ret.push_back(res);
}
return ret;
}
Crossings path_self_crossings(Path const &p) {
Crossings ret;
std::vector<std::vector<unsigned> > cull = sweep_bounds(bounds(p));
std::vector<std::vector<double> > spl = curves_mono_splits(p);
std::vector<std::vector<Rect> > bnds = curves_split_bounds(p, spl);
for(unsigned i = 0; i < cull.size(); i++) {
Crossings res;
for(unsigned k = 1; k < spl[i].size(); k++)
for(unsigned l = k+1; l < spl[i].size(); l++)
mono_curve_intersect(p[i], spl[i][k-1], spl[i][k], p[i], spl[i][l-1], spl[i][l], res);
offset_crossings(res, i, i);
append(ret, res);
for(unsigned jx = 0; jx < cull[i].size(); jx++) {
unsigned j = cull[i][jx];
res.clear();
std::vector<std::vector<unsigned> > cull2 = sweep_bounds(bnds[i], bnds[j]);
for(unsigned k = 0; k < cull2.size(); k++) {
for(unsigned lx = 0; lx < cull2[k].size(); lx++) {
unsigned l = cull2[k][lx];
mono_curve_intersect(p[i], spl[i][k-1], spl[i][k], p[j], spl[j][l-1], spl[j][l], res);
}
}
//if(fabs(int(i)-j) == 1 || fabs(int(i)-j) == p.size()-1) {
Crossings res2;
for(unsigned k = 0; k < res.size(); k++) {
if(res[k].ta != 0 && res[k].ta != 1 && res[k].tb != 0 && res[k].tb != 1) {
res.push_back(res[k]);
}
}
res = res2;
//}
offset_crossings(res, i, j);
append(ret, res);
}
}
return ret;
}
*/
offset_crossings(res, i, i);
//if(fabs(int(i)-j) == 1 || fabs(int(i)-j) == p.size()-1) {
}
}
//}
offset_crossings(res, i, j);
}
}
return ret;
}
}
}
}
return results;
}
}
/*
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 :