PK Interface Programming Concepts
Chapters | PK Tokens (Numeric) >>> |
The PK interface is presented as a collection of C declarations for tokens, structures and functions which are defined in the file
parasolid_kernel.h
in the Parasolid release area.
The PK Interface has been written as a replacement for the Kernel Interface (KI) and has been written in C. The PK Interface is the preferred interface but, where necessary, KI calls can be included in an application.
For further information see Chapter 2, "Parasolid Concepts", of the Parasolid Functional Description manual. This information is fundamental to the understanding of Parasolid programming concepts and should therefore be read and understood.
All PK functions have names of the form PK_ <OBJECT>_ <text>. The text is usually a verb/noun combination.
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.
In the PK each option has to be explicitly selected as ON/OFF/etc. by being passed collectively in an options structure.
A PK class is a naming convention that usually has some functions. These C functions all have names of the standard form PK_XXXX_text_text.
When the class has an object belonging to it (which it usually does) the name of their C type is of the form PK_XXXX_t. These objects may be either:
Objects with tags are considered to be special, as there is run-time support for type enquiries; and some inheritance; these we call entities. The entity classes they belong to inherit from ENTITY.
A PK class often has other types associated with it, structures of one form or another or token enumerations, and these have names of the form PK_XXXX_text_t. 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.
Classes that have a special structure type called a standard form, which is a method of representing the data encapsulated by objects belonging to the class, have names of the form PK_XXXX_sf_t.
Optional arguments and option switches passed to functions are collected together in a single structure and passed as one argument, an options structure. Functions with options structure, e.g. PK_FACE_contains_vectors, should not support optionally null output arrays.
Note: Option structures are named by adding the string "_o_t" to the function name. |
So that all the fields in a structure are set to the default values, each option structure must be initialized before use by using a corresponding macro. The default values set by the macro are, in general, shown in the documentation for each options structure, in brackets after the field name and type.
The application then only needs to reset those fields for which it does not wish to use the default. Functions themselves do not have a default action, they always reference the given option structure.
Note: Option structure initializer macros are named by replacing the "_o_t" string at the end of the function name with "_o_m". |
Each option structure has a
version
field, which is not set directly by the application, but is initialized by the corresponding option macro. This allows Parasolid to detect which version the code was compiled under so later versions can avoid attempting to read nonexistent fields.
Example of calling a PK function using an options structure:
PK_FACE_t face; PK_TOPOL_t topol; PK_VECTOR_t point; PK_FACE_contains_vectors_o_t option; point.coord[0] = 5.0; point.coord[1] = 5.0; point.coord[2] = 0.0; /*Initialize all fields in options structure for PK_FACE_contains_vectors*/ PK_FACE_contains_vectors_o_m(option); /* Specify point */ option.vectors = &point; option.n_vectors = 1; pk_ifail = PK_FACE_contains_vectors (face, &option, &topol); /* Test for pk_ifail */ |
The const modifier is used in Parasolid to protect the application's data from being altered by Parasolid in any unintended way. More specifically, it is used to:
const PK_LINE_sf_t *line_sf
When the type of a function argument is declared using const, then this protection applies within that function, and within any it calls to any depth; that is, const-ness is propagated downwards. It is not necessary for applications to declare variables using the const modifier to pass them to Parasolid.
The meaning of the const modifier is described using the type
int
.
number
is a pointer to an integer. The value of that integer may not be changed. This form is used for receiving a variable by address. Variables are received by address when:
numbers
is an array of integers. No member of the arrays may be changed. This form of declaration is used for all received arrays.
number
is a pointer to an integer. The integer may be changed but the pointer can not be changed. This ensures that whatever happens within a Parasolid function, it is going to return information to the places that the application told it to.
number
is a pointer to a pointer to an integer. It can be thought of as
number
being a pointer to
middle
, and
middle
being a pointer to a first integer in an array of integers. The integers and
middle
may be changed but the pointer to
middle
cannot be changed. This is the form used to return information of variable size. Parasolid allocates space for the return information, and returns a pointer to that space.
Sometimes function arguments which are passed by value are declared to be const:
This has no effect at the interface. Its effect is internal to Parasolid.
When a function argument is declared using array notation, [], the argument is automatically a constant pointer to the first element of the array. Thus a returned argument may be declared as:
PK_TOPOL_t topologies[]
PK_TOPOL_t *const topologies
const
, then Parasolid can not change its value.
const
in the middle, then Parasolid can not change where it is.A Parasolid function argument is used either to receive information from the application, or to return information to the application, but never both.
PK_ERROR_code_t PK_THING_do_something ( /* received arguments */ const PK_THING_t *in_thing /* returned arguments */ PK_THING_t *const out_thing ) |
if the application calls this as:
PK_THING_do_something(&my_thing, &my_thing);
anything may happen, so do not do it.
Variable length data is returned from the PK as C arrays which can be split into the following three categories with respect to their memory requirement.
The application declares the space at compile time and pass a pointer to it to Parasolid. These arguments appear as, for example,
type name[3]
in the PK function headers. Space declared at compile time does not need to be explicitly freed.
The application allocates space at run-time and passes a pointer to it to Parasolid. These arguments appear as
type name[]
or
type *const name
in the function headers (an array of indeterminate length). The space allocated should be freed by the application at some time later when it is no longer required.
The application should declare a pointer to the returned type, and pass a pointer to this pointer to Parasolid. Parasolid sets the pointer to point to the returned information. These arguments appear as or
type **const name
in the function headers. It is the application's job to free this memory after it is no longer required.
The PK_MEMORY functions provide an interface by which the application can handle the allocation and freeing of space for variable length returned arguments from the PK:
It is necessary that applications free all memory allocated on its behalf by the PK when returning arguments of the
type **const name
form.
The function PK_MEMORY_register_callbacks registers with Parasolid the allocation and freeing functions that Parasolid is to use for variable length PK returns.
The functions PK_MEMORY_alloc and PK_MEMORY_free are merely interfaces directly to the registered allocation and freeing functions provided for applications that favor a layered architecture.
If a PK function succeeds, then the space for any variable length returns can be freed by calling PK_MEMORY_free. If a PK function fails, and has already allocated any space for variable length returns, then Parasolid frees that space by calling the registered free function.
When a structure is returned from a function and that structure contains a pointer then the space for what is pointed to is allocated by Parasolid and so must be later freed by the application. In particular, standard forms are structures of fixed size but they may point to variable length arrays.
As an example, PK_BCURVE_ask returns PK_BCURVE_sf_t which, because it is of fixed size is declared as:
PK_BCURVE_sf_t *const bcurve_sf
The structure PK_BCURVE_sf_t contains the field:
and space for the knot vector is allocated by Parasolid.
Hence the more general rule is that whenever returned information has two levels of indirection, then the space is allocated by Parasolid. In the simple cases, the two levels of indirection are indicated by declarations of the form:
but the two levels may be split where the first is a pointer to a structure and the second is a pointer within the structure.
Some return arguments declared in the form:
may be set to NULL before the function 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' as in:
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) ) |
This function may be called as:
PK_ERROR_code_t status; PK_BODY_t body = ... int n_faces; status = PK_BODY_ask_faces (body, &n_faces, NULL); |
to just find the number of faces.
This use of NULL is only allowed in those cases where it is explicitly documented. Functions which have option structures never have optional return arguments.
Some return structures have code supplied to free the space pointed to by the structure. For a return structure whose name is of the form:
Note: This code is supplied to assist application developers and is not a core part of the PK interface. |
This code is currently supplied in:
The following simple code demonstrates how the PK interface looks in use.
Note: 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); |
Chapters | PK Tokens (Numeric) >>> |