Author Topic: Intersect with - how to get those points?  (Read 8170 times)

0 Members and 1 Guest are viewing this topic.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Intersect with - how to get those points?
« on: October 12, 2011, 04:57:33 AM »
I'm having some difficulty with a little routine of mine. I'm trying to make a lisp which draws a roller-shutter section. Now I'm using a helix to make the spiral around the winding pole, then I've got some variation in blocks depicting the slats / grille joints.

So the idea is to use the length of the block as a radius for a circle starting from the origin (vlax-curve-getPointAtParam obj 0.0). Then obtaining the intersections and finding the one (if more than one) where the point's parameter is the least, yet still more than the previous (i.e. the next intersection to define the next insertion as well as the current rotation).

The problem I'm having is to find the intersections. E.g. I'm doing the following as test on the command-line:
Code: [Select]
Command: helix...

Command: (setq en (entlast) eo (vlax-ename->vla-object en))
#<VLA-OBJECT IAcadHelix2 3050b1f4>

Command: cr
CIRCLE Specify center point for circle or [3P/2P/Ttr (tan tan radius)]:  ...

Command: (setq cn (entlast) co (vlax-ename->vla-object cn))
#<VLA-OBJECT IAcadCircle2 3726b66c>

Command: (setq ipts (vla-IntersectWith eo co 0))
#<variant 8197 ...>

Command: (setq ipts (vlax-variant-value ipts))
#<safearray...>

Command: (setq ipts (vlax-safearray->list ipts))
; error: ActiveX Server returned an error: Invalid index

Command: (vlax-safearray-get-dim ipts)
1

Command: (vlax-safearray-get-element ipts 0)
; error: ActiveX Server returned an error: Invalid index
As you can see I'm unable to convert the safearray to a list. Nor can I extract the first element. Is this some issue with a helix perhaps?

Edit: BTW, I've tried this as well:
Code: [Select]
Command: (vlax-safearray-get-element ipts 1)
; error: ActiveX Server returned an error: Invalid index

Command: (vlax-safearray-get-l-bound ipts 0)
; error: ActiveX Server returned an error: Invalid index

Command: (vlax-safearray-get-l-bound ipts 1)
0
« Last Edit: October 12, 2011, 05:03:19 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Intersect with - how to get those points?
« Reply #1 on: October 12, 2011, 05:15:48 AM »
As an example, this is the type of thing I'm trying to achieve. Though drawing that manually took me 2 hours, and due to several differences (box-size due to height & slat lengths) one of these sections is simply not going to cut it on this project.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

ribarm

  • Gator
  • Posts: 3225
  • Marko Ribar, architect
Re: Intersect with - how to get those points?
« Reply #2 on: October 12, 2011, 05:43:01 AM »
Maybe this can help you... It helped me in some situations...

Lee-Mac subfunctions - intersections

or this :

ge_intersectwith.lsp

M.R.

As you can see in ge_intersectwith.lsp, intersectwith supports SPLINE objecct, so perhaps if you can convert Helix to Spline, you should achieve intersection between spline and circle...
« Last Edit: October 12, 2011, 05:56:18 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3225
  • Marko Ribar, architect
Re: Intersect with - how to get those points?
« Reply #3 on: October 12, 2011, 06:14:30 AM »
Just checked, with "EXPLODE" you can convert Helix to Spline, but before explode do vla-copy on Helix so you can later erase dummy SPLINE... Don't use vla-Explode, just (command "_.explode" entname), because with vla-Explode after exploding you can't find object with (ssget "_P") and with simple (command "_.explode" entname) you can find object although it has changed and after explode has new entity handle, name and new all other properties, but you can find it with (ssget "_P")...

M.R.
« Last Edit: October 12, 2011, 06:33:16 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

Lee Mac

  • Seagull
  • Posts: 12906
  • London, England
Re: Intersect with - how to get those points?
« Reply #4 on: October 12, 2011, 08:25:06 AM »
Irne,

To check for an empty safearray, test the upper bound of the first dimension - this will be negative if the safearray is empty.

e.g.:

Code: [Select]
(setq var (vla-intersectwith <object1> <object2> acextendnone))

(setq arr (vlax-variant-value var))

(if (< 0 (vlax-safearray-get-u-bound arr 1))
    (vlax-safearray->list arr)
)

However, I would be inclined to use vlax-invoke, since this will return nil (empty list) as opposed to an empty safearray.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Intersect with - how to get those points?
« Reply #5 on: October 12, 2011, 08:51:54 AM »
Thanks ribarm & Lee ...  I'll probably just create the helix, then generate the spline from the DXF codes (seeing as I'm trying to steer clear of too much command-line stuff and Helix doesn't evan have a vla-Explode for it). Something like this seems to work:
Code: [Select]
(defun Helix2Spline (ename / data)
  (setq data (entmake (vl-remove-if
                        '(lambda (i) (member (car i) '(-1 5)))
                        (subst '(0 . "SPLINE")
                               '(0 . "HELIX")
                               (reverse (cdr (member '(100 . "AcDbHelix") (reverse (entget ename)))))
                        )
                      )
             )
  )
  (if (entmake data) (entlast))
)

Though even going with an explode it still gives an error:
Code: [Select]
Command: helix
...

Command: x
EXPLODE
...

Command: (setq so (vlax-ename->vla-object (entlast)))
#<VLA-OBJECT IAcadSpline2 16c566f4>

Command: cr
CIRCLE Specify center point for circle...

Command: (setq co (vlax-ename->vla-object (entlast)))
#<VLA-OBJECT IAcadCircle2 173c1334>

Command: (setq iPts (vlax-invoke so 'IntersectWith co 0))
nil

Command: (setq aPts (vlax-variant-value (vla-IntersectWith so co 0)))
#<safearray...>

Command: (vlax-safearray-get-dim aPts)
1

Command: (vlax-safearray-get-u-bound aPts 1)
-1
And I've purposefully drawn the circle to intersect the spiral 3 times, both drawn on WCS with elevations of 0 and all z values=0. So it seems it's an issue with intersects between circles and splines. I've noticed this doing the drawing manually, since an intersect OSnap doesn't want to work - have to trim the circle and then snap to the arc's end. But I'm certainly not going to do that programatically  :pissed:

Anyone know where I can read up on the math involved? I'm looking for obtaining the xy coordinates of a point at a known coord-length away from a known point on an Archimedean spiral. If I can get it mathematically I'd not even need draw the helix in the first place. But that's way over my minor league math skills  :ugly:
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Intersect with - how to get those points?
« Reply #6 on: October 12, 2011, 08:57:33 AM »
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

alanjt

  • Needs a day job
  • Posts: 5352
  • Standby for witty remark...
Re: Intersect with - how to get those points?
« Reply #7 on: October 12, 2011, 08:59:26 AM »
However, I would be inclined to use vlax-invoke, since this will return nil (empty list) as opposed to an empty safearray.
x2
Civil 3D 2019 ~ Windohz 7 64bit
Dropbox

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Intersect with - how to get those points?
« Reply #8 on: October 12, 2011, 09:30:38 AM »
Reminds me of this old lisp.
http://forums.augi.com/showthread.php?t=38106&highlight=Conveyor.lsp
Thanks Cab!

That seems to work "mostly". It's not exact as it's using the "arc-length" instead of the cord-length of the spiral. But for this purpose it seems "reasonable" - just need to adjust the "links" close to the centre.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Intersect with - how to get those points?
« Reply #9 on: October 12, 2011, 09:42:17 AM »
Oh, I see the distance is critical on the tight curves.
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Intersect with - how to get those points?
« Reply #10 on: October 12, 2011, 11:22:52 AM »
Oh, I see the distance is critical on the tight curves.
Yep. I'm working on a way to figure one out using brute force and a fuzz distance:
Code: [Select]
;;; Obtain the point a specified cord-length away from a source point along a curve
;;; Arguments: Obj  = vla-object / ename of curve
;;;            Pt   = Source point
;;;            Dist = Required cord-length (negative means to the back)
;;;            Fuzz = Allowed error in distance
(defun IB:curve-getPointAtCordDistFromPoint (Obj Pt Dist Fuzz / pa1 pa2 pt2 len len1 len2 mult)
  (setq mult (if (minusp Dist)
               -1.
               1.
             ) ;Multiplier for fuzz distance
        pa1  (vlax-curve-getParamAtPoint Obj (vlax-curve-getClosestPointTo Obj Pt)) ;Param at source
        len1 (vlax-curve-getDistAtParam Obj pa1) ;Source length
        len  Dist
        pa2  (vlax-curve-getParamAtDist Obj (+ len1 len)) ;Param at Dist away
        pt2  (vlax-curve-getPointAtParam Obj pa2) ;Point at Dist away
        len2 (vlax-curve-getDistAtParam Obj pa2) ;Destination length
  )
  ;; Loop until cord distance is close enough
  (while (not (equal (- len2 len1) Dist Fuzz))
    (setq len  (+ len (* Fuzz mult)) ;Increment length by fuzz factor (allow negative)
          pa2  (vlax-curve-getParamAtDist Obj (+ len1 len)) ;Param at Dist away
          pt2  (vlax-curve-getPointAtParam Obj pa2) ;Point at Dist away
          len2 (vlax-curve-getDistAtParam Obj pa2) ;Destination length
    )
  )
  pt2
)
Untested, but I think the principal is sound  :whistle:

Will come back with results as I'm now running into a situation where my previous advice just didn't cut the cake  :doa:
http://www.cadtutor.net/forum/showthread.php?60221-Arraying-Block-Spiral-Curve-Roller-Shutter
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

ribarm

  • Gator
  • Posts: 3225
  • Marko Ribar, architect
Re: Intersect with - how to get those points?
« Reply #11 on: October 12, 2011, 01:24:15 PM »
Irne, the problem with finding intersections with helix is that it's never planar even if you enter height 0.0...
So I've made routines that will segment helix or any other 2D object and make sure z value of segmented spline points are 0.0 if they are near 0.0 (0.0 < z value < 1e-4)... Use these first routine on your helix, and second on your circle and newly created spline from helix (green color)... You should get results...

Regards,
M.R.

Code: [Select]
(defun c:seg ( / APERT CLD CMDE ENTL ENTLAY ENTLIST ENTN K1 K1SEL K2 K2SEL KRPT LAY LAYOB N NC NN OSM PAUSE POCPT PT PT0 PTLIST PTLISTA PTN PTSEL PTSELRED PTSLEN SS )
(setq osm (getvar 'osmode))
(setq cmde (getvar 'cmdecho))
(setq apert (getvar 'aperture))
(terpri)
(prompt "\nSegmenting all 3D lines, plylines and curves with segmented SPLINE")
(prompt "\nENTER to continue")
(terpri)
(textpage)
(command "\\")
(setvar 'osmode 0)
(setvar 'cmdecho 0)
(setvar 'aperture 1)
(prompt "\nSelect object for segmentation")
(setq ss (ssget "_+.:E:S"))
(setq n (getint "\nInput number of segmentations : "))
(initget 1 "Open Closed")
(setq cld (getkword "\nIs selected object (Open / Closed) : "))
(if (= cld "Open")(setq nc (+ n 1)))
(if (= cld "Closed")(setq nc n))
(setq lay (getvar 'clayer))
(if (= (tblsearch "layer" "new") nil)
  (command "-layer" "n" "new" "")
  (progn
  (prompt "\nAborting: Delete Layer (new) witch is used by this routine, press ENTER")
  (command pause)
  (exit)
  )
)
(setvar 'clayer "new")
(command "divide" ss n)
(setq ptsel (ssget "X" '((0 . "POINT") (8 . "new")) ))
(setq entn (ssname ss 0))
(setq entl (entget entn))
(setq entlay (assoc 8 entl))
(setq layob (cdr entlay))
(setvar 'clayer lay)
(if (= cld "Open")
  (progn
  (setq k1 (ssname ptsel 0))
  (setq k1sel (ssadd))
  (ssadd k1 k1sel)
  (setq k2 (ssname ptsel (- (sslength ptsel) 1)))
  (setq k2sel (ssadd))
  (ssadd k2 k2sel)
  (setvar 'osmode 1)
  (prompt "\nStarting point is near displayed one - press ENTER")
  (sssetfirst k1sel k1sel)
  (command "regen")
  (command "\\")
  (prompt "\nNow pick starting point according to previously displayed near one : ")
  (command "point" "\\")
  (setq pocpt (entlast))
  (prompt "\nEnding point is near displayed one - press ENTER")
  (sssetfirst k2sel k2sel)
  (command "regen")
  (command "\\")
  (prompt "\nNow pick ending point according to previously displayed near one : ")
  (command "point" "\\")
  (setq krpt (entlast))
  (setq ptselred (ssadd))
  (ssadd pocpt ptselred)
  (setq ptslen (sslength ptsel))
  (setq nn -1)
    (repeat ptslen
    (setq nn (+ 1 nn))
    (setq entn (ssname ptsel nn))
    (ssadd entn ptselred)
    )
  (ssadd krpt ptselred)
  )
)
(setq nn -1)
(repeat nc
  (setq nn (+ 1 nn))
  (if (eq cld "Closed")(setq ptselred ptsel) ())
  (setq entn (ssname ptselred nn))
  (setq entlist (entget entn))
  (setq entl (assoc 10 entlist))
  (setq pt (cdr entl))
  (if (and (= cld "Closed")(= nn 0)) (setq pt0 pt))
  (entdel entn)
  (setq ptlista (cons pt ptlista))
)
(if (= cld "Closed")
(setq ptlista (cons pt0 ptlista))
)
(mapcar '(lambda (x) (if (< 0 (caddr x) 1e-4) (progn (setq ptn (list (car x) (cadr x) 0.0)) (setq ptlist (cons ptn ptlist))) (setq ptlist (cons x ptlist)) ) ) ptlista)
(setvar 'osmode 0)
(command "._spline")
(foreach ptn ptlist
  (command ptn)
)
(command "" "" "")
(command "change" "l" "" "p" "c" "green" "")
(command "-purge" "la" "new" "n")
(setvar 'osmode osm)
(setvar 'cmdecho cmde)
(setvar 'aperture apert)
(princ)
)

Code: [Select]
;;-----------------=={ Get Intersections }==------------------;;
;;                                                            ;;
;;  Returns a list of all points of intersection between      ;;
;;  two objects                                               ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2011 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  obj1, obj2 - VLA-Objects                                  ;;
;;------------------------------------------------------------;;
;;  Returns:  List of intersection points, or nil             ;;
;;------------------------------------------------------------;;

(defun LM:GetIntersections ( obj1 obj2 )
  (LM:GroupByNum (vlax-invoke obj1 'IntersectWith obj2 acExtendNone) 3)
)

;;-----------------=={ Group by Number }==--------------------;;
;;                                                            ;;
;;  Groups a list into a list of lists, each of length 'n'    ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  l - List to process                                       ;;
;;  n - Number of elements by which to group the list         ;;
;;------------------------------------------------------------;;
;;  Returns:  List of lists, each of length 'n'               ;;
;;------------------------------------------------------------;;

(defun LM:GroupByNum ( l n / r)
  (if l
    (cons
      (reverse (repeat n (setq r (cons (car l) r) l (cdr l)) r))
      (LM:GroupByNum l n)
    )
  )
)

---------------------------------------------------------------

(defun c:interse1e2 ( / e1 e2 ) (vl-load-com)
  (if
    (and
      (setq e1 (car (entsel "\nSelect First Object: ")))
      (setq e2 (car (entsel "\nSelect Second Object: ")))
    )
    (progn
    (terpri)
    (princ (LM:GetIntersections (vlax-ename->vla-object e1) (vlax-ename->vla-object e2)))
    )
  )
  (princ)
)
« Last Edit: October 12, 2011, 02:03:27 PM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3225
  • Marko Ribar, architect
Re: Intersect with - how to get those points?
« Reply #12 on: October 12, 2011, 05:06:53 PM »
Even better solution :
Explode Helix and use this routine on exploded spline (you should make it planar) :

Code: [Select]
(defun c:splf nil (c:splineflatten) )
(defun c:splineflatten ( / spl splA coords coordsn ptx pty ptz pt coordsnvar )
  (vl-load-com)
  (setq spl (car (entsel "\nPick spline")))
  (setq splA (vlax-ename->vla-object spl))
  (setq coords (vlax-safearray->list (vlax-variant-value (vla-get-ControlPoints splA))))
  (setq coordsn '())
  (repeat (/ (length coords) 3)
    (setq ptx (car coords))
    (setq pty (cadr coords))
    (setq ptz (caddr coords))
    (if (< 0 ptz 1e-4) (setq ptz 0.0) )
    (setq pt (list ptx pty ptz))
    (setq coords (cdddr coords))
    (setq coordsn (append coordsn pt))
  )
  (setq coordsnvar (vlax-make-variant (vlax-safearray-fill (vlax-make-safearray vlax-vbdouble (cons 0 (- (length coordsn) 1))) coordsn)))
  (vla-put-ControlPoints splA coordsnvar)   
(princ)
)
(princ "\nShortcut for c:splineflatten is c:splf")
(princ)

After this use previously posted c:interse1e2 and you should get results...

M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube