Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Find the midpoint of a bulge in a polyline

24 REPLIES 24
SOLVED
Reply
Message 1 of 25
cncah
3504 Views, 24 Replies

Find the midpoint of a bulge in a polyline

Hello again. I was working on a lisp program this weekend that would automatically create the geometry necessary for milling parts on our CNC router. Thanks to a great amount of help from this forum I was able to obtain quite a bit of information. After getting the program to work on the part I was using as a template, I've now been trying it out on some other parts here at work and finding out that I will have to go a different route on comparing the vertex points and bulges to make the program work for multiple styles of parts instead of parts that match my template dwg. I'm wondering how to find the midpoint of a bulge arc? I've been looking online and seen how to get the chord length, but I'm needing to find the midpoint of the arc in each bulge of the polyline. Here is a picture of what I'm needing to find. I've placed the X,Y zero on the midpoint.I appreciate any help as always.

Polyline Bulge Midpoint.JPG

24 REPLIES 24
Message 2 of 25
Kent1Cooper
in reply to: cncah


@cncah wrote:

.... I'm wondering how to find the midpoint of a bulge arc? I've been looking online and seen how to get the chord length, but I'm needing to find the midpoint of the arc in each bulge of the polyline. ....

 


Probably the easiest way is by (vlax-curve) Parameter values, since it doesn't require any geometrical calculations.  The vertex at the start of the arc segment will have a whole-number Parameter value, and the vertex at the end of it will have the next whole-number Parameter value.  If, for example, the vertext at the start is the second vertex in the Polyline, that will be at Parameter value 1.0 [the beginning of the entire Polyline is Parameter value zero].  From there, you can get the midpoint of the arc segment by adding 0.5 to the Parameter value of the vertex at its start -- Parameter values are linear between vertices.  This would return the arc midpoint in that case:

 

(vlax-curve-getPointAtParam PolylineEntityName 1.5)

 

The same approach will also find the midpoint of a line segment.

 

If you have reason to save the Polyline as a VLA Object with (vlax-ename->vla-object) for other purposes, the (vlax-curve...) functions can work with either that or its entity name.

Kent Cooper, AIA
Message 3 of 25
cncah
in reply to: Kent1Cooper

That works! It gave the midpoint for 1 of the bulges, but how do I get it to return a value for each one? I haven't used vla or vlax commands yet and don't know if there is a way to apply this to all vertices of my vertex list. Or would I need to create a different list altogether using mapcar and lambda in a foreach loop?

Message 4 of 25
hencoop
in reply to: cncah

I use my old polyline bulge function for working with bulges.  It uses some formulas I regularly refer to on page 6-18 "Properties of the Circle" in the Miscellaneous Data and Mathematical Tables section of my well used AISC Manual of Steel Construction - Eigth Edition.  I am sure that it is not exclusive to this publication.
This function requires the bulged vertex point and the point following, e.g., ((CDR (ASSOC 10 <bulged vertex entity data>))(ASSOC 42 <next vertex entity data>))(CDR (ASSOC 10 <next vertex entity data>)). The polyline must not be an LWPolyline when obtaining the entity data (CONVERTPOLY converts them to Heavy polylines).
After invoking this function I would just plot the point thus (POLAR radpt radang arcrad) which would return the arc midpoint. Not too slick but this function will handle just about every polyline bulge problem I ever have.

(DEFUN seg_dist (a b /) ; 'a' is a list, a=((pline vertex point)(assoc 42 <bulge vertex entity data>)) b=(next vertex point) ; seg_dist sets the following variables from "point-bulge-point" (polyline style) arc definition: ; i_ang = included angle ; chordlen = chord length ; chordang = angle of chord a-b (2D - in XY plane) ; arcrad = radius ; radang = angle of radius from center point through midpoint of chord ; radpt = radius point ; seg_len = length of arc along circumference ; tan_ang = angle to subtract from chord angle to calculate tangent angle (SETQ i_ang (* 4.0 (ATAN (CDADR a))) chordlen (DISTANCE (LIST (CAAR a) (CADAR a)) (LIST (CAR b) (CADR b))) chordang (ANGLE (LIST (CAAR a) (CADAR a)) (LIST (CAR b) (CADR b))) arcrad (IF (OR (ZEROP chordlen) ; [(4 b-squared) + (c-squared)]/8b = radius (ZEROP (CDADR a)) ) ;_ end of OR nil (/ (+ (* 4 (/ (* chordlen (CDADR a)) 2) ; b squared (/ (* chordlen (CDADR a)) 2) ; b is perpindicular height of arc from center of chord ) ;_ end of * (* chordlen chordlen) ; c squared; c is the chord length ) ;_ end of + (* 8 (/ (* chordlen (CDADR a)) 2)) ; 8b ) ;_ end of / ) ;_ end of IF radang (IF (ZEROP (CDADR a)) ;angle to radpt nil (+ (- chordang (* (ATAN (CDADR a)) 2)) (/ PI 2)) ) ;_ end of IF radpt (IF (ZEROP (CDADR a)) nil (IF arcrad (POLAR (CAR a) radang arcrad) nil ) ) ;_ end of IF seg_len (IF arcrad (* i_ang arcrad) chordlen ) ;_ end of IF tan_ang (* 2.0 (ATAN (CDR (ASSOC 42 a)))) ) ;_ end of setq )

 

AutoCAD User since 1989. Civil Engineering Professional since 1983
Product Ver.: 13.6.1781.0 Civil 3D 2024.3 Update
Built On:        U.152.0.0 AutoCAD 2024.1.2
                        27.0.37.14 Autodesk AutoCAD Map 3D 2024.0.1
                        8.6.52.0 AutoCAD Architecture 2024
Message 5 of 25
hencoop
in reply to: cncah

Quick correction... I mistated some info, the ASSOC 42 data should be of the bulged vertex (the 1st vertex).

AutoCAD User since 1989. Civil Engineering Professional since 1983
Product Ver.: 13.6.1781.0 Civil 3D 2024.3 Update
Built On:        U.152.0.0 AutoCAD 2024.1.2
                        27.0.37.14 Autodesk AutoCAD Map 3D 2024.0.1
                        8.6.52.0 AutoCAD Architecture 2024
Message 6 of 25
Kent1Cooper
in reply to: cncah


@cncah wrote:

That works! It gave the midpoint for 1 of the bulges, but how do I get it to return a value for each one? I haven't used vla or vlax commands yet and don't know if there is a way to apply this to all vertices of my vertex list. Or would I need to create a different list altogether using mapcar and lambda in a foreach loop?


That's quite doable, but a question:  Are you looking for a list, and if so, of midpoints of all arc segments only, or of all midpoints including those of line segments, or something that ties the arc-segment midpoints to the vertices at their ends somehow?  An example of the kind of list [or whatever] you want from an example Polyline would be helpful.  I expect it will be easier to do using the Polyline's Parameter values directly, and not starting from a list of vertices, though the latter could also be done.

Kent Cooper, AIA
Message 7 of 25
cncah
in reply to: Kent1Cooper

I was trying to use the vertices to compare them to each other based on distance and if they met a certain criteria, then create my layers and new entities as needed. So if the midpoint of the bulge could be added to the list in between each vertex point that would be perfect.

Message 8 of 25
Kent1Cooper
in reply to: cncah


@cncah wrote:

.... if the midpoint of the bulge could be added to the list in between each vertex point that would be perfect.


This will get you all vertices and all midpoints, including those of line segments:

(setq
  pl (car (entsel "\nSelect Polyline: "))
  endpar (fix (vlax-curve-getEndParam pl))
  step 0
  ptlist (list (vlax-curve-getStartPoint pl)); starting vertex
); setq
(repeat
  (if (vlax-curve-isClosed pl)
    (1- (* endpar 2)); then
    (* endpar 2); else
  ); if
  (setq ptlist
    (cons (vlax-curve-getPointAtParam pl (setq step (+ step 0.5))) ptlist); step through vertices and midpoints
  ); setq
); repeat
(reverse ptlist)

 

If for a closed Polyline you would want the end point [same as the start point] included to finish things out, then just have it repeat (* endpar 2) times without the (if) function, in which case you could dispense with the endpar variable.

 

To have it omit midpoints of line segments, it could be made to, for example, compare the angles between vertex-to-midpoint and midpoint-to-next vertex, and if they're equal, don't add that midpoint to the list.  Or it could also be made to look for midpoints only where bulge factors are non-zero, but that would involve some kind of extra step such as correlating between vertex entries in entity data and Parameter values, or a conversion to a VLA object and the use of (vla-getBulge).

Kent Cooper, AIA
Message 9 of 25
cncah
in reply to: Kent1Cooper

Thanks Kent, that should do perfectly. I greatly appreciate the help!Smiley Very Happy

Message 10 of 25
owenwengerd
in reply to: cncah

Keep in mind that Kent's algorithm relies on undocumented relationships between parameters and points on the curve. Better would be to use the distance versions instead of the parameter versions. See my QuirkyPolyline blog post for more information.

--
Owen Wengerd
ManuSoft
Message 11 of 25
cncah
in reply to: Kent1Cooper

Kent, how would the code look if you wanted discard line segments?

Message 12 of 25
Kent1Cooper
in reply to: cncah


@cncah wrote:

Kent, how would the code look if you wanted discard line segments?


Do you mean you want to leave out only the midpoints of line segments, or do you not want nothing at all about line segments, i.e. not even vertices at their ends unless they are also at the end of an arc segment?

Kent Cooper, AIA
Message 13 of 25
cncah
in reply to: Kent1Cooper

No, I would like the vertices. Just not needing to process the midpoints of the line segments.

Message 14 of 25
Kent1Cooper
in reply to: owenwengerd


@owenwengerd wrote:

Keep in mind that Kent's algorithm relies on undocumented relationships between parameters and points on the curve. Better would be to use the distance versions instead of the parameter versions. See my QuirkyPolyline blog post for more information.


Well, there's a notion I had never run across before.  It would add some to the code, and I think would require an actual list of vertices [since even at-the-vertex Parameter values in quirky Polylines neither are whole numbers nor do they differ from each other by whole numbers], but it could certainly be accounted for.  I guess one question would be how likely a Polyline is to go quirky, that is, what circumstances might make one that way?

Kent Cooper, AIA
Message 15 of 25
hencoop
in reply to: Kent1Cooper

Processing a heavy polyline is pretty simple. Depending upon how you select
it you may need to find the end (SEQEND) before the beginning (POLYLINE) but
then it is just (ENTNEXT .) to step through the vertices until the SEQEND
entity pops up again. (The SEQEND entity contains the ENAME of the
POLYLINE).

Every VERTEX of a heavy polyline will have a value for the bulge (ASSOC 42
). If the bulge value is 0 then it is a straight segment. Every
value that is not 0 indicates the start of an arc segment. Very easy to
find everything that you need without any of the "quirky". Use the function
included earlier (seg_dist .) on the VERTEX entity data with bulge > 0 and
calculate the middle of the bulge with (POLAR ).
The values are stored as variables from the use
of (seg_dist a b) as described before.



COOPER FRANCIS

Description: cid:image001.jpg@01CDD7B1.25961B30

140 Aqua Shed Court

Aberdeen End, NC 28315

Office: (910) 420-1437

Fax: (910) 637-0096

Cell: (910) 603-3487

lkcengineering.com
License No. P-1095
AutoCAD User since 1989. Civil Engineering Professional since 1983
Product Ver.: 13.6.1781.0 Civil 3D 2024.3 Update
Built On:        U.152.0.0 AutoCAD 2024.1.2
                        27.0.37.14 Autodesk AutoCAD Map 3D 2024.0.1
                        8.6.52.0 AutoCAD Architecture 2024
Message 16 of 25
Kent1Cooper
in reply to: hencoop


@hencoop wrote:
Processing a heavy polyline is pretty simple. ....

I imagine not many people use heavy 2D polylines except when it can't be avoided [e.g. they always result from Fit- or Spline-curving in Pedit].  So, cncah, are yours heavy or lightweight?  If lightweight, the (entnext) approach won't work, but the DXF 42 entries for the bulges are in the entity data -- it's just a little more complicated to tie them to their vertices, but not too hard.

Kent Cooper, AIA
Message 17 of 25
cncah
in reply to: Kent1Cooper

All lightweight.

Message 18 of 25
hencoop
in reply to: Kent1Cooper

I typically CONVERTPOLY ALL to heavy weight.  Ever since the inception of "Lightweight" polylines.  The early problems with them were more trouble than the touted benefit of space savings for files.  They still have some issues every now and again for me.

 

I found them to be more complicated to deal with in programs precisely because of the data structure and it seemed a waste of time to reprogram what I had already written just so I could use them with my programs.  I did add some code to several apps so they could handle both but I typically avoid using new things just because they are new.  If they provide a significant benefit, improvement, or advantage in my work then I'll use them.  I'm still looking for that with LWPolylines.  I've long had my polyline problems solved with respect to the still valid POLYLINE entity and it ain't broke so I didn't fix it.  If ever Autodesk eliminates the POLYLINE entity then it'll be broke and I'll have to fix it.

AutoCAD User since 1989. Civil Engineering Professional since 1983
Product Ver.: 13.6.1781.0 Civil 3D 2024.3 Update
Built On:        U.152.0.0 AutoCAD 2024.1.2
                        27.0.37.14 Autodesk AutoCAD Map 3D 2024.0.1
                        8.6.52.0 AutoCAD Architecture 2024
Message 19 of 25
Ajilal.Vijayan
in reply to: cncah

By using the bulge value

 

(vl-load-com)
(setq
  pl (car (entsel "\nSelect Polyline: "))
  plobj (vlax-ename->vla-object pl)
  step 0
  ptlist (list)
  crlist (vlax-get-property plobj 'coordinates)
  crlist (vlax-safearray->list  (variant-value crlist))
); setq

;gile
(defun mid (p1 p2)
  (mapcar '(lambda (x1 x2) (/ (+ x1 x2) 2.0)) p1 p2)
)

(repeat ( / (length crlist) 2)
(setq blg (vla-getbulge plobj step));Get the bulge value
(if ( /= blg 0)
(progn
(setq pt1 (vlax-curve-getPointAtParam plobj step ));vertex @ bulge start
(setq pt2 (vlax-curve-getPointAtParam plobj ( + step 1)));vertex @ bulge end
(setq pt3 (mid pt1 pt2));midpoint of pt1 and pt2
(setq ang (angle pt1 pt2));angle of pt1 and pt2
(setq pt4 (polar pt3 ( - ang 1.570796326794897)  (*(distance pt1 pt3 )blg)));bulge midpoint
(setq ptlist (cons pt4 ptlist))
);progn
);if
(setq step ( + step 1))
); repeat
(setq ptlist(reverse ptlist))

 

Message 20 of 25
owenwengerd
in reply to: Kent1Cooper

To make the code robust, you have to calculate the distance at each vertex (so that you can average distances to obtain the midpoint distance), but you don't actually need the vertex for anything else. A quirky polyline could come about because a third party developer makes one that way, or because Autodesk changes the AutoCAD implementation. The odds of one or both happening are 100% -- it's not a question of "if", but a question of "when".


@Kent1Cooper wrote:

Well, there's a notion I had never run across before.  It would add some to the code, and I think would require an actual list of vertices [since even at-the-vertex Parameter values in quirky Polylines neither are whole numbers nor do they differ from each other by whole numbers], but it could certainly be accounted for.  I guess one question would be how likely a Polyline is to go quirky, that is, what circumstances might make one that way?


 

--
Owen Wengerd
ManuSoft

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost