Using the PK Interface   

<<< Further Implementation Decisions Chapters

Contents

[back to top]


Introduction

The PK interface is a collection of C declarations for tokens, structures and functions. The complete set of definitions are listed in the file 'parasolid_kernel.h' on the Parasolid Release CD. This appendix explains some of the conventions used for naming and calling functions in the PK.

[back to top]


PK interface functions

All PK functions have names of the form PK_ <CLASS>_ <operation>, where

Parasolid entities are organized in an object-oriented class hierarchy such that a function that is called on <CLASS> can also be called on all the subclasses of <CLASS>. For example, PK_CURVE_ask_fin can be called on any subclass of CURVE, such as CIRCLE, ELLIPSE, or LINE.

Each function has a fixed set of arguments: some are used to supply data, and others are used to return information. Argument types are simple values, arrays, and structures.

You must set each argument explicitly when calling PK functions, rather than omitting them completely. This is made easier by the use of option structures and initialization macros.

[back to top]

Types associated with PK classes

When a PK class has an object belonging to it (which it nearly always has) the name of the C type for that object is of the form PK_ <CLASS>_t.

A PK class may have other types associated with it - structures or token enumerations - and these have names of the form PK_ <CLASS>_ <text>_t. An example of this is PK_SESSION_frustrum_t, which is the type you use when declaring a frustrum. When these types are more directly associated with a particular function their names reflect this, as there are naming conventions for options structures, type classifications, etc.

[back to top]

Using function arguments correctly

A PK function argument is used either to receive information from the application, or to return information to your application, but never both.

For example, given a PK function with the following declaration:

 

PK_ERROR_code_t  PK_THING_do_something
(
/* received arguments */
const PK_THING_t  *in_thing
/* returned arguments */
PK_THING_t *const  out_thing
)

You should never call this function as follows, since the results are undefined:

PK_THING_do_something(&my_thing, &my_thing);

 

Warning: The order in which entities are returned from a given PK function, and the underlying geometric representations of faces and edges, are not guaranteed to be consistent between different versions of Parasolid. Consequently, your application should not depend on either of these things.

[back to top]


Types of structures

Much of the information passed in PK function code is collected together in related groups, or structures. There are three basic structures that you need to be aware of:

[back to top]

Passing arguments in options structures

Optional arguments and option switches passed to functions are generally collected together in a single structure and passed as one argument, known as an options structure. Option structures are named by adding the string "_o_t" to the function name.

 

Warning: The first field of any options structure is the version number ( o_t_version ). Your application must never set or alter this value.

Using macros to initialize options structures

Before you can use an options structure, every field in the structure must be given a value. To make this easier, a macro is available for each option structure that sets every field in the structure to a default value.

After calling the macro, you just need to set any fields that you want to use a different value for. Functions themselves do not have a default action; they always reference the given option structure.

To get the macro name for a given option structure replace the "_o_t" string at the end of the structure name with "_o_m".

An example call to a PK function that uses an options structure is shown below:

 

/* Declare entities */
PK_FACE_t    face; 
PK_TOPOL_t   topol;
PK_VECTOR_t  point;
point.coord[0] = 5.0;
point.coord[1] = 5.0;
point.coord[2] = 0.0;

/* Declare options structure */
PK_FACE_contains_vectors_o_t  option; 

/* Initialize options structure fields */
PK_FACE_contains_vectors_o_m(option); 

option.vectors = &point;    /* Override default values for two fields*/
option.n_vectors = 1;

/* Make the function call */
pk_ifail = PK_FACE_contains_vectors (face, &option, &topol);
/* Test for pk_ifail */

[back to top]

Standard form structures

Many classes have a special structure known as a "standard form", that needs to be used when creating instances of that class. You can think of a standard form as a template for given class instance. Standard forms always have names of the form PK_ <CLASS>_sf_t.

Most entities have associated standard forms that contain the definitions of curves, surfaces, and so on required for those entities (though some, such as bodies and vertices, do not). Some other classes also have an associated standard form (such as PK_AXIS1_sf_t), even though there is no equivalent entity.

The same standard form for a class is used whether the calling function is an input function or an output function. For example, PK_CYL_sf_t is used by both PK_CYL_create and PK_CYL_ask.

The following example shows how a cylinder is created using the standard form for a cylinder:

 

PK_CYL_t my_cylinder;
PK_CYL_sf_t my_cyl_sf;

my_cyl_sf.basis_set.location.coord[0] = 1.0;
my_cyl_sf.basis_set.location.coord[1] = 2.0;
my_cyl_sf.basis_set.location.coord[2] = 3.0;
my_cyl_sf.basis_set.axis.coord[0] = 1.0;
my_cyl_sf.basis_set.axis.coord[1] = 0.0;
my_cyl_sf.basis_set.axis.coord[2] = 0.0;
my_cyl_sf.basis_set.ref_direction.coord[0] = 0.0;
my_cyl_sf.basis_set.ref_direction.coord[1] = 1.0;
my_cyl_sf.basis_set.ref_direction.coord[2] = 0.0;
my_cyl_sf.radius = 5;

PK_CYL_create(&my_cyl_sf, &my_cylinder);

[back to top]

Return structures

Some PK functions pass information back to your application using a return structure. Return structures are used when a lot of related information needs to be handed back to your application, such as tracking information describing the changes made to a part as the result of a function call. The names of return structures end in "r_t" - for example, the return structure that returns information about which topology was split, deleted, or created, is called PK_TOPOL_track_r_t.

[back to top]


Memory management for returned arguments

Returned arguments to PK functions consume variable amounts of data that are returned from the PK as C arrays. The extent to which you need to control memory allocation for these arguments depends on how easy it is to determine how much memory is required for them.

 

Requirement

Procedure

If the size of the argument is known at compile time.

Your application declares the space at compile time and passes a pointer to it to Parasolid. Arguments like this are shown in the PK function headers as, for example, type name[3] . You do not need to explicitly free space declared in this way.

If the size of the argument can be determined by your application at run time before making the function call.

Your application allocates space at run-time and passes a pointer to it to Parasolid. Arguments like this are shown in the PK function headers as, for example, type name[] or type *const name . Your application needs to free the space allocated when it is no longer required.

In all other cases Parasolid dynamically allocates space to return the array, using PK_MEMORY_alloc.

Your application declares a pointer to the returned type, and passes a pointer to this pointer to Parasolid. Parasolid sets this pointer to point to the returned information. Arguments like this are shown in the PK function headers as, for example, type **const name . Your application needs to free the space allocated when it is no longer required. This is described in Section B.4.1, "Memory management functions in the PK".

[back to top]

Memory management functions in the PK

Your application allocates and frees memory for variable length return arguments using PK_MEMORY functions. These functions ensure that your application can free memory when it has been allocated by Parasolid, and that space is freed consistently regardless of where it was originally allocated. If the functions are not registered, then the default memory allocation and freeing functions for the operating system are used.

If a PK function fails, and has already allocated space for variable length returns, then Parasolid frees the space by calling the FMFREE function directly.

The example below demonstrates how to use PK_MEMORY_free to free space used by a return argument once it is no longer needed.

 

PK_BODY_t my_body;
int n_faces;
PK_FACE_t *my_faces;

PK_BODY_ask_faces(my_body, &n_faces, &my_faces);
...
...
...
PK_MEMORY_free(my_faces);

[back to top]

Return structures containing pointers

In general, whenever the returned argument is a pointer to a pointer, Parasolid allocates space for whatever is pointed to at the end of the line, and your application frees that space when it is finished with, using PK_MEMORY_free. You can spot two levels of indirection like this easily by looking for a declaration of the form:

type	 **const name

Sometimes, a PK function returns a pointer to a structure that itself contains a pointer. In this case, it can be harder to spot the second level of indirection. In particular, standard forms (structures that represent the data encapsulated by an object of a particular class) have a fixed size, but they may point to variable length arrays.

For example, PK_BCURVE_ask returns a standard form PK_BCURVE_sf_t which, because it is a fixed size, is declared as:

PK_BCURVE_sf_t				 *const bcurve_sf

The structure PK_BCURVE_sf_t contains the field:

double		 *knot

and space for the knot vector is allocated by Parasolid.

Most PK functions that return information using return structures have equivalent memory destructing functions to free up all the memory allocated to the structure in one call. The names of these functions end in "_r_f" - for example, the freeing function for the return structure PK_blend_rib_r_t is PK_blend_rib_r_f.

[back to top]

Optional return arguments

You can set some return arguments declared in the form

type	 **const name

to NULL in the function call to indicate that this information is not to be returned and no space is to be allocated for it. Such arguments are indicated by the word 'optional' in the function header.

An example of an optional return argument is shown below:

 

PK_ERROR_code_t 	PK_BODY_ask_faces
(
--- received arguments ---
PK_BODY_t 		body, 	--- a body
--- returned arguments ---
int        		*const n_faces, 	--- number of faces (>= 0)
PK_FACE_t 		**const faces 	--- faces (optional)
)

In order to just return the number of faces, rather than the faces themselves, set the faces argument to NULL in the function call as follows:

 

PK_ERROR_code_t	 	status;
PK_BODY_t	 body = ...
int	 n_faces;
status = PK_BODY_ask_faces (body, &n_faces, NULL);

This use of NULL is only allowed where it is explicitly documented. Functions which have option structures never have optional return arguments.

[back to top]


Example code

The following simple example demonstrates how the PK interface is used. This example sets an attribute on a face, but ignores the possibility of errors.

 

/* Assume a face in a valid model has been selected */ 
PK_FACE_t    face = ... ;

/* Local variables for attribute code */ 
PK_ERROR_code_t status;
PK_ATTDEF_t     colour_defn;
PK_ATTRIB_t     colour_attrib;
double          rgb[3];

/* Locate the definition of the   */ 
/* system defined color attribute */ 
status = PK_ATTDEF_find("SDL/TYSA_COLOUR", &colour_defn);

/* Create a new attribute of type color */ 
/* attached to the given face           */ 
status = PK_ATTRIB_create_empty
               ( face, colour_defn, &colour_attribute );

/* Fill in the fields of the attribute */ 
/* with the desired values             */ 
rgb[0] = 0.25; rgb[1] = 0.25; rgb[2] = 0.5;
status = PK_ATTRIB_set_doubles(colour_attrib, 0, 3, rgb);

[back to top]


Integrating with MS Visual Studio

If you are using Microsoft Visual Studio to develop your Parasolid-powered application, you need to integrate Parasolid's DLL, LIB, and header files correctly into your project environment. This is done as follows:

[back to top]

Adding pskernel.lib to MS Visual C++

To add pskernel.lib into the MS Visual C++ environment, choose Project > Settings to display the Project Settings dialog, and follow the instructions in Figure B-1.

 

Figure B-1 Adding pskernel.lib to the MS Visual Studio environment

[back to top]

Specifying an additional include directory

You can add one or more directories to the list of directories that are searched for include files. Choose Project > Settings to display the Project Settings dialog, and follow the instructions in Figure B-2.

 

Figure B-2 Adding an additional include directory to MS Visual Studio

 

[back to top]

<<< Further Implementation Decisions Chapters