Author Topic: Extruding Faces  (Read 4289 times)

0 Members and 1 Guest are viewing this topic.

willmswamp

  • Guest
Extruding Faces
« on: April 26, 2011, 08:03:41 PM »
To all,

I am trying to write a .NET add-in to select a 3D solid and a line (where one endpoint of the line lies on a face of the solid).  The add-in will then extrude the face in which the endpoint lies, using the line as the path of extrusion.  See starting conditions in picture:




My code in its current form is below.  But it is not currently working.  I have been scratching my head over this one for awhile, any ideas?

Thanks in advance for any help,
Will
Acad 2009, VB Express 2008

Code: [Select]
Imports System
Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.BoundaryRepresentation
Imports BrFace = Autodesk.AutoCAD.BoundaryRepresentation.Face

<Assembly: CommandClass(GetType(Autodesk.AutoCAD.ExtrudeFace.SOMRClass))>

Namespace Autodesk.AutoCAD.ExtrudeFace

    Public Class SOMRClass


        <CommandMethod("exf")> _
       Public Sub ExtrudeFace()

            Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
            Dim acCurDb As Database = acDoc.Database
            Dim acDocEd As Editor = acDoc.Editor

            'set up prompt selection options
            Dim acPromptEntOpt1 As PromptEntityOptions = New PromptEntityOptions("")

            acPromptEntOpt1.Message = vbLf & "Select a 3D Solid: "
            acPromptEntOpt1.SetRejectMessage(vbLf & "Select a 3D Solid only!")
            acPromptEntOpt1.AddAllowedClass(GetType(Solid3d), True)

            'ask the user to select the 3d solid
            Dim acPromptEntRes1 As PromptEntityResult = acDocEd.GetEntity(acPromptEntOpt1)

            If acPromptEntRes1.Status = PromptStatus.OK Then

                'set up prompt selection options
                Dim acPromptEntOpt2 As PromptEntityOptions = New PromptEntityOptions("")

                acPromptEntOpt2.Message = vbLf & "Select the path of extrusion: "
                acPromptEntOpt2.SetRejectMessage(vbLf & "Select a line only!")
                acPromptEntOpt2.AddAllowedClass(GetType(Line), True)

                'ask the user to select the path of extrusion
                Dim acPromptEntRes2 As PromptEntityResult = acDocEd.GetEntity(acPromptEntOpt2)

                If acPromptEntRes2.Status = PromptStatus.OK Then

                    Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()

                        Try

                            'get the solid
                            Dim acSolid As Solid3d = acTrans.GetObject(acPromptEntRes1.ObjectId, OpenMode.ForRead)
                            'get the line
                            Dim acLine As Line = acTrans.GetObject(acPromptEntRes2.ObjectId, OpenMode.ForRead)
                            'get the startpoint of the line
                            Dim acStartPt As Point3d = acLine.StartPoint
                            'get the end point of the line
                            Dim acEndPt As Point3d = acLine.EndPoint


                            'convert the line to a curve
                            Dim acCurve As Curve = TryCast(acLine, Curve)

                            If acCurve <> Nothing Then

                                'Build the BRep topology object to traverse
                                Using acBrep As Brep = New Brep(acSolid)

                                    Dim acFaceColl As BrepFaceCollection = acBrep.Faces

                                    For Each acFace As BrFace In acFaceColl

                                        'test to see if either point lies on the face
                                        Dim ContainmentVal1 As PointContainment = New PointContainment()
                                        acFace.GetPointContainment(acStartPt, ContainmentVal1)
                                        Dim ContainmentVal2 As PointContainment = New PointContainment()
                                        acFace.GetPointContainment(acEndPt, ContainmentVal2)

                                        'if the point lies on the face, then extrude the face
                                        If ContainmentVal1 = PointContainment.Inside Or ContainmentVal2 = PointContainment.Inside Then

                                            'extrude the face, this line throws an exception
                                            Dim FaceSubEntIds() As SubentityId = New SubentityId() {acFace.SubentityPath.SubentId}
                                            acSolid.ExtrudeFacesAlongPath(FaceSubEntIds, acCurve)

                                        End If

                                    Next

                                End Using

                            End If

                        Catch ex As System.Exception

                            acDocEd.WriteMessage(vbLf & "Exception: " & ex.Message)

                        End Try

                        'commit the transaction
                        acTrans.Commit()

                    End Using

                End If

            End If

        End Sub

    End Class

End Namespace
« Last Edit: April 26, 2011, 08:18:42 PM by willmswamp »

Jeff H

  • Needs a day job
  • Posts: 6150
Re: Extruding Faces
« Reply #1 on: April 26, 2011, 08:32:06 PM »
Are you getting errors?

Draftek

  • Guest
Re: Extruding Faces
« Reply #2 on: April 27, 2011, 08:25:33 AM »
I'd suggest creating a region to mimic the face and then extrude that along the path.

But, your error may be the fact you are trying to use a curve class and not the line itself.

« Last Edit: April 27, 2011, 08:37:35 AM by Draftek »

kaefer

  • Guest
Re: Extruding Faces
« Reply #3 on: April 27, 2011, 09:53:08 AM »
I'd suggest creating a region to mimic the face and then extrude that along the path.

Any idea on how to create a Region, Polyline or whatever Entity else may be needed from the faces in question? That then will be used as our planar sweep entity?

Quote
But, your error may be the fact you are trying to use a curve class and not the line itself.

That's not what the method signature says.
public virtual void ExtrudeFacesAlongPath(Autodesk.AutoCAD.DatabaseServices.SubentityId[ ] subentityIds, Autodesk.AutoCAD.DatabaseServices.Curve path)

Draftek

  • Guest
Re: Extruding Faces
« Reply #4 on: April 27, 2011, 10:13:26 AM »
1. - Sure, but its not going to be a couple lines of code.

2. Per the help document for the method (always best to read this first):
Quote
This method extrudes the given faces along the given path curve entity, which must be an AcDbLine, AcDbArc, AcDbCircle, AcDbEllipse, AcDbSpline, AcDb2dPolyline, or a non-spline fit AcDb3dPolyline. The path should not have self-intersections and, preferably, should not have high curvature areas. If one of the end points of the path is not on the plane of the region, then the path will be moved to make this true.

Another problem (and I'm guessing here) is that I'm fairly sure this (the curve) would have to be a database resident object.

kaefer

  • Guest
Re: Extruding Faces
« Reply #5 on: April 27, 2011, 10:52:27 AM »
1. - Sure, but its not going to be a couple lines of code.

Well, that's the trouble with replacing a single line of code which should work but won't with lots of lines of code.

Just to demo your point, here's a halfbaked attempt to sweep a closed Polyline derived from the face in question. I'm pretty sure there are much better ways to do it,

Code: [Select]
[<CommandMethod "exf">]
let extrudeFaceCmd() =
    let doc = acApp.DocumentManager.MdiActiveDocument
    let db = doc.Database
    let ed = doc.Editor
    let peo1 =
        new PromptEntityOptions(
            "",
            Message = "Select a 3D Solid: " )
    peo1.SetRejectMessage "Select a 3D Solid only!"
    peo1.AddAllowedClass(typeof<Solid3d>, false)
    let per1 = ed.GetEntity peo1
    if per1.Status = PromptStatus.OK then
        let peo2 =
            new PromptEntityOptions(
                "",
                Message = "Select the path of extrusion: " )
        peo2.SetRejectMessage "Select a curve only!"
        peo2.AddAllowedClass(typeof<Curve>, false)
        let per2 = ed.GetEntity peo2
        if per2.Status = PromptStatus.OK then
            use tr = db.TransactionManager.StartTransaction()
            let cspace = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) :?> BlockTableRecord
            try
                let sol = tr.GetObject(per1.ObjectId, OpenMode.ForRead) :?> Solid3d
                let cur = tr.GetObject(per2.ObjectId, OpenMode.ForRead) :?> Curve
                let brep = new Brep(sol)
                for face in brep.Faces do
                    let mutable cv1 = new PointContainment()
                    face.GetPointContainment(cur.StartPoint, &cv1) |> ignore
                    let mutable cv2 = new PointContainment()
                    face.GetPointContainment(cur.EndPoint, &cv2) |> ignore
                    if cv1 = PointContainment.Inside || cv2 = PointContainment.Inside then
                        let p3d = new Polyline3d(Closed = true)
                        cspace.AppendEntity p3d |> ignore
                        tr.AddNewlyCreatedDBObject(p3d, true)
                        let first = ref true
                        for l in face.Loops do
                            for e in l.Edges do
                                if !first then
                                    let v = new PolylineVertex3d(e.Vertex1.Point)
                                    p3d.AppendVertex v|> ignore
                                    tr.AddNewlyCreatedDBObject(v, true)
                                    first := false
                                else
                                    let v = new PolylineVertex3d(e.Vertex2.Point)
                                    p3d.AppendVertex v |> ignore
                                    tr.AddNewlyCreatedDBObject(v, true)
                        let sol = new Solid3d(RecordHistory = true)
                        sol.CreateSweptSolid(
                            p3d,
                            cur,
                            new SweepOptions() )
                        cspace.AppendEntity sol |> ignore
                        tr.AddNewlyCreatedDBObject(sol, true)
                    else
                        ed.WriteMessage("\nStart or end point not inside face. ")
            with ex -> ed.WriteMessage("\n{0}\n{1}\n{2} ", ex.Message, ex.Source, ex.StackTrace)
            tr.Commit()

willmswamp

  • Guest
Re: Extruding Faces
« Reply #6 on: April 27, 2011, 01:49:32 PM »
Another way to do it that would work is to explode the solid and iterate through the DB Object Collection until the region in which the endpoint lies is found and then extrude that region along the path.  Then dispose of the DB Object Collection.  This would work equally well for faces with circular or curved boundaries.

However, in my quest for more complete understanding of the API, I am still puzzled as to why the method in my original example is not working.  :|

The exception occurs at the line,

Dim FaceSubEntIds() As SubentityId = New SubentityId() {acFace.SubentityPath.SubentId}

The exception message doesn't give details, it simply says "Exception of type 'Autodesk.AutoCAD.BoundaryRepresentation.Exception' was thrown."

From my testing, it appears that the curve used as the path does not have to be database resident.  Also, concerning the curve class, from the documentation, "The Curve class is the base class for all the entity classes that are variations of a curve such as Arc, Circle, Ellipse, Spline, and others."  Lines and polylines can also be curves.  The extrusion methods require a curve as the extrusion path.

Thanks for the comments so far! :-)


Draftek

  • Guest
Re: Extruding Faces
« Reply #7 on: April 27, 2011, 03:40:20 PM »
hmm.

I'm in the middle of figuring some of this out myself to do some parametric constraints.

I think your going to need the protocol extensions to extract only the planer sub entities.

Just guessing, but I should know more in a few weeks.


Draftek

  • Guest
Re: Extruding Faces
« Reply #8 on: April 27, 2011, 03:52:58 PM »
As far as using the curve, your wasting your time and code as an implicit cast is done for you.

You can try this out for yourself by creating a method that takes a curve as an a argument and then create a client that passes any of the derived classes to it.

willmswamp

  • Guest
Re: Extruding Faces
« Reply #9 on: April 27, 2011, 05:55:53 PM »
hmm.

I'm in the middle of figuring some of this out myself to do some parametric constraints.

I think your going to need the protocol extensions to extract only the planer sub entities.

Just guessing, but I should know more in a few weeks.


I will look forward to hearing what you discover.  Thanks!

As far as using the curve, your wasting your time and code as an implicit cast is done for you.

You can try this out for yourself by creating a method that takes a curve as an a argument and then create a client that passes any of the derived classes to it.


Ah! I see.  Thanks for setting me straight!  :-)