Unable to Create Surface Patch in AutoCAD Using API

Unable to Create Surface Patch in AutoCAD Using API

kovacsv1
Advocate Advocate
403 Views
3 Replies
Message 1 of 4

Unable to Create Surface Patch in AutoCAD Using API

kovacsv1
Advocate
Advocate

Hi,

So I try to extract solids from non-planar 3D plines with Acad API with the following workflow in mind:

  • create 3D polylines
  • create surface using Surface.CreatePatchSurface
  • thicken surface

It works using the UI, altough I have issues doing it with the API.
The Surface.CreatePatchSurface Method throws eInvalidInput exception and I don’t know why.
I have listed and checked all inputs and they seem to be fine. Can someone please take a look?
I do this in Dynamo, so the code is in Python, but hopefully it should not matter.

I have tried it with a single rectangle, but it does not work either.

# Load the Python Standard and DesignScript Libraries
import sys
import clr
from System import Array

# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')

# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
import Autodesk.AutoCAD.DatabaseServices as acaddbs
from Autodesk.AutoCAD.Geometry import *

# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *

# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN

adoc = Application.DocumentManager.MdiActiveDocument
editor = adoc.Editor

plines = IN[0]

with adoc.LockDocument():
    db = adoc.Database  # Get the active document's database
    with db.TransactionManager.StartTransaction() as t:
        bt = t.GetObject(db.BlockTableId, acaddbs.OpenMode.ForRead)  # Get the Block Table
        model_space_id = bt[acaddbs.BlockTableRecord.ModelSpace]       # Get the ModelSpace id
        btr = t.GetObject(model_space_id, acaddbs.OpenMode.ForWrite)       # Get ModelSpace for writing
        
        composite_path_ref = None   # This will hold the final PathRef for a polyline
        all_lines = None            # To store the exploded lines collection

        # Process each polyline in the input list
        for pline in plines:
            # Get the ObjectId of the polyline
            poly_id = pline.InternalObjectId
            obj = t.GetObject(poly_id, acaddbs.OpenMode.ForWrite)
            
            # Prepare a collection to store the exploded entities (lines)
            lines = acaddbs.DBObjectCollection()
            obj.Explode(lines)
            
            # List to hold FullSubentityPath objects for each exploded segment
            full_subentity_paths_list = []
            
            # Iterate over the exploded lines and create a FullSubentityPath for each segment
            for i, line in enumerate(lines):
                #btr.AppendEntity(line)
                #t.AddNewlyCreatedDBObject(line, True)
                # Convert the line's ObjectId into a .NET array of ObjectId
                object_id_array = Array[acaddbs.ObjectId]([line.ObjectId])
                
                # Create a SubentityId for the line segment (using SubentityType.Edge and index i)
                subentity_id = acaddbs.SubentityId(acaddbs.SubentityType.Edge, i)
                
                # Create the FullSubentityPath for this line segment
                #Option1
                full_sub_path = acaddbs.FullSubentityPath(object_id_array, subentity_id)
                #Option2                
                line_egderef = acaddbs.EdgeRef(line)
                #Option3(not working)
                full_sub_path_egderef = acaddbs.EdgeRef(full_sub_path)
            
                full_subentity_paths_list.append(line_egderef)
                
            # Convert the list of FullSubentityPath objects into a .NET array
            full_subentity_paths_array = Array[acaddbs.EdgeRef](full_subentity_paths_list)
            #Needed in case of Option1
            empty_fullsub_path = Array.CreateInstance(acaddbs.FullSubentityPath, 0)
            
            # Create a composite PathRef from the array of FullSubentityPath objects
            #composite_path_ref = acaddbs.PathRef(full_subentity_paths_array,empty_fullsub_path)
            composite_path_ref = acaddbs.PathRef(full_subentity_paths_array)
            editor.WriteMessage("Composite PathRef created: {0}\n".format(composite_path_ref))
            
            # Create an empty constraint collection
            constraint_ids = acaddbs.ObjectIdCollection()
    
            # Define continuity and bulge values
            continuity = 0 # G1 (tangent) continuity
            bulge = 0   # Moderate bulge
    
            # Create the patch surface using the composite PathRef
            #surf = acaddbs.Surface.CreatePatchSurface(composite_path_ref, constraint_ids, continuity, bulge)
            # Optionally, store the exploded lines from the last polyline processed
            try:
                surf = acaddbs.Surface.CreatePatchSurface(composite_path_ref, constraint_ids, continuity, bulge)
                editor.WriteMessage("Patch surface created successfully.\n")
            except Exception as ex:
                editor.WriteMessage(f"Failed to create patch surface: {ex}\n")
            all_lines = lines
        
        # Commit the transaction before ending
        t.Commit()
        
        #Checking pathref
        outlistcurves = []
        edgerefs = composite_path_ref.EdgeRefs
        for edgeref in edgerefs:
            outlistcurves.append(edgeref.Curve.Length)
            

# Assign your output to the OUT variable.
OUT = composite_path_ref, all_lines, constraint_ids,composite_path_ref.EdgeRefs[0].Curve.StartPoint, subentity_id.Index,full_sub_path.IsNull,outlistcurves

 

0 Likes
Accepted solutions (2)
404 Views
3 Replies
Replies (3)
Message 2 of 4

kovacsv1
Advocate
Advocate
Accepted solution

Okay, Claude solved it for me 😅


Turns out I forgot to add the exploded DBobject lines to the block table.

From Claude:
Here are the key issues I’ve fixed in the code:

  1. ObjectId vs DB Objects: You were mixing direct DB objects with ObjectId references when creating EdgeRefs, which can cause the EInvalidInput error.
  2. Adding objects to model space: For the exploded lines to be valid, they need to be added to the model space and properly registered with the transaction manager.
  3. EdgeRef Creation: The EdgeRef constructor should be used with actual curve objects, not with FullSubentityPath objects.
0 Likes
Message 3 of 4

_gile
Consultant
Consultant
Accepted solution

Hi,

 

You do not need to explode the polyline 3d, you can simply use it as EdgeRef.

public static ObjectId CreatePatchSurface(Polyline3d poly3d, bool associativeEnabled = true)
{
    var pathRef = new PathRef(new[] { new EdgeRef(poly3d) });
    var ids = new ObjectIdCollection();
    return AcDb.Surface.CreatePatchSurface(pathRef, ids, 0, 0.0, associativeEnabled);
}

 

 

 

 

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 4 of 4

kovacsv1
Advocate
Advocate

oh, you are right, thank you.

0 Likes