turn on suggestions

Auto-suggest helps you quickly narrow down your search results by suggesting possible matches as you type.

Showing results for

Close

.NET

- Autodesk Community
- >
- AutoCAD Customization
- >
- .NET
- >
- Re: Offset Irregularity

Topic Options

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic to the Top
- Bookmark
- Subscribe
- Printer Friendly Page

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

737 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

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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!

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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.

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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?

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

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

Stephen Preston

Autodesk Developer Network

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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.

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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

- Mark as New
- Bookmark
- Subscribe
- Subscribe to RSS Feed
- Highlight
- Email to a Friend
- Report Inappropriate Content

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

Search This Board

Auto-suggest helps you quickly narrow down your search results by suggesting possible matches as you type.

Showing results for

Need installation help?

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

- Privacy | Legal Notices & Trademarks | Report Noncompliance | Site map | © Copyright 2014 Autodesk Inc. All rights reserved

Except where otherwise noted, this work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. Please see the Autodesk Creative Commons FAQ for more information.