evereux / pycatia

python module for CATIA V5 automation
MIT License
204 stars 53 forks source link

Question about using iObjects from pycatia #192

Closed CesarAero closed 8 months ago

CesarAero commented 9 months ago

Dear pycatia community,

I am facing a difficulty with pycatia and I couldn't find the right place to ask it. I hope that you could provide me some support as I couldn't find the right answer in the pycatia documentation, the CATIA macro recorder or asking ChatGPT...

My problem is linked with the usage of iObjects for hybrid shape operations (Generative Shape Design workbench tools). It is quite simple to use the GUI to project a sketch or to select a plane and make hybrid operations but accessing to the right elements via pycatia is quite challenging. I have created a reproducer of my problem where a simple tasks needs to be achieved: to project a sketch into another plane. Here you can download the pycatia code that I've coded to show my problem (I changed the extension to .txt because I couldn't send .py codes)

problem_reproducer.txt

# ----- Packages
# ----------------------------------------------------------------------- #
from pycatia import catia
from pycatia.mec_mod_interfaces.hybrid_body import HybridBody
from pycatia.mec_mod_interfaces.hybrid_shape import HybridShape
from pycatia.in_interfaces.reference import Reference
from pycatia.mec_mod_interfaces.part import Part
from pycatia.mec_mod_interfaces.part_document import PartDocument

# %%
# ============================================================================= #
# ----- Create CATIA part
# ============================================================================= #
#
caa = catia()
application = caa.application
documents = application.documents
if documents.count > 0:
    for document in documents:
        document.close() # Close all the open documents

# Create Part
documents.add('Part')

# Get references to document, parts and tools to create geometries
document = application.active_document      # document = caa.documents[0]
part = document.part.com_object             # Get Part  
partbody = part.Bodies.Item("PartBody")     # Get PartBody  
sketches = partbody.Sketches                # Get sketches on PartBody 
shpfac = part.ShapeFactory                  # Get ShapeFactory 
hybrid_bodies = Part(part).hybrid_bodies    # Get Hybrid Bodies 
hsf = Part(part).hybrid_shape_factory       # Get Hybrid Shape Factory 
selection = document.selection              # Get document selection

# Get main planes
plane_XY = part.OriginElements.PlaneXY
plane_YZ = part.OriginElements.PlaneYZ
plane_ZX = part.OriginElements.PlaneZX

# %%
# ============================================================================= #
# ----- Create elements before reaching the problem
# ============================================================================= #
#
# ----- Create sketch with a circle
sketch_1 = sketches.Add(plane_XY)
sketch_1.name = "sketch_1"
ske2D_1 = sketch_1.OpenEdition()

circ2proj = ske2D_1.CreateClosedCircle(0, 0, 100)
circ2proj.name = "circle_to_project"

# sketch close edition 
sketch_1.CloseEdition()

# Update the document
document.part.update()

# ----- Create a plane where the sketch needs to be projected
aux_bodies = hybrid_bodies.add()
aux_bodies.name = "auxiliar bodies"

# %% --------------------------------------------------------------------------
# Problem 1: I cannot use directly plane_XY so I need to duplicate plane XY
# -----------------------------------------------------------------------------
p1 = hsf.add_new_point_coord(0, 0, 0)
p2 = hsf.add_new_point_coord(1, 0, 0)
p3 = hsf.add_new_point_coord(0, 1, 0)
aux_bodies.append_hybrid_shape(p1)
aux_bodies.append_hybrid_shape(p2)
aux_bodies.append_hybrid_shape(p3)
plane_XY_2 = hsf.add_new_plane3_points(p1, p2, p3)
plane_XY_2.name = "duplicated plane XY"
aux_bodies.append_hybrid_shape(plane_XY_2)

# Create plane where projection is needed
plane_proj = hsf.add_new_plane_offset(plane_XY_2, 200.0, False)
plane_proj.name = "plane_projection"
aux_bodies.append_hybrid_shape(plane_proj)
# -----------------------------------------------------------------------------

# # %% --------------------------------------------------------------------------
# # Propper solution: Doesn't work (plane_XY isn't a iObject)
# # -----------------------------------------------------------------------------
# # Create plane where projection is needed
# plane_proj = hsf.add_new_plane_offset(plane_XY, 200.0, False)
# plane_proj.name = "plane_projection"
# aux_bodies.append_hybrid_shape(plane_proj)
# # -----------------------------------------------------------------------------

# # %% --------------------------------------------------------------------------
# # Propper solution 2:  Doesn't work neither (Use the selection function)
# # -----------------------------------------------------------------------------
# # Create plane where projection is needed
# selection.clear();
# selection.add(plane_XY)
# plane_proj = hsf.add_new_plane_offset(selection, 200.0, False)
# selection.clear()
# plane_proj.name = "plane_projection"
# aux_bodies.append_hybrid_shape(plane_proj)
# # -----------------------------------------------------------------------------

# Update the document
document.part.update()

# %%
# ============================================================================= #
# ----- Problem 2: Project cruve from "sketch_1" into plane "plane_proj"
# ============================================================================= #
#
# %% --------------------------------------------------------------------------
# Approach 1: Try to project the sketch (as you would do in the GUI)
# -----------------------------------------------------------------------------
proj_sketch = hsf.add_new_project(sketch_1, plane_proj)
proj_sketch.name = "proj_sketch"
aux_bodies.append_hybrid_shape(proj_sketch)
# -----------------------------------------------------------------------------

# %% --------------------------------------------------------------------------
# Approach 2: Select the curve and project it
# -----------------------------------------------------------------------------
sketch_curve = sketch_1.GeometricElements.item("circle_to_project")
proj_sketch = hsf.add_new_project(sketch_1, plane_proj)
proj_sketch.name = "proj_sketch"
aux_bodies.append_hybrid_shape(proj_sketch)
# -----------------------------------------------------------------------------

I am facing 2 main problems in this reproducer :

  1. I cannot use the "plane_XY = part.OriginElements.PlaneXY" variable to create an offset plane using "plane_proj = hsf.add_new_plane_offset(i_plane, i_offset, i_orientation)" because the plane_XY belongs to "PartBody" and it seems that plane_XY isn't an "i_plane". I couldn't eve use the selection function. Solution: I had to duplicate the plane as a hybrid body.
  2. I cannot project the curve in sketch_1 in the new plane using the function "hsf.add_new_project(i_element, i_support)" once again because sketch_1 isn't a iObject. I also tried addressing directly the curve that I want to project by using "sketch_curve = sketch_1.GeometricElements.item("circle_to_project")" but this doesn't make the sketch curve a i_curve.

I am aware that working with sketches and hybrid bodies is challending even in CATIA VB due to the differences in the used workbenches. Which would be the right way to address to the part bodies and use them in hybrid operations? Or should I convert them always into iObjects?

Thank you in advance!

evereux commented 9 months ago

You need to read the source code / documentation to see what objects a class method requires.

For example add_new_project requires a reference object, not a sketch object.

Take a look at the examples for creating references as it's a common requirement. This is not a pycatia thing but a CATIA COM interface thing.

CesarAero commented 9 months ago

Thank you evereux for your message,

I managed to fix the problem of the reference to the XY plane by using the Reference class and I don’t need anymore to duplicate the plane.

However the problem with projecting the sketch persists. I have also tried to pass the curve inside the sketch to the add_new_project function through the interface functions edge and shape from pycatia.mec_mod_interfaces as: from pycatia.mec_mod_interfaces.shape import Shape sketch_curve = sketch_1.GeometricElements.item("circle_to_project") proj_sketch = hsf.add_new_project(Shape(sketch_curve), plane_proj) proj_sketch.name = "proj_sketch" aux_bodies.append_hybrid_shape(proj_sketch)

But this operation is not possible: image

I have checked some forums about programing in CATIA and this operation in VB is simply: Set reference1 = part.CreateReferenceFromObject(sketch_1) Set reference2 = part.CreateReferenceFromObject(plane_proj) Set hybridShapeProject = hybridShapeFactory.AddNewProject(reference1, reference2)

There is no need to convert the sketches because I guess that the VB interface takes all this into account.

I couldn't find helpful information about how to use a sketch in hybrid operations using pycatia. Could you give me some advice about how to face this issue? I could in exchange prepare an example script for this specific problem and give it to you so you can post is as example for this particular operation. Then future users can go directly and learn from this script.

evereux commented 9 months ago

Be careful with how you're using pycatia here. You're calling the COM interface methods directly and not the pycatia based ones so you could get unexpected behavior. I don't know if that is the issue here.

eg:

sketch_curve = sketch_1.GeometricElements.item("circle_to_project")

See the GeometricElements? pycatia uses pythons naming conventions standards so you won't see capitalized class method names. See sketch.geometric_elements

I couldn't find helpful information about how to use a sketch in hybrid operations using pycatia.

I get this type of question a lot but the reality is, if you can do it VBA, it's pretty much the same in pycatia, just a different language.

Anyways, this works for me (note the class method names are all lower_case). I've a geometrical set called ConstructionGeometry that contains a sketch Sketch.1 and a plane Plane.1.


from pycatia import catia
from pycatia.mec_mod_interfaces.part_document import PartDocument

caa = catia()
application = caa.application
document: PartDocument = application.active_document
part = document.part
hybrid_bodies = part.hybrid_bodies
construction_geometry = hybrid_bodies.item("ConstructionGeometry")
hybrid_shapes = construction_geometry.hybrid_shapes
sketches = construction_geometry.hybrid_sketches
sketch = sketches.get_item_by_name("Sketch.1")
plane = hybrid_shapes.item("Plane.1")

ref_sketch = part.create_reference_from_object(sketch)
ref_plane = part.create_reference_from_object(plane)

hsf = part.hybrid_shape_factory
projection = hsf.add_new_project(ref_sketch, ref_plane)

construction_geometry.append_hybrid_shape(projection)

part.update()

Looking at your small sample above it looks like you still haven't created a reference from the sketch.

There is no need to convert the sketches because I guess that the VB interface takes all this into account.

I don't know what you mean here?

CesarAero commented 9 months ago

I found my errors. As you mentioned, I was using the COM interface methods directly and not the pycatia based ones. Now my script works perfectly and does the job. I will pay more attention to this in the future...

I leave here the fixed code in case you want to use it somehow as example or if someone else runs into the same problem: problem_reproducer.txt

evereux commented 9 months ago

Glad you got it fixed. 👍

evereux commented 8 months ago

Closing as issue seems to be now resolved.