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)); }
/** * adg_path_append_primitive: * @path: an #AdgPath * @primitive: the #CpmlPrimitive to append * * Appends @primitive to @path. The primitive to add is considered the * continuation of the current path so the <structfield>org</structfield> * component of @primitive is not used. Anyway the current point is * checked against it: they must be equal or the function will fail * without further processing. * * Since: 1.0 **/ void adg_path_append_primitive(AdgPath *path, const CpmlPrimitive *primitive) { AdgPathPrivate *data; CpmlPrimitive *primitive_dup; g_return_if_fail(ADG_IS_PATH(path)); g_return_if_fail(primitive != NULL); g_return_if_fail(primitive->org != NULL); g_return_if_fail(primitive->data != NULL); data = path->data; g_return_if_fail(primitive->org->point.x == data->cp.x && primitive->org->point.y == data->cp.y); /* The primitive data could be modified by pending operations: * work on a copy */ primitive_dup = cpml_primitive_deep_dup(primitive); _adg_append_primitive(path, primitive_dup); g_free(primitive_dup); }
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 void _adg_do_fillet(AdgPath *path, CpmlPrimitive *current) { AdgPathPrivate *data; CpmlPrimitive *last, *current_dup, *last_dup; gdouble radius, offset, pos; CpmlPair center, vector, p[3]; data = path->data; last = &data->last; current_dup = cpml_primitive_deep_dup(current); last_dup = cpml_primitive_deep_dup(last); radius = data->operation.data.fillet.radius; offset = _adg_is_convex(last_dup, current_dup) ? -radius : radius; /* Find the center of the fillet from the intersection between * the last and current primitives offseted by radius */ cpml_primitive_offset(current_dup, offset); cpml_primitive_offset(last_dup, offset); if (cpml_primitive_put_intersections(current_dup, last_dup, 1, ¢er) == 0) { g_warning(_("%s: fillet with radius of %lf is not applicable here"), G_STRLOC, radius); g_free(current_dup); g_free(last_dup); return; } /* Compute the start point of the fillet */ pos = cpml_primitive_get_closest_pos(last_dup, ¢er); cpml_primitive_put_vector_at(last_dup, pos, &vector); cpml_vector_set_length(&vector, offset); cpml_vector_normal(&vector); p[0].x = center.x - vector.x; p[0].y = center.y - vector.y; /* Compute the mid point of the fillet */ cpml_pair_from_cairo(&vector, current->org); vector.x -= center.x; vector.y -= center.y; cpml_vector_set_length(&vector, radius); p[1].x = center.x + vector.x; p[1].y = center.y + vector.y; /* Compute the end point of the fillet */ pos = cpml_primitive_get_closest_pos(current_dup, ¢er); cpml_primitive_put_vector_at(current_dup, pos, &vector); cpml_vector_set_length(&vector, offset); cpml_vector_normal(&vector); p[2].x = center.x - vector.x; p[2].y = center.y - vector.y; g_free(current_dup); g_free(last_dup); /* Change the end point of the last primitive */ cpml_primitive_set_point(last, -1, &p[0]); /* Change the start point of the current primitive */ cpml_primitive_set_point(current, 0, &p[2]); /* Add the fillet arc */ data->operation.action = ADG_ACTION_NONE; adg_path_append(path, CPML_ARC, &p[1], &p[2]); }