Skip to content

Instantly share code, notes, and snippets.

@MadhukarMoogala
Created November 25, 2024 16:26
Show Gist options
  • Save MadhukarMoogala/57be825b2175027411d36bdfc27fe434 to your computer and use it in GitHub Desktop.
Save MadhukarMoogala/57be825b2175027411d36bdfc27fe434 to your computer and use it in GitHub Desktop.
Updates the profile curve of an associative planar surface in AutoCAD.
/// <summary>
/// Updates the profile curve of an associative planar surface in AutoCAD.
/// Assumes the user has selected a planar surface with a rectangular profile curve.
/// Demonstrates the workflow for:
/// - Verifying surface associativity
/// - Extracting and transforming the profile
/// - Updating the surface with a modified profile
/// </summary>
[CommandMethod("UpdateAssociatePlanarSurface")]
public static void UpdateAssociatePlanarSurface()
{
// Get the active AutoCAD database
Database activeDatabase = HostApplicationServices.WorkingDatabase;
// Prompt the user to select a surface
PromptEntityOptions surfaceSelectionPrompt = new PromptEntityOptions("\nSelect a surface: ");
surfaceSelectionPrompt.SetRejectMessage("Must be a Surface!"); // Reject non-surface entities
surfaceSelectionPrompt.AddAllowedClass(typeof(DBSurface), exactMatch: false);
Editor documentEditor = Application.DocumentManager.MdiActiveDocument.Editor;
PromptEntityResult selectionResult = documentEditor.GetEntity(surfaceSelectionPrompt);
// Exit if selection is canceled or invalid
if (selectionResult.Status != PromptStatus.OK)
return;
// Begin a transaction to handle database changes
using Transaction transaction = selectionResult.ObjectId.Database.TransactionManager.StartTransaction();
try
{
// Access the selected surface
DBSurface selectedSurface = transaction.GetObject(selectionResult.ObjectId, OpenMode.ForWrite) as DBSurface;
if (selectedSurface == null)
return;
// Check if the surface is associative by verifying the CreationActionBodyId
var surfaceCreationActionId = selectedSurface.CreationActionBodyId;
bool isSurfaceAssociative = false;
if (surfaceCreationActionId != ObjectId.Null)
{
AssocActionBody associatedActionBody = transaction.GetObject(surfaceCreationActionId, OpenMode.ForRead) as AssocActionBody;
isSurfaceAssociative = associatedActionBody != null;
}
if (isSurfaceAssociative)
{
// Retrieve the associated action body for the planar surface
AssocPlaneSurfaceActionBody planeActionBody = transaction.GetObject(surfaceCreationActionId, OpenMode.ForWrite) as AssocPlaneSurfaceActionBody;
// Retrieve the input path parameters for the action body
planeActionBody.GetInputPaths(out EdgeRef[][][] edgeReferenceLayers);
// List to store extracted entities from edge references
var ents = new List<Entity>();
// Extract entities from the nested edge reference layers
for (int layerIndex = 0; layerIndex < edgeReferenceLayers.Length; layerIndex++)
{
EdgeRef[][] edgeReferenceRows = edgeReferenceLayers[layerIndex];
for (int rowIndex = 0; rowIndex < edgeReferenceRows.Length; rowIndex++)
{
EdgeRef[] edgeReferences = edgeReferenceRows[rowIndex];
for (int referenceIndex = 0; referenceIndex < edgeReferences.Length; referenceIndex++)
{
// Convert edge references to entities and store them
Entity extractedEntity = edgeReferences[referenceIndex].CreateEntity();
extractedEntity.ColorIndex = 1; // Optional: Set the color for visual distinction
extractedEntity.SetDatabaseDefaults();
ents.Add(extractedEntity);
SubEntityUtilities.PostToDataBase(extractedEntity); // Add the entity to the database
}
}
}
// Clone the first extracted profile and apply a transformation
var profile = ents[0].Clone() as Entity;
if (profile is Polyline pl)
{
// Calculate the centroid of the polyline for transformation
var center = GetCentroid(pl);
// Apply a scaling transformation to the profile
profile.TransformBy(Matrix3d.Scaling(10, center));
// Update the input path with the modified profile
var edges = new List<EdgeRef> { new EdgeRef(profile) };
planeActionBody.UpdateInputPath(0, new PathRef(edges.ToArray()));
}
// Reevaluate the associative network to apply the changes
AssocManager.EvaluateTopLevelNetwork(activeDatabase, null, 0);
}
// Commit the transaction to save changes
transaction.Commit();
}
catch (System.Exception ex)
{
// Handle errors and abort the transaction if necessary
documentEditor.WriteMessage($"\nError: {ex.Message}");
transaction.Abort();
}
}
/// <summary>
/// Calculates the centroid of a closed polyline.
/// Throws an exception if the polyline is not closed.
/// </summary>
/// <param name="polyline">The closed polyline for which the centroid is calculated.</param>
/// <returns>The centroid of the polyline as a Point3d.</returns>
public static Point3d GetCentroid(Polyline polyline)
{
if (!polyline.Closed)
throw new Exception(ErrorStatus.InvalidInput, "Polyline must be closed");
double area = 0, cx = 0, cy = 0;
int numVertices = polyline.NumberOfVertices;
// Apply the Shoelace formula for centroid and area calculation
for (int i = 0; i < numVertices; i++)
{
Point2d p1 = polyline.GetPoint2dAt(i);
Point2d p2 = polyline.GetPoint2dAt((i + 1) % numVertices);
double temp = p1.X * p2.Y - p2.X * p1.Y;
area += temp;
cx += (p1.X + p2.X) * temp;
cy += (p1.Y + p2.Y) * temp;
}
area *= 0.5;
cx /= (6 * area);
cy /= (6 * area);
// Return the calculated centroid
return new Point3d(cx, cy, 0);
}
@MadhukarMoogala
Copy link
Author

AssocFramework.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment