'MyLadder' script
This is the complete 'MyLadder' script that can be stored in a Script Source type COS object, as described in Storing the builder script in the project.
Show/hide script
Copy
/* */
#include "include/dmutil.h"
#include "include/dm_cos_schema.h"
#include "include/quants.h"
#include "include/geoutils.h"
#include "include/geotypes.h"
#include "include/pm.h"
#include "include/pm_core_tags.h"
#include "include/array.mac"
#include "include/PmBeamUtils.h"
#include "include/ParamFormUI.h"
/* ============================================================================================================
Utility scripts:
To see the mandatory APIs to implement, if creating a custom structural unit, jump to the end:
'The function APIs to define a custom structural unit'
============================================================================================================ */
/*
Get name of the new structural unit (group).
The name should be such that it is highly unlikely that the name would be already in use or that some
other designer might try to use the same.
For 100% sure we can only know if the name is in use for those objects present in this specific PM area model
right now.
WARNING: You must not try to scan objects at the connected COS server. Due to distributed design, same IDs could
be used in other COS servers, without my COS server yet knowing it.
And we MUST NOT launch any service denial attacks to the COS server, which might be serving e.g. 100 concurrent clients.
Usually the real world design SCOPE vs. naming rules are such, that no naming collisions occur, even if people are
working without knowing which IDs the other designer uses (e.g. the id includes the name of the block.
(E.g. Hardly ever two designers work parallel with structural units of the same block ..)
The user, when creates a structural unit, can change the id.
*/
get_default_groupname()
{
area_no = PM_GET_CURRENT_DESAREA();
for(i=1;i<9999;i=i+1;){
gna ="";
S_PRINTF(gna,"ST.%.3d.%.3d", area_no, i);
/* Example: if area no = 22, then name will be ST.022.001,ST.022.002, ..*/
grp_h = PM_FIND_BY_NAME(gna);
/* Break the loop if a free name found*/
if(ISINT(grp_h)){
return(gna);
}
}
return(0);
}
/*
Read the parameter value as a tag value (string) and convert to the correct data type
*/
get_param_from_tagrec(handle tr, string tagn, string format,var)
{
st=0;
val=DM_GET_TAGVAL(tr,tagn,st);
if(val =="" | st != 0){
U_CONFIRM("Cannot load from the config file tag <"+tagn+">!");
st=-1;
return(0);
}
n=S_SCANF(val,format,var);
if(n!=1)return(-1);
else return(0);
}
/*
To create a simple ladder we use PmBeamUtils.h functionality:
- a local to global transformation is defined first.
- Then the ladder is defined in its local coordinate system, i.e at bottom center point at origin, facing direction towards x-negative.
- when created it is transformed acc. to the set transformation.
*/
create_vertical_ladder(int system_id, string stringer_pid, float ladder_height, string rung_pid, float rung_width, float step_height,
float loc_x_orig_in_global, float loc_y_orig_in_global, float loc_z_orig_in_global,
float du_dx, float du_dy, float du_dz,
float dv_dx, float dv_dy, float dv_dz, handle set_h
)
{
SetBeamTransformation(TRUE,loc_x_orig_in_global,loc_y_orig_in_global,loc_z_orig_in_global,
du_dx,du_dy,du_dz,
dv_dx,dv_dy,dv_dz );
st = create_stringers(system_id, stringer_pid, ladder_height, rung_width, set_h);
if(st){
SetBeamTransformation(FALSE,loc_x_orig_in_global,loc_y_orig_in_global,loc_z_orig_in_global,
du_dx,du_dy,du_dz,
dv_dx,dv_dy,dv_dz );
return(-1);
}
st = create_rungs(system_id, rung_pid, ladder_height, rung_width, step_height, set_h);
if(st){
SetBeamTransformation(FALSE,loc_x_orig_in_global,loc_y_orig_in_global,loc_z_orig_in_global,
du_dx,du_dy,du_dz,
dv_dx,dv_dy,dv_dz );
return(-1);
}
return(0);
}
create_rungs(int system_id, string rung_pid, float ladder_height, float rung_width, float step_height, handle set_h )
{
int nr_rungs;
nr_rungs = ladder_height/step_height;
dh = ladder_height - nr_rungs * step_height;
if( dh < 1.0 ){
nr_rungs = nr_rungs - 1;
z1 = step_height;
}
else{
z1 = (ladder_height - (nr_rungs-1)*step_height)/2.0;
}
for(n = 0; n<nr_rungs; n=n+1;){
z = z1 + n*step_height;
st = create_rung(system_id, rung_pid,rung_width,z, set_h);
if(st)return(-1);
}
return(0);
}
create_rung(int system_id,string rung_pid, float rung_width, float z, handle set_h)
{
mirror_u = FALSE; mirror_v = FALSE;
d_u_x = 0.0;
d_u_y = 0.0;
d_u_z = -1.0;
x1 = 0.0;
y1 = -rung_width/2.0;
z1 = z;
x2 = 0.0;
y2 = rung_width/2.0;
z2 = z;
beam_h = CreateBeam( rung_pid, system_id, BEAM_RORG_CENTER_RIGHT, mirror_u, mirror_v,
d_u_x, d_u_y, d_u_z,
x1, y1, z1, x2, y2, z2);
if(ISINT(beam_h)){
U_CONFIRM("Failed to create rung!");
return(-1);
}
PM_ADD_OBJECT_TO_SET(beam_h, set_h);
return(0);
}
create_stringers(int system_id, string stringer_pid, float ladder_height, float rung_width, handle set_h )
{
b1_x1=0.0;
b1_y1=rung_width/2.0;
b1_z1=0.0;
b1_x2=0.0;
b1_y2=rung_width/2.0;
b1_z2=ladder_height;
mirror_u = FALSE;
mirror_v = FALSE;
d_u_x = 0.0;
d_u_y = 1.0;
d_u_z = 0.0;
beam1_h = CreateBeam( stringer_pid, system_id, BEAM_RORG_CENTER_RIGHT, mirror_u, mirror_v,
d_u_x, d_u_y, d_u_z,
b1_x1, b1_y1, b1_z1, b1_x2, b1_y2, b1_z2);
if(ISINT(beam1_h)){
U_CONFIRM("Failed to create stringer 1!");
return(-1);
}
PM_ADD_OBJECT_TO_SET(beam1_h, set_h);
b1_x1=0.0;
b1_y1=-rung_width/2.0;
b1_z1=0.0;
b1_x2=0.0;
b1_y2=-rung_width/2.0;
b1_z2=ladder_height;
mirror_u = FALSE;
mirror_v = TRUE;
d_u_x = 0.0;
d_u_y = -1.0;
d_u_z = 0.0;
beam2_h = CreateBeam( stringer_pid, system_id, BEAM_RORG_CENTER_RIGHT, mirror_u, mirror_v,
d_u_x, d_u_y, d_u_z,
b1_x1, b1_y1, b1_z1, b1_x2, b1_y2, b1_z2);
if(ISINT(beam2_h)){
U_CONFIRM("Failed to create stringer 2!");
return(-1);
}
PM_ADD_OBJECT_TO_SET(beam2_h, set_h);
return(0);
}
allocate_and_set_extra_materials(config_tr_h, extramaterials_h)
{
string pid;
float amount;
int n_emats;
n=0;
bolts_pid="";
st = get_param_from_tagrec(config_tr_h, "bol","%s",bolts_pid);
nuts_pid="";
st = get_param_from_tagrec(config_tr_h, "nut","%s",nuts_pid);
washers_pid="";
st = get_param_from_tagrec(config_tr_h, "wsh","%s",washers_pid);
if( bolts_pid == "" | nuts_pid == "" | washers_pid == "" ){
return(0);
}
extramaterials_h = alloc_2darray(3,2);
amount = 4.0;
put_2darray(extramaterials_h,0,0, bolts_pid);
put_2darray(extramaterials_h,0,1, amount);
put_2darray(extramaterials_h,1,0, nuts_pid);
put_2darray(extramaterials_h,1,1, amount);
put_2darray(extramaterials_h,2,0, washers_pid);
put_2darray(extramaterials_h,2,1, amount);
return(3);
}
allocate_and_set_attributes(config_tr_h, attrs_h)
{
/* Example code:
- notice that invalid attribute value will make assignment to fail -without giving an
analysis why. Script programmers are clever enough to check the validity agains COS schema vs. this code.
*/
attrs_h = alloc_2darray(1,2);
put_2darray(attrs_h,0,0,"Design Status"); /* "Name" of attribute, as seen in "Attribute Properties" -tool (Manage COS) */
put_2darray(attrs_h,0,1,"Under Work"); /* Must be in valid range, or , if string, shorter than max length */
n_attrs=1;
return(n_attrs);
}
/*
When creating a ladder and having selected via the Construction Settings the static parameters the builder script
requests the designer to give some runtime parameters. Typically some points and directions.
The 3D model of the structural unit is built via combining the static parameters with the runtime given values.
*/
get_runtime_parameter_values( float ladder_height, float loc_x_orig_in_global, float loc_y_orig_in_global, float loc_z_orig_in_global,
float du_dx, float du_dy, float du_dz, float dv_dx, float dv_dy, float dv_dz )
{
if( get_origin_and_height(loc_x_orig_in_global, loc_y_orig_in_global, loc_z_orig_in_global,ladder_height) )return(-1);
refp_x = loc_x_orig_in_global;
refp_y = loc_y_orig_in_global;
refp_z = loc_z_orig_in_global+ladder_height/2.0;
dx=0.0; dy=0.0; dz=0.0;
/* local u in global */
if( get_facing_direction(refp_x, refp_y, refp_z, dx, dy, dz) )return(-1);
du_dx = dx;
du_dy = dy;
du_dz = dz;
/* local v in global */
VEC_CROSS_PRODUCT(dx,dy,dz,0,0,-1, dv_dx, dv_dy, dv_dz);
return(0);
}
get_origin_and_height(float x1, float y1, float z1, float height)
{
x2=0.0;
y2=0.0;
z2=0.0;
cnt=TRUE;
while(cnt){
tracep = PM_NEW_TRACEP();
PM_GET_CURRENT_LOC(x1, y1, z1);
/* starting point for horizontal beam */
key = PM_GET_POINT("Point 1: ladder's center on lower platform", tracep, x1, y1, z1);
if ( key < 0 )
return(-1);
tracep = PM_NEW_TRACEP();
PM_TRACEP_RUBBERBAND(tracep, x1, y1, z1);
PM_TRACEP_CURSOR(tracep, 2);
x2 = x1;
y2 = y1;
z2 = z1;
key = PM_GET_POINT("Point 2: Z-level of the ladder upper end", tracep, x2, y2, z2);
height= z2-z1;
if(key < 0)
return(-1);
else{
if(z2 > z1){
return(0);
}
else{
U_CONFIRM("The upper end cannot be lower than the lower end!");
}
}
}
}
/*
"Facing direction" is the direction vector which points from the ladder to your face when you are to climb.
Thus the ladder is rotated around Z-axis acc. to the given facing direction.
*/
get_facing_direction(float refp_x, float refp_y, float refp_z, float dx, float dy, float dz)
{
dx = 1.0;
dy = 0.0;
dz = 0.0;
cnt=TRUE;
while(cnt){
PM_SET_CURRENT_LOC(refp_x, refp_y, refp_z);
tracep = PM_NEW_TRACEP();
PM_TRACEP_RUBBERBAND(tracep, refp_x, refp_y, refp_z);
key = PM_GET_DIRECTION("Ladder's facing direction", tracep, refp_x, refp_y,
refp_z, dx, dy, dz);
if ( key < 0 )
return(-1);
dz=0.0;
len = VEC_UNITV(dx,dy,dz);
if( len < 0.9 ){
U_CONFIRM("Facing direction cannot be parallel to ladder height!");
}
else{
/*swap the dir for more logical facing direction for the geometry, as we happened to define it */
dx = -dx;
dy = -dy;
return(0);
}
}
return(-1);
}
/*
Create a vertical ladder as a set of 3D Model Objects (BEAMs as Plant Modeller objects)
Input:
system_id System id.
config_tr_h Tag record handle. The parameters as defined in the Construction Settings for Structural Units.
stringer_pid String. Part Id of the stringers
rung_pid String. Part Id of the rungs
Output:
ladder_set Set handle. Set of objects to be assigned to the steel unit group by the caller.
Return values:
int -1 Failed. E.g. Bad or missing parameters ...
int 1 User canceled the operation.
int 0 Succeeded to build a ladder
*/
create_my_ladder( int system_id, handle config_tr_h, string stringer_pid, string rung_pid, ladder_set)
{
rung_width = 0.0;
step_height = 0.0;
st = get_param_from_tagrec(config_tr_h, "stw","%f",rung_width);
if(st)return(-1);
st = get_param_from_tagrec(config_tr_h, "sth","%f",step_height);
if(st)return(-1);
ladder_height=0.0;
loc_x_orig_in_global = 0.0;
loc_y_orig_in_global = 0.0;
loc_z_orig_in_global = 0.0;
du_dx=0.0; du_dy = 0.0; du_dz = 0.0;
dv_dx=0.0; dv_dy = 0.0; dv_dz = 0.0;
st = get_runtime_parameter_values( ladder_height, loc_x_orig_in_global, loc_y_orig_in_global,loc_z_orig_in_global,
du_dx,du_dy,du_dz, dv_dx,dv_dy,dv_dz);
if( st ){
return(st);
}
set_h = PM_INIT_SET();
st = create_vertical_ladder(system_id, stringer_pid, ladder_height, rung_pid, rung_width, step_height,
loc_x_orig_in_global, loc_y_orig_in_global,loc_z_orig_in_global,
du_dx,du_dy,du_dz, dv_dx,dv_dy,dv_dz, set_h );
if(st){
PM_FREE_SET(set_h);
return(st);
}
ladder_set = set_h;
return(0);
}
/* ============================================================================================================
The function APIs to define a custom structural unit:
These functions will be called from the Structural Unit Designer kernel.
If you debug these functions and "Step over" or "Step in" to the calling function
you are going to get a runtime error which complains that file xxxx does not exist.
This is due to entering a binary kernel script, which source (xxxx) is not available.
(Then just press 'Run' to go ahead)
============================================================================================================ */
/*
Get the definitions of static parameters. The parameter definitions are needed by the editor tools to build an user interface to enter values for static parameters.
The parameter values, to be edited with the editor, are to be stored into a Construction Settings -object.
Arguments:
Output:
param_defs_h handle: parameter definitions: type, min/max range, default value ...
Return values:
On success: Number of parameter definitions (integer > 0)
On error: Integer -1.
*/
GetTemplateParametersOf_MyLadder_01(param_defs_h)
{
param_defs_h=0;
np=0;
is_err=0;
/* Mandatory for all structural steel unit templates: */
is_err= is_err + FrmStringParameterDefine(param_defs_h, DM_COSA_NAME, "Name", PM_L_OBJN,FALSE, np);
is_err= is_err + FrmStringParameterDefine(param_defs_h, DM_COSA_DSC, "Description", PM_L_OBJN,TRUE, np);
FrmParameterPropertySet( np-1, param_defs_h, "rws", "2" );
/* 'MyLadder' template specific.. MUST NOT USE ANY OF THE FIXED TAGS OF INTERFACE DEFINITIONS */
is_err= is_err + FrmBeamParameterDefine(param_defs_h, "bst", "Beam for stringers",FALSE, np);
is_err= is_err + FrmBeamParameterDefine(param_defs_h, "bru", "Beam for rungs",FALSE, np);
is_err= is_err + FrmQuantityParameterDefine(param_defs_h, "sth", "Rise height (vertical distance between the rungs)",100, 500, DM_Q_LENGTH, np);
FrmParameterPropertySet( np-1, param_defs_h, "def", "300" );
is_err= is_err + FrmQuantityParameterDefine(param_defs_h, "stw", "Rung width",100, 800, DM_Q_LENGTH, np);
FrmParameterPropertySet( np-1, param_defs_h, "def", "500" );
/*Fixing materials: to be added as extra material to the st. unit group */
is_err= is_err + FrmPartIdParameterDefine(param_defs_h, "bol",
"Bolts (for fixing)", "BOLT*",FALSE, np);
is_err= is_err + FrmPartIdParameterDefine(param_defs_h, "nut",
"Nuts", "NUT*",FALSE, np);
is_err= is_err + FrmPartIdParameterDefine(param_defs_h, "wsh",
"Washers", "WASH*",FALSE, np);
if(is_err){
FrmParameterDefinitionsFree(param_defs_h);
params=0;
np=0;
return(-1);
}
return(np);
}
GetTemplateParametersOf_MyLadder_02(param_defs_h)
{
param_defs_h=0;
np=0;
is_err=0;
/* Mandatory for all structural steel unit templates: */
is_err= is_err + FrmStringParameterDefine(param_defs_h, DM_COSA_NAME, "Name", PM_L_OBJN,FALSE, np);
is_err= is_err + FrmStringParameterDefine(param_defs_h, DM_COSA_DSC, "Description", PM_L_OBJN,TRUE, np);
FrmParameterPropertySet( np-1, param_defs_h, "rws", "2" );
/* 'MyLadder' template specific.. MUST NOT USE ANY OF THE FIXED TAGS OF INTERFACE DEFINITIONS */
is_err= is_err + FrmBeamParameterDefine(param_defs_h, "bst", "Beam for stringers and rungs",FALSE, np);
is_err= is_err + FrmQuantityParameterDefine(param_defs_h, "sth", "Rise height (vertical distance between the rungs)",100, 500, DM_Q_LENGTH, np);
FrmParameterPropertySet( np-1, param_defs_h, "def", "300" );
is_err= is_err + FrmQuantityParameterDefine(param_defs_h, "stw", "Rung width",100, 800, DM_Q_LENGTH, np);
FrmParameterPropertySet( np-1, param_defs_h, "def", "500" );
if(is_err){
FrmParameterDefinitionsFree(param_defs_h);
param_defs_h=0;
np=0;
return(-1);
}
return(np);
}
/*
Get the system id for the new structural unit to create
Arguments:
Input:
tmpl_header_tr_h handle (tag record): header data, originating to the template definition
params_tr_h handle (tag record): static parameters, as stored in Construction Settings -object.
Return values:
On success: integer: valid system id number
On error: integer -1
*/
GetSystemIdOf_MyLadder_01( handle tmpl_header_tr_h, handle params_tr_h)
{
return(18);
}
GetSystemIdOf_MyLadder_02( handle tmpl_header_tr_h, handle params_tr_h)
{
return(18);
}
/*
Get the default group name to be proposed to the designer as the name of the new structural unit.
Arguments:
Input:
tmpl_header_tr_h handle (tag record): header data, originating to the template definition
params_tr_h handle (tag record): static parameters, as stored in Construction Settings -object.
Return values:
On success: string: name of the new structural unit.
On error: integer 0
*/
GetDefaultGroupNameOf_MyLadder_01( handle tmpl_header_tr_h, handle params_tr_h)
{
gna = get_default_groupname();
return(gna);
}
GetDefaultGroupNameOf_MyLadder_02( handle tmpl_header_tr_h, handle params_tr_h)
{
gna = get_default_groupname();
return(gna);
}
/*
Interfaces to create structural unit:
- geometry
- extra materials
- attributes
Arguments:
Input:
system_id integer: system id for the 3D model objects to create.
config_tr_h handle (tag record): The static parameters of the Constrcution Settings -object
and the name and description of the Construction Settings -object.
Output:
unit_set_h handle (set): Set of created Model Objects.
n_attrs integer: Number of assigned attributes
attrs handle (2d_array: n x 2): Attribute "name" -"value"
n_emats integer: Number of extra materials
extramaterials_h handle (2d_array: n x 2): Attribute "name" -"value"
Return values:
Standard integer values.
*/
MyLadder_01(int system_id, handle config_tr_h, unit_set_h, int n_attrs, attrs_h, int n_emats, extramaterials_h)
{
n_emats = 0;
n_attrs = 0;
stringer_pid="";
st = get_param_from_tagrec(config_tr_h, "bst","%s",stringer_pid);
if(st)return(-1);
rung_pid="";
st = get_param_from_tagrec(config_tr_h, "bru","%s",rung_pid);
if(st)return(-1);
/* create the 3D Model Objects, assign to set: */
st = create_my_ladder( system_id, config_tr_h, stringer_pid, rung_pid, unit_set_h);
if(st) return(st);
/* get extra materials: */
n_emats = allocate_and_set_extra_materials(config_tr_h, extramaterials_h);
/* get attributes: */
n_attrs = allocate_and_set_attributes(config_tr_h, attrs_h);
return(st);
}
/*
MyLadder_02 uses same material (PID) for rungs as for stringers.
Thus it does not define material for rungs separately in COnstruction Settings
No extra materials nor attributes defined.
*/
MyLadder_02(int system_id, handle config_tr_h, unit_set_h, int n_attrs, attrs, int n_emats, extramaterials_h)
{
n_emats = 0;
n_attrs = 0;
stringer_pid="";
st = get_param_from_tagrec(config_tr_h, "bst","%s",stringer_pid);
if(st)return(-1);
rung_pid = stringer_pid;
return(create_my_ladder( system_id, config_tr_h, stringer_pid, rung_pid, unit_set_h));
}