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 gboolean _adg_is_convex(const CpmlPrimitive *primitive1, const CpmlPrimitive *primitive2) { CpmlVector v1, v2; gdouble angle1, angle2; cpml_primitive_put_vector_at(primitive1, -1, &v1); cpml_primitive_put_vector_at(primitive2, 0, &v2); /* Probably there is a smarter way to get this without trygonometry */ angle1 = cpml_vector_angle(&v1); angle2 = cpml_vector_angle(&v2); if (angle1 > angle2) angle1 -= G_PI*2; return angle2-angle1 > G_PI; }
/** * cpml_segment_put_vector_at: * @segment: a #CpmlSegment * @pos: the position value * @vector: the destination #CpmlVector * * Gets the steepness 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 * steepness, that is only when @pos is 0 or 1.</listitem> * </itemizedlist> * </important> * * Since: 1.0 **/ void cpml_segment_put_vector_at(const CpmlSegment *segment, double pos, CpmlVector *vector) { CpmlPrimitive primitive; cpml_primitive_from_segment(&primitive, (CpmlSegment *) segment); /* Handle the common cases: start and end points */ if (pos == 0) { cpml_primitive_put_vector_at(&primitive, 0, vector); return; } if (pos == 1) { while (cpml_primitive_next(&primitive)) ; cpml_primitive_put_vector_at(&primitive, 1, vector); return; } }
static void _cpml_sanity_put_vector_at(gint i) { CpmlSegment segment; CpmlPrimitive primitive; CpmlVector vector; cpml_segment_from_cairo(&segment, (cairo_path_t *) adg_test_path()); cpml_primitive_from_segment(&primitive, &segment); switch (i) { case 1: cpml_primitive_put_vector_at(NULL, 1, &vector); break; case 2: cpml_primitive_put_vector_at(&primitive, 1, NULL); break; default: g_test_trap_assert_failed(); break; } }
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]); }