static void _cpml_sanity_put_intersections(gint i) { CpmlSegment segment; CpmlPrimitive primitive1, primitive2; CpmlPair pair; /* Set primitive1 to 1.1 and primitive 2 to 2.2, * so there is an intersection point in (1, 1) */ cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); cpml_primitive_from_segment(&primitive1, &segment); cpml_segment_next(&segment); cpml_primitive_from_segment(&primitive2, &segment); cpml_primitive_next(&primitive2); switch (i) { case 1: cpml_primitive_put_intersections(NULL, &primitive2, 2, &pair); break; case 2: cpml_primitive_put_intersections(&primitive1, NULL, 2, &pair); break; case 3: cpml_primitive_put_intersections(&primitive1, &primitive2, 2, NULL); break; default: g_test_trap_assert_failed(); break; } }
static void _cpml_method_put_intersections(void) { CpmlSegment segment; CpmlPrimitive primitive1, primitive2; CpmlPair pair[2]; /* Set primitive1 to 1.1 (first segment, first primitive) */ cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); cpml_primitive_from_segment(&primitive1, &segment); /* Set primitive2 to 2.1 (second segment, first primitive) */ cpml_segment_next(&segment); cpml_primitive_from_segment(&primitive2, &segment); /* primitive1 (1.1) does not intersect primitive2 (2.1) */ g_assert_cmpuint(cpml_primitive_put_intersections(&primitive1, &primitive2, 2, pair), ==, 0); cpml_primitive_next(&primitive2); /* primitive1 (1.1) intersects primitive2 (2.2) in (1, 1) */ g_assert_cmpuint(cpml_primitive_put_intersections(&primitive1, &primitive2, 2, pair), ==, 1); adg_assert_isapprox(pair[0].x, 1); adg_assert_isapprox(pair[0].y, 1); g_assert_cmpint(cpml_primitive_is_inside(&primitive1, pair), ==, 1); g_assert_cmpint(cpml_primitive_is_inside(&primitive2, pair), ==, 1); /* Check the intersection is not returned when not requested */ g_assert_cmpuint(cpml_primitive_put_intersections(&primitive1, &primitive2, 0, pair), ==, 0); cpml_primitive_next(&primitive1); /* primitive1 (1.2) does not intersect primitive2 (2.2) */ g_assert_cmpuint(cpml_primitive_put_intersections(&primitive1, &primitive2, 2, pair), ==, 0); cpml_primitive_next(&primitive1); /* primitive1 (1.3) does not intersect primitive2 (2.2) */ g_assert_cmpuint(cpml_primitive_put_intersections(&primitive1, &primitive2, 2, pair), ==, 0); cpml_primitive_next(&primitive1); /* primitive1 (1.4) intersects primitive2 (2.2), but outside their boundaries */ g_assert_cmpuint(cpml_primitive_put_intersections(&primitive1, &primitive2, 2, pair), ==, 1); adg_assert_isapprox(pair[0].x, 1); adg_assert_isapprox(pair[0].y, -1); g_assert_cmpint(cpml_primitive_is_inside(&primitive1, pair), ==, 0); g_assert_cmpint(cpml_primitive_is_inside(&primitive2, pair), ==, 0); }
static void _cpml_method_get_n_points(void) { CpmlSegment segment; CpmlPrimitive primitive; size_t n_points; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); /* Line */ cpml_primitive_from_segment(&primitive, &segment); n_points = cpml_primitive_get_n_points(&primitive); g_assert_cmpuint(n_points, ==, 2); /* Arc */ cpml_primitive_next(&primitive); n_points = cpml_primitive_get_n_points(&primitive); g_assert_cmpuint(n_points, ==, 3); /* Curve */ cpml_primitive_next(&primitive); n_points = cpml_primitive_get_n_points(&primitive); g_assert_cmpuint(n_points, ==, 4); /* Close: although the end point is not needed, the CPML API * returns 2 points to treat this primitive as a CPML_LINE */ cpml_primitive_next(&primitive); n_points = cpml_primitive_get_n_points(&primitive); g_assert_cmpuint(n_points, ==, 2); }
/** * cpml_segment_offset: * @segment: a #CpmlSegment * @offset: the offset distance * * Offsets a segment of the specified amount, that is builds a "parallel" * segment at the @offset distance from the original one and returns the * result by replacing the original @segment. * * <important> * <title>TODO</title> * <itemizedlist> * <listitem>Closed path are not yet managed: an elegant solution is not * so obvious: use <function>cpml_close_offset</function> when * will be available.</listitem> * <listitem>Degenerated primitives, such as lines of length 0, are not * managed properly.</listitem> * </itemizedlist> * </important> * * Since: 1.0 **/ void cpml_segment_offset(CpmlSegment *segment, double offset) { CpmlPrimitive primitive; CpmlPrimitive last_primitive; CpmlPair old_end; cairo_path_data_t org, *old_org; int first_cycle; cpml_primitive_from_segment(&primitive, segment); first_cycle = 1; do { if (! first_cycle) { cpml_pair_to_cairo(&old_end, &org); old_org = primitive.org; primitive.org = &org; } cpml_primitive_put_point(&primitive, -1, &old_end); cpml_primitive_offset(&primitive, offset); if (! first_cycle) { cpml_primitive_join(&last_primitive, &primitive); primitive.org = old_org; } cpml_primitive_copy(&last_primitive, &primitive); first_cycle = 0; } while (cpml_primitive_next(&primitive)); }
static void _adg_rescan(AdgPath *path) { AdgPathPrivate *data; CpmlSegment segment; CpmlPrimitive current, *last, *over; data = path->data; last = &data->last; over = &data->over; last->segment = NULL; last->org = NULL; last->data = NULL; over->segment = NULL; over->org = NULL; over->data = NULL; /* When no data is present, just bail out */ if (! cpml_segment_from_cairo(&segment, _adg_read_cairo_path(path))) return; do { cpml_primitive_from_segment(¤t, &segment); do { cpml_primitive_copy(over, last); cpml_primitive_copy(last, ¤t); } while (cpml_primitive_next(¤t)); } while (cpml_segment_next(&segment)); }
static void _cpml_method_put_pair_at(void) { CpmlSegment segment; CpmlPrimitive primitive; CpmlPair pair; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); /* Line */ cpml_primitive_from_segment(&primitive, &segment); cpml_primitive_put_pair_at(&primitive, 0, &pair); adg_assert_isapprox(pair.x, 0); adg_assert_isapprox(pair.y, 1); cpml_primitive_put_pair_at(&primitive, 1, &pair); adg_assert_isapprox(pair.x, 3); adg_assert_isapprox(pair.y, 1); cpml_primitive_put_pair_at(&primitive, 0.5, &pair); adg_assert_isapprox(pair.x, 1.5); adg_assert_isapprox(pair.y, 1); /* Arc */ cpml_primitive_next(&primitive); cpml_primitive_put_pair_at(&primitive, 0, &pair); adg_assert_isapprox(pair.x, 3); adg_assert_isapprox(pair.y, 1); cpml_primitive_put_pair_at(&primitive, 1, &pair); adg_assert_isapprox(pair.x, 6); adg_assert_isapprox(pair.y, 7); cpml_primitive_put_pair_at(&primitive, 0.5, &pair); adg_assert_isapprox(pair.x, 3.669); adg_assert_isapprox(pair.y, 4.415); /* Close */ cpml_primitive_next(&primitive); /* TODO: not yet implemented * cpml_primitive_put_pair_at(&primitive, 0, &pair); * adg_assert_isapprox(pair.x, 6); * adg_assert_isapprox(pair.y, 7); * cpml_primitive_put_pair_at(&primitive, 1, &pair); * adg_assert_isapprox(pair.x, -2); * adg_assert_isapprox(pair.y, 2); * cpml_primitive_put_pair_at(&primitive, 0.5, &pair); * adg_assert_isapprox(pair.x, 1); * adg_assert_isapprox(pair.y, 1); */ /* Close */ cpml_primitive_next(&primitive); cpml_primitive_put_pair_at(&primitive, 0, &pair); adg_assert_isapprox(pair.x, -2); adg_assert_isapprox(pair.y, 2); cpml_primitive_put_pair_at(&primitive, 1, &pair); adg_assert_isapprox(pair.x, 0); adg_assert_isapprox(pair.y, 1); cpml_primitive_put_pair_at(&primitive, 0.5, &pair); adg_assert_isapprox(pair.x, -1); adg_assert_isapprox(pair.y, 1.5); }
static void _cpml_method_put_vector_at(void) { CpmlSegment segment; CpmlPrimitive primitive; CpmlVector vector; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); /* Line */ cpml_primitive_from_segment(&primitive, &segment); cpml_primitive_put_vector_at(&primitive, 0, &vector); adg_assert_isapprox(vector.x, 3); adg_assert_isapprox(vector.y, 0); cpml_primitive_put_vector_at(&primitive, 1, &vector); adg_assert_isapprox(vector.x, 3); adg_assert_isapprox(vector.y, 0); cpml_primitive_put_vector_at(&primitive, 0.5, &vector); adg_assert_isapprox(vector.x, 3); adg_assert_isapprox(vector.y, 0); /* Arc */ cpml_primitive_next(&primitive); cpml_primitive_put_vector_at(&primitive, 0, &vector); adg_assert_isapprox(vector.x, -0.077); adg_assert_isapprox(vector.y, 0.997); cpml_primitive_put_vector_at(&primitive, 1, &vector); adg_assert_isapprox(vector.x, 0.844); adg_assert_isapprox(vector.y, 0.537); cpml_primitive_put_vector_at(&primitive, 0.5, &vector); adg_assert_isapprox(vector.x, 0.447); adg_assert_isapprox(vector.y, 0.894); /* Close */ cpml_primitive_next(&primitive); /* TODO: not yet implemented * cpml_primitive_put_vector_at(&primitive, 0, &vector); * adg_assert_isapprox(vector.x, 6); * adg_assert_isapprox(vector.y, 7); * cpml_primitive_put_vector_at(&primitive, 1, &vector); * adg_assert_isapprox(vector.x, -2); * adg_assert_isapprox(vector.y, 2); * cpml_primitive_put_vector_at(&primitive, 0.5, &vector); * adg_assert_isapprox(vector.x, 1); * adg_assert_isapprox(vector.y, 1); */ /* Close */ cpml_primitive_next(&primitive); cpml_primitive_put_vector_at(&primitive, 0, &vector); adg_assert_isapprox(vector.x, 2); adg_assert_isapprox(vector.y, -1); cpml_primitive_put_vector_at(&primitive, 1, &vector); adg_assert_isapprox(vector.x, 2); adg_assert_isapprox(vector.y, -1); cpml_primitive_put_vector_at(&primitive, 0.5, &vector); adg_assert_isapprox(vector.x, 2); adg_assert_isapprox(vector.y, -1); }
static void _cpml_method_put_intersections_with_segment(void) { CpmlSegment segment; CpmlPrimitive primitive; CpmlPair pair[4]; /* Set primitive to first segment, first primitive */ cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); cpml_primitive_from_segment(&primitive, &segment); /* Set segment to the second segment */ cpml_segment_next(&segment); /* primitive (1.1) intersects segment (2) in (1, 1) */ g_assert_cmpuint(cpml_primitive_put_intersections_with_segment(&primitive, &segment, 4, pair), ==, 1); adg_assert_isapprox(pair[0].x, 1); adg_assert_isapprox(pair[0].y, 1); cpml_primitive_next(&primitive); /* primitive (1.1) does not intersect segment (2) */ g_assert_cmpuint(cpml_primitive_put_intersections_with_segment(&primitive, &segment, 4, pair), ==, 0); /* Set primitive to second segment, first primitive */ cpml_primitive_from_segment(&primitive, &segment); /* Set segment to the first segment */ cpml_segment_reset(&segment); /* primitive (2.1) intersects segment (1) in extrapolation. * TODO: change this behavior! They must not intersect. */ g_assert_cmpuint(cpml_primitive_put_intersections_with_segment(&primitive, &segment, 4, pair), ==, 1); adg_assert_isapprox(pair[0].x, 2); adg_assert_isapprox(pair[0].y, 0); cpml_primitive_next(&primitive); /* primitive (2.2) wrongly intersects segment (1) */ g_assert_cmpuint(cpml_primitive_put_intersections_with_segment(&primitive, &segment, 4, pair), ==, 1); adg_assert_isapprox(pair[0].x, 2); adg_assert_isapprox(pair[0].y, 0); }
static void _cpml_sanity_from_segment(gint i) { CpmlPrimitive primitive; CpmlSegment segment; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); switch (i) { case 1: cpml_primitive_from_segment(NULL, &segment); break; case 2: cpml_primitive_from_segment(&primitive, NULL); break; default: g_test_trap_assert_failed(); break; } }
/** * cpml_segment_to_cairo: * @segment: a #CpmlSegment * @cr: the destination cairo context * * Appends the path of @segment to @cr. The segment is "flattened", * that is %CPML_ARC primitives are approximated by one or more * %CPML_CURVE using cpml_arc_to_cairo(). Check its documentation * for further details. * * Since: 1.0 **/ void cpml_segment_to_cairo(const CpmlSegment *segment, cairo_t *cr) { CpmlPrimitive primitive; cpml_primitive_from_segment(&primitive, (CpmlSegment *) segment); do { cpml_primitive_to_cairo(&primitive, cr); } while (cpml_primitive_next(&primitive)); }
static void _cpml_method_from_segment(void) { CpmlSegment segment; CpmlPrimitive primitive; g_assert_true(cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path())); cpml_primitive_from_segment(&primitive, &segment); g_assert_nonnull(primitive.segment); g_assert_nonnull(primitive.org); g_assert_nonnull(primitive.data); }
/** * cpml_segment_dump: * @segment: a #CpmlSegment * * Dumps the specified @segment to stdout. Useful for debugging purposes. * * Since: 1.0 **/ void cpml_segment_dump(const CpmlSegment *segment) { CpmlPrimitive primitive; int first_call = 1; cpml_primitive_from_segment(&primitive, (CpmlSegment *) segment); do { cpml_primitive_dump(&primitive, first_call); first_call = 0; } while (cpml_primitive_next(&primitive)); }
/** * cpml_segment_put_extents: * @segment: a #CpmlSegment * @extents: where to store the extents * * Gets the whole extents of @segment. * * Since: 1.0 **/ void cpml_segment_put_extents(const CpmlSegment *segment, CpmlExtents *extents) { CpmlPrimitive primitive; CpmlExtents primitive_extents; extents->is_defined = 0; cpml_primitive_from_segment(&primitive, (CpmlSegment *) segment); do { cpml_primitive_put_extents(&primitive, &primitive_extents); cpml_extents_add(extents, &primitive_extents); } while (cpml_primitive_next(&primitive)); }
static void _cpml_method_get_length(void) { CpmlSegment segment; CpmlPrimitive primitive; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); cpml_segment_next(&segment); cpml_primitive_from_segment(&primitive, &segment); adg_assert_isapprox(cpml_primitive_get_length(&primitive), 1); cpml_primitive_next(&primitive); adg_assert_isapprox(cpml_primitive_get_length(&primitive), 2); }
/** * cpml_segment_get_length: * @segment: a #CpmlSegment * * Gets the whole length of @segment. * * Returns: the requested length * * Since: 1.0 **/ double cpml_segment_get_length(const CpmlSegment *segment) { CpmlPrimitive primitive; double length; cpml_primitive_from_segment(&primitive, (CpmlSegment *) segment); length = 0; do { length += cpml_primitive_get_length(&primitive); } while (cpml_primitive_next(&primitive)); return length; }
static void _cpml_method_put_extents(void) { CpmlSegment segment; CpmlPrimitive primitive; CpmlExtents extents; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); /* Line */ cpml_primitive_from_segment(&primitive, &segment); cpml_primitive_put_extents(&primitive, &extents); g_assert_true(extents.is_defined); adg_assert_isapprox(extents.org.x, 0); adg_assert_isapprox(extents.org.y, 1); adg_assert_isapprox(extents.size.x, 3); adg_assert_isapprox(extents.size.y, 0); /* Arc: the extents are computed precisely... let's ensure * at least all the 3 points are included */ cpml_primitive_next(&primitive); cpml_primitive_put_extents(&primitive, &extents); g_assert_true(extents.is_defined); g_assert_cmpfloat(extents.org.x, <=, 3); g_assert_cmpfloat(extents.org.y, <=, 1); g_assert_cmpfloat(extents.size.x, >=, 3); g_assert_cmpfloat(extents.size.y, >=, 6); /* Curve: actually the extents are computed by using the * convex hull (hence the exact coordinates of the points) */ cpml_primitive_next(&primitive); cpml_primitive_put_extents(&primitive, &extents); g_assert_true(extents.is_defined); adg_assert_isapprox(extents.org.x, -2); adg_assert_isapprox(extents.org.y, 2); adg_assert_isapprox(extents.size.x, 12); adg_assert_isapprox(extents.size.y, 9); /* Close */ cpml_primitive_next(&primitive); cpml_primitive_put_extents(&primitive, &extents); g_assert_true(extents.is_defined); adg_assert_isapprox(extents.org.x, -2); adg_assert_isapprox(extents.org.y, 1); adg_assert_isapprox(extents.size.x, 2); adg_assert_isapprox(extents.size.y, 1); }
/** * cpml_segment_put_pair_at: * @segment: a #CpmlSegment * @pos: the position value * @pair: the destination #CpmlPair * * Gets the coordinates of the point lying on @segment 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. * The relation <constant>0 < @pos < 1</constant> should be satisfied, * although some cases accept value outside this range. * * <important> * <title>TODO</title> * <itemizedlist> * <listitem>The actual implementation returns only the start and end points, * that is only when @pos is 0 or 1.</listitem> * </itemizedlist> * </important> * * Since: 1.0 **/ void cpml_segment_put_pair_at(const CpmlSegment *segment, double pos, CpmlPair *pair) { CpmlPrimitive primitive; cpml_primitive_from_segment(&primitive, (CpmlSegment *) segment); /* Handle the common cases: start and end points */ if (pos == 0) { cpml_primitive_put_pair_at(&primitive, 0, pair); } if (pos == 1) { while (cpml_primitive_next(&primitive)) ; cpml_primitive_put_pair_at(&primitive, 1, pair); } }
static void _cpml_method_copy_data(void) { CpmlSegment segment; CpmlPrimitive original, *primitive; int n; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); cpml_primitive_from_segment(&original, &segment); /* Check incompatible primitives are not copied */ primitive = cpml_primitive_deep_dup(&original); ++primitive->data[0].header.length; g_assert_cmpint(cpml_primitive_copy_data(primitive, &original), ==, 0); --primitive->data[0].header.length; ++primitive->data[0].header.type; g_assert_cmpint(cpml_primitive_copy_data(primitive, &original), ==, 0); --primitive->data[0].header.type; do { primitive = cpml_primitive_deep_dup(&original); ++primitive->org->point.x; ++primitive->org->point.y; for (n = 1; n < primitive->data[0].header.length; ++n) { ++primitive->data[n].point.x; ++primitive->data[n].point.y; } g_assert_cmpfloat(primitive->org->point.x, !=, original.org->point.x); g_assert_cmpfloat(primitive->org->point.y, !=, original.org->point.y); for (n = 1; n < primitive->data[0].header.length; ++n) { g_assert_cmpfloat(primitive->data[n].point.x, !=, original.data[n].point.x); g_assert_cmpfloat(primitive->data[n].point.y, !=, original.data[n].point.y); } g_assert_cmpint(cpml_primitive_copy_data(primitive, &original), ==, 1); adg_assert_isapprox(primitive->org->point.x, original.org->point.x); adg_assert_isapprox(primitive->org->point.y, original.org->point.y); for (n = 1; n < primitive->data[0].header.length; ++n) { adg_assert_isapprox(primitive->data[n].point.x, original.data[n].point.x); adg_assert_isapprox(primitive->data[n].point.y, original.data[n].point.y); } g_free(primitive); } while (cpml_primitive_next(&original)); }
static void _cpml_behavior_browsing(void) { CpmlSegment segment; CpmlPrimitive primitive, primitive_copy; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); cpml_primitive_from_segment(&primitive, &segment); adg_assert_isapprox((primitive.org)->point.x, 0); adg_assert_isapprox((primitive.org)->point.y, 1); g_assert_cmpint((primitive.data)->header.type, ==, CPML_LINE); g_assert_true(cpml_primitive_next(&primitive)); adg_assert_isapprox((primitive.org)->point.x, 3); adg_assert_isapprox((primitive.org)->point.y, 1); g_assert_cmpint((primitive.data)->header.type, ==, CPML_ARC); g_assert_true(cpml_primitive_next(&primitive)); adg_assert_isapprox((primitive.org)->point.x, 6); adg_assert_isapprox((primitive.org)->point.y, 7); g_assert_cmpint((primitive.data)->header.type, ==, CPML_CURVE); g_assert_true(cpml_primitive_next(&primitive)); adg_assert_isapprox((primitive.org)->point.x, -2); adg_assert_isapprox((primitive.org)->point.y, 2); g_assert_cmpint((primitive.data)->header.type, ==, CPML_CLOSE); g_assert_false(cpml_primitive_next(&primitive)); cpml_primitive_reset(&primitive); g_assert_true(cpml_primitive_next(&primitive)); cpml_primitive_reset(&primitive); cpml_primitive_reset(&primitive); g_assert_true(cpml_primitive_next(&primitive)); g_assert_true(cpml_primitive_next(&primitive)); g_assert_true(cpml_primitive_next(&primitive)); g_assert_false(cpml_primitive_next(&primitive)); cpml_primitive_copy(&primitive_copy, &primitive); g_assert_false(cpml_primitive_next(&primitive_copy)); cpml_primitive_reset(&primitive); g_assert_false(cpml_primitive_next(&primitive_copy)); cpml_primitive_reset(&primitive_copy); g_assert_true(cpml_primitive_next(&primitive_copy)); }
static void _cpml_method_copy(void) { CpmlSegment segment; CpmlPrimitive original; CpmlPrimitive primitive = { NULL, NULL, NULL }; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); cpml_primitive_from_segment(&original, &segment); g_assert_false(original.segment == primitive.segment); g_assert_false(original.org == primitive.org); g_assert_false(original.data == primitive.data); cpml_primitive_copy(&primitive, &original); g_assert_true(original.segment == primitive.segment); g_assert_true(original.org == primitive.org); g_assert_true(original.data == primitive.data); }
/** * cpml_segment_put_intersections: * @segment: the first #CpmlSegment * @segment2: the second #CpmlSegment * @n_dest: maximum number of intersections to return * @dest: the destination vector of #CpmlPair * * Computes the intersections between @segment and @segment2 and * returns the found points in @dest. If the intersections are more * than @n_dest, only the first @n_dest pairs are stored in @dest. * * To get the job done, the primitives of @segment are sequentially * scanned for intersections with any primitive in @segment2. This * means @segment has a higher precedence over @segment2. * * Returns: the number of intersections found * * Since: 1.0 **/ size_t cpml_segment_put_intersections(const CpmlSegment *segment, const CpmlSegment *segment2, size_t n_dest, CpmlPair *dest) { CpmlPrimitive portion; size_t partial, total; cpml_primitive_from_segment(&portion, (CpmlSegment *) segment); total = 0; do { partial = cpml_primitive_put_intersections_with_segment(&portion, segment2, n_dest - total, dest + total); total += partial; } while (total < n_dest && cpml_primitive_next(&portion)); return total; }
/** * cpml_segment_transform: * @segment: a #CpmlSegment * @matrix: the matrix to be applied * * Applies @matrix on all the points of @segment. * * Since: 1.0 **/ void cpml_segment_transform(CpmlSegment *segment, const cairo_matrix_t *matrix) { CpmlPrimitive primitive; cairo_path_data_t *data; size_t n_points; cpml_primitive_from_segment(&primitive, segment); cairo_matrix_transform_point(matrix, &(primitive.org)->point.x, &(primitive.org)->point.y); do { data = primitive.data; if (data->header.type != CPML_CLOSE) { n_points = cpml_primitive_get_n_points(&primitive); while (--n_points > 0) { ++data; cairo_matrix_transform_point(matrix, &data->point.x, &data->point.y); } } } while (cpml_primitive_next(&primitive)); }
static void _cpml_method_get_closest_pos(void) { CpmlSegment segment; CpmlPrimitive primitive; CpmlPair pair; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); cpml_primitive_from_segment(&primitive, &segment); /* Line */ pair.x = 0; pair.y = 1; adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 0); pair.x = 3; pair.y = 1; adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 1); pair.x = -1; pair.y = -1; adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 0); pair.x = 4; pair.y = 2; adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 1); pair.x = 1.5; pair.y = 0; adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 0.5); /* Arc */ cpml_primitive_next(&primitive); /* TODO: not yet implemented * pair.x = 3; pair.y = 1; * adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 0); * pair.x = 6; pair.y = 7; * adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 1); * pair.x = 0; pair.y = 0; * adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 0); * pair.x = 10; pair.y = 10; * adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 1); */ /* Close */ cpml_primitive_next(&primitive); /* TODO: not yet implemented * pair.x = 6; pair.y = 7; * adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 0); * pair.x = -2; pair.y = 2; * adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 1); * pair.x = 10; pair.y = 10; * adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 0); * pair.x = 0; pair.y = 0; * adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 1); */ /* Close */ cpml_primitive_next(&primitive); pair.x = -2; pair.y = 2; adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 0); pair.x = 0; pair.y = 1; adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 1); pair.x = -3; pair.y = 3; adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 0); pair.x = 1; pair.y = 0; adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 1); pair.x = -1; pair.y = 1.5; adg_assert_isapprox(cpml_primitive_get_closest_pos(&primitive, &pair), 0.5); }
static void _cpml_method_offset(void) { CpmlSegment original, *segment; CpmlPrimitive primitive, line, curve; CpmlPrimitive *backup; /* Work on a copy to avoid modifying the original cairo path */ cpml_segment_from_cairo(&original, (cairo_path_t *) adg_test_path()); segment = cpml_segment_deep_dup(&original); cpml_primitive_from_segment(&primitive, segment); /* Offsetting and de-offsetting can introduce rounding errors * so we use adg_assert_isapprox instead of g_assert_cmpfloat */ /* Line */ cpml_primitive_copy(&line, &primitive); cpml_primitive_offset(&primitive, 1); adg_assert_isapprox((primitive.org)->point.x, 0); adg_assert_isapprox((primitive.org)->point.y, 2); adg_assert_isapprox(primitive.data[1].point.x, 3); adg_assert_isapprox(primitive.data[1].point.y, 2); cpml_primitive_offset(&primitive, -1); adg_assert_isapprox((primitive.org)->point.x, 0); adg_assert_isapprox((primitive.org)->point.y, 1); adg_assert_isapprox(primitive.data[1].point.x, 3); adg_assert_isapprox(primitive.data[1].point.y, 1); /* Arc */ cpml_primitive_next(&primitive); cpml_primitive_offset(&primitive, 1); adg_assert_isapprox((primitive.org)->point.x, 2.003); adg_assert_isapprox((primitive.org)->point.y, 0.923); adg_assert_isapprox(primitive.data[1].point.x, 3.156); adg_assert_isapprox(primitive.data[1].point.y, 5.537); adg_assert_isapprox(primitive.data[2].point.x, 5.463); adg_assert_isapprox(primitive.data[2].point.y, 7.844); cpml_primitive_offset(&primitive, -1); adg_assert_isapprox((primitive.org)->point.x, 3); adg_assert_isapprox((primitive.org)->point.y, 1); adg_assert_isapprox(primitive.data[1].point.x, 4); adg_assert_isapprox(primitive.data[1].point.y, 5); adg_assert_isapprox(primitive.data[2].point.x, 6); adg_assert_isapprox(primitive.data[2].point.y, 7); /* Curve */ cpml_primitive_next(&primitive); cpml_primitive_copy(&curve, &primitive); /* The offset algorithm for curves is an approximation, so * offsetting +1 and -1 does not return the original curve. * Keeping a backup around to restore the original data. */ backup = cpml_primitive_deep_dup(&curve); /* Testing different algorithms */ cpml_curve_offset_algorithm(CPML_CURVE_OFFSET_ALGORITHM_GEOMETRICAL); cpml_primitive_offset(&primitive, 1); adg_assert_isapprox((primitive.org)->point.x, 5.293); adg_assert_isapprox((primitive.org)->point.y, 7.707); adg_assert_isapprox(primitive.data[1].point.x, 7.889); adg_assert_isapprox(primitive.data[1].point.y, 8.515); adg_assert_isapprox(primitive.data[2].point.x, 11.196); adg_assert_isapprox(primitive.data[2].point.y, 9.007); adg_assert_isapprox(primitive.data[3].point.x, -1.4); adg_assert_isapprox(primitive.data[3].point.y, 1.2); cpml_primitive_copy_data(&primitive, backup); cpml_curve_offset_algorithm(CPML_CURVE_OFFSET_ALGORITHM_BAIOCA); cpml_primitive_offset(&primitive, 1); adg_assert_isapprox((primitive.org)->point.x, 5.293); adg_assert_isapprox((primitive.org)->point.y, 7.707); adg_assert_isapprox(primitive.data[1].point.x, 6.901); adg_assert_isapprox(primitive.data[1].point.y, 9.315); adg_assert_isapprox(primitive.data[2].point.x, 10.806); adg_assert_isapprox(primitive.data[2].point.y, 10.355); adg_assert_isapprox(primitive.data[3].point.x, -1.4); adg_assert_isapprox(primitive.data[3].point.y, 1.2); cpml_primitive_copy_data(&primitive, backup); cpml_curve_offset_algorithm(CPML_CURVE_OFFSET_ALGORITHM_HANDCRAFT); cpml_primitive_offset(&primitive, 1); adg_assert_isapprox((primitive.org)->point.x, 5.293); adg_assert_isapprox((primitive.org)->point.y, 7.707); adg_assert_isapprox(primitive.data[1].point.x, -5.758); adg_assert_isapprox(primitive.data[1].point.y, -3.344); adg_assert_isapprox(primitive.data[2].point.x, 24.987); adg_assert_isapprox(primitive.data[2].point.y, 20.99); adg_assert_isapprox(primitive.data[3].point.x, -1.4); adg_assert_isapprox(primitive.data[3].point.y, 1.2); cpml_primitive_copy_data(&primitive, backup); g_free(backup); cpml_curve_offset_algorithm(CPML_CURVE_OFFSET_ALGORITHM_DEFAULT); /* Close: this primitive does not own data points but should * modify the points of the previous and next primitives */ cpml_primitive_next(&primitive); cpml_primitive_offset(&primitive, 1); adg_assert_isapprox((curve.org)->point.x, 6); adg_assert_isapprox((curve.org)->point.y, 7); adg_assert_isapprox(curve.data[3].point.x, -1.553); adg_assert_isapprox(curve.data[3].point.y, 2.894); adg_assert_isapprox((line.org)->point.x, 0.447); adg_assert_isapprox((line.org)->point.y, 1.894); adg_assert_isapprox(line.data[1].point.x, 3); adg_assert_isapprox(line.data[1].point.y, 1); cpml_primitive_offset(&primitive, -1); adg_assert_isapprox((curve.org)->point.x, 6); adg_assert_isapprox((curve.org)->point.y, 7); adg_assert_isapprox(curve.data[3].point.x, -2); adg_assert_isapprox(curve.data[3].point.y, 2); adg_assert_isapprox((line.org)->point.x, 0); adg_assert_isapprox((line.org)->point.y, 1); adg_assert_isapprox(line.data[1].point.x, 3); adg_assert_isapprox(line.data[1].point.y, 1); g_free(segment); }
static gboolean _adg_append_operation(AdgPath *path, AdgAction action, ...) { AdgPathPrivate *data; AdgOperation *operation; va_list var_args; data = path->data; if (data->last.data == NULL) { g_warning(_("%s: requested a '%s' operation on a path without current primitive"), G_STRLOC, _adg_action_name(action)); return FALSE; } operation = &data->operation; if (operation->action != ADG_ACTION_NONE) { g_warning(_("%s: requested a '%s' operation while a '%s' operation was active"), G_STRLOC, _adg_action_name(action), _adg_action_name(operation->action)); /* XXX: http://dev.entidi.com/p/adg/issues/50/ */ return FALSE; } va_start(var_args, action); switch (action) { case ADG_ACTION_CHAMFER: operation->data.chamfer.delta1 = va_arg(var_args, double); operation->data.chamfer.delta2 = va_arg(var_args, double); break; case ADG_ACTION_FILLET: operation->data.fillet.radius = va_arg(var_args, double); break; case ADG_ACTION_NONE: va_end(var_args); return TRUE; default: g_warning(_("%s: %d path operation not recognized"), G_STRLOC, action); va_end(var_args); return FALSE; } operation->action = action; va_end(var_args); if (data->last.data[0].header.type == CPML_CLOSE) { /* Special case: an action with the close primitive should * be resolved now by changing the close primitive to a * line-to and using it as second operand and use the first * primitive of the current segment as first operand */ guint length; cairo_path_data_t *path_data; CpmlSegment segment; CpmlPrimitive current; length = data->cairo.array->len; /* Ensure the close path primitive is not the only data */ g_return_val_if_fail(length > 1, FALSE); /* Allocate one more item once for all to accept the * conversion from a close to line-to primitive */ data->cairo.array = g_array_set_size(data->cairo.array, length + 1); path_data = (cairo_path_data_t *) data->cairo.array->data; --data->cairo.array->len; /* Set segment and current (the first primitive of segment) */ cpml_segment_from_cairo(&segment, _adg_read_cairo_path(path)); while (cpml_segment_next(&segment)) ; cpml_primitive_from_segment(¤t, &segment); /* Convert close path to a line-to primitive */ ++data->cairo.array->len; path_data[length - 1].header.type = CPML_LINE; path_data[length - 1].header.length = 2; path_data[length] = *current.org; data->last.segment = &segment; data->last.org = &path_data[length - 2]; data->last.data = &path_data[length - 1]; _adg_do_action(path, action, ¤t); } return TRUE; }
static void _cpml_method_set_point(void) { gsize data_size; CpmlSegment original, *segment; CpmlPrimitive primitive; CpmlPair pair, pair2; int equality; /* Work on a copy to not modify the original path data */ cpml_segment_from_cairo(&original, (cairo_path_t *) adg_test_path()); data_size = original.num_data * sizeof(cairo_path_data_t); segment = cpml_segment_deep_dup(&original); /* Line */ cpml_primitive_from_segment(&primitive, segment); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, ==, 0); cpml_primitive_put_point(&primitive, 0, &pair); pair.x += 1; cpml_primitive_set_point(&primitive, 0, &pair); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); pair.x -= 1; cpml_primitive_set_point(&primitive, 0, &pair); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, ==, 0); cpml_primitive_put_point(&primitive, 1, &pair); pair.y += 1; cpml_primitive_set_point(&primitive, 1, &pair); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); /* On a CPML_LINE primitives, -1 and 1 indices are equals */ cpml_primitive_put_point(&primitive, -1, &pair2); adg_assert_isapprox(pair.x, pair2.x); adg_assert_isapprox(pair.y, pair2.y); memcpy(segment->data, original.data, data_size); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, ==, 0); cpml_primitive_put_point(&primitive, 2, &pair); pair.x += 1; pair.y += 1; /* This should be a NOP without segfaults */ cpml_primitive_set_point(&primitive, 2, &pair); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, ==, 0); /* From now on, memcpy() is assumed to force equality (as already * proved by the previous assertions) and pair2 is used as a * different-from-everything pair, that is setting pair2 on any * point will break the equality between segment->data and * original.data */ pair2.x = 12345; pair2.y = 54321; /* Arc */ cpml_primitive_next(&primitive); cpml_primitive_set_point(&primitive, 0, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); memcpy(segment->data, original.data, data_size); cpml_primitive_set_point(&primitive, 1, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); memcpy(segment->data, original.data, data_size); cpml_primitive_set_point(&primitive, 2, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); memcpy(segment->data, original.data, data_size); cpml_primitive_set_point(&primitive, 3, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, ==, 0); /* Curve */ cpml_primitive_next(&primitive); cpml_primitive_set_point(&primitive, 0, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); memcpy(segment->data, original.data, data_size); cpml_primitive_set_point(&primitive, 1, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); memcpy(segment->data, original.data, data_size); cpml_primitive_set_point(&primitive, 2, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); memcpy(segment->data, original.data, data_size); cpml_primitive_set_point(&primitive, 3, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); memcpy(segment->data, original.data, data_size); cpml_primitive_set_point(&primitive, 4, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, ==, 0); /* Close */ cpml_primitive_next(&primitive); cpml_primitive_set_point(&primitive, 0, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); memcpy(segment->data, original.data, data_size); cpml_primitive_set_point(&primitive, 1, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, !=, 0); memcpy(segment->data, original.data, data_size); cpml_primitive_set_point(&primitive, 2, &pair2); equality = memcmp(original.data, segment->data, data_size); g_assert_cmpint(equality, ==, 0); g_free(segment); }
static void _cpml_method_put_point(void) { CpmlSegment segment; CpmlPrimitive primitive; CpmlPair pair; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); /* Line */ cpml_primitive_from_segment(&primitive, &segment); cpml_primitive_put_point(&primitive, 0, &pair); adg_assert_isapprox(pair.x, 0); adg_assert_isapprox(pair.y, 1); cpml_primitive_put_point(&primitive, 1, &pair); adg_assert_isapprox(pair.x, 3); adg_assert_isapprox(pair.y, 1); cpml_primitive_put_point(&primitive, 2, &pair); adg_assert_isapprox(pair.x, 3); adg_assert_isapprox(pair.y, 1); /* The negative indices are checked only against CPML_LINE */ cpml_primitive_put_point(&primitive, -1, &pair); adg_assert_isapprox(pair.x, 3); adg_assert_isapprox(pair.y, 1); cpml_primitive_put_point(&primitive, -2, &pair); adg_assert_isapprox(pair.x, 0); adg_assert_isapprox(pair.y, 1); cpml_primitive_put_point(&primitive, -3, &pair); adg_assert_isapprox(pair.x, 0); adg_assert_isapprox(pair.y, 1); /* Arc */ cpml_primitive_next(&primitive); cpml_primitive_put_point(&primitive, 0, &pair); adg_assert_isapprox(pair.x, 3); adg_assert_isapprox(pair.y, 1); cpml_primitive_put_point(&primitive, 1, &pair); adg_assert_isapprox(pair.x, 4); adg_assert_isapprox(pair.y, 5); cpml_primitive_put_point(&primitive, 2, &pair); adg_assert_isapprox(pair.x, 6); adg_assert_isapprox(pair.y, 7); cpml_primitive_put_point(&primitive, 3, &pair); adg_assert_isapprox(pair.x, 6); adg_assert_isapprox(pair.y, 7); /* Curve */ cpml_primitive_next(&primitive); cpml_primitive_put_point(&primitive, 0, &pair); adg_assert_isapprox(pair.x, 6); adg_assert_isapprox(pair.y, 7); cpml_primitive_put_point(&primitive, 1, &pair); adg_assert_isapprox(pair.x, 8); adg_assert_isapprox(pair.y, 9); cpml_primitive_put_point(&primitive, 2, &pair); adg_assert_isapprox(pair.x, 10); adg_assert_isapprox(pair.y, 11); cpml_primitive_put_point(&primitive, 3, &pair); adg_assert_isapprox(pair.x, -2); adg_assert_isapprox(pair.y, 2); cpml_primitive_put_point(&primitive, 4, &pair); adg_assert_isapprox(pair.x, -2); adg_assert_isapprox(pair.y, 2); /* Close */ cpml_primitive_next(&primitive); cpml_primitive_put_point(&primitive, 0, &pair); adg_assert_isapprox(pair.x, -2); adg_assert_isapprox(pair.y, 2); cpml_primitive_put_point(&primitive, 1, &pair); adg_assert_isapprox(pair.x, 0); adg_assert_isapprox(pair.y, 1); cpml_primitive_put_point(&primitive, 2, &pair); adg_assert_isapprox(pair.x, 0); adg_assert_isapprox(pair.y, 1); }