Example #1
0
File: adg-path.c Project: bert/adg
/**
 * adg_path_reflect:
 * @path:                 an #AdgPath
 * @vector: (allow-none): the slope of the axis
 *
 * Reflects the first segment or @path around the axis passing
 * throught (0, 0) and with a @vector slope. The internal segment
 * is duplicated and the proper transformation (computed from
 * @vector) to mirror the segment is applied on all its points.
 * The result is then reversed with cpml_segment_reverse() and
 * appended to the original path with adg_path_append_segment().
 *
 * For convenience, if @vector is <constant>NULL</constant> the
 * path is reversed around the x axis <constant>(y = 0)</constant>.
 *
 * Since: 1.0
 **/
void
adg_path_reflect(AdgPath *path, const CpmlVector *vector)
{
    AdgModel *model;
    cairo_matrix_t matrix;
    CpmlSegment segment, *dup_segment;

    g_return_if_fail(ADG_IS_PATH(path));
    g_return_if_fail(vector == NULL || vector->x != 0 || vector->y != 0);

    model = (AdgModel *) path;

    if (vector == NULL) {
        cairo_matrix_init_scale(&matrix, 1, -1);
    } else {
        CpmlVector slope;
        gdouble cos2angle, sin2angle;

        cpml_pair_copy(&slope, vector);
        cpml_vector_set_length(&slope, 1);

        if (slope.x == 0 && slope.y == 0) {
            g_warning(_("%s: the axis of the reflection is not known"),
                      G_STRLOC);
            return;
        }

        sin2angle = 2. * vector->x * vector->y;
        cos2angle = 2. * vector->x * vector->x - 1;

        cairo_matrix_init(&matrix, cos2angle, sin2angle,
                          sin2angle, -cos2angle, 0, 0);
    }

    if (!adg_trail_put_segment((AdgTrail *) path, 1, &segment))
        return;

    /* No need to reverse an empty segment */
    if (segment.num_data == 0 || segment.num_data == 0)
        return;

    dup_segment = cpml_segment_deep_dup(&segment);
    if (dup_segment == NULL)
        return;

    cpml_segment_reverse(dup_segment);
    cpml_segment_transform(dup_segment, &matrix);
    dup_segment->data[0].header.type = CPML_LINE;

    adg_path_append_segment(path, dup_segment);

    g_free(dup_segment);

    _adg_dup_reverse_named_pairs(model, &matrix);
}
Example #2
0
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);
}
Example #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);
}