int IntersectionPoints(const Circle &circleA, const Circle &circleB, Vector2 &point1, Vector2 &point2) { const Vector2 ¢reA(circleA.GetCentre()); const Vector2 ¢reB(circleB.GetCentre()); float radiusA(circleA.GetRadius()); float radiusB(circleB.GetRadius()); Vector2 aToB(centreB - centreA); float distSq = aToB.MagnitudeSquared(); if (distSq == 0.0f) { // circles have the same centre // either 0 or infinite number of intersection points return 0; } float dist = Sqrt(distSq); if (dist > radiusA + radiusB || dist < Abs(radiusA - radiusB)) { // Circles are not intersecting or one is contained within the other return 0; } float distInv = 1.0f / dist; float radiusASq(radiusA * radiusA); float radiusBSq(radiusB * radiusB); float a = (radiusASq - radiusBSq + distSq) * (0.5f * distInv); float h = Sqrt(radiusASq - a * a); Vector2 aToBDir(aToB * distInv); Vector2 m(centreA + a * aToBDir); Vector2 aToBNorm(-aToBDir.y, aToBDir.x); if (h == 0.0f) { point1 = m; return 1; } else { point1 = m + h * aToBNorm; point2 = m - h * aToBNorm; return 2; } }
void TessellateTri( std::vector< bspVertex_t >& outVerts, std::vector< triangle_t >& outIndices, float amount, float normalOffsetScale, const bspVertex_t& a, const bspVertex_t& b, const bspVertex_t& c ) { auto LPassedC = [ &c ]( const glm::vec3& point, const glm::vec3& sig ) -> bool { return ( glm::sign( c.position - point ) != sig ); }; float step = 1.0f / amount; // Use these as a basis for when either the a or b traversal vectors // have passed vertex c glm::vec3 aSig = glm::sign( c.position - a.position ); glm::vec3 bSig = glm::sign( c.position - b.position ); std::unique_ptr< baryCoordSystem_t > triCoordSys( new baryCoordSystem_t( a.position, b.position, c.position ) ); bspVertex_t bToC( ( c - b ) * step ); bspVertex_t aToC( ( c - a ) * step ); bspVertex_t aToBStep( ( b - a ) * step ); std::vector< triangle_t > curStrip; // Points which walk along the edges bspVertex_t a2( a ); bspVertex_t b2( b ); while ( true ) { if ( glm::any( glm::isnan( a2.position ) ) || glm::any( glm::isnan( b2.position ) ) ) break; // If either of these are set to true, then we'll have // triangles which exist outside of the parent tri. if ( LPassedC( a2.position, aSig ) || LPassedC( b2.position, bSig ) ) break; if ( a2.position == c.position || b2.position == c.position ) break; // Path trace the edges of our triangle defined by vertices a2 and b2 bspVertex_t aToB( b2 - a2 ); float walk = 0.0f; float walkLength = 0.0f; float walkStep = glm::length( aToBStep.position ) / glm::length( aToB.position ); float endLength = glm::length( aToB.position ); while ( walkLength < endLength ) { bspVertex_t gv1( a2 + aToB * walk ); bspVertex_t gv2( gv1 + aToBStep ); bspVertex_t gv3( gv1 + aToC ); bspVertex_t gv4( gv3 + aToBStep ); gv1.position += gv1.normal * normalOffsetScale; gv2.position += gv2.normal * normalOffsetScale; gv3.position += gv3.normal * normalOffsetScale; gv4.position += gv4.normal * normalOffsetScale; size_t numVertices; triangle_t t1; // There should be a reasonable workaround for this; maybe scale // the vertices or something like that. if ( !triCoordSys->IsInTri( gv3.position ) || !triCoordSys->IsInTri( gv2.position ) ) goto end_iteration; numVertices = outVerts.size(); gv1.color = glm::u8vec4( 255 ); gv2.color = glm::u8vec4( 255 ); gv3.color = glm::u8vec4( 255 ); { auto v1Iter = std::find( outVerts.begin(), outVerts.end(), gv1 ); if ( v1Iter == outVerts.end() ) { outVerts.push_back( gv1 ); t1.indices[ 0 ] = numVertices++; } else { t1.indices[ 0 ] = v1Iter - outVerts.begin(); } auto v2Iter = std::find( outVerts.begin(), outVerts.end(), gv2 ); if ( v2Iter == outVerts.end() ) { outVerts.push_back( gv2 ); t1.indices[ 1 ] = numVertices++; } else { t1.indices[ 1 ] = v2Iter - outVerts.begin(); } auto v3Iter = std::find( outVerts.begin(), outVerts.end(), gv3 ); if ( v3Iter == outVerts.end() ) { outVerts.push_back( gv3 ); t1.indices[ 2 ] = numVertices++; } else { t1.indices[ 2 ] = v3Iter - outVerts.begin(); } } curStrip.push_back( t1 ); // Attempt a second triangle, providing v4 // is within the bounds if ( !triCoordSys->IsInTri( gv4.position ) ) goto end_iteration; { auto v4Iter = std::find( outVerts.begin(), outVerts.end(), gv4 ); triangle_t t2 = { { t1.indices[ 2 ], t1.indices[ 1 ], 0 } }; if ( v4Iter == outVerts.end() ) { outVerts.push_back( gv4 ); t2.indices[ 2 ] = numVertices; } else { t2.indices[ 2 ] = v4Iter - outVerts.begin(); } curStrip.push_back( t2 ); } end_iteration: walk += walkStep; walkLength = glm::length( aToB.position * walk ); } outIndices.insert( outIndices.end(), curStrip.begin(), curStrip.end() ); curStrip.clear(); a2 += aToC; b2 += bToC; } }