double angleBetween(const LineSegment& one, const LineSegment& two) // will return angle in radians measured from line one to line two -- negative if one has greater slope than two { // assume both lines pass through the origin -- find the angles each form with the x axis using the slope // atan returns -pi/2 to +pi/2 double angle1 = atan(one.slope()); double angle2 = atan(two.slope()); double ret = 0.0; // If the slopes of the lines have the same, they are in the same quadrent if( (one.slope() >= 0 && two.slope() >= 0) || (one.slope() < 0 && two.slope() < 0)) { // simply return the difference between the angles of the two lines ret = angle1 - angle2; } else { // lines fall in different quadrents // Add the absolute values of the two lines, then set the sign based on which slope has the greater absolute value ret = fabs(angle1) + fabs(angle2); // if line one has a slope > 0, then sign of difference is negative if(one.slope() > 0) { ret = -1*ret; } } return ret; }
Coord findIntersection(LineSegment& one, LineSegment& two, bool extrapolate) { Coord foundCoord = noCoord; // return variable, defaults to noCoord if cannot find // get point-slope information for each line // point-slope: form Y-y1 = m(X-x1) one.normalize(); two.normalize(); double m1 = one.slope(); double m2 = two.slope(); Coord pt1 = one.A; Coord pt2 = two.A; // check for same-slope ... if so, then must do something else if(m1 == m2) { // check to see if the lines have overlapping endpoints - if so, choose one of those endpoints if( one.onSegment(two.A) ) foundCoord = two.A; if( one.onSegment(two.B) ) foundCoord = two.B; if( two.onSegment(one.A) ) foundCoord = one.A; if( two.onSegment(one.B) ) foundCoord = one.B; } else // if lines have different slopes, derive coordinates of intersection from intersection of point-slope formulas { // edge case: check for infinite slope on either one if(isinf<double>(m1)) { // TODO } if(isinf<double>(m2)) { // TODO } foundCoord.x = (pt2.y - pt1.y + m1*pt1.x - m2*pt2.x) / (m1 - m2); foundCoord.y = m1*(foundCoord.x - pt1.x) + pt1.y; // if we are constraining this to the actual points within the segments, need to make sure it exists on both segments if(!extrapolate) { if( !one.onSegment(foundCoord) || !two.onSegment(foundCoord) ) { foundCoord = noCoord; // cannot find this point on both segments } } } return foundCoord; }
Coord findIntersection(LineSegment& one, LineSegment& two, double extrapolatePercentage) { // extrapolate both lines out by making new segments that are larger one.normalize(); two.normalize(); // A < B // line one double ext1 = extrapolatePercentage*one.length(); Coord A1 (one.A.x-ext1, one.A.y-ext1*one.slope()); Coord B1 (one.B.x+ext1, one.B.y+ext1*one.slope()); LineSegment L1 (A1, B1); // line one double ext2 = extrapolatePercentage*two.length(); Coord A2 (two.A.x-ext2, two.A.y-ext2*two.slope()); Coord B2 (two.B.x+ext2, two.B.y+ext2*two.slope()); LineSegment L2 (A2, B2); // lines are now ready for intersection check return findIntersection(L1, L2, false); }
bool LineSegment::colinear(const LineSegment& l) const // lines are colinear if their slopes are the same AND if there is a point they both pass through { if(l.slope() != slope()) return false; // assert: lines are the same slope LineSegment buffer1(l); // to preserve const LineSegment buffer2(*this); if( findIntersection(buffer1, buffer2, true) == noCoord) // check for a point lying on both lines return false; // assert: we found a point that lies on both lines return true; }