Synopsis
#include <cpml1/cpml.h> enum CpmlPrimitiveType; struct CpmlPrimitive; size_t cpml_primitive_type_get_n_points (CpmlPrimitiveType type
); void cpml_primitive_from_segment (CpmlPrimitive *primitive
,CpmlSegment *segment
); void cpml_primitive_copy (CpmlPrimitive *primitive
,const CpmlPrimitive *src
); void cpml_primitive_reset (CpmlPrimitive *primitive
); int cpml_primitive_next (CpmlPrimitive *primitive
); size_t cpml_primitive_get_n_points (const CpmlPrimitive *primitive
); double cpml_primitive_get_length (const CpmlPrimitive *primitive
); void cpml_primitive_put_extents (const CpmlPrimitive *primitive
,CpmlExtents *extents
); int cpml_primitive_set_point (CpmlPrimitive *primitive
,int n_point
,const CpmlPair *pair
); int cpml_primitive_put_point (const CpmlPrimitive *primitive
,int n_point
,CpmlPair *pair
); void cpml_primitive_put_pair_at (const CpmlPrimitive *primitive
,double pos
,CpmlPair *pair
); void cpml_primitive_put_vector_at (const CpmlPrimitive *primitive
,double pos
,CpmlVector *vector
); double cpml_primitive_get_closest_pos (const CpmlPrimitive *primitive
,const CpmlPair *pair
); size_t cpml_primitive_put_intersections (const CpmlPrimitive *primitive
,const CpmlPrimitive *primitive2
,size_t n_dest
,CpmlPair *dest
); size_t cpml_primitive_put_intersections_with_segment (const CpmlPrimitive *primitive
,const CpmlSegment *segment
,size_t n_dest
,CpmlPair *dest
); void cpml_primitive_offset (CpmlPrimitive *primitive
,double offset
); int cpml_primitive_join (CpmlPrimitive *primitive
,CpmlPrimitive *primitive2
); void cpml_primitive_to_cairo (const CpmlPrimitive *primitive
,cairo_t *cr
); void cpml_primitive_dump (const CpmlPrimitive *primitive
,int org_also
);
Description
A primitive is an atomic geometric element found inside CpmlSegment. The available primitives are the same defined by cairo_path_data_type_t with the additional CPML_ARC type (check CpmlPrimitiveType for further information) and without CPML_MOVE as it is not considered a primitive and it is managed in different way: the moveto primitives are only used to define the origin of a segment.
Details
enum CpmlPrimitiveType
typedef enum { CPML_MOVE = CAIRO_PATH_MOVE_TO, CPML_LINE = CAIRO_PATH_LINE_TO, CPML_CURVE = CAIRO_PATH_CURVE_TO, CPML_CLOSE = CAIRO_PATH_CLOSE_PATH, CPML_ARC = 88 } CpmlPrimitiveType;
This is a type compatible with cairo_path_data_type_t type. It is basically the same enum but it embodies an important difference: it can be used to specify the special CPML_ARC primitive. Having two different types is a good way to make clear when a function expect or not embedded CPML_ARC primitives.
Arcs are used extensively in technical drawing: some operations are trivials with arcs and a nightmare with cubic Bézier curves. Actually, at least up to version 1.10.2, the cairo library does not support arc primitives natively and there is no plan they will be ever supported.
The CPML library supports arc natively, converting them to curves
when the CpmlSegment is returned to the cairo context, for instance
when using cpml_segment_to_cairo()
.
equivalent to CAIRO_PATH_MOVE_TO


equivalent to CAIRO_PATH_LINE_TO


equivalent to CAIRO_PATH_CURVE_TO


equivalent to CAIRO_PATH_CLOSE_PATH


an arc representation at CPML level 
Since 1.0
struct CpmlPrimitive
struct CpmlPrimitive { CpmlSegment *segment; cairo_path_data_t *org; cairo_path_data_t *data; };
As for CpmlSegment, also the primitive is unobtrusive. This means CpmlPrimitive does not include any coordinates but instead keeps pointers to the original segment (and, by transition, to the underlying CpmlPath struct).
CpmlSegment * 
the source CpmlSegment 
cairo_path_data_t * 
a pointer to the first point of the primitive 
cairo_path_data_t * 
the array of the path data, prepended by the header 
Since 1.0
cpml_primitive_type_get_n_points ()
size_t cpml_primitive_type_get_n_points (CpmlPrimitiveType type
);
Gets the number of points required to identify the type
primitive.

a primitive type 
Returns : 
the number of points or 0 on errors 
Since 1.0
cpml_primitive_from_segment ()
void cpml_primitive_from_segment (CpmlPrimitive *primitive
,CpmlSegment *segment
);
Initializes primitive
to the first primitive of segment
.

the destination CpmlPrimitive struct 

the source segment. [allownone] 
Since 1.0
cpml_primitive_copy ()
void cpml_primitive_copy (CpmlPrimitive *primitive
,const CpmlPrimitive *src
);
Copies src
in primitive
. This is a shallow copy: the internal fields
of primitive
refer to the same memory as the original src
primitive.

the destination CpmlPrimitive 

the source CpmlPrimitive. [allownone] 
Since 1.0
cpml_primitive_reset ()
void cpml_primitive_reset (CpmlPrimitive *primitive
);
Resets primitive
so it refers to the first primitive of the
source segment.

a CpmlPrimitive 
Since 1.0
cpml_primitive_next ()
int cpml_primitive_next (CpmlPrimitive *primitive
);
Changes primitive
so it refers to the next primitive on the
source segment. If there are no more primitives, primitive
is
not changed and 0 is returned.

a CpmlPrimitive 
Returns : 
1 on success, 0 if no next primitive found or errors. [type boolean]

Since 1.0
cpml_primitive_get_n_points ()
size_t cpml_primitive_get_n_points (const CpmlPrimitive *primitive
);
Gets the number of points required to identify primitive
.
It is similar to cpml_primitive_type_get_n_points()
but using
a primitive
instance instead of a type.

a CpmlPrimitive 
Returns : 
the number of points or 0 on errors.

Since 1.0
cpml_primitive_get_length ()
double cpml_primitive_get_length (const CpmlPrimitive *primitive
);
Abstracts the length()
family functions by providing a common
way to access the underlying primitivespecific implementation.
The function returns the length of primitive
.

a CpmlPrimitive 
Returns : 
the requested length or 0 on errors 
Since 1.0
cpml_primitive_put_extents ()
void cpml_primitive_put_extents (const CpmlPrimitive *primitive
,CpmlExtents *extents
);
Abstracts the extents()
family functions by providing a common
way to access the underlying primitivespecific implementation.
This function stores in extents
the bounding box of primitive
.
On errors, that is if the extents cannot be calculated for some reason, this function does nothing.

a CpmlPrimitive 

where to store the extents. [out callerallocates] 
Since 1.0
cpml_primitive_set_point ()
int cpml_primitive_set_point (CpmlPrimitive *primitive
,int n_point
,const CpmlPair *pair
);
Sets the specified n_point
of primitive
to pair
. The n_point
index starts from 0: if n_point
is 0, the start point (the origin)
is changed, 1 for the second point and so on. If n_point
is
negative, it is considered as a negative index from the end, so
that 1 is the end point, 2 the point before the end point and
so on.
CPML_CLOSE is managed in a special way: if n_point
is 1 or 1 and primitive
is a closepath, this function cycles
the source CpmlSegment and returns the first point. This is
needed because requesting the end point (or the second point)
of a close path is a valid operation and must returns the origin
of the segment.

a CpmlPrimitive 

the index of the point to retrieve 

the source CpmlPair. [allownone] 
Returns : 
1 if the point to be set is existent, 0 otherwise. [type gboolean]

Since 1.0
cpml_primitive_put_point ()
int cpml_primitive_put_point (const CpmlPrimitive *primitive
,int n_point
,CpmlPair *pair
);
Gets the specified n_point
from primitive
and stores it into
pair
. The n_point
index is subject to the same rules explained
in the cpml_primitive_set_point()
function.

a CpmlPrimitive 

the index of the point to retrieve 

the destination CpmlPair. [out callerallocates][allownone] 
Returns : 
1 if the point is found, 0 otherwise. [type gboolean]

Since 1.0
cpml_primitive_put_pair_at ()
void cpml_primitive_put_pair_at (const CpmlPrimitive *primitive
,double pos
,CpmlPair *pair
);
Abstracts the put_pair_at()
family functions by providing a common
way to access the underlying primitivespecific implementation.
It gets the coordinates of the point lying on primitive
at position pos
. pos
is an homogeneous factor where 0 is the
start point, 1 the end point, 0.5 the mid point and so on.
pos
can be less than 0 or greater than 1
, in which case the
coordinates of pair
are interpolated.
On errors, that is if the coordinates cannot be calculated for some reason, this function does nothing.

a CpmlPrimitive 

the position value 

the destination CpmlPair. [out callerallocates] 
Since 1.0
cpml_primitive_put_vector_at ()
void cpml_primitive_put_vector_at (const CpmlPrimitive *primitive
,double pos
,CpmlVector *vector
);
Abstracts the put_vector_at()
family functions by providing a common
way to access the underlying primitivespecific implementation.
It gets the steepness of the point at position pos
on primitive
.
pos
is an homogeneous factor where 0 is the start point, 1 the
end point, 0.5 the mid point and so on.
pos
can be less than 0 or greater than 1
, in which case the
coordinates of pair
are interpolated.
On errors, that is if the steepness cannot be calculated for some reason, this function does nothing.

a CpmlPrimitive 

the position value 

the destination CpmlVector. [out callerallocates] 
Since 1.0
cpml_primitive_get_closest_pos ()
double cpml_primitive_get_closest_pos (const CpmlPrimitive *primitive
,const CpmlPair *pair
);
Returns the pos value of the point on primitive
nearest to pair
.
The returned value is always clamped between 0
and 1
.

a CpmlPrimitive 

the coordinates of the subject point. [allownone] 
Returns : 
the requested pos value between 0 and 1 , or 1 on errors.

Since 1.0
cpml_primitive_put_intersections ()
size_t cpml_primitive_put_intersections (const CpmlPrimitive *primitive
,const CpmlPrimitive *primitive2
,size_t n_dest
,CpmlPair *dest
);
Finds the intersection points between the given primitives and
returns the result in dest
. The size of dest
should be enough
to store n_dest
CpmlPair. The maximum number of intersections
is dependent on the type of the primitive involved in the
operation. If there are at least one Bézier curve involved, up to
4
intersections could be returned. Otherwise, if there is an arc
the intersections will be 2
at maximum. For line primitives, there
is only 1
point (or 0
if the lines are parallel).
Note
The convention used by the CPML library is that a primitive should
implement only the intersection algorithms with lower degree
primitives. This is required to avoid code duplication: intersection
between arc and Bézier curves must be implemented by CPML_CURVE and
intersection between lines and arcs must be implemented by CPML_ARC.
cpml_primitive_put_intersections()
will take care of swapping the
arguments if they are not properly ordered.

the first CpmlPrimitive 

(allownone) the second CpmlPrimitive 

maximum number of intersections to return 

the destination buffer that can contain n_dest CpmlPair. [out callerallocates][array length=n_dest][allownone]

Returns : 
the number of intersection points found or 0 if the primitives do not intersect or on errors. 
Since 1.0
cpml_primitive_put_intersections_with_segment ()
size_t cpml_primitive_put_intersections_with_segment (const CpmlPrimitive *primitive
,const CpmlSegment *segment
,size_t n_dest
,CpmlPair *dest
);
Computes the intersections between segment
and primitive
by
sequentially scanning the primitives in segment
and looking
for their intersections with primitive
.
If the intersections are more than n_dest
, only the first
n_dest
pairs are stored.

a CpmlPrimitive 

a CpmlSegment. [allownone] 

maximum number of intersections to return 

the destination buffer that can contain n_dest CpmlPair. [out callerallocates][array length=n_dest][allownone]

Returns : 
the number of intersection points found or 0 if the items do not intersect or on errors. 
Since 1.0
cpml_primitive_offset ()
void cpml_primitive_offset (CpmlPrimitive *primitive
,double offset
);
Given a primitive, computes the same (or approximated) parallel
primitive distant offset
from the original one and returns
the result by changing primitive
.
On errors, that is if the offset primitive cannot be calculated for some reason, this function does nothing.

a CpmlPrimitive 

distance for the computed offset primitive 
Since 1.0
cpml_primitive_join ()
int cpml_primitive_join (CpmlPrimitive *primitive
,CpmlPrimitive *primitive2
);
Joins two primitive modifying the end point of primitive
and the
start point of primitive2
so that the resulting points will overlap.
TODO
 Actually, the join is done by extending the end vector
of
primitive
and the start vector ofprimitive2
and interpolating the intersection: this means no primitive dependent code is needed. Anyway, it is likely to change in the future because this approach is quite naive when curves are involved.

the first CpmlPrimitive 

the second CpmlPrimitive. [inout][transfer none] 
Returns : 
1 on success, 0 if the primitives cannot be joint.
. [type boolean]

Since 1.0
cpml_primitive_to_cairo ()
void cpml_primitive_to_cairo (const CpmlPrimitive *primitive
,cairo_t *cr
);
Renders a single primitive
to the cr
cairo context.
As a special case, if the primitive is a CPML_CLOSE, an
equivalent line is rendered, because a close path left alone
is not renderable.
Also a CPML_ARC primitive is treated specially, as it is not natively supported by cairo and has its own rendering API.

a CpmlPrimitive 

the destination cairo context. [inout][transfer none] 
Since 1.0
cpml_primitive_dump ()
void cpml_primitive_dump (const CpmlPrimitive *primitive
,int org_also
);
Dumps info on the specified primitive
to stdout: useful for
debugging purposes. If org_also
is 1, a CPML_MOVE to the
origin is prepended to the data otherwise the
org
field is not used.

a CpmlPrimitive 

whether to output also the origin coordinates 
Since 1.0