enum intersectType; enum intersectType { DOESNT_INTERSECT = 0, // Doesn't intersect INTERSECT = 1, // Intersects SAME_LINE_OVERLAP = 2, // Lines are the same ENDS_OVERLAP = 3 // Intersects at exactly one point (endpoint) }; /* This intersection is based on code by Joseph O'Rourke and is provided for use in COMP20003 Assignment 2. The approach for intersections is: - Use the bisector to construct a finite segment and test it against the half-edge. - Use O'Rourke's segseg intersection (https://hydra.smith.edu/~jorourke/books/ftp.html) to check if the values overlap. */ /* Generates a segment with each end at least minLength away in each direction from the bisector midpoint. Returns 1 if b intersects the given half-edge on this segment, 0 otherwise. Sets the intersection point to the given x, y positions. */ /* Returns -1, 0 or 1, based on the area enclosed by the three points. 0 corresponds to no area enclosed. */ int areaSign(double sx, double sy, double ex, double ey, double x, double y); /* Returns 1 if the point (x, y) is in the line from s(x, y) to e(x, y), 0 otherwise. */ int collinear(double sx, double sy, double ex, double ey, double x, double y); int collinear(double sx, double sy, double ex, double ey, double x, double y){ /* Work out area of parallelogram - if it's 0, points are in the same line. */ if (areaSign(sx, sy, ex, ey, x, y) == 0){ return 1; } else { return 0; } } int areaSign(double sx, double sy, double ex, double ey, double x, double y){ double areaSq; /* |AB x AC|^2, squared area */ /* See https://mathworld.wolfram.com/CrossProduct.html */ areaSq = (ex - sx) * (y - sy) - (x - sx) * (ey - sy); if(areaSq > 0.0){ return 1; } else if(areaSq == 0.0){ return 0; } else { return -1; } } /* Returns 1 if point (x, y) is between (sx, sy) and (se, se) */ int between(double sx, double sy, double ex, double ey, double x, double y); int between(double sx, double sy, double ex, double ey, double x, double y){ if(sx != ex){ /* If not vertical, check whether between x. */ if((sx <= x && x <= ex) || (sx >= x && x >= ex)){ return 1; } else { return 0; } } else { /* Vertical, so can't check _between_ x-values. Check y-axis. */ if((sy <= y && y <= ey) || (sy >= y && y >= ey)){ return 1; } else { return 0; } } } enum intersectType parallelIntersects(double heSx, double heSy, double heEx, double heEy, double bSx, double bSy, double bEx, double bEy, double *x, double *y); enum intersectType parallelIntersects(double heSx, double heSy, double heEx, double heEy, double bSx, double bSy, double bEx, double bEy, double *x, double *y){ if(!collinear(heSx, heSy, heEx, heEy, bSx, bSy)){ /* Parallel, no intersection so don't set (x, y) */ return DOESNT_INTERSECT; } /* bS between heS and heE */ if(between(heSx, heSy, heEx, heEy, bSx, bSy)){ *x = bSx; *y = bSy; return SAME_LINE_OVERLAP; } /* bE between heS and heE */ if(between(heSx, heSy, heEx, heEy, bEx, bEy)){ *x = bEx; *y = bEy; return SAME_LINE_OVERLAP; } /* heS between bS and bE */ if(between(bSx, bSy, bEx, bEy, heSx, heSy)){ *x = heSx; *y = heSy; return SAME_LINE_OVERLAP; } /* heE between bS and bE */ if(between(bSx, bSy, bEx, bEy, heEx, heEy)){ *x = heEx; *y = heEy; return SAME_LINE_OVERLAP; } return DOESNT_INTERSECT; } enum intersectType intersects( ... , double *x, double *y); enum intersectType intersects( ... , double *x, double *y){ /* Half-edge x, y pair */ double heSx = ...; double heSy = ...; double heEx = ...; double heEy = ...; /* Bisector x, y pair */ double bSx = ...; double bSy = ...; double bEx = ...; double bEy = ...; /* Parametric equation parameters */ double t1; double t2; /* Numerators for X and Y coordinate of intersection. */ double numeratorX; double numeratorY; /* Denominators of intersection coordinates. */ double denominator; /* See http://www.cs.jhu.edu/~misha/Spring20/15.pdf for explanation and intuition of the algorithm here. x_1 = heSx, y_1 = heSy | p_1 = heS x_2 = heEx, y_2 = heEy | q_1 = heE x_3 = bSx , y_3 = bSy | p_2 = bS x_4 = bEx , y_4 = bEy | q_2 = bE ---------------------------------------- So the parameters t1 and t2 are given by: | t1 | | heEx - heSx bSx - bEx | -1 | bSx - heSx | | | = | | | | | t2 | | heEy - heSy bSy - bEy | | bSy - heSy | Hence: | t1 | 1 | bSy - bEy bEx - bSx | | bSx - heSx | | | = --------- | | | | | t2 | ad - bc | heSy - heEy heEx - heSx | | bSy - heSy | where a = heEx - heSx b = bSx - bEx c = heEy - heSy d = bSy - bEy */ /* Here we calculate ad - bc */ denominator = heSx * (bEy - bSy) + heEx * (bSy - bEy) + bEx * (heEy - heSy) + bSx * (heSy - heEy); if(denominator == 0){ /* In this case the two are parallel */ return parallelIntersects(heSx, heSy, heEx, heEy, bSx, bSy, bEx, bEy, x, y); } /* Here we calculate the top row. | bSy - bEy bEx - bSx | | bSx - heSx | | | | | | | | bSy - heSy | */ numeratorX = heSx * (bEy - bSy) + bSx * (heSy - bEy) + bEx * (bSy - heSy); /* Here we calculate the bottom row. | | | bSx - heSx | | | | | | heSy - heEy heEx - heSx | | bSy - heSy | */ numeratorY = -(heSx * (bSy - heEy) + heEx * (heSy - bSy) + bSx * (heEy - heSy)); /* Use parameters to convert to the intersection point */ t1 = numeratorX/denominator; t2 = numeratorY/denominator; *x = heSx + t1 * (heEx - heSx); *y = heSy + t1 * (heEy - heSy); /* Make final decision - if point is on segments, parameter values will be between 0, the start of the line segment, and 1, the end of the line segment. */ if (0.0 < t1 && t1 < 1.0 && 0.0 < t2 && t2 < 1.0){ return INTERSECT; } else if(t1 < 0.0 || 1.0 < t1 || t2 < 0.0 || 1.0 < t2){ /* s or t outside of line segment. */ return DOESNT_INTERSECT; } else { /* ((numeratorX == 0) || (numeratorY == 0) || (numeratorX == denominator) || (numeratorY == denominator)) */ return ENDS_OVERLAP; } }