Examples of Script Functions

The following examples demonstrate the use of script extern functions.

Object Browser

The following example demonstrates how to:

  • pick an object

  • create a view

  • visualize the object into the view

Copy
/* Create an axonometric view around the selected object. */

#include include/dmutil.h
#include include/pm.h
main()
{
 cnt = TRUE;
 while(cnt == TRUE){
 /* Pick any object */
 nth = 0; /* returns the pipe segment number if
 PIPE object selected */
 obj = PM_PICK_OBJECT("Pick object",nth);
 /* If CANCEL pressed then make an 
 early return */
 if(ISINT(obj))return(0);
 view_h = visualize_obj_in_axo_view(obj,"ObjView");
Copy
st = DM_CALL_SCRIPT("macro/ChooseAction.mac",
 "ChooseAction",
 "Object Browser",
 "Select Action",
 "Close View and Exit\nExit\nContinue"
 );
 if(st==1){
 PM_CLOSE_VIEW(view_h);
 return(0);
 }
 else if(st == 2){
 return(0);
 }
 }
}
visualize_obj_in_axo_view(obj,view_name)
{
 /*
 Check that a view with this name is 
 not currently open
 */
 in_drawing = FALSE; /* false, since we are 
 dealing with work views */
 v = PM_GET_HANDLE_OF_OPENED_VIEW(view_name,
 in_drawing); 
 /* 
 If 'v' is an integer then the view is not 
 open. If 'v' is a valid handle the old view
 must be closed before creating a new one.
 */
 if( !ISINT(v) ){
 PM_CLOSE_VIEW(v);
 }
    
Copy
   /* 
 Get the minimum bounding box of the object
 x,y,z coordinates
 */
 xmin = 0; xmax = 0; ymin = 0; ymax = 0; 
 zmin = 0; zmax = 0;
 PM_GET_BBOX_OF_OBJECT(obj, xmin, xmax, ymin,
 ymax, zmin, zmax); 
 /* Create an axonometric view */
 v = create_view(obj, view_name, xmin, ymin,
 zmax, -1, -1, 1);
 return(v);
}
/* 
 Create a new view. Visualize the object. 
 Zoom the view. 
 Remove hidden lines
 and shade the view.
*/
Copy
create_view(obj,view_name,x,y,z, dx,dy,dz)
{
 /* We are making a work view -not a view 
 of a drawing */
 into_drawing = FALSE; 
 /* next two dummy arguments in this case: */
 screen = "";
 xserver = "";
 view = PM_CREATE_VIEW(view_name, into_drawing,
 screen, xserver); 
 /* 
 Set the view point, view direction, 
 pipe centerline visibility.
 Also set the view to enclose the 
 whole model
 */
 PM_SET_VIEW_PARAMETERS(view,"POINT",x,y,z,
 "VDIR", dx,dy,dz,
 "CL_NS_LIM",1,
 "LIMITS",0,0,0,0,0);  
Copy
    /* 
 We need to have a PM set to be able to
 visualize the object 
 in the view 
 */
 set = PM_INIT_SET();
 PM_ADD_OBJECT_TO_SET(obj, set); 
 PM_VISUALIZE_SET_TO_VIEW(set, view); 
 /* The temporary set is not needed any more */
 PM_FREE_SET(set);
 /*
 Get the limits of the bounding box that
 encloses all objects 
 visualized so far
 */
 umin = 0; umax = 0; vmin = 0; vmax = 0; 
 wmin = 0; wmax = 0;
 PM_GET_VIEW_PARAMETERS(view, "BBOX", umin,
 umax, vmin, vmax, wmin, wmax);
 /* Margin at the sides of the view after
 zooming */
 margin = 100;
 /* Zoom the view */
 PM_SET_VIEW_PARAMETERS(view, "WINDOW", 
 umin - margin, umax + margin, vmin -
 margin, vmax + margin );
 /* Remove hidden lines and shade */
 PM_RM_HLINES_FROM_VIEW(view);

 /*
 Could be shaded too
 PM_SHADE_VIEW(view,0);
 */
 return(view);
}

/*
 Boolean function
 Return values: View exists == 1 (true), 
 view does not exist == 0 (false)
*/
view_exist(vn)
{
 next = 0;
 go_on = 1;
 status = 0;
 while( go_on){
 name = PM_GET_NAME_OF_NEXT_VIEW("", next,
 status);
 if(ISINT(name))return(0);
 if(name == vn)return(1);
 }
}

Browse Set via Walkaround

The following example demonstrates how to:

  • define a set
  • use the walkaround module to visualize the set
Copy
#include "include/dmutil.h"
#include "include/pm.h"
global float MaxDiagonal, SetMx, SetMy, SetMz;
global float Xmin, Xmax, Ymin, Ymax, Zmin, Zmax;

compute_box_for_set(set)
{
 nr = PM_NR_MEMBERS_IN_SET(set);
 Xmin = 0; Xmax = 0;
 Ymin = 0; Ymax = 0;
 Zmin = 0; Zmax = 0;
 PM_GET_BBOX_OF_SET(set,Xmin,Xmax,Ymin,Ymax,Zmin,
 Zmax);
 SetMx = (Xmin + Xmax)/2;
 SetMy = (Ymin + Ymax)/2;
 SetMz = (Zmin + Zmax)/2;
 MaxDiagonal = SQRT((Xmax-Xmin)*(Xmax-Xmin) + 
 (Ymax-Ymin)*(Ymax-Ymin) + 
 (Zmax-Zmin)*(Zmax-Zmin));
}

/* replace this with your own pick object handler as needed */
pickhandler(obj, nth_pc)
{
 U_MESSAGE("Some object has been picked.");
 return(0);
}
/*
 Interface of this tool script.
 You can call WalkAroundSet from other scripts
 with PM_CALL_SCRIPT
 external function.
*/
WalkAroundSet(set,shadingrules)
{
 compute_box_for_set(set);
 /*
 ** Camera position is given so that 
 ** PM can compute 
 ** viewing angle or
 ** move the camera so that the box that 
 ** we specify 
 ** becomes completely visible.
 ** We'll request that the first image 
 ** is generated so that all of the
 ** set is visible.
 */
 viewangle = 45;
 dz = (Zmax - Zmin)/2;
 dy = (Ymax - Ymin)/2;
 if (dz > dy)
 d = dz;
 else
 d = dy;
 camera_x = SetMx + 2000;
 camera_y = SetMy + 2000;
 camera_z = SetMz + 2000;
 mrg = 50;
Copy
     r = PM_WALKAROUND(set, "CAMERA", camera_x, 
 camera_y, camera_z,
 "TARGET", SetMx, SetMy,
 SetMz,
 "VIEWANGLE", viewangle,
 "SHOWBOXMINP", Xmin-mrg,
 Ymin-mrg, Zmin-mrg,
 "SHOWBOXMAXP", Xmax+mrg,
 Ymax+mrg, Zmax+mrg,
 "BACKPLANEDIST",
 MaxDiagonal/2,
 "PERSPECTIVE", 1,
 "ROTATE_CAMERA", 1,
 "SHADINGRULES",
 shadingrules,
 "PICKHANDLER",
 "pickhandler",
 "WALKDIR", 1, 0, 0);
 if (r == 0)
 U_MESSAGE("Settings saved");
 else if (r == 1)
 U_MESSAGE("Settings not saved");
 else
 U_MESSAGE("Interface error");
}
/*
 A main function for testing
*/
main()
{
 set = PM_DEFINE_SET("Set for walkaround.");
 if (set == 0) return(-1);
 WalkAroundSet(set,"NormalShading.ssr");
}

Accessing Object Data

The following example demonstrates how to:

  • define a set
  • scan a set
  • access data of an object
Copy
/*
 Accessing data of a selected set of objects
*/

#include include/dmutil.h
#include include/pm.h

main()
{
 /* define the set interactively */
 set = PM_DEFINE_SET("Process set of objects");
 /* CANCEL pressed ? */
 if(ISINT(set))return(0);
 n_items = PM_NR_MEMBERS_IN_SET(set);
 /* scan all objects in the set */
 for(i=0; i<n_items; i=i+1;){
 obj = PM_GET_MEMBER_IN_SET(set, i); 
 
 /* 
 Extract data via a tag.
 see "VOL 2: Plant Modeller
 Administration: Customizing Documents"
 for list of available object tags
 NOTICE that all tag values are
 character strings even if they
 describe a number !
 */
 U_MESSAGE("====== Object no: "
 +ITOASCII(i+1)+ " ========");
 sys = PM_GET_OBJDATA(obj,0,"sys");
 U_MESSAGE("System "+sys);
 /* Object type */
 obt = PM_GET_OBJDATA(obj,0,"obt");
 /* Actually there are no "extra materials"
 in the 3D model */
 if( obt == "0" )type = "extra material";
 else if( obt == "1" ){
 U_MESSAGE("Type: equipment");
 } 
 else if( obt == "2" ){
 U_MESSAGE("Type: standard comp");
 pli = PM_GET_OBJDATA(obj,0,"pli");
 U_MESSAGE("Pipeline: "+pli);
 vpo = PM_GET_OBJDATA(obj,0,"vpo");
 if(! ISINT(vpo)){
 U_MESSAGE("Valve pos: "+vpo);
 }
 ipo = PM_GET_OBJDATA(obj,0,"ipo");
 if(! ISINT(ipo)){
 U_MESSAGE("Instr. pos: "+ipo);
 }
 }
 else if( obt == "4" ){
 U_MESSAGE("Type: structural");
 }
 else if( obt == "5" ){
 U_MESSAGE("Type: beam");
 }
 else if( obt == "6" ){
 U_MESSAGE("Type: HVAC");
 }
 else if( obt == "9" ){
 U_MESSAGE("Type: piping part");
 pli = PM_GET_OBJDATA(obj,0,"pli");
 U_MESSAGE("Pipeline: "+pli);
 }
 else if( obt == "14" ){
 U_MESSAGE("Type: attribute");
 }
 else if( obt == "15" ){
 U_MESSAGE("Type: group");
 }
 else {
 U_CONFIRM("Unknown object type<" +
 obt+"> !!");
 return(-1);
 }
 }
 /* free the temporarily allocated memory */
 PM_FREE_SET(set);
}

Examples_At Anchor2

Query Specification of a PIPE/STDCOMP

The following example demonstrates how to:

  • pick a PIPE or STDCOMP object
  • extract piping specification which was used when the object was built
  • make a selection tool with the "advanced" user interface tools
Copy
/*  We use a selection tool for showing the current spec yet the selection does not have any meaning in this context. */
#include "include/dmutil.h"
#include "include/pm.h"
main()
{
 cont=TRUE;
 /* Examine all objects in one loop */
 while(cont==TRUE){
 
 obsolete = 0;
 /* get the handle of the STDC or PIPE object. Ignore other object types */
 obj = PM_PICK_OBJECT( "Object to examine spec", obsolete, "STANDCMP","PIPE");
Copy
         /* 
 It is very typical that externs and
 script functions which return
 a valid handle when succeed return
 integer 0 when they fail.
 Thus a common method to trace success
 is to compare the type
 of the variable which receives the
 return value against type:
 INTEGER.
 If the type of the variable IS integer
 the call failed, otherwise
 the call succeeded.
 the following expression returns either
 TRUE or FALSE:
 ( NOT ( variable IS INTEGER) )
 */
 if( ! ISINT(obj) ){
 /* hi-light while extracting data */
 PM_HIGHLIGHT_OBJECT(obj, 1);
 /* get the name of a selected spec */
 spec = get_spec( obj );
 if( ISINT(spec) ){
 U_MESSAGE("No spec selected");
 }
 else {
 U_MESSAGE(
 "Specification selected : " +
 spec);
 }
 /* hi-light off */
 PM_HIGHLIGHT_OBJECT(obj, 0);
 cont = U_YESNO("OK to Continue",1);
 }
 else cont = FALSE;
 }
 
 return(0);
}

/*
** Get the name of the selected specification
** Return int 0 if error
*/
get_spec( handle obj )
{
 /* object's pipeline */
 pli = PM_GET_OBJDATA(obj, 0, "pli");
 if( ISINT(pli) ){
 U_MESSAGE("Error");
 return(0);
 }
 /* pipeline is a group object, so get 
 it's handle */
 pli_h = PM_FIND_BY_NAME(pli);
 if( ISINT(pli_h) ){
 U_MESSAGE("Error");
 return(0);
 }
 /* the three specs of the pipeline: */
 ps1 = PM_GET_OBJDATA(pli_h,0,"ps1");
 ps2 = PM_GET_OBJDATA(pli_h,0,"ps2");
 ps3 = PM_GET_OBJDATA(pli_h,0,"ps3");
 if( ISINT(ps1) & ISINT(ps2) & ISINT(ps3) ){
 U_MESSAGE("No specs in pipeline "+pli+
 " !! ??" );
 return(0);
 }
 sel = A_ALLOC(3);
 if( ISINT(ps1) )
 A_PUT(sel,0,"no spec1");
 else
 A_PUT(sel,0,ps1);
 if( ISINT(ps2) )
 A_PUT(sel,1,"no spec2");
 else
 A_PUT(sel,1,ps2);
 if( ISINT(ps3) )
 A_PUT(sel,2,"no spec3");
 else
 A_PUT(sel,2,ps3);
 default = 0;
 /* spec of the object */
 obj_spc = PM_GET_OBJDATA(obj,0,"spc");
 /* set the default selection to be the spec 
 of the object */
 if( ! ISINT(obj_spc) ){
 for( i=0; i<3; i=i+1; ){
 if( A_GET(sel,i) == obj_spc ){
 default = i;
 i = 3;
 }
 }
 }
 else {
 U_MESSAGE("Out of Spec Component");
 }
 seltool = "macro/../../dm/macro/Select.mac";
 selected = PM_CALL_SCRIPT(seltool, "U_Select", 
 "Select Specification", 3, sel, default);
 /* Canceled ?*/
 if( selected < 0 ){ 
 A_FREE( sel ); /* avoid memory leaks */
 return(0); 
 }
 spec = A_GET(sel,selected);
 /* User selected a "dummy" entry */
 if( HEAD(spec,3) == "no " ){
 U_MESSAGE("Dummy spec selected");
 A_FREE( sel ); 
 return(0);
 }
 A_FREE( sel ); 
 return( spec );
}

Examples_At Anchor1

Building Model by Writing/Reading MDLs

The following example demonstrates how to:

  • get 3D points
  • use 2D arrays to store data
  • build new objects via MDL files
Copy
/*
 This script "routes" a set of beams on a
 horizontal plane.
 A set of points is first collected into a 2D
 array.
 The z-coordinate of the first point is the
 z-level of the
 routing.
*/
#include "include/dmutil.h"
#include "include/pm.h"
#include "include/geoutils.h"
#include "include/array.mac"
/* 'modebits' parameter of the PM_READ_MDL() function: */
#define READ_MDL_AS_MODULE 1
#define READ_MDL_COPY_EXISTING_OBJECTS 2
#define READ_MDL_MIRROR_Y 4
/* 'type' parameter of the PM_CREATE_TMAT()
 function: */
#define TMAT_TYPE_LOCAL_Z_DIR 0
#define TMAT_TYPE_LOCAL_X_Y_DIRS 1
#define TMAT_TYPE_LOCAL_Z_X_DIRS 2
#define TMAT_TYPE_LOCAL_X_DIRS 3
/* Part id of the beam to be routed */
/* 
 NOTICE this PID is profile in the example
 project. 
 It is not necessaryly present in YOUR project 
*/
global string SteelPid = "SFS2026____-15";
/* The integer system id */
global int SysIdNumber = 5;
main()
{
 /* let the user to enter an array of points */
 points = 0;
 n_points = get_points( points );
 /* at least two points needed to define 
 a beam */
 if( n_points <= 2 )return(-1);
 /* create beams according to the array 
 of points */
 create_beams(n_points, points); 
 /* free array of points */
 free_2darray(points);
 return(0);
}
/*
 Collect points
*/
get_points(points)
{
 a_pts = 0; /* number of allocated point 
 rows */
 n_pts = 0; /* number of used point rows */
 pts = 0; /* handle to the points-array */
 
 /* create a new trace point structure 
 - notice that these are freed
 when the script terminates */
 tracep = PM_NEW_TRACEP();
 x = 0; y = 0; z = 0;
 /* loop until DONE or CANCELed */
 cont = 1;
 while( cont ) {
 PM_GET_CURRENT_LOC(x,y,z);
 key = PM_GET_POINT("Point", tracep, 
 x, y, z);
 /*
 key: the keyboard key which was 
 pressed to accept the point.
 key < 0 == CANCELed
 key == 'space' (32) == POINT ACCEPTED
 key == 'F12' == ']' == (93) == DONE
 */
 if( key < 0 )
 return(-1);
 else if( key == 93 ){
 cont = 0;
 }
 else if( key == 32 ){
 /* alloc new space to array, 
 if needed: */
 /* first time */
 if( a_pts == 0 ){
 a_pts = 5;
 pts = alloc_2darray(a_pts,3);
 }
 /* more space needed */
 else if(a_pts == n_pts){
 a_pts = a_pts + 5;
 realloc_2darray(pts,a_pts,3);
 }
 /* put {x,y,z} of the point into the 
 2D array */
 put_2darray(pts,n_pts,0,x);
 put_2darray(pts,n_pts,1,y);
 put_2darray(pts,n_pts,2,z);
 n_pts = n_pts+1;
 }
 } 
 /* update the handle of the 'points' array 
 and return number of 
 rows in the table */
 points = pts;
 return(n_pts);
}

Copy
create_beams(n_pts, pts)
{
handle tmat_h;
 /* Just need to have some legal filename */
 fn = "foo.mdl";
 /* The owner id number of the current area */
 owner = PM_GET_CURRENT_DESAREA();
 /* Create a new empty file */
 if( F_EXIST(fn) )F_DELETE_FILE(fn);
 F_CREATE_FILE(fn);
 f = F_OPEN_FILE(fn,"w");
 /* system number */
 sys = SysIdNumber;
 /* Get the z coordinate from the first point */
 z = get_2darray(pts,0,2);
 /* Scan all points. Create an MDL of beams 
 from point to point */
 for(i=0;i<n_pts-1;i=i+1;){
 if( i > 0 )dump_end_of_record(f);
 x1 = get_2darray(pts,i,0);
 y1 = get_2darray(pts,i,1);
 x2 = get_2darray(pts,i+1,0);
 y2 = get_2darray(pts,i+1,1);
 dx = 0;
 dy = 0;
 dz = 0;
 dx1 = x1 - x2;
 dy1 = y1 - y2;
 dz1 = 0;
 /* convert deltas to unit vector 
 components */
 VEC_UNITV(dx1,dy1,dz);
 dx2 = -dx1;
 dy2 = -dy1;
 dz2 = 0;
 /* 
 Gets the local x-dir of the 
 cross section , i.e. the 
 rotation of the beam around its 
 routing axis (routing direction).
 Here we use the vector cross product 
 to get the correct direction.
 */
 st = VEC_CROSS_PRODUCT(dx1, dy1, dz1, 0, 0,
 1, dx, dy, dz);
 if( st ) {
 U_CONFIRM("Error in cross product");
 }
 /* Dump the MDL entry of one steel into a
 file */
 steel( f, SteelPid, owner, sys, x1, y1, z,
 x2, y2, z, dx, dy, dz, dx1, dy1, dz1,
 dx2,dy2,dz2 );
 }
 dump_end_of_mdl(f);
 f = F_CLOSE_FILE(f);
 
 /* 
 No module, no copy, no mirror, 
 tmat_h ignored since tmat_h is 
 only used if loading MDL 'as module' 
 */
 modebits = 0;
 
 /* The following tmat definition is a 
 dummy one, but since the type of
 the 'tmat_h' argument is strictly checked by
 the system we must use a true transformation
 matrix handle here */
 tmat_h = PM_CREATE_TMAT(TMAT_TYPE_LOCAL_Z_DIR,
 x1, y1, z,0, 0, 1, 0, 0, 0); 
 st = PM_READ_MDL(fn, modebits, "", tmat_h); 
 if( st ){
 U_CONFIRM("Failed to read MDL in");
 return(-1);
 }
 return(0);
}
dump_end_of_record(f)
{
 /* a comma and a NEWLINE */
 F_PRINTF(f,",\n");
}
dump_end_of_mdl(f)
{
 /* just NEWLINE */
 F_PRINTF(f,"\n");
}
/*
 Create a BEAM record into the MDL file
 Arguments:
 f: file, pid: part_id, owner: design area id
 sys: system id, point1, point2, 
 direction of local x of the cross section
 end cut direction at point1
 end cut direction at point2
*/
steel(f, string pid, int owner, int sys,
 x1,y1,z1,x2,y2,z2, dx,dy,dz, 
 dx1,dy1,dz1, dx2,dy2,dz2)
{
 /* See documentation of MDL in VOL2. */
 F_PRINTF(f,"STEL(%s,ST(%d,ffffffff,%d,0,1),",
 pid,owner,sys);
 F_PRINTF(f,
 "P(%.2f,%.2f,%.2f),P(%.2f,%.2f,%.2f),",
 x1,y1,z1,x2,y2,z2);
    
Copy
    F_PRINTF(f,
"D(%.6f,%.6f,%.6f),D(%.6f,%.6f,%.6f),D(%.6f,%.6f,%.6f))",
 dx,dy,dz, dx1,dy1,dz1, dx2,dy2,dz2 ); 
}
            

Examples_At Anchor1