evereux / pycatia

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

[QUESTION] RELATIONS #219

Closed ozserhatt closed 3 months ago

ozserhatt commented 3 months ago

Can you help me dear friends ? I can not create a relation with parameter value on Part Number

from pycatia import catia
from pycatia.product_structure_interfaces.product_document import ProductDocument
from pycatia.mec_mod_interfaces.part_document import PartDocument

caa = catia()
application = caa.application
doc = application.documents
active_document = ProductDocument(application.active_document.com_object)
product = active_document.product
part_num = product.part_number

if product.is_catpart():
    cat_type = product.reference_product.type == "CATPart"
    print(product.reference_product.name)
    part_document = PartDocument(doc.item(product.reference_product.file_name).com_object)
    part = part_document.part
    parameters = part.parameters
    relations = part.relations

    root_parameter_set = parameters.root_parameter_set
    parameter_sets = root_parameter_set.parameter_sets

    bom_parameter_set = parameter_sets.item("BOM")
    part_name = bom_parameter_set.direct_parameters.item("PART-NAME").value

    relations.create_formula("formula1", "", part_num, f"{part_name}")

ERROR :

return Formula(self.relations.CreateFormula(i_name, i_comment, i_output_parameter.com_object, i_formula_body))
                                                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'str' object has no attribute 'com_object'
evereux commented 3 months ago

Look at the error messsage, look at the method you're calling and see what it expects. relations

You need to pass a Parameter not a str.

I would expect

    part_name = bom_parameter_set.direct_parameters.item("PART-NAME").value

    relations.create_formula("formula1", "", part_num, f"{part_name}")

to be more like

    param_part_name = bom_parameter_set.direct_parameters.item("PART-NAME")

    relations.create_formula("formula1", "", param_part_name, param_part_name.value)

But, this will generate an error. I'm not sure how to solve this as I don't understand what your end goal here is. The relation itself doesn't make much sense.

There are examples of using relations in:

https://github.com/evereux/pycatia/blob/master/user_scripts/create_bounding_box.py

https://github.com/evereux/pycatia/blob/master/user_scripts/wing_surface_from_naca_profile.py

Also, record a macro mimicking what it is you're trying to do and read the generated code. Should give you some pointers.

ozserhatt commented 3 months ago

I want to relation, parameter of Part Number with my local parameter PART-NAME. If i write on parameter PART-NAME : "xxxx" , it will be change my Part Number to "xxxx" I sent macro for you

Sub CATMain()

Dim partDocument1 As PartDocument
Set partDocument1 = CATIA.ActiveDocument

Dim part1 As Part
Set part1 = partDocument1.Part

Dim relations1 As Relations
Set relations1 = part1.Relations

Dim parameters1 As Parameters
Set parameters1 = part1.Parameters

Dim parameter1 As Parameter
Set parameter1 = parameters1.Item("Part2\Part Number")

Dim formula1 As Formula
Set formula1 = relations1.CreateFormula("Formula.1", "", parameter1, "`BOM\POS-NO` +" & """" & "_" & """" & "+`BOM\PART-NAME` ")

formula1.Rename "Formula.1"

End Sub
evereux commented 3 months ago

OK I understand now.

You need to get the Part Number Parameter from the Part. The essential line being root_part_number = parameters.item(f'{product.part_number}\Part Number')

from pycatia import catia
from pycatia.product_structure_interfaces.product_document import ProductDocument
from pycatia.mec_mod_interfaces.part_document import PartDocument

caa = catia()
application = caa.application
documents = application.documents
product_document: ProductDocument = application.active_document
product = product_document.product

part_document = PartDocument(documents.item(product.reference_product.file_name).com_object)
part = part_document.part
parameters = part.parameters
relations = part.relations

root_part_number = parameters.item(f'{product.part_number}\Part Number')

root_parameter_set = parameters.root_parameter_set
parameter_sets = root_parameter_set.parameter_sets

bom_parameter_set = parameter_sets.item("BOM")
param_part_name = bom_parameter_set.direct_parameters.item("PART-NAME")

relations.create_formula("formula1", "", param_part_name, f"`{root_part_number.name}`")
ozserhatt commented 3 months ago

Actually, I try to say it will be reverse so, if i write in param_part_name , I want see on my PartNumber automatically. I try it but it does not run..

from pycatia import catia
from pycatia.product_structure_interfaces.product_document import ProductDocument
from pycatia.mec_mod_interfaces.part_document import PartDocument

caa = catia()
application = caa.application
documents = application.documents
product_document: ProductDocument = application.active_document
product = product_document.product

part_document = PartDocument(documents.item(product.reference_product.file_name).com_object)
part = part_document.part
parameters = part.parameters
relations = part.relations

root_part_number = parameters.item(f'{product.part_number}\Part Number')

root_parameter_set = parameters.root_parameter_set
parameter_sets = root_parameter_set.parameter_sets

bom_parameter_set = parameter_sets.item("BOM")
param_part_name = bom_parameter_set.direct_parameters.item("PART-NAME")

relations.create_formula("formula1", "", root_part_number, f"`{param_part_name.value}`")
SyntaxWarning: invalid escape sequence '\P'
  root_part_number = parameters.item(f'{product.part_number}\Part Number')
evereux commented 3 months ago

You need to use the param_part_name.name as I did above but you need to drop the root part number.

Explore the output of param_part_name.name to understand the need of the split.

Replace the last line with this:


param_part_name_without_parent = param_part_name.name.split('\\', 1)[1]
relations.create_formula("formula1", "", root_part_number, f"`{param_part_name_without_parent}`")

Reading your macro above you should have been able to debug this yourself. 😄

ozserhatt commented 3 months ago

Aff, man, i can not do it

from pycatia import catia
from pycatia.product_structure_interfaces.product_document import ProductDocument
from pycatia.mec_mod_interfaces.part_document import PartDocument

caa = catia()
application = caa.application
documents = application.documents
product_document: ProductDocument = application.active_document
product = product_document.product

part_document = PartDocument(documents.item(product.reference_product.file_name).com_object)
part = part_document.part
parameters = part.parameters
relations = part.relations

root_part_number = parameters.item(f'{product.part_number}\Part Number')

root_parameter_set = parameters.root_parameter_set
parameter_sets = root_parameter_set.parameter_sets

part_num = parameters.item("part_number")
bom_parameter_set = parameter_sets.item("BOM")
param_part_name = bom_parameter_set.direct_parameters.item("PART-NAME")

param_part_name_without_parent = param_part_name.name.split('\\', 1)[1]
relations.create_formula("formula1", "", root_part_number, f"`{param_part_name_without_parent}`")
raise CATIAApplicationException(f'Could not find parameter name "{index}".')
pycatia.exception_handling.exceptions.CATIAApplicationException: Could not find parameter name "part_number".
evereux commented 3 months ago

I can't tell what line it's failing on from your error log. If it's root_part_number = parameters.item(f'{product.part_number}\Part Number') you need to ask yourself why?

Is there a parameter in the parameters collection called Part Number? Print out the contents of the parameters collection.

I suspect this is a locale issue where your installation of CATIA V5 uses your locality translation of Part Number.

Again, simple to debug, no?

evereux commented 3 months ago

Try removing this, it's not relevant to what we're doing here as far as I can see:

part_num = parameters.item("part_number")

I can't help anymore unless I see the script error output regarding where the failure was.

evereux commented 3 months ago

I've written this stand alone script that should work for anyone. It'll fail for those not using an English locale for Catia V5 but will get a warning message related to that.

Also, note the use of Parameters.get_name_to_use_in_relation. Just discovered that, very useful!


"""
    Creates the string  parameter `part_number`. The `Document`s `Part Number`
    (for english locales) is then linked to the output of `part_number` using
    relations / formula.
    Changing the parameter `part_number` will then update the `Document`s
    `Part Number`.

    Requirements: The active document must be a CATPart.
"""
```python
from pycatia import catia
from pycatia.exception_handling.exceptions import CATIAApplicationException
from pycatia.mec_mod_interfaces.part_document import PartDocument

caa = catia()
application = caa.application
documents = application.documents
part_document: PartDocument = application.active_document
part = part_document.part
product = part_document.product
parameters = part.parameters
relations = part.relations

# first check to see if the parameter already exists, if not then create it
try:
    param_part_number = parameters.item('part_number')
except CATIAApplicationException:
    param_part_number = parameters.create_string('part_number', 'TempName')

try:
    param_root_part_number = parameters.item(f'{product.part_number}\Part Number')
except CATIAApplicationException:
    raise CATIAApplicationException('Change "Part Number" to the correct translation for your locale')

relations.create_formula('Formula.1', '', param_root_part_number, f'`{parameters.get_name_to_use_in_relation(param_part_number)}`')
ozserhatt commented 3 months ago

That was good stuff man, but still I can not for sub-parameters. 1- I have a sub-parameterset called BOM 2-I have a sub-parameter inside BOM called PART-NAME 3- Not give a raise or error, but it does not work. 4-Can you try this code ? And you can see from +Relations on Catia. We have a warning icon.

from pycatia import catia
from pycatia.exception_handling.exceptions import CATIAApplicationException
from pycatia.mec_mod_interfaces.part_document import PartDocument

caa = catia()
application = caa.application
documents = application.documents
part_document: PartDocument = application.active_document
part = part_document.part
product = part_document.product
parameters = part.parameters
relations = part.relations
root_parameter_set = parameters.root_parameter_set
parameter_sets = root_parameter_set.parameter_sets
bom_set = parameter_sets.item("BOM")
# first check to see if the parameter already exists, if not then create it
try:
    param_part_number = bom_set.direct_parameters.item("PART-NAME")
except CATIAApplicationException:
    param_part_number = parameters.create_string('part_number', 'TempName')

try:
    param_root_part_number = parameters.item(f'{product.part_number}\Part Number')
except CATIAApplicationException:
    raise CATIAApplicationException('Change "Part Number" to the correct translation for your locale')

relations.create_formula('Formula.1', '', param_root_part_number, f'`{bom_set.direct_parameters.get_name_to_use_in_relation(param_part_number)}`')
Mithro86 commented 3 months ago

If you want the parameter to be created under the set "BOM", do like this.

bom_set.direct_parameters.create_string('part_number', 'TempName'). And there was an error with the fstring for the relation.

from pycatia import catia
from pycatia.exception_handling.exceptions import CATIAApplicationException
from pycatia.mec_mod_interfaces.part_document import PartDocument

caa = catia()
application = caa.application
documents = application.documents
part_document: PartDocument = application.active_document
part = part_document.part
product = part_document.product
parameters = part.parameters
relations = part.relations
root_parameter_set = parameters.root_parameter_set
parameter_sets = root_parameter_set.parameter_sets
bom_set = parameter_sets.item("BOM")
# first check to see if the parameter already exists, if not then create it
try:
    param_part_number = bom_set.direct_parameters.item("PART-NAME")
except CATIAApplicationException:
    param_part_number = bom_set.direct_parameters.create_string('part_number', 'TempName')

try:
    param_root_part_number = parameters.item(f'{product.part_number}\Part Number')
except CATIAApplicationException:
    raise CATIAApplicationException('Change "Part Number" to the correct translation for your locale')

relations.create_formula('Formula.1', '', param_root_part_number, f'{bom_set.direct_parameters.get_name_to_use_in_relation(param_part_number)}')
ozserhatt commented 3 months ago

Well done ! Thank you dear Mithro. Problem solved :)

ozserhatt commented 3 months ago

Bro! If it is active document Product so, you have a tree with part in product document. This is not working.

raise CATIAApplicationException(f'Could not find parameter name "{index}".')
pycatia.exception_handling.exceptions.CATIAApplicationException: Could not find parameter name "Product2\Part Number".

tree

I have a loop to add formula all parts.

evereux commented 3 months ago

I have edited my script above to include a description to explicitly state that's it's designed for use in a CATPart.

If you want it to work for a CATProduct you'll need to implement some of the logic already seen in this topic, written by you.

If you want to get this to work when looping through a product you'll need to implement some of the logic in #213 which was started by you.

ozserhatt commented 3 months ago

Yeah, I know that but it does not work. When in loop , it is trying to find a parameter of Part Number for product. But my loop , if it is product, run again loop and if it is part, create formula I have recursive loop.

ozserhatt commented 3 months ago

Another question is : How can i relation with two parameters ? I try it but i can not find really. There is an yellow warning error on formula.

from pycatia import catia
from pycatia.exception_handling.exceptions import CATIAApplicationException
from pycatia.mec_mod_interfaces.part_document import PartDocument

caa = catia()
application = caa.application
documents = application.documents
part_document: PartDocument = application.active_document
part = part_document.part
product = part_document.product
parameters = part.parameters
relations = part.relations
root_parameter_set = parameters.root_parameter_set
parameter_sets = root_parameter_set.parameter_sets
bom_set = parameter_sets.item("BOM")
# first check to see if the parameter already exists, if not then create it
                try:
                    param_part_number = bom_set.direct_parameters.item("PART-NAME")
                    param_pos_no = bom_set.direct_parameters.item("POS-NO")
                except CATIAApplicationException:
                    param_part_number = bom_set.direct_parameters.create_string('PART-NAME', 'TempName')
                    param_pos_no = bom_set.direct_parameters.create_string('POS-NO', '00_000')
                try:
                    param_root_part_number = parameters.item(f'{product.part_number}\Part Number')
                except CATIAApplicationException:
                    raise CATIAApplicationException(
                        'Change "Part Number" to the correct translation for your locale')

                param1 = bom_set.direct_parameters.get_name_to_use_in_relation(param_part_number)
                param2 = bom_set.direct_parameters.get_name_to_use_in_relation(param_pos_no)

                relations.create_formula('PART-NUMBER', '', param_root_part_number,
                                         f"'{param1}_{param2}'")
Mithro86 commented 3 months ago

relations.create_formula('PART-NUMBER', '', param_root_part_number, f'{param1}+"_"+{param2}')
ozserhatt commented 3 months ago

Thank you really, dear brother !!!

evereux commented 3 months ago

Thankyou for the help @Mithro86 . 👍

ozserhatt commented 3 months ago

If you select a part on tree, that's OK! But ; When you select a product if you want to loop it inside parts, it is an error :

I think it try to find a Part Number parameter for product.

raise CATIAApplicationException(f'Could not find parameter name "{index}".')
pycatia.exception_handling.exceptions.CATIAApplicationException: Could not find parameter name "Product3\Part Number".
ozserhatt commented 3 months ago
param_root_part_number = parameters.item(f'{product.part_number}\Part Number')

I need to " f'(part.part_number}\Part Number) " But the class of Part does not exist PART NUMBER function

evereux commented 3 months ago

I don't understand. param_root_part_number = parameters.item(f'{product.part_number}\Part Number') is correct and works in the context of the examples so far.

Why this isn't working for you I don't know. I'm guessing it's to do with the way you're looping through a Product. You haven't provided any code and my crystal ball is currently broken.

Mithro86 commented 3 months ago

I think it is something like this you are looking for? It goes trough the Product and adds "BOM"-set and creates the relation for renaming. Added some logic for the renaming based on position and parent product.


from pycatia import catia
from pycatia.in_interfaces.documents import Documents
from pycatia.product_structure_interfaces.product_document import ProductDocument
from pycatia.product_structure_interfaces.product import Product
from pycatia.mec_mod_interfaces.part import Part
from pycatia.mec_mod_interfaces.part_document import PartDocument
from pycatia.exception_handling.exceptions import CATIAApplicationException

caa = catia()
application = caa.application
documents = application.documents
active_document = ProductDocument(application.active_document.com_object)
product = active_document.product

def work_in_part(part_document, i, sub_product_id):
    part = part_document.part
    part = Part(part.com_object)
    parameters = part.parameters
    relations = part.relations
    root_set = parameters.root_parameter_set

    # check for subset otherwise create subset
    try:
        bom_set = root_set.parameter_sets.item("BOM")
    except:
        bom_set = root_set.parameter_sets.create_set("BOM")
    try:
        param_part_number = bom_set.direct_parameters.item("PART-NAME")
        param_pos_no = bom_set.direct_parameters.item("POS-NO")
    except CATIAApplicationException:
        param_part_number = bom_set.direct_parameters.create_string('PART-NAME', 'TempName')
        pos_no = str(i).zfill(3)
        sub_product_id = str(sub_product_id).zfill(2)
        param_pos_no = bom_set.direct_parameters.create_string('POS-NO', f'{sub_product_id}_{pos_no}')

    part_product = Product(part_document.get_item(part.name).com_object)

    try:
        param_root_part_number = parameters.item(f'{part_product.part_number}\\Part Number')
        param1 = bom_set.direct_parameters.get_name_to_use_in_relation(param_part_number)
        param2 = bom_set.direct_parameters.get_name_to_use_in_relation(param_pos_no)
        relations.create_formula('PART-NUMBER', '', param_root_part_number, f'{param1}+"_"+{param2}')
        part.update()
    except CATIAApplicationException:
        raise CATIAApplicationException(
            'Change "Part Number" to the correct translation for your locale')

def traverse_product_structure(product, documents, sub_product_id_counter=[0], parent_sub_product_id=0):
    children = product.get_children()
    for i, child in enumerate(children):
        if child.reference_product.type == "CATProduct":
            sub_product_id_counter[0] += 1
            current_sub_product_id = sub_product_id_counter[0]
            traverse_product_structure(child, documents, sub_product_id_counter, current_sub_product_id)
        elif child.reference_product.type == "CATPart":
            part_document = PartDocument(documents.item(child.reference_product.file_name).com_object)
            work_in_part(part_document, i, parent_sub_product_id)

traverse_product_structure(product, documents)
Mithro86 commented 3 months ago

Edited to handle deeper level sub-products.

evereux commented 3 months ago

Thanks for taking the time to do this. Appreciated.

evereux commented 3 months ago

Closing as original issue is resolved.