I am writing a routine that is supposed to get the heights and radii of all cylinders in a drawing. The cylinders are not necessarily aligned with WCS.
I am able to successfully find and identify which 3D Solids are cylinders, but am having a really hard time determining the height and radii of these entities. I am using ARX and the COM interface to get to the place where I identify the entity as a cylinder. From there I have tried either using properties of the Solid3D class, or the Acad3DSolid class. Example properties include: centroid, moments of inertia, principal moments, bounding box etc. Volume is also a property. I believe there is some math that can be done with these properties to determine height and radius, but most of my attempts only work if the cylinder is aligned with WCS. The requirements dictate the cylinder can be at any orientation. The Autodesk.AutoCAD.Geometry.Cylinder object does have a height and radius property, but I cannot find away to cast either the Solid3D or Acad3DSolid objects into the geometry. Any help would be appreciated, either with the correct math to determine on the object properties or some way to utilize another class. Looking at the properties of a cylinder in AutoCAD itself, the 3DSolid cylinder solidType clearly have height and radius properties (see screen shot).
Private Shared Sub getCylinderLengths()
Dim Solid3DobjectIDs As New List(Of ObjectId)
Solid3DobjectIDs = getAll3dSolidObjIDs() 'returns a list of objectID that are of type 3DSolid
Dim db As Database = HostApplicationServices.WorkingDatabase
If Solid3DobjectIDs.Count > 0 Then
For Each objid In Solid3DobjectIDs
Using t As Transaction = db.TransactionManager.StartTransaction()
Dim thisSolid As Solid3d = TryCast(t.GetObject(objid, OpenMode.ForRead), Solid3d)
Dim AcadSol As Autodesk.AutoCAD.Interop.Common.Acad3DSolid = thisSolid.AcadObject
If AcadSol.SolidType = "Cylinder" Then
'find radius and height here.
End If
t.Commit()
End Using
Next
End If
End Sub
Solved! Go to Solution.
Solved by _gile. Go to Solution.
I don't think the Solid3DMassProperties will give you what you want.
You'll probably need to make use of the BREP API
// Assembly acdbmgdbrep, Version 24.2.0.0 |
Location for me: | D:\ObjectARX_2023\inc\acdbmgdbrep.dll |
The API assumes a 'healthy' knowledge of 3D solids creation .
Regards
// Called Kerry in my other life.
Everything will work just as you expect it to, unless your expectations are incorrect.
Sometimes the question is more important than the answer.
class keyThumper<T> : Lazy<T>; another Swamper
Hi,
As @kdub_nz said, using the Boundary Representation is a good way.
Here's an example:
private static bool IsCylinder(Solid3d solid, out double radius, out double height)
{
radius = height = 0.0;
using (var brep = new Brep(solid))
{
var cylinder = brep.Faces
.Select(face => ((ExternalBoundedSurface)face.Surface).BaseSurface)
.FirstOrDefault(surface => surface is Cylinder);
if (cylinder == null)
return false;
radius = ((Cylinder)cylinder).Radius;
height = ((Cylinder)cylinder).Height.Length;
return true;
}
}
And a testing command:
[CommandMethod("TEST")]
public void Test()
{
var doc = AcAp.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var peo = new PromptEntityOptions("\nSelect cylinder: ");
peo.SetRejectMessage("\nSelected object is not a Solid 3d.");
peo.AddAllowedClass(typeof(Solid3d), true);
var per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK) return;
using (var tr = db.TransactionManager.StartTransaction())
{
var solid = (Solid3d)tr.GetObject(per.ObjectId, OpenMode.ForRead);
if (IsCylinder(solid, out double radius, out double height))
{
ed.WriteMessage($"\nRadius = {radius}\tHeight = {height}");
}
else
{
ed.WriteMessage("\nSelected solid 3d is not a cylinder.");
}
tr.Commit();
}
}
@_gileThank you so much! Your solution is working and it doesn't seem to care about the alignment of the solid. For posterity, here is my implementation in VB.NET. If you're ever in Montana I'll buy you a beer. Had been really stuck on this.
Private Shared Function isCylinder(ByVal solid As Solid3d, ByRef radius As Double, ByRef height As Double)
radius = height = 0
Using brep = New BoundaryRepresentation.Brep(solid)
Dim cylinder = brep.Faces.[Select](Function(face) (CType(face.Surface, ExternalBoundedSurface)).BaseSurface).FirstOrDefault(Function(surface) TypeOf surface Is Cylinder)
If cylinder Is Nothing Then Return False
radius = (CType(cylinder, Cylinder)).Radius
height = (CType(cylinder, Cylinder)).Height.Length
Return True
End Using
End Function
It's been interesting getting under the hood and seeing how CAD deals with solids. 3D geometry is not for the faint of heart!
Can't find what you're looking for? Ask the community or share your knowledge.