bool ribi::Geometry::IsCounterClockwise(const Doubles& angles) const noexcept { const int sz = static_cast<int>(angles.size()); assert(sz >= 2 && "Need at least two angles to determine if these are counter-clockwise"); for (int i=0; i!=sz-1; ++i) { if (!IsCounterClockwise(angles[i],angles[i+1])) return false; } //Calculate cumulative clockwise distance const double tau{boost::math::constants::two_pi<double>()}; double sum{0.0}; for (int i=0; i!=sz-1; ++i) { const double diff{angles[i] - angles[i+1]}; //Order reversed compared to IsClockwise if (diff > 0.0) { sum += diff; } else { assert(diff + tau > 0.0); sum += (diff + tau); } } return sum < tau; }
bool ribi::Geometry::IsCounterClockwiseCartesianHorizontal(const Coordinats2D& points) const noexcept { //Points are determined from their center const auto center(CalcCenter(points)); Doubles angles; angles.reserve(points.size()); std::transform(points.begin(),points.end(), std::back_inserter(angles), [this,center](const Coordinat2D& coordinat) { return GetAngleClockCartesian( coordinat - center ); } ); return IsCounterClockwise(angles); }
/// //Uses the Jarvis March algorithm to determine the smallest convex hull around //a 2D set of points in the XY plane. // //Parameters: // hullList: The list to store all points on the hull // rigidBodies: The list of all pointmasses which we are forming the hull around void JarvisMarch(std::vector<int> &hullList, const std::vector<RigidBody> &rigidBodies) { //Step 1: Find the left-most point int pointOnHull = 0; int size = rigidBodies.size(); for(int i = 1; i < size; i++) { if(rigidBodies[i].position.x < rigidBodies[pointOnHull].position.x) pointOnHull = i; } //Step 2: Create second variable to hold prospective points on the hull which can still be outruled int endPoint = 0; //Until we loop back around to the left-most point while(hullList.size() <= 0 || endPoint != hullList[0]) { //Add the current point to the hull list hullList.push_back(pointOnHull); //Set the current prospective point as the first point endPoint = 0; for(int i = 1; i < size; i++) { //Construct an edge from the last point on the hull to the ith point glm::vec2 edge1 = glm::vec2(rigidBodies[i].position - rigidBodies[pointOnHull].position); //Construct an edge from the last point on the hull to the current prospective point glm::vec2 edge2 = glm::vec2(rigidBodies[endPoint].position - rigidBodies[pointOnHull].position); //If the edge to the ith point is counter clockwise with respect to the edge to the prospective point //Set the prospective point to the point at i if(endPoint == pointOnHull || IsCounterClockwise(edge1, edge2)) { endPoint = i; } } //Set the point on hull pointOnHull = endPoint; } }
ol::Collision ol::Shape:: LineStripCollision( const std_container1 &vertices, const std_container2 &otherVertices, const Placement &thisPlacement, const Placement &otherPlacement, bool getResults, bool thisConnectFirstAndLast, bool otherConnectFirstAndLast ) const { if( vertices.size() < 2 || otherVertices.size() < 2 ) { OlError( "An empty shape can't ever collide!" ); return Collision( false ); } Vec2D thisCo = thisPlacement.GetPosition(); Vec2D otherCo = otherPlacement.GetPosition(); Matrix2D thisTransform = thisPlacement.Get2DMatrix(); Matrix2D otherTransform = otherPlacement.Get2DMatrix(); typename std_container1::const_iterator thisIter = vertices.begin(); const Vec2D rotationPivot = thisPlacement.GetRotationPivot(); const Vec2D otherRotationPivot = otherPlacement.GetRotationPivot(); Vec2D thisPrev = thisTransform.Transform( *thisIter - rotationPivot ) + thisCo + rotationPivot; thisIter++; std::vector< LinePair * > segmentLists; // Loop through each vertex // while( true ) { bool breakNow = false; // Test if we've reached the last line segment // if( thisIter == vertices.end() ) { if( !thisConnectFirstAndLast ) { break; } breakNow = true; thisIter = vertices.begin(); } Vec2D thisVertex = thisTransform.Transform( *thisIter - rotationPivot ) + thisCo + rotationPivot; thisIter++; typename std_container2::const_iterator otherIter = otherVertices.begin(); Vec2D otherPrev = otherTransform.Transform( *otherIter - otherRotationPivot ) + otherCo + otherRotationPivot; otherIter++; // Loop through each vertex of the other polygon // while( true ) { bool breakNow = false; // Test if we've reached the last line segment of the other polygon // if( otherIter == otherVertices.end() ) { if( !otherConnectFirstAndLast ) { break; } breakNow = true; otherIter = otherVertices.begin(); } Vec2D otherVertex = otherTransform.Transform( *otherIter - otherRotationPivot ) + otherCo + otherRotationPivot; otherIter++; // Test for collision // if( IsCounterClockwise( thisPrev, thisVertex, otherPrev ) != IsCounterClockwise( thisPrev, thisVertex, otherVertex ) && IsCounterClockwise( otherPrev, otherVertex, thisPrev ) != IsCounterClockwise( otherPrev, otherVertex, thisVertex )) { if( !getResults ) { return Collision( true ); } else { Line thisLine( thisVertex, thisPrev ); Line otherLine( otherVertex, otherPrev ); segmentLists.push_back( new LinePair( thisLine, otherLine )); /* return Collision( thisLine, otherLine );*/ } } // Is last line segment of the other polygon processed? // if( breakNow ) { break; } // Advance to the next vertex of the other polygon // otherPrev = otherVertex; } // Is last line segment processed? // if( breakNow ) { break; } // Advance to the next vertex // thisPrev = thisVertex; } if( !segmentLists.empty() ) { return Collision( segmentLists ); } return Collision( false ); }