You can determine whether a polyline is winding clockwise or counterclockwise by tracking round the polyline, and checking if each segment bends to the left or the right. The following code snippet does this. It sums up the total turn of each segment. This can be within the segment ( if its an arc ) or between one segment and the next. The result of the function is a winding number. If it winds to the left, it will be positive; if it winds to the right, it will be negative. Note that the algorithm does not determine whether the polyline is self-intersecting and could even fail if the polyline is indeed self-intersecting.
Adesk::Boolean polyWindingNumber( AcDbPolyline*pPoly, int&winding ) { if( !pPoly->isClosed() ) { return Adesk::kFalse; } double turn = 0; int nSegs = pPoly->numVerts(); AcGeVector3dArray startTans(nSegs); AcGeVector3dArray endTans(nSegs); double TWOPI = 6.28318530718; double PIBYTWO = 1.570796326795; for( int i=0;isegType(i) == AcDbPolyline::kArc ) { AcGeCircArc2d arc; pPoly->getArcSegAt(i, arc ); AcGeVector2d startTan; AcGeVector2d endTan; AcGeVector2dArray startDerivs; arc.evalPoint( arc.startAng(), 1, startDerivs ); startTan = startDerivs[0]; AcGeVector2dArray endDerivs; arc.evalPoint( arc.endAng(), 1, endDerivs); endTan = endDerivs[0]; startTans.append(AcGeVector3d(startTan.x, startTan.y,0.0)); endTans.append(AcGeVector3d(endTan.x, endTan.y, 0.0)); double ang = arc.endAng() - arc.startAng(); turn += arc.isClockWise() ? -ang : ang; } else if(pPoly->segType(i) == AcDbPolyline::kLine ) { AcGeLineSeg2d line; pPoly->getLineSegAt(i, line ); AcGeVector2d tan2d = line.endPoint() -line.startPoint(); AcGeVector3d tan = AcGeVector3d( tan2d.x, tan2d.y, 0.0); startTans.append(tan); endTans.append(tan); } } nSegs = startTans.length(); for(int i=0;i 0 ? angle: -angle; turn += angle; } turn = turn / TWOPI; double lower = floor( turn ); double tol = 1e-6; if( (turn - lower ) < tol) winding = (int)lower; else if( (( lower + 1 ) - turn ) < tol ) winding = (int)(lower + 1); else return Adesk::kFalse; return Adesk::kTrue; } static void AsdkUtilsPolyWind(void) { ads_name eName; ads_point pt; if( RTNORM != acedEntSel(L"nPlease pick a polyline to test", eName, pt) ) return; AcDbObjectId id; acdbGetObjectId( id, eName ); AcDbPolyline*pPoly; acdbOpenObject(pPoly, id, AcDb::kForRead ); if(pPoly == NULL ) return; int winding =0; if( polyWindingNumber(pPoly, winding ) ) { acutPrintf(L"nPolygon has winding number %d", winding ); } else { acutPrintf(L"nCannot calculate winding number for polyline"); } pPoly->close(); }

Leave a Reply