bool PointProjectionTools::segmentIntersect(const CCVector2& A, const CCVector2& B, const CCVector2& C, const CCVector2& D) { CCVector2 AB = B-A; CCVector2 AC = C-A; CCVector2 AD = D-A; PointCoordinateType cross_AB_AC = AB.cross(AC); PointCoordinateType cross_AB_AD = AB.cross(AD); //both C and D are on the same side of AB? if (cross_AB_AC * cross_AB_AD > 0) { //no intersection return false; } CCVector2 CD = D-C; CCVector2 CB = B-C; PointCoordinateType cross_CD_CA = -CD.cross(AC); PointCoordinateType cross_CD_CB = CD.cross(CB); //both A and B are on the same side of CD? if (cross_CD_CA * cross_CD_CB > 0) { //no intersection return false; } PointCoordinateType cross_AB_CD = AB.cross(CD); if (fabs(cross_AB_CD) != 0) //AB and CD are not parallel { //where do they intersect? //PointCoordinateType v = cross_AB_AC/cross_AB_CD; //assert(v >= 0 && v <= 1); return true; } else //AB and CD are parallel (therefore they are colinear - see above tests) { PointCoordinateType dAB = AB.norm(); PointCoordinateType dot_AB_AC = AB.dot(AC); if (dot_AB_AC >= 0 && dot_AB_AC < dAB * AC.norm()) { //C is between A and B return true; } PointCoordinateType dot_AB_AD = AB.dot(AD); if (dot_AB_AD >= 0 && dot_AB_AD < dAB * AD.norm()) { //D is between A and B return true; } //otherwise there's an intersection only if B and C are on both sides! return (dot_AB_AC * dot_AB_AD < 0); } }
/** Only if the point lies 'in front of' the segment! Returns -1.0 otherwise. **/ PointCoordinateType ComputeSquareDistToEdge(const CCVector2& P, const CCVector2& A, const CCVector2& B) { CCVector2 AP = P-A; CCVector2 AB = B-A; PointCoordinateType dot = AB.dot(AP); // = cos(PAB) * ||AP|| * ||AB|| if (dot < 0) { //return AP.norm2(); return -1.0; } else { PointCoordinateType squareLengthAB = AB.norm2(); if (dot > squareLengthAB) { //return (P-B).norm2(); return -1.0; } else { CCVector2 HP = AP - AB * (dot / squareLengthAB); return HP.norm2(); } } }
/** \return The nearest point distance (or -1 if no point was found!) **/ static PointCoordinateType FindNearestCandidate( unsigned& minIndex, const VertexIterator& itA, const VertexIterator& itB, const std::vector<Vertex2D>& points, const std::vector<HullPointFlags>& pointFlags, PointCoordinateType minSquareEdgeLength, PointCoordinateType maxSquareEdgeLength, bool allowLongerChunks = false) { //look for the nearest point in the input set PointCoordinateType minDist2 = -1; CCVector2 AB = **itB - **itA; PointCoordinateType squareLengthAB = AB.norm2(); unsigned pointCount = static_cast<unsigned>(points.size()); for (unsigned i = 0; i < pointCount; ++i) { const Vertex2D& P = points[i]; if (pointFlags[P.index] != POINT_NOT_USED) continue; //skip the edge vertices! if (P.index == (*itA)->index || P.index == (*itB)->index) continue; //we only consider 'inner' points CCVector2 AP = P - **itA; if (AB.x * AP.y - AB.y * AP.x < 0) { continue; } PointCoordinateType dot = AB.dot(AP); // = cos(PAB) * ||AP|| * ||AB|| if (dot >= 0 && dot <= squareLengthAB) { CCVector2 HP = AP - AB * (dot / squareLengthAB); PointCoordinateType dist2 = HP.norm2(); if (minDist2 < 0 || dist2 < minDist2) { //the 'nearest' point must also be a valid candidate //(i.e. at least one of the created edges is smaller than the original one //and we don't create too small edges!) PointCoordinateType squareLengthAP = AP.norm2(); PointCoordinateType squareLengthBP = (P - **itB).norm2(); if ( squareLengthAP >= minSquareEdgeLength && squareLengthBP >= minSquareEdgeLength && (allowLongerChunks || (squareLengthAP < squareLengthAB || squareLengthBP < squareLengthAB)) ) { minDist2 = dist2; minIndex = i; } } } } return (minDist2 < 0 ? minDist2 : minDist2/squareLengthAB); }
//! Returns true if the AB and CD segments intersect each other bool Intersect(const CCVector2& A, const CCVector2& B, const CCVector2& C, const CCVector2& D) { if (cross(A,B,C) * cross(A,B,D) >= 0) //both points are on the same side? No intersection return false; CCVector2 AB = B-A; CCVector2 AC = C-A; CCVector2 CD = D-C; PointCoordinateType q = CD.y * AB.x - CD.x * AB.y; if (fabs(q) > ZERO_TOLERANCE) //AB and CD are not parallel { //where do they interest? PointCoordinateType p = AC.x * AB.y - AC.y * AB.x; PointCoordinateType v = p/q; if (v <= 0 || v >= 1) //not CD! return false; //test further with AB p = CD.y * AC.x - CD.x * AC.y; v= p/q; return (v > 0 && v < 1); //not AB? } else //AB and CD are parallel { PointCoordinateType dAB = AB.norm(); PointCoordinateType dAC = AC.norm(); PointCoordinateType dot = AB.dot(AC) / (dAB * dAC); if (fabs(dot) < 0.999) { //not colinear return false; } else { //colinear --> do they actually intersect? return (dAC < dAB || (D-A).norm() < dAB); } } }