Author Topic: Creating an AutoCAD polyline from an exploded region  (Read 12486 times)

0 Members and 1 Guest are viewing this topic.

WOWENS

  • Newt
  • Posts: 60
Creating an AutoCAD polyline from an exploded region
« on: July 17, 2012, 03:39:37 PM »
'the code came from
'Through the Interface
'by Kean Walmsley

'August 25, 2008
'Creating an AutoCAD polyline from an exploded region using .NET


' Create a plane to convert 3D coords
' into Region coord system
Dim pl As New Plane(New Point3d(0, 0, 0), reg.Normal)


'Code to make the PLine


' The resulting Polyline
Dim p As New Polyline()


' Once we have added all the Polyline's vertices,
' transform it to the original region's plane
p.TransformBy(Matrix3d.PlaneToWorld(pl))

'the above code works if the region was drawn flat with a 0 elevation.
'if the region was drawn in some other elevation then the new pLine
'will not be in the same location as the region was.

'so here is my work around for that, but was wondering if there is a better way of doing it?
'im still trying to learn .net so any help would be great.
'I would prefer to learn the right way, instead of using my work around.

Dim bp As Brep = New Brep(reg)

'get a point for the Region
Dim RegPoint3d As Point3d = bp.Vertices.GetEnumerator().Current.Point

'convert the 3d point to the pline plane
Dim NewPoint2d As Point2d = RegPoint3d.Convert2d(pl)

'convert the 2D point to a 3D point
Dim TempPoint3d As Point3d = New Point3d(NewPoint2d.X, NewPoint2d.Y, 0)

' transform it to the original region's plane
Dim NewPoint3d As Point3d = TempPoint3d.TransformBy(Matrix3d.PlaneToWorld(pl))

'Get Vector3D
Dim NewVector3d As Vector3d = NewPoint3d.GetVectorTo(RegPoint3d)

'move back to the same place were the region was
p.TransformBy(Matrix3d.Displacement(NewVector3d))

fixo

  • Guest
Re: Creating an AutoCAD polyline from an exploded region
« Reply #1 on: July 17, 2012, 04:41:43 PM »
Code: [Select]
<CommandMethod("craw")> _
        Public Shared Sub CreateRegionFromConnected()
            Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument

            Dim ed As Editor = doc.Editor

            Dim db As Database = doc.Database

            Dim objs As New DBObjectCollection()

            Dim regcoll As New DBObjectCollection()

            Using tr As Transaction = db.TransactionManager.StartTransaction()

                Dim btr As BlockTableRecord = TryCast(tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite), BlockTableRecord)

                Dim tvs As TypedValue() = New TypedValue() {New TypedValue(0, "line,arc,polyline")}

                Dim points As New Point3dCollection()

                Dim sf As New SelectionFilter(tvs)

                Dim sres As PromptSelectionResult = ed.GetSelection(sf)

                If sres.Status <> PromptStatus.OK Then
                    ed.WriteMessage(vbLf & "Invalid selection!")

                    Return
                End If

                For Each selobj As SelectedObject In sres.Value
                    Dim obj As DBObject = TryCast(tr.GetObject(selobj.ObjectId, OpenMode.ForWrite, False), DBObject)


                    objs.Add(obj)
                Next

                regcoll = Region.CreateFromCurves(objs)

                Dim reg As Region = TryCast(regcoll(0), Region)

                btr.AppendEntity(reg)

                tr.AddNewlyCreatedDBObject(reg, True)
                ' you might be want to remove parent objects here  //

                tr.Commit()
            End Using
        End Sub

WOWENS

  • Newt
  • Posts: 60
Re: Creating an AutoCAD polyline from an exploded region
« Reply #2 on: July 17, 2012, 05:01:02 PM »
Thank you

fixo

  • Guest
Re: Creating an AutoCAD polyline from an exploded region
« Reply #3 on: July 17, 2012, 05:06:10 PM »
You're welcome
:)

TheMaster

  • Guest
Re: Creating an AutoCAD polyline from an exploded region
« Reply #4 on: July 17, 2012, 06:43:36 PM »
Exploding a region results in a variety of primitives, but never a polyline.

It doesn't look like Fixo's code will create a polyline, and you need to keep
in mind that regions can contain ACIS curves (splines, ellipses, etc.), that
cannot be joined to form a polyline directly. As long as you know that your
regions are not comprised of ACIS entities, you can just use the PEDIT/Join
subcommand to convert the primitives produced by exploding the region
to a polyline.

'the code came from
'Through the Interface
'by Kean Walmsley

'August 25, 2008
'Creating an AutoCAD polyline from an exploded region using .NET


' Create a plane to convert 3D coords
' into Region coord system
Dim pl As New Plane(New Point3d(0, 0, 0), reg.Normal)


'Code to make the PLine


' The resulting Polyline
Dim p As New Polyline()


' Once we have added all the Polyline's vertices,
' transform it to the original region's plane
p.TransformBy(Matrix3d.PlaneToWorld(pl))

'the above code works if the region was drawn flat with a 0 elevation.
'if the region was drawn in some other elevation then the new pLine
'will not be in the same location as the region was.

'so here is my work around for that, but was wondering if there is a better way of doing it?
'im still trying to learn .net so any help would be great.
'I would prefer to learn the right way, instead of using my work around.

Dim bp As Brep = New Brep(reg)

'get a point for the Region
Dim RegPoint3d As Point3d = bp.Vertices.GetEnumerator().Current.Point

'convert the 3d point to the pline plane
Dim NewPoint2d As Point2d = RegPoint3d.Convert2d(pl)

'convert the 2D point to a 3D point
Dim TempPoint3d As Point3d = New Point3d(NewPoint2d.X, NewPoint2d.Y, 0)

' transform it to the original region's plane
Dim NewPoint3d As Point3d = TempPoint3d.TransformBy(Matrix3d.PlaneToWorld(pl))

'Get Vector3D
Dim NewVector3d As Vector3d = NewPoint3d.GetVectorTo(RegPoint3d)

'move back to the same place were the region was
p.TransformBy(Matrix3d.Displacement(NewVector3d))

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: Creating an AutoCAD polyline from an exploded region
« Reply #5 on: July 18, 2012, 02:27:43 AM »
Hi,

Here's a solution which seems to work wharever the region normal and elevation.
It works with regions containing 'holes' (creates a ployline for the outerloop and one foreach inner loop).
The code uses the PolylineSegment and PolylineSegmentCollection classes defined in the GeometryExtensions library.

Code - C#: [Select]
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.Runtime;
  6. using GeometryExtensions;
  7.  
  8. namespace RegionToPolyline
  9. {
  10.     public class Commands
  11.     {
  12.         [CommandMethod("Test")]
  13.         public void Test()
  14.         {
  15.             Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
  16.             PromptEntityOptions peo = new PromptEntityOptions("\nSelect a region: ");
  17.             peo.SetRejectMessage("Only a region !");
  18.             peo.AddAllowedClass(typeof(Region), true);
  19.             PromptEntityResult per = ed.GetEntity(peo);
  20.             if (per.Status != PromptStatus.OK) return;
  21.             RegionToPolyline(per.ObjectId, false);
  22.         }
  23.  
  24.         public ObjectIdCollection RegionToPolyline(ObjectId regId, bool erase)
  25.         {
  26.             Database db = regId.Database;
  27.             using (Transaction tr = db.TransactionManager.StartTransaction())
  28.             {
  29.                 Region reg = (Region)tr.GetObject(regId, OpenMode.ForRead);
  30.                 BlockTableRecord btr = (BlockTableRecord)tr.GetObject(reg.OwnerId, OpenMode.ForWrite);
  31.  
  32.                 Plane plane = new Plane(Point3d.Origin, reg.Normal);
  33.                 Extents3d ext = reg.GeometricExtents;
  34.                 Point3d pt = new Point3d();
  35.  
  36.                 PolylineSegmentCollection segCol = new PolylineSegmentCollection();
  37.                 using (DBObjectCollection segments = new DBObjectCollection())
  38.                 {
  39.                     reg.Explode(segments);
  40.                     for (int i = 0; i < segments.Count; i++)
  41.                     {
  42.                         DBObject obj = segments[i];
  43.                         switch (obj.GetType().Name)
  44.                         {
  45.                             case "Line":
  46.                                 Line line = (Line)obj;
  47.                                 pt = line.StartPoint;
  48.                                 LineSegment2d ls = new LineSegment2d(
  49.                                     pt.Convert2d(plane),
  50.                                     line.EndPoint.Convert2d(plane));
  51.                                 segCol.Add(new PolylineSegment(ls));
  52.                                 break;
  53.                             case "Arc":
  54.                                 Arc arc = (Arc)obj;
  55.                                 pt = arc.StartPoint;
  56.                                 CircularArc2d ca = new CircularArc2d(
  57.                                     pt.Convert2d(plane),
  58.                                     arc.GetPointAtParameter((arc.EndParam - arc.StartParam) / 2.0).Convert2d(plane),
  59.                                     arc.EndPoint.Convert2d(plane));
  60.                                 segCol.Add(new PolylineSegment(ca));
  61.                                 break;
  62.                             case "Circle":
  63.                                 Circle c = (Circle)obj;
  64.                                 pt = c.Center;
  65.                                 segCol.AddRange(new PolylineSegmentCollection(c));
  66.                                 break;
  67.                             case "Ellipse":
  68.                                 Ellipse el = (Ellipse)obj;
  69.                                 pt = el.Center;
  70.                                 segCol.AddRange(new PolylineSegmentCollection(el));
  71.                                 break;
  72.                             case "Spline":
  73.                                 Spline spl = (Spline)obj;
  74.                                 pt = spl.StartPoint;
  75.                                 if (reg.Normal.IsParallelTo(Vector3d.ZAxis))
  76.                                 {
  77.                                     segCol.AddRange(new PolylineSegmentCollection((Polyline)spl.ToPolyline()));
  78.                                 }
  79.                                 else
  80.                                 {
  81.                                     DBObjectCollection objcol = new DBObjectCollection();
  82.                                     spl.ToPolyline().Explode(objcol);
  83.                                     foreach (DBObject o in objcol)
  84.                                     {
  85.                                         segments.Add(o);
  86.                                     }
  87.                                 }
  88.                                 break;
  89.                         }
  90.                         obj.Dispose();
  91.                     }
  92.                     if (erase)
  93.                     {
  94.                         reg.UpgradeOpen();
  95.                         reg.Erase();
  96.                     }
  97.                     ObjectIdCollection retVal = new ObjectIdCollection();
  98.                     foreach (PolylineSegmentCollection psc in segCol.Join())
  99.                     {
  100.                         Polyline pl = psc.ToPolyline();
  101.                         pl.TransformBy(Matrix3d.PlaneToWorld(plane));
  102.                         pl.Elevation = pt.TransformBy(Matrix3d.WorldToPlane(plane)).Z;
  103.                         retVal.Add(btr.AppendEntity(pl));
  104.                         tr.AddNewlyCreatedDBObject(pl, true);
  105.                     }
  106.                     tr.Commit();
  107.                     return retVal;
  108.                 }
  109.             }
  110.         }
  111.     }
  112. }
  113.  
Speaking English as a French Frog

WOWENS

  • Newt
  • Posts: 60
Re: Creating an AutoCAD polyline from an exploded region
« Reply #6 on: July 18, 2012, 07:54:26 AM »
thank you all for all the information and guidance

Inciner

  • Guest
Re: Creating an AutoCAD polyline from an exploded region
« Reply #7 on: October 15, 2012, 12:55:17 PM »
My version (mod) on LISP

Code: [Select]
;;1D_Inciner
(defun c:R2 (/    *error*  oldEcho  Ent      curSet   ;2:04 07.04.2011 Retopl mod by 1D
  curObj   ObjArr   curMemb  errFlag  actDoc   item
  ss MT i MT1 ss1
)
  (vl-load-com)

  (defun *error* (msg)
    (vla-EndUndoMark actDoc)
    (setvar "CMDECHO" oldEcho)
    (princ msg)
    (princ)
  ) ;_ end of *error*

(defun r2plc (ss / );

(setq i 0); chesk curSet selset for empty entries
(repeat (sslength ss)
             (if
             (not (vlax-ename->vla-object (ssname ss i)))
             (setq ss (ssdel (ssname ss i) ss)))
(setq i (1+ i))
);repeat

(setq Ent (ssname ss (setq item (1- item))));___ entity
(setq curObj (vlax-ename->vla-object Ent)); ___VLA entity
 
(if (vlax-write-enabled-p curObj)
(progn
  (setq curSet nil
curSet (ssadd)
ObjArr (vlax-safearray->list
(vlax-variant-value
   (vla-Explode curObj)
)
       )
  )
(vla-delete curObj); ___explode to ObjArr


  (foreach memb ObjArr
    (setq memb (vlax-vla-object->ename memb))
    (if (member
  (cdr (assoc 0 (entget Memb)))
  '("LINE" "ARC" "LWPOLYLINE")
)
      (setq curSet (ssadd Memb CurSet));___Curset from linearc chunks
    ) ;_ end if


(if (member
 (cdr (assoc 0 (entget Memb)))
 '("REGION")
 )
   (progn      
   (setq ss1 (ssadd Memb ss1));___ss1 from Reg
   )
);if

  ) ;_ end foreach

(if (> (sslength ss1) 0)
(setq i 0); chesk ss1 selset for empty entries
(repeat (sslength ss1)
             (if
             (not (vlax-ename->vla-object (ssname ss1 i)))
             (setq ss1 (ssdel (ssname ss1 i) ss1)))
             (setq i (1+ i))
             ));___clean ss1

(if (> (sslength curSet) 0)
(setq i 0); chesk curSet selset for empty entries
(repeat (sslength curSet)
             (if
             (not (vlax-ename->vla-object (ssname curSet i)))
             (setq curSet (ssdel (ssname curSet i) curSet)))
(setq i (1+ i))
             ));___clean curset


(if (> (sslength curSet) 0)
    (progn
(command "_.ucs" "_ob" (ssname curSet 0))
(command "_.pedit" (ssname curSet 0) "_j" CurSet "" "")
      (while (> (getvar "CMDACTIVE") 0) (command ""))
      (command "_.ucs" "_p")


(setq MT curSet i 0)
(repeat (sslength MT)
(setq MT1 (ssname MT i))
(setq i (1+ i)
VSS (ssadd MT1 VSS))
)

;;(command "_.chprop" MT "" "_C" 12 "")

(princ "\n<<< Polyline created: >>>")
) ;_ end progn
);if
 
) ;_ end progn
);if
);defun r2plc

; MAIN PART

(setvar "DRAWORDERCTL" 0)
(setq oldEcho (getvar "CMDECHO") actDoc (vla-get-ActiveDocument (vlax-get-acad-object)))
(vla-StartUndoMark actDoc)
(setvar "CMDECHO" 0)
(setvar "PEDITACCEPT" 1)
(setvar "UCSFOLLOW" 0)
(setq VSS nil VSS (ssadd)); lines/arc chunks collector
(setq ss1 nil ss1 (ssadd)); complex region's chunks collector
(princ "select regions")

(if (setq ss (ssget
;"_X"
    (list '(0 . "REGION") (cons 410 (getvar "CTAB")))

));setq
(progn
        (repeat (setq item (sslength ss))
        (r2plc ss));repeat
       
        (if (> (sslength ss1) 0)
            (progn
            (princ "\nAddictive Regions:")
            (princ (sslength ss1))
                 (repeat (setq item (sslength ss1))
                 (r2plc ss1));repeat
            ) ;_ end progn
        );if

);progn
);if

(setq i 0); chesk VSS selset for empty entries and joining chunks
(repeat (sslength VSS)
             (if
             (vlax-ename->vla-object (ssname VSS i))
             (vl-cmdf "_PEDIT" "_M" VSS "" "_J" "_J" "_B" 0 "")
             )
             (setq i (1+ i))
);repeat

(princ "\nComplete")
  (setvar "CMDECHO" oldEcho)
(setvar "DRAWORDERCTL" 3)
  (vla-EndUndoMark actDoc)
  (princ)
)

chisinwolf

  • Mosquito
  • Posts: 11
Re: Creating an AutoCAD polyline from an exploded region
« Reply #8 on: June 11, 2013, 07:23:13 AM »
Hi Inciner or anybody else that may be able to help.

Regarding your Lisp, I tried it and it worked very well indeed. So many thanks for that.

However after running it, I then experienced a problem with another Lisp that I regularly use called Pre_Cal.lsp, which allows you to select closed lines by window, and turns the selection into a polyline or region depending on your choice.
I now get this text on the command line after running Pre_Cal.lsp: -

"Command: pre_cal
Initializing...
Select first corner:
Select other corner:

Invalid option keyword.
Function cancelled"

Here is the Pre_Cal.lsp Code: -

Code: [Select]
(defun c:pre_cal ( / f_pt o_pt n r blk_oj sub_oj li_oj pli_oj hat_oj p_line sp kw)
   
   
   (setvar "cmdecho" 0)
   (setq f_pt (getpoint "\nSelect first corner: "))
   (setq o_pt (getcorner f_pt "\nSelect other corner: "))
   (princ "\n")
   
   (setq blk_oj (ssget "w" f_pt o_pt '((2 . "UCLOSE"))))   
   (if (/= nil blk_oj)
      (command "_erase" blk_oj "")
   )
   
   (repeat 2
      (setq blk_oj (ssget "w" f_pt o_pt
      '((-4 . "<or") (0 . "INSERT") (0 . "REGION") (-4 . "or>"))))
     
      (if (/= nil blk_oj)
         (command "_explode" blk_oj)
      )
   )
   
   (setq hat_oj (ssget "w" f_pt o_pt '((0 . "HATCH"))))   
   (if (/= nil hat_oj)
      (command "_erase" hat_oj "")
   )
   
   (setq pli_oj (ssget "w" f_pt o_pt '((0 . "LWPOLYLINE"))))
   (if (/= nil pli_oj) (command "_explode" pli_oj))
   
   (setq li_oj (ssget "w" f_pt o_pt
   '((-4 . "<or") (0 . "LINE") (0 . "ARC") (-4 . "or>"))))
   
   (while (/= nil li_oj)
      (setq sub_oj (ssname li_oj 0)) 
      (command "_pedit" sub_oj "y" "J" (ssget "w" f_pt o_pt) "" "X")
      (setq li_oj (ssget "w" f_pt o_pt
      '((-4 . "<or") (0 . "LINE") (0 . "ARC") (-4 . "or>"))))
   )
   
   (setq pli_oj (ssget "w" f_pt o_pt '((0 . "LWPOLYLINE"))))
   
   (setq n 0 r 1)
   (if (/= nil pli_oj)
      (progn
         
         (repeat (sslength pli_oj)
            (setq p_line (entget (ssname pli_oj n)))
            (if (= 0 (cdr (assoc 70 p_line)))
               (progn
                  (setq r nil)
                  (setq sp (cdr (assoc 10 p_line)))
                  (command "_insert" "uclose" sp "" "" "")
               )
            )
            (setq n (1+ n))
         )
      )
   )
   (if (= nil r)
      (progn
         (setq blk_oj (ssget "w" f_pt o_pt '((0 . "LWPOLYLINE"))))
         (while (/= blk_oj nil)
            (command "_explode" blk_oj)
            (setq blk_oj (ssget "w" f_pt o_pt '((0 . "LWPOLYLINE"))))
         )
         (princ "*ERROR* : Found at least one polyline is not closed !")
      )
      (progn
         (initget "Polyline  Region")
         (setq kw (getkword "\nGenerate Region/<Polyline>:"))
         (if (= kw "Region")
            (command "_region" (ssget "w" f_pt o_pt
               '((-4 . "<or")
                  (0 . "LWPOLYLINE") (0 . "CIRCLE")
               (-4 . "or>"))) ""
            )
            (progn
               (setq pli_oj (ssget "w" f_pt o_pt '((0 . "LWPOLYLINE"))))
               (setq kw (strcat (itoa (sslength pli_oj)) " Polyline is generated"))
(princ kw)
            )         
         )
      )
   )
   (setvar "cmdecho" 1)
   (princ)   
)

I wonder if anybody might be able to pinpoint why this error has started to occur only since I ran the lisp by Inciner.

Could it be some variable that has been re-set?
Unfortunately, I am not fluent in lisp, so unable to pick through it myself. I would be grateful for any help.

Thanks.


chisinwolf

  • Mosquito
  • Posts: 11
Re: Creating an AutoCAD polyline from an exploded region
« Reply #9 on: June 11, 2013, 10:29:04 PM »
I am happy to say that I think I have solved this problem.

The Region to Polyline lisp appears to change the default value of "peditaccept" to 1.
I changed it back to default 0, and now my Pre_Cal.lsp works again.

 :-)


Rusel

  • Guest
Re: Creating an AutoCAD polyline from an exploded region
« Reply #10 on: February 20, 2015, 05:25:37 PM »
Hello,
How can we find all closed boundaries from all lines in the drawing. CreateFromCurves doesn't work if all of the selected curves to do not form a closed region and sometimes create more than needed. In the attached picture is a very simple example of air ducts drawn with lines. I want to convert them to closed polylines and find 2 closed ones in the picture below not 3 (the outermost big duct).
Thanks,

nekitip

  • Guest
Re: Creating an AutoCAD polyline from an exploded region
« Reply #11 on: February 23, 2015, 05:12:00 AM »
Hello,
How can we find all closed boundaries from all lines in the drawing. CreateFromCurves doesn't work if all of the selected curves to do not form a closed region and sometimes create more than needed. In the attached picture is a very simple example of air ducts drawn with lines. I want to convert them to closed polylines and find 2 closed ones in the picture below not 3 (the outermost big duct).
Thanks,
I have not tried it now, but didn't you get two regions from this picture?

Rusel

  • Guest
Re: Creating an AutoCAD polyline from an exploded region
« Reply #12 on: February 25, 2015, 02:33:50 AM »
Hello,
I get 2 regions from this picture, 2 desperate and 1 the outer most.
In a complex drawing there will be lots of unwanted regions.
Thanks,