.NET

Reply
Contributor
dmleves49
Posts: 18
Registered: ‎04-21-2011
Message 1 of 8 (741 Views)

Offset Irregularity

741 Views, 7 Replies
08-09-2011 10:52 AM

I've modified my offset quantity using GetOffsetCurves to be a negative number so as to ensure that my offset polyline is always inside the original but it is working erratically. Sometimes it is outside with a negative number and other times inside. I was thinking of testing the resulting Plines length to ensure that it is smaller (I realise there could possibly be morew than one but this would not happen in my case.)

 

Does this sound overly cumbersome? Would a rollback be necessary to "undo" the polyline if it is longer and therefore outside the original?

 

Any suggestions would be welcome.

 

Dale

Valued Mentor
fieldguy
Posts: 376
Registered: ‎03-31-2005
Message 2 of 8 (723 Views)

Re: Offset Irregularity

08-09-2011 03:33 PM in reply to: dmleves49

We had this problem as well - we wanted to offset a pline inside.  We found that the direction the pline was created determined which way a negative offset went.  I can't remember which is which now - I'd guess that a counter clockwise pline and a negative offset would result in "inside".  I like your idea that it should be smaller.

 

Are you using a transaction?  If so, you could test that the new pline is shorter and only committ the transaction if it passes.  There is probably several ways.

 

Thanks for the idea!

*Expert Elite*
chiefbraincloud
Posts: 753
Registered: ‎02-13-2008
Message 3 of 8 (718 Views)

Re: Offset Irregularity

08-09-2011 05:09 PM in reply to: fieldguy

I have a function in which I had exactly the same problem.  My solution at the time was to do what the OP asked about, and check the length of the resultant polyline, and just dispose it if it was wrong. 

 

I have been fiddling with it today, and discovered that it did seem to be related to the direction the polyline was drawn, so I wrote a simple routine to try to determine what direction the polyline was drawn, and now I'm going to try to utilize that in my OffsetPoly function.

 

FYI my simple routine to CheckPolyDir works for me because I can expect a certain level of simplicity in the polylines I'm dealing with.  The more complicated the polyline, the more difficult it would be to figure out the direction.

Dave O.                                                                  Sig-Logos32.png
Board Manager
StephenPreston
Posts: 400
Registered: ‎05-22-2006
Message 4 of 8 (713 Views)

Re: Offset Irregularity

08-09-2011 05:51 PM in reply to: chiefbraincloud

No matter how complex the closed polygon, the total angle subtended by the segments will tell you whether the polyline runs clockwise or counterclockwise. Here's an ObjectARX DevNote from the ADN website. This should be suitable pseudo-code for creating a .NET equivalent. You'll have to test whether running this test is faster than performing the offset (I suspect it is).

 

>>>

How to test the winding (turn) of a closed polyline?

 
Issue

How can I test whether a polyline winds clockwise or counterclockwise?

 
Solution

This can be determined 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 test does not determine whether the polyline is self-intersecting.

One detail to note is that the algorithm will fail if the pline cuts back on itself along the same line.

 

 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;i<nSegs; i++ )
  {
   if( pPoly->segType(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<nSegs; i++ )
  {
   double angle = endTans[i].angleTo( startTans[(i+1)%nSegs] );   
   AcGeVector3d norm =  endTans[i].crossProduct(startTans[(i+1)%nSegs] ); 
   angle = norm.z > 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)
 {
   // TODO: Implement the command  
  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();
    // end of function
 }

<<<

 

Cheers,

Stephen Preston
Autodesk Developer Network
*Expert Elite*
chiefbraincloud
Posts: 753
Registered: ‎02-13-2008
Message 5 of 8 (706 Views)

Re: Offset Irregularity

08-09-2011 08:26 PM in reply to: StephenPreston

Thanks for chiming in Stephen.  I watch this group via RSS feed, and I've been pleased by the recent increase in posts by the ADN team.  You in particular, but I have noticed a couple of other names I recognize as well.

 

My algorithm does the same thing (I shortened the process with an assumption that is safe for my particular purpose, but not for all purposes), but I tend to only provide answers here that relate to the AutoCAD API's, or occasionally basic programming stuff, but not Mathematics, Trigonometry, or Geometry, which is where I feel this particular problem lies.

Dave O.                                                                  Sig-Logos32.png
Contributor
dmleves49
Posts: 18
Registered: ‎04-21-2011
Message 6 of 8 (703 Views)

Re: Offset Irregularity

08-09-2011 08:42 PM in reply to: StephenPreston

Thanks alot Stephen! I suspected it was something to do with the way the polyline was created (Winding). I just finished reading "Creating Geometric and Dimensional Constraints..." not 5 minutes ago. A little above my head but a little stretching never hurts. I'll get some much needed training by translating this code into VB .net!

 

Thank you again very much.

 

Dale

Distinguished Mentor
gasty1001
Posts: 533
Registered: ‎04-11-2010
Message 7 of 8 (696 Views)

Re: Offset Irregularity

08-09-2011 09:37 PM in reply to: dmleves49

Hi,

 

Other way to test CCW/CW of a polyline is to calculate the "oriented area" of the pline, it sign will tell if is it ccw or cw, like this :

 

Public Function IsCCW(ByVal pl As Polyline) As Boolean
        Dim pc As New Point3dCollection
        Dim sp, ep As Double
                sp = pl.StartParam
        ep = pl.EndParam

        For i = sp To ep
            pc.Add(pl.GetPointAtParameter(i))
        Next

        If Not pl.Closed Then
            pc.Add(pl.GetPointAtParameter(sp))
        End If

        Dim s As Double = 0
        Dim n As Integer = pc.Count - 2

        For i = 0 To n
            Dim p1 As Point3d = pc(i)
            Dim p2 As Point3d = pc(i + 1)

            s = s + (p1.X * p2.Y - p2.X * p1.Y)
        Next

        If s > 0 Then
            Return True
        Else
            Return False
        End If
End Function

Valued Contributor
FFlix
Posts: 95
Registered: ‎11-15-2011
Message 8 of 8 (619 Views)

Re: Offset Irregularity

11-28-2011 09:44 AM in reply to: dmleves49

FYI - or,

 

a practical solution is to set a datum, offset with positive value and if the distance to datum is larger/smaller than from the original then offset by negative value.

 

(start- and endpoints of a polyline, and therefore its overall direction, may be checked with the associated start and endparam property. if the poly is closed, a third point and param could be retrieved.)

 

felix

Post to the Community

Have questions about Autodesk products? Ask the community.

New Post
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.