Synopsis

#include <cpml-1/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 move-to 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().

CPML_MOVE

equivalent to CAIRO_PATH_MOVE_TO

CPML_LINE

equivalent to CAIRO_PATH_LINE_TO

CPML_CURVE

equivalent to CAIRO_PATH_CURVE_TO

CPML_CLOSE

equivalent to CAIRO_PATH_CLOSE_PATH

CPML_ARC

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 *segment;

the source CpmlSegment

cairo_path_data_t *org;

a pointer to the first point of the primitive

cairo_path_data_t *data;

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.

type :

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.

primitive :

the destination CpmlPrimitive struct

segment :

the source segment. [allow-none]

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.

primitive :

the destination CpmlPrimitive

src :

the source CpmlPrimitive. [allow-none]

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.

primitive :

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.

primitive :

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.

primitive :

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 primitive-specific implementation. The function returns the length of primitive.

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 primitive-specific 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.

primitive :

a CpmlPrimitive

extents :

where to store the extents. [out caller-allocates]

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 close-path, 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.

primitive :

a CpmlPrimitive

n_point :

the index of the point to retrieve

pair :

the source CpmlPair. [allow-none]

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.

primitive :

a CpmlPrimitive

n_point :

the index of the point to retrieve

pair :

the destination CpmlPair. [out caller-allocates][allow-none]

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 primitive-specific 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.

primitive :

a CpmlPrimitive

pos :

the position value

pair :

the destination CpmlPair. [out caller-allocates]

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 primitive-specific 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.

primitive :

a CpmlPrimitive

pos :

the position value

vector :

the destination CpmlVector. [out caller-allocates]

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.

primitive :

a CpmlPrimitive

pair :

the coordinates of the subject point. [allow-none]

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.

primitive :

the first CpmlPrimitive

primitive2 :

(allow-none) the second CpmlPrimitive

n_dest :

maximum number of intersections to return

dest :

the destination buffer that can contain n_dest CpmlPair. [out caller-allocates][array length=n_dest][allow-none]

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.

primitive :

a CpmlPrimitive

segment :

a CpmlSegment. [allow-none]

n_dest :

maximum number of intersections to return

dest :

the destination buffer that can contain n_dest CpmlPair. [out caller-allocates][array length=n_dest][allow-none]

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.

primitive :

a CpmlPrimitive

offset :

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 of primitive2 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.

primitive :

the first CpmlPrimitive

primitive2 :

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.

primitive :

a CpmlPrimitive

cr :

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.

primitive :

a CpmlPrimitive

org_also :

whether to output also the origin coordinates

Since 1.0