Code Red => .NET => Topic started by: Keith Brown on March 03, 2016, 04:18:45 PM

Title: Sweeping a Solid
Post by: Keith Brown on March 03, 2016, 04:18:45 PM
I have created some simple code to sweep a circle around a polyline.  Unfortunately in wireframe mode the swept solid does not look the same as one created manually using the sweep command as shown in the first picture below.


In this picture, I have the manual sweep on the left and the one created by code on the right.


Here is the code that generated the solid above.  I cannot think straight today.  What do you think needs to be done in order for it to look correct in wireframe?

Code - Visual Basic: [Select]
  1.    Private Sub InputButton1_Click(sender As Object, e As EventArgs) Handles InputButton1.Click
  2.        using Active.Document.LockDocument()
  3.            Using transaction = Active.Database.TransactionManager.StartTransaction()
  4.                Dim modelSpace = Active.Database.ModelSpace(OpenMode.ForWrite)
  5.                Dim polylineSegmentCollection = New PolylineSegmentCollection()
  6.                Using lineSegment1 = New LineSegment2d(New Point2d(- 4, 4), New Point2d(- 4, 0))
  7.                    Dim lineSegment = new PolylineSegment(lineSegment1)
  8.                    polylineSegmentCollection.Add(lineSegment)
  9.                End Using
  10.                Dim arcSegment = new PolylineSegment(New Point2d(- 4, 0), New Point2d(4, 0), 1, 0)
  11.                polylineSegmentCollection.Add(arcSegment)
  12.                Using lineSegment2 = New LineSegment2d(New Point2d(4, 0), New Point2d(4, 4))
  13.                    Dim lineSegment = new PolylineSegment(lineSegment2)
  14.                    polylineSegmentCollection.Add(lineSegment)
  15.                End Using
  16.                Using centerLine = polylineSegmentCollection.ToPolyline()
  17.                    modelSpace.AppendEntity(centerLine)
  18.                    transaction.AddNewlyCreatedDBObject(centerLine, True)
  19.                    Dim solid = New Solid3d()
  20.                    Using circle = New Circle(Point3d.Origin, Vector3d.ZAxis, .5)
  21.                        Dim sweepOptionsBuilder = New SweepOptionsBuilder()
  22.                        sweepOptionsBuilder.Align = SweepOptionsAlignOption.AlignSweepEntityToPath
  23.                        sweepOptionsBuilder.BasePoint = Point3d.Origin
  24.                        sweepOptionsBuilder.Bank = True
  25.                        solid.CreateSweptSolid(circle, centerline, sweepOptionsBuilder.ToSweepOptions())
  26.                    End Using
  27.                    modelSpace.AppendEntity(solid)
  28.                    transaction.AddNewlyCreatedDBObject(solid, True)
  29.                    transaction.Commit()
  30.                End Using
  31.            End Using
  32.        End Using
  33.    End Sub

I am using Gile's Geometry Extensions to create the polyline and have not shown the code for those methods.  If you need them a simple google search will find the correct thread.
Title: Re: Sweeping a Solid
Post by: kdub on March 03, 2016, 10:43:41 PM

That is weird,
It looks like ISOLINES DISPSILH VSEDGES etc system variables are being changed for one solid .... and I wasn't aware that could be done.
Title: Re: Sweeping a Solid
Post by: Master_Shake on March 08, 2016, 01:09:53 PM
Were both sweep paths (left and right) created programmatically?
Title: Re: Sweeping a Solid
Post by: Keith Brown on March 08, 2016, 01:15:32 PM
Yes.  The sweep manually was done by running the program once and then deleting the solid portion of it and sweeping the circle along the polyline path.
Title: Re: Sweeping a Solid
Post by: MexicanCustard on March 09, 2016, 07:40:57 AM
You are in vanilla, right?  If you're in a vertical, I would look at the display manager and see if that's affecting it.
Title: Re: Sweeping a Solid
Post by: Keith Brown on March 09, 2016, 10:45:27 AM
Yes, running Vanilla AutoCAD.  Well a vertical that starts Vanilla Autocad.  That being said if it was the Display Representation I believe that it would effect both 3d Solids similarly.  They would both look the same.

The problem with the solid created in code that the circle appears to be rotated somewhat when it is swept.  The circle rotation is constant, it is just not aligned with the path correctly.  I have tried all of the sweep builder options and have not come up with anything that appears to work.

My next option will be to try to get this in front of the developers over at the official .NET page and see if they come up with anything.

I am wondering if anyone else running the code has the same issue?  Or is it just me.  I could try building the polyline differently and see if that has an effect but I believe that it will probably not.
Title: Re: Sweeping a Solid
Post by: Jeff H on March 09, 2016, 11:30:52 AM
I can temporarily mimic it I think in UI


But if I orbit or regen then first sweep updates to look like second one with ISOLINES = 2.

Title: Re: Sweeping a Solid
Post by: Master_Shake on March 09, 2016, 12:57:43 PM
I can temporarily mimic it I think in UI


But if I orbit or regen then first sweep updates to look like second one with ISOLINES = 2.

What's odd is that those are system variables, not entity specific properties.
Title: Re: Sweeping a Solid
Post by: MickD on March 09, 2016, 02:51:14 PM
It's like the circle isn't aligned properly for the sweep.
I was thinking you may need to translate and align the circle normal with the polyline start segment direction like you would with an Extrude but I think this call looks after that:

Code - C#: [Select]
  1. sweepOptionsBuilder.Align = SweepOptionsAlignOption.AlignSweepEntityToPath

try changing

Code - C#: [Select]
  1. sweepOptionsBuilder.BasePoint = Point3d.Origin


Code - C#: [Select]
  1. sweepOptionsBuilder.BasePoint = centerLine.StartPoint

Personally, I probably would have used Extrude along path as the 3dSolid section is constant whereas a sweep can have a taper and many other properties that might not be needed.
You would probably have to do the transformation yourself though but that is trivial.
Title: Re: Sweeping a Solid
Post by: Keith Brown on March 11, 2016, 07:38:02 AM
I got some time last night to look at this again and I still have not had any luck.  I tried all of the suggestions listed above and still basically got the same results.  Even the ExtrudeAlongPath is looking incorrect.  I am beginning to think that I have something else wrong with my system settings.   

Code - Visual Basic: [Select]
  1.        using Active.Document.LockDocument()
  2.            Using transaction = Active.Database.TransactionManager.StartTransaction()
  3.                Dim modelSpace = Active.Database.ModelSpace(OpenMode.ForWrite)
  4.                Dim polylineSegmentCollection = New PolylineSegmentCollection()
  5.                Using lineSegment1 = New LineSegment2d(New Point2d(-4, 4), New Point2d(-4, 0))
  6.                    Dim lineSegment = new PolylineSegment(lineSegment1)
  7.                    polylineSegmentCollection.Add(lineSegment)
  8.                End Using
  9.                Dim arcSegment = new PolylineSegment(New Point2d(-4, 0), New Point2d(4, 0), 1, 0)
  10.                polylineSegmentCollection.Add(arcSegment)
  11.                Using lineSegment2 = New LineSegment2d(New Point2d(4, 0), New Point2d(4, 4))
  12.                    Dim lineSegment = new PolylineSegment(lineSegment2)
  13.                    polylineSegmentCollection.Add(lineSegment)
  14.                End Using
  15.                Using centerLine = polylineSegmentCollection.ToPolyline()
  16.                    Dim solid1 = New Solid3d()
  17.                    Using circle = New Circle(centerLine.StartPoint, Vector3d.YAxis, .5)
  18.                        Dim sweepOptionsBuilder = New SweepOptionsBuilder()
  19.                        sweepOptionsBuilder.Align = SweepOptionsAlignOption.AlignSweepEntityToPath
  20.                        sweepOptionsBuilder.BasePoint = centerLine.StartPoint
  21.                        sweepOptionsBuilder.Bank = True
  22.                        solid1.CreateSweptSolid(circle, centerline, sweepOptionsBuilder.ToSweepOptions())
  23.                    End Using
  24.                    modelSpace.AppendEntity(solid1)
  25.                    transaction.AddNewlyCreatedDBObject(solid1, True)
  27.                    Dim solid2 = New Solid3d()
  28.                    Using circle2 = New Circle(centerLine.StartPoint, Vector3d.YAxis, 0.5)
  29.                        Dim circleCollection = New DBObjectCollection()
  30.                        circleCollection.Add(circle2)
  31.                        Dim regionCollection = Autodesk.AutoCAD.DatabaseServices.Region.CreateFromCurves(circleCollection)
  32.                        Dim region As Region = regionCollection(0)
  33.                        solid2.ExtrudeAlongPath(region, centerLine, 0.0)
  34.                    End Using
  35.                    solid2.TransformBy(Matrix3d.Displacement(New Vector3d(-12, 0, 0)))
  36.                    modelSpace.AppendEntity(solid2)
  37.                    transaction.AddNewlyCreatedDBObject(solid2, True)
  38.                    transaction.Commit()
  39.                End Using
  40.            End Using
  41.        End Using

ISOLINES does remedy the situation but only if you make it a high value and as Jeff mentioned changing it back and regening just resets it to its originally sucky condition.

What I am trying to accomplish is the beginnings of making a U-Bolt.  I thought this was going to be an easy exercise but apparently I over estimated my own ability.  :(
Title: Re: Sweeping a Solid
Post by: MickD on March 11, 2016, 06:04:33 PM
I think I've come across this before too Keith and as long it doesn't affect the integrity of your system/data, don't let it worry you too much unless your 2d output is suffering. :)
Title: Re: Sweeping a Solid
Post by: Keith Brown on March 12, 2016, 01:01:28 PM
Well I kept at it and came up with a solution that works for me.  I noticed that when used the ExtrudeAlongPath api that only the first segment of the polyline was incorrect.  So i just made the first segment the minimum length that Autocad would accept for an extrusion which in this case was 0.001.

I made a couple modifications to the code and this is what I came up with.  Hopefully it will help someone in the future.

Code - Visual Basic: [Select]
  1. Private Sub InputButton1_Click(sender As Object, e As EventArgs) Handles InputButton1.Click
  2.   Me.CancelCommands()
  3.   using Active.Document.LockDocument()
  4.      Using transaction = Active.Database.TransactionManager.StartTransaction()
  5.         Dim modelSpace = Active.Database.ModelSpace(OpenMode.ForWrite)
  6.         Dim uBolt = CreateUBolt(0.375, 3.5, 3.0)
  7.         If uBolt IsNot Nothing Then
  8.            modelSpace.AppendEntity(uBolt)
  9.            transaction.AddNewlyCreatedDBObject(uBolt, True)
  10.         Else
  11.            Active.WriteMessage("Unable to create a UBolt with the current dimensions.")
  12.         End If
  13.         transaction.Commit()
  14.      End Using
  15.   End Using
  16. End Sub
  18. ''' <summary>
  19. ''' Cancels any current command by sending escape to the command line twice.
  20. ''' </summary>
  21. Private Sub CancelCommands()
  22.   If CShort(CoreApplication.GetSystemVariable("CMDACTIVE")) <> 0 Then
  23.      Active.Document.SendStringToExecute(ChrW(27) & ChrW(27), False, True, False)
  24.      Utils.PostCommandPrompt()
  25.   End If
  26. End Sub
  28. Private Const MinimumExtrusionLength = .001
  31. ''' <summary>
  32. ''' Createsa 3D UBolt with a center point at the world origin.  To change the centerpoint, tranform the solid after creation.
  33. ''' </summary>
  34. ''' <param name="uBoltDiameter">The u bolt diameter.</param>
  35. ''' <param name="pipeDiameter">The pipe diameter.</param>
  36. ''' <param name="extendedLength">The extended length of the ubolt beyond the diameter..</param>
  37. ''' <returns>A Solid3D representation of the UBolt</returns>
  38. ''' <exception cref="System.ArgumentOutOfRangeException">
  39. ''' UBolt Diameter is too small.
  40. ''' or
  41. ''' Pipe Diameter is to small.
  42. ''' </exception>
  43. Private Function CreateUBolt(uBoltDiameter As Double, pipeDiameter As Double, extendedLength As Double) As Solid3d
  45.   If uBoltDiameter <= MinimumExtrusionLength Then
  46.      Throw New ArgumentOutOfRangeException(NameOf(uBoltDiameter), "UBolt Diameter is too small.")
  47.   End If
  48.   If pipeDiameter <= MinimumExtrusionLength Then
  49.      Throw New ArgumentOutOfRangeException(NameOf(pipeDiameter), "Pipe Diameter is to small.")
  50.   End If
  51.   Dim centerToCenter = (pipeDiameter / 2) + uBoltDiameter
  53.   ' While not probable, it is possible that the sum value is greater then the largest double value.  Input values for
  54.   ' extended length should take this into account.
  55.   Dim straightLength = (pipeDiameter / 2) + extendedLength
  56.   Dim uBolt = New Solid3d()
  57.   Dim polylineSegmentCollection = New PolylineSegmentCollection()
  58.   using lineSegment1 = New LineSegment2d(New Point2d(-1 * centerToCenter, straightLength), New Point2d(-1 * centerToCenter, straightLength - minimumExtrusionLength))
  59.      Dim lineSegment = New PolylineSegment(lineSegment1)
  60.      polylineSegmentCollection.Add(lineSegment)
  61.   End Using
  62.   Using lineSegment2 = New LineSegment2d(New Point2d(-1 * centerToCenter, straightLength - minimumExtrusionLength), New Point2d(-1 * centerToCenter, 0))
  63.      Dim lineSegment = new PolylineSegment(lineSegment2)
  64.      polylineSegmentCollection.Add(lineSegment)
  65.   End Using
  66.   Dim arcSegment = new PolylineSegment(New Point2d(-1 * centerToCenter, 0), New Point2d(centerToCenter, 0), 1, 0)
  67.   polylineSegmentCollection.Add(arcSegment)
  68.   Using lineSegment3 = New LineSegment2d(New Point2d(centerToCenter, 0), New Point2d(centerToCenter, straightLength))
  69.      Dim lineSegment = new PolylineSegment(lineSegment3)
  70.      polylineSegmentCollection.Add(lineSegment)
  71.   End Using
  72.   Using centerLine = polylineSegmentCollection.ToPolyline()
  73.      Using profile = New Circle(centerLine.StartPoint, Vector3d.YAxis, uBoltDiameter)
  74.         Try
  75.            Dim profileCollection = New DBObjectCollection()
  76.            profileCollection.Add(profile)
  77.            Dim profileRegionCollection = Autodesk.AutoCAD.DatabaseServices.Region.CreateFromCurves(profileCollection)
  78.            Dim profileRegion As Region = profileRegionCollection(0)
  79.            uBolt.ExtrudeAlongPath(profileRegion, centerLine, 0.0)
  80.            uBolt.CleanBody()
  81.         Catch exception As Exception
  82.            Log.Logger.Error(exception, "Unable to extrude the 3D Solid")
  83.            Return Nothing
  84.         End Try
  86.      End Using
  87.   End Using
  88.   Return uBolt
  89. End Function
Title: Re: Sweeping a Solid
Post by: Master_Shake on March 14, 2016, 07:57:28 AM
Curious, kind of makes sense but I wonder what the absolute minimum is as there is a soft-coded maximum limit on extrusions.

Also, is it a concern that you added an additional vertex into the solid? Might be beneficial (if possible in .net) to clean the 3D solid after extrusion.

Title: Re: Sweeping a Solid
Post by: Master_Shake on March 14, 2016, 07:57:51 AM
Pre-Clean attached
Title: Re: Sweeping a Solid
Post by: Keith Brown on March 14, 2016, 09:12:19 AM
I was unaware that you could 'Clean' solids.

I updated the previous post with the CleanBody() method.  Thanks for the info.

I do believe that .001 is the minimum length for solid functions. 
Title: Re: Sweeping a Solid
Post by: huiz on April 12, 2019, 09:00:51 AM
Quite old this topic but useful information now I am working on this.

I found out that a Solid created by the AutoCAD Command creates a more intelligent 3D Solid than I create with code. Do a list on both and you will see this:

Code: [Select]

                  3DSOLID   Layer: "0"
                            Space: Model space
                   Color: BYLAYER    Linetype: "Continuous"
                   LineWeight: Default
                   Handle = 145
         History = None
    Show History = No
   Bounding Box: Lower Bound X = 159.809  , Y = 159.747  , Z = 0.341
                 Upper Bound X = 198.179  , Y = 186.957  , Z = 4.638

Code: [Select]

                  3DSOLID   Layer: "0"
                            Space: Model space
                   Handle = 157
         History = None
    Show History = No
      Solid type = Sweep
     Sweep length: 38.867
 Profile rotation: 0.00
 Scale along path: 1.000
 Twist along path: 0.00
Press ENTER to continue:
             Bank: Off
   Bounding Box: Lower Bound X = 173.891  , Y = 144.954  , Z = -0.692
                 Upper Bound X = 205.943  , Y = 169.206  , Z = 0.692

So, the API probably just create a 3D Solid and AutoCAD can create a more intelligent object.

Also, and that makes it really weird, the coded solid get XData added! Why?

Code: [Select]

* Registered Application Name: ACAD_STEPID
* Code 1071, 32-bit signed long integer: 2