Beispiel #1
0
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));
}
Beispiel #2
0
/**
 * 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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
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, &center) == 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, &center);
    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, &center);
    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]);
}