cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Community Tip - You can subscribe to a forum, label or individual post and receive email notifications when someone posts a new topic or reply. Learn more! X

Get all ProCsys in an assembly

Tim_1996
7-Bedrock

Get all ProCsys in an assembly

In an assembly I want to visit all the ProCsys with a certain name and then get there coordinates. I have tried several examples which use ProSolidCsysVisit(), including the ProUtilCollectSolidCsys() and ProUtilCsysFind() functions. I know how to get the coordinates with the ProSelection typ by selecting a Csys with ProSelect() but now I have to use the ProCsys typ. But I also think I am not using the functions ProUtilCollectSolidCsys() and ProUtilCsysFind() correctly because I don´t get a list of ProCsys, only one value.

Can someone help me to understand this? There are also some things I didn´t find any explanation, like what is the "handle to the solid" or what does "PRO_TK_E_NOT_FOUND" mean?

 

Thanks a lot!
Tim

22 REPLIES 22
rghadge
15-Moonstone
(To:Tim_1996)

@Tim_1996,

 

Please use below APIs:

  1. Use API ProSolidCsysVisit() - To visit all CSYS features in model
  2. Use APIs ProCsysToGeomitem() and ProModelitemNameGet() in filter function of above API and visit only those CSYS features based on specific name of CSYS.
  3. Use API ProCsysDataGet() to get ProGeomitemdata csys_data. Extract origin of CSYS using csys_data->data.p_csys_data->origin

Answers to your additional questions:

1. What is 'handle to the solid'?

Ans.: Handle to solid is pointer to solid i.e. ProSolid

2. What does PRO_TK_E_NOT_FOUND means?

Ans.: If any API returns error PRO_TK_E_NOT_FOUND then, it means that API found 0 objects which that API is supposed to look for in specified model.

Thank you very much, I will try it!

Maybe a stupid question but what exactly is a solid? 

rghadge
15-Moonstone
(To:Tim_1996)

@Tim_1996,

 

Solid is nothing but, the solid model in Creo Parametric. Please read Toolkit User's Guide to understand more in detail about Creo Parametric Toolkit.

 

Also, please open separate threads or cases for each query so that individual questions would be addressed separately in different threads. 

I tried this way and it kind of worked but not the way I wanted. It visit some csys but only a few and I can't even find those csys in my Creo model. I think I have to go recursively in deeper subsystems, but I'm not sure. Here is what I have:

 

 

 

ProError FilterFunction(ProCsys p_csys, ProAppData app_data) {

    ProModelitem r_geom_item;
    ProName csysName;
    ProSolid model = ((UserCsysAppData*)app_data)->model;
    ProCsysToGeomitem(model, p_csys, &r_geom_item);
    ProModelitemNameGet(&r_geom_item, csysName);
    strcpy(((UserCsysAppData*)app_data)->csys_name, csysName);

    if(strcmp(csysName,"ENTRY")){
        return(PRO_TK_CONTINUE);
    }
    else {
        return(PRO_TK_NO_ERROR);
    }
}


ProError VisitActionFunction(ProCsys p_csys, ProError filter_return, ProAppData app_data) {

    if (filter_return == PRO_TK_NO_ERROR) {
        ProGeomitemdata* csys_data;
        ProCsysDataGet(p_csys, &csys_data);  // get data
        int coor[3];
        coor[0] = csys_data->data.p_csys_data->origin[0];
        coor[1] = csys_data->data.p_csys_data->origin[1];
        coor[2] = csys_data->data.p_csys_data->origin[2];

        // write data
        FILE* fp;
        fp = fopen("Csys_data1.txt", "a");
        ProName csysName;
        strcpy(csysName, ((UserCsysAppData*)app_data)->csys_name);
        char* csysName2 = (char*)calloc(100, sizeof(char));
        ProWstringToString(csysName2, csysName);
        fprintf(fp, "%s\t\t%d\t%d\t%d\n", csysName2, coor[0], coor[1], coor[2]);
        fclose(fp);

        return(PRO_TK_NO_ERROR);
    }
}


ProMdl model;
UserCsysAppData	app_data;
status = ProMdlCurrentGet(&model);
app_data.model = model;
status = ProSolidCsysVisit((ProSolid)model, (ProCsysVisitAction)VisitActionFunction, (ProCsysFilterAction)FilterFunction, (ProAppData)&app_data);

 

 

 

If I understand it correctly, ProSolidCsysVisit() gets the first Csys possible and then calls the filter function. The filter decides if the action function does something with that csys or not. What I don't understand is how ProSolidCsysVisit() navigates through the different Csys and where I need to do a recursive action to get ALL the Csys in the assembly.

rghadge
15-Moonstone
(To:Tim_1996)

Hi @Tim_1996,

 

Please go through response from @RolandRaytchev to understand how to recursively visit assembly and get assembly component. You can visit CSYS of each component and get its origin.

RPN
17-Peridot
17-Peridot
(To:Tim_1996)

No, the visit function calls just a filter, only if the filter return PRO_TK_NO_ERROR you will have it in your final data. Without the filter you would have to do this in your code, with the filter you know that the result will already contain what you want. So you look for "ENTRY" in that case you will get a maximum of 1 csys, because names must be unique.

 

One last note, appdata should contain an array where you save all valid cordinate systems. You add this to the array in your filter.

Tim_1996
7-Bedrock
(To:RPN)

But where does the ProCsys come from if not from ProSolidCsysVisit()? I just use the ProCsys which is handed over to the filter function.

 

Okay, I thought "ENTRY" would be the name because it is written at the Csys in the 3D environment. Than I have to filter by type or something. Any idea how I can get this "type" which is displayed at the Csys?

Hi @Tim_1996 ,

because I did nothing the last 5 years with Toolkit possibly I do not remember accurately  but so far I remember .

You meant you can select the coordinate system with ProSelect . In this case to understand where is the CSYS you can check selection with ProSelectionAsmcomppathGet()  to get the Asmcomppath and print it to see  the direct assembly component level.

- is the CSYS an assembly feature or it is a feature in some part which has specific asmcomppath. The mentioned workflow by @rghadge    should work pretty good when the  csys feature is an assembly feature or you know that it is in part or subassembly and you have the handle of the mdl /solid

But let say if it is inside a component or subassembly ->in this case so far I remember what I did in the past something like this:

I did first call ProSolidFeatVisit  and  used a filter to check if  the feature is form type PRO_FEAT_COMPONENT 

IF yes then I will then

-check the workflow suggested by @rghadge   to find if the CSYS is inside of the current visited model. If not yes found and  stop - if not found yet  then continue with :

-check if the model is an assembly and call recursively the ProSolidFeatVisit . So  this  is one of the workflows what could be used when we search a specific CSYS feature in the assembly but we do not    not know where is it -> in Top assembly or in some part /subassembly component on some specific component level depth.

OK let remember a name of a feature could be not unique. Means we could have in different components / part a feature with the same name.

So  when I know the component path so I could e.g. take directly the part by ProAsmcomppathMdlGet() and then used the suggested workflow by  

@rghadge 

PS - the question what is ProSolid.

It is simple  casted ProMdl object handle to ProSolid .... some thing like      ....ProMdl mdl;      (ProSolid) mdl....    - but, please,  pay attention you can do this  cast only if you are sure that the ProMdl type is PRO_ASSEMBLY or PRO_PART (othewise such casting  do not make any sense)- so means before you will cast  ProMdl handle to ProSolid you can check the ProMdl type e.g. by the fucntion ProMdlTypeGet()

I tried this way and it kind of worked but not the way I wanted. It visit some csys but only a few and I can't even find those csys in my Creo model. I think I have to go recursively in deeper subsystems, but I'm not sure. Here is what I have:

 

ProError FilterFunction(ProCsys p_csys, ProAppData app_data) {

    ProModelitem r_geom_item;
    ProName csysName;
    ProSolid model = ((UserCsysAppData*)app_data)->model;
    ProCsysToGeomitem(model, p_csys, &r_geom_item);
    ProModelitemNameGet(&r_geom_item, csysName);
    strcpy(((UserCsysAppData*)app_data)->csys_name, csysName);

    if(strcmp(csysName,"ENTRY")){
        return(PRO_TK_CONTINUE);
    }
    else {
        return(PRO_TK_NO_ERROR);
    }
}


ProError VisitActionFunction(ProCsys p_csys, ProError filter_return, ProAppData app_data) {

    if (filter_return == PRO_TK_NO_ERROR) {
        ProGeomitemdata* csys_data;
        ProCsysDataGet(p_csys, &csys_data);  // get data
        int coor[3];
        coor[0] = csys_data->data.p_csys_data->origin[0];
        coor[1] = csys_data->data.p_csys_data->origin[1];
        coor[2] = csys_data->data.p_csys_data->origin[2];

        // write data
        FILE* fp;
        fp = fopen("Csys_data1.txt", "a");
        ProName csysName;
        strcpy(csysName, ((UserCsysAppData*)app_data)->csys_name);
        char* csysName2 = (char*)calloc(100, sizeof(char));
        ProWstringToString(csysName2, csysName);
        fprintf(fp, "%s\t\t%d\t%d\t%d\n", csysName2, coor[0], coor[1], coor[2]);
        fclose(fp);

        return(PRO_TK_NO_ERROR);
    }
}


ProMdl model;
UserCsysAppData	app_data;
status = ProMdlCurrentGet(&model);
app_data.model = model;
status = ProSolidCsysVisit((ProSolid)model, (ProCsysVisitAction)VisitActionFunction, (ProCsysFilterAction)FilterFunction, (ProAppData)&app_data);

 

If I understand it correctly, ProSolidCsysVisit() gets the first Csys possible and then calls the filter function. The filter decides if the action function does something with that csys or not. What I don't understand is how ProSolidCsysVisit() navigates through the different Csys and where I need to do a recursive action to get ALL the Csys in the assembly.

Hey, Thank you first!

You are talking of ProSolidFeatVisit() and PRO_FEAT_COMPONENT, but I am looking for Csys. Is this important or do I have to use the equavilant functions for Csys?

Hi @Tim_1996 ,

here a old example (Creo 3.0) where I did  visit assembly and highlighting components - should show the principle. Then name of it is not relevant- bug... coming from my old template.  It is old nmake project  - files in src subfolder. and the mean program and visit is in PTTestBug.c

Please, let me know if you have question to it. Thanks

... in the mentioned project in previous post the relevant code will  show how to visit recursively the assembly. So you will have there a handle of each component /part or sub assembly. 

For the question how to visit the CSYS in  ProSolid I found a siimple  code on old disk (fortunately it did not chrash)  form my first attempst to do this many years ago therefore is not perfect but still possible it could help:

 

....
....
  ....
   ....
  ProMdl theModel;
  int status;
  ProName theName;
  char dummy[100];

  
  status = ProMdlCurrentGet( &theModel );
  JlCheckStatus( status );
  status = ProMdlNameGet( theModel, theName );
  JlCheckStatus( status );
  ProMessageDisplay(msgfile,"user %s", "Hello" );
  ProMessageDisplay( msgfile, "user %s %s",
		     "The name of the current Model is ",
		     ProWstringToString( dummy, theName ) );
 status = UserCSYSTest((ProSolid) theModel);
 ....
  ....
   ....
 
//=================================
 typedef struct surface_visit_data

{

  FILE      *fp;

  ProSolid   part;

} AxisVisitData_t;

/*==========================================================================
============================================================================*/

ProError UserDemoCsysAct(

    ProCsys     Csys,

    ProError    filt_status,

    ProAppData  app_data)

{

    ProError          status;

    AxisVisitData_t  *p_data = (AxisVisitData_t*)app_data;

    ProSolid          part = p_data->part;

    FILE             *fp = p_data->fp;

    int               id;

    ProModelitem      modelitem;

    ProFeature        feature;

    ProFeattype       ftype;

    ProName           wname;

    char              name[PRO_NAME_SIZE];

    ProSelection      selection;
    ProBoolean   visible;

/*---------------------------------------------------------------*\

    Get the axis identifier.

\*---------------------------------------------------------------*/

    status = ProCsysIdGet (Csys, &id);

    if (status != PRO_TK_NO_ERROR)

        return (status);

/*---------------------------------------------------------------*\

    Make a ProModelitem handle for the axis.

\*---------------------------------------------------------------*/

    status = ProModelitemInit (part, id, PRO_CSYS, &modelitem);

    if (status != PRO_TK_NO_ERROR)

        return (status);

/*---------------------------------------------------------------*\
    Get the feature to which   belongs.
\*---------------------------------------------------------------*/

    status = ProGeomitemFeatureGet (&modelitem, &feature);

    if (status != PRO_TK_NO_ERROR)

        return (status);

/*---------------------------------------------------------------*\

    Get the feature type.

\*---------------------------------------------------------------*/

    status = ProFeatureTypeGet (&feature, &ftype);

    if (status != PRO_TK_NO_ERROR)

        return (status);

/*---------------------------------------------------------------*\

    If the type was not HOLE, skip it.

\*---------------------------------------------------------------*/

    if (ftype != PRO_FEAT_CSYS)
    
    	{
	printf("\nFTYPE =%d\n",ftype);
        return (PRO_TK_NO_ERROR);
	 }
	 
	status = ProFeatureVisibilityGet(&feature,&visible) ;
	if(visible !=PRO_B_TRUE)
	
    	{
	printf("\nNONVISIBLE FEATURE NUMBARO : %d\n", feature.id);
        return (PRO_TK_NO_ERROR);
	 }
/*---------------------------------------------------------------*\

    Get the name of the Csys.

\*---------------------------------------------------------------*/

    status = ProModelitemNameGet (&modelitem, wname);

    if (status != PRO_TK_NO_ERROR)

        return (status);

    ProWstringToString (name, wname);

/*---------------------------------------------------------------*\
    Print out name and  identifier.
\*---------------------------------------------------------------*/

    fprintf (fp, "CSYS %s belongs to CSYS feature %d\n", name,

             feature.id);
/*---------------------------------------------------------------*\
    Highlight
\*---------------------------------------------------------------*/

    ProSelectionAlloc (NULL, &feature, &selection);

    ProSelectionHighlight (selection, PRO_COLOR_HIGHLITE);

    ProSelectionFree (&selection);

    return (PRO_TK_NO_ERROR);
}
ProError UserDemoCsysFlt(

    ProCsys     Csys,

    ProAppData  app_data) 
    {
    AxisVisitData_t  *p_data = (AxisVisitData_t*)app_data;
    ProSolid          part = p_data->part;
    FILE             *fp = p_data->fp;
    ProFeature        feature;
    ProFeatStatus fstatus;
    int               id;
    ProModelitem      modelitem;
    

    printf("\nFILTER FUNCTION\n");
    
      status = ProCsysIdGet (Csys, &id);

    if (status != PRO_TK_NO_ERROR)

        return (status);
        


    status = ProModelitemInit (part, id, PRO_CSYS, &modelitem);

    if (status != PRO_TK_NO_ERROR)

        return (status);

/*---------------------------------------------------------------*\

    Get the feature to which the Csys belongs.

\*---------------------------------------------------------------*/

    status = ProGeomitemFeatureGet (&modelitem, &feature);

    if (status != PRO_TK_NO_ERROR)

        return (status);

    status = ProFeatureStatusGet(&feature,&fstatus);
    if(fstatus == PRO_FEAT_SUPPRESSED) return (PRO_TK_CONTINUE);
    else 
    return (PRO_TK_NO_ERROR); 
  
    
    }
 //=======================================
 where the function definition of 
 ProError UserCSYSTest(ProSolid         part)

{

    ProError         status;

    AxisVisitData_t  data;

    data.part = part;

/*---------------------------------------------------------------*\

    Open the text file.

\*---------------------------------------------------------------*/

    data.fp = fopen ("visit_test.dat","w");

/*---------------------------------------------------------------*\

    Visit all the axes using the visit and filter functions

    above. Pass the owning solid and the text file pointer

    using the app_data argument.

\*---------------------------------------------------------------*/

    status = ProSolidCsysVisit (part, UserDemoCsysAct,

                                UserDemoCsysFlt, (ProAppData)&data);

/*---------------------------------------------------------------*\

    Close the file

\*---------------------------------------------------------------*/

    fclose (data.fp);

    return (PRO_TK_NO_ERROR);

}
....
  ....
   ....

There some of the object name are misleading  -I think I wanted to do some quick test where I did not attapt all name of objects properly...

Hi @Tim_1996 , 

possibly you could ignorre my last post. I did not see that you already did this action ( receiving the csys in the ProSolid). I see that you posted code...

rghadge
15-Moonstone
(To:Tim_1996)

Hi @Tim_1996,

 

If you are interested to get CSYS features of assembly components (sub levels of assembly) then, yes you need to recursively visit assembly and get ProMdl (or ProSolid) of each component. And, then visit CSYS of each ProSolid.

Okay, so I always call ProSolidCsysVisit() after I got ProSolid and it is of the right type, correct? How can I get the ProSolid?

rghadge
15-Moonstone
(To:Tim_1996)

@Tim_1996,

 

Use API ProMdlCurrentGet() to get ProMdl of top level assembly model. And, use API ProAsmcompMdlGet() to get ProMdl handle of assembly component.

You can type cast ProMdl as ProSolid.

And what do I hand over the function ProAsmcompMdlGet()? With the ProCsys it is not working.

RPN
17-Peridot
17-Peridot
(To:Tim_1996)

In an assembly, if you have a component, this is a Feature. ProAsmcompMdlGet () will give you the model handle for that Feature ID, this is for sure a solid 🙂

From the feature ID 235 in MYASSY.ASM

OWNER MyAssy

Type  FEATURE

ID  235

 

to the Model and RunTime ID

OWNER MyPart

Type  PART

ID  34

 

Here you translate the feature ID to a Solid Model ID, because if you have now the Solid Model Handle, you can call CsysVisit for this Model as well, check the Tcl Code, your Logic should be similar. You have very ofter a complex var with Owner, Type and ID (Mostly the Model Item). Think about a Database where you do a 'Select ...' this is the same here. In Creo there are a lot of tables (Arrays) linked via Owner, Type,ID. It's a simple mapping.

 

A component can be assembled multiple times, but the Feature ID Path to each component is unique.

 

ProError ProAsmcompMdlGet (ProAsmcomp *p_feat_handle, ProMdl *p_mdl_handle);

 

Purpose: Retrieves the component model, given a component feature.

Input Arguments:
p_feat_handle - The handle to the component feature Output Arguments:
p_mdl_handle - The model handle to be initialized

RPN
17-Peridot
17-Peridot
(To:Tim_1996)

I guess you have a synchronous app, you can setup your button to be only active in assembly mode, else the first think you check is that your current active model is an assembly. This is for sure a Solid 😉 und this current model is now your handle to call  ProSolidCsysVisit. Your app data should have an empty initialized ProArray, this array is filled with your filter if your app says yes, this is what I need. After that Call to ProSolidCsysVisit you check the ProArray Size, if 0, upps nothing found, else you can loop through the Array or whatever you have setup in your AppData (I guess you have a couple a csys model items in one Array). 

Note: If you do this recursive for all members in the assembly keep in mind that the origin data needs to be transformed to the assembly level, that means during parsing the assembly you need to make sure that the model ID path is saved or handled.

 

You see, there is a lot to consider 😫, but if you are 25 years old, you have plenty of time 😎, have fun!!

RPN
17-Peridot
17-Peridot
(To:Tim_1996)

If you have an assembly, I thought you would like to search for a csys by a special name within the whole structure. If you only want to search the given assembly, you don't need to visit the assembly by components, in that case ProSolidCsysVisit() for the assembly is enough. And keep in mind, if you call ProCsysIdGet((ProCsys) csys, &ID) in your filter function, the ID is not the feature ID. You get the model item type PRO_CSYS, in the visit function, but this is not a PRO_FEATURE, so you need to get the feature id, to extract the feature name for your match. And only for the whole structure a matrix transform may required.

RPN
17-Peridot
17-Peridot
(To:Tim_1996)

PRO_TK_E_NOT_FOUND will be returned if the call was successfully but no data was found.

SOLID, I would say a solid is everything where the Creo file extension is either '.PRT' (model type PRO_PART) or '.ASM' (model type PRO_ASSEMBLY)

Tcl Code less than 30 lines (in a colored image, after that clear uncolored code) follows, C logic is very similar > 30 lines 😀, even if you use your own filter function

GetCsysByNames.png

 

 

 

 

# Side effects
# Each component is checked 
# and the point data is not transformed
# to the top level assembly
#
# Function Input:
# FP	: The handle to the open file
# MDL	: The Name of the Solid Model
# Pat	: The pattern to match, e.g A* match ACSYS
proc Get_Csys_Match {FP MDL PAT} {
	foreach GEOM_ID [ps_visit csys  -model $MDL] {
		# Get the Feature ID for this geom id
		set FEAT_ID [ps_geom to_feat_ids -model $MDL -- CSYS $GEOM_ID]
		# Get the Feature Name
		set FEAT_NAME [ps_feat name -model $MDL -- $FEAT_ID]
		# Now the Match check
		# Here do a match of the csys name by the given pattern
		# if not match, continue
		if {![string match -nocase $PAT $FEAT_NAME]} {
			continue
		}
		# Prepare the Output
		set Record [list $MDL $FEAT_NAME]
		# Get the Csys Data to an csysObj 
		ps_data csys  -model $MDL -- $GEOM_ID CsysData 
		# extract each vector, skip origin and other data
		foreach vector [list xvector yvector zvector origin] {
			# from the csysObj extract the 3D point data to an pointObj 
			CsysData $vector Point
			# lappend the 3D Values by expanding to the output record list
			lappend Record {*}[Point 3d_values]
		}
		# write the data in our file, use ',' as an seperator
		puts $FP [join $Record ,]
	}
}

# Function Input:
# FP	: The handle to the open file
# ASM	: The Name of the Assembly
# Pat	: The pattern to match, e.g A* match ACSYS
proc Get_Assy_Csys_Match {FP ASM PAT} {
	# Get it for the assembyl as well
	Get_Csys_Match	$FP $ASM $PAT
	# Vist the given assembly, get all feature IDs 
	# where the feature type is a component
	foreach FID [ps_visit type  -model $ASM -- COMPONENT] {
		# Get the model name from this feature ID
		set MDL [ps_assy component_name -model $ASM -- $FID ]
		# Now get all Geom ID from each CSYS in this Solid
		# No filter for sub types like skeleton, ... 
		Get_Csys_Match	$FP $MDL $PAT
		# Recursive Call
		# If the model is an assembly, 
		# search in this assembly as well
		if { [ps_model is_assembly -model $MDL]} {
			Get_Assy_Csys_Match	$FP $MDL $PAT
		}

	}
	# Done and return
	return
}

proc CSYS_Test {} {
	# The Pattern to search for
	set PAT	A*
	# use the current active Model
	set MODEL [ps_model cur]
	# Prepare the filename
	set outname [format "%s_csys_data.csv" $MODEL]
	# open the file
	set FP [open $outname w]
	# write the header, use ',' as an seperator
	puts $FP [join [list Model CsysName xvecx xvecy xvecz yvecx yvecy yvecz zvecx zvecy zvecz ovecx ovecy ovecz] ,]
	# get the data
	Get_Assy_Csys_Match $FP $MODEL $PAT
	# close the file
	close $FP
	# Done and return
	return
}
# just call it
CSYS_Test

 

 

 

 

Sample Out

 

SampleOut.png

 

Have fun 😇

Top Tags