[PATCH] arc autogap finally working
- From: Grégoire Dooms <dooms info ucl ac be>
- To: discussions about usage and development of dia <dia-list gnome org>
- Subject: [PATCH] arc autogap finally working
- Date: Mon, 25 Jul 2005 16:18:52 +0200
Hi folks,
I took a few hours to work on debugging my arc autogap code.
I is now useable.
There is still a small bug when the non connected end of the arc is very
close to the border of the connected object. I think this is due to
rounding errors in the code for SHIFT-move handle which is reused to
trim the arc in autogap.
Also it is not yet possible to have a startgap and an endgap from/to the
same central CP.
Have a nice (holy)day,
--
Grégoire
Index: arc.c
===================================================================
RCS file: /cvs/gnome/dia/objects/standard/arc.c,v
retrieving revision 1.42
diff -u -r1.42 arc.c
--- arc.c 10 Jul 2005 15:09:33 -0000 1.42
+++ arc.c 25 Jul 2005 14:13:00 -0000
@@ -88,8 +88,10 @@
static void arc_save(Arc *arc, ObjectNode obj_node, const char *filename);
static DiaObject *arc_load(ObjectNode obj_node, int version, const char *filename);
static int arc_compute_midpoint(Arc *arc, const Point * ep0, const Point * ep1 , Point * midpoint);
-static void calculate_arc_object_edge(Arc *arc, real ang_start, real ang_end, DiaObject *obj, Point *target);
+static void calculate_arc_object_edge(Arc *arc, real ang_start, real ang_end, DiaObject *obj, Point *target,
gboolean clockwiseness);
static void arc_get_point_at_angle(Arc *arc, Point* point, real angle);
+real round_angle(real angle);
+real get_middle_arc_angle(real angle1, real angle2, gboolean clock);
static ObjectTypeOps arc_type_ops =
{
@@ -498,17 +500,42 @@
*midpoint = midpos;
return 1;
}
-/** updates point to the point on the arc at angle angle */
+/** updates point to the point on the arc at angle angle degrees */
void arc_get_point_at_angle(Arc *arc, Point* point, real angle)
{
Point vec;
vec.x = cos(angle/180.0*M_PI);
- vec.y = sin(angle/180.0*M_PI);
+ vec.y = -sin(angle/180.0*M_PI);
point_copy(point,&arc->center);
point_add_scaled(point,&vec,arc->radius);
}
+/** returns the angle in [0,360[ corresponding to this angle*/
+real round_angle(real angle){
+ real a = angle;
+ while (a<0) a+=360;
+ while (a>=360) a-=360;
+ return a;
+}
+/** returns the angle in the middle from angle1 to angle2*/
+real get_middle_arc_angle(real angle1, real angle2, gboolean clock)
+{
+ angle1 = round_angle(angle1);
+ angle2 = round_angle(angle2);
+ real delta = (angle2-angle1);
+ if (delta<0) delta+=360;
+ if (clock)
+ return round_angle(angle1-(360-delta)/2);
+ else
+ return round_angle(angle1+delta/2);
+}
+
+#define TRACE_DIST
+/* PRE: ang_start should be outside object.
+ * ang_end should be inside
+ * if both are inside or if ang_start is very close , then the point at ang_start is returned
+ */
static void
-calculate_arc_object_edge(Arc *arc, real ang_start, real ang_end, DiaObject *obj, Point *target)
+calculate_arc_object_edge(Arc *arc, real ang_start, real ang_end, DiaObject *obj, Point *target, gboolean
clockwiseness)
{
#define MAXITER 25
#ifdef TRACE_DIST
@@ -518,42 +545,43 @@
real mid1, mid2, mid3;
real dist;
int i = 0;
+ int j = 0;
mid1 = ang_start;
- mid2 = (ang_start + ang_end)/2;
+ mid2 = get_middle_arc_angle(ang_start, ang_end, clockwiseness);
mid3 = ang_end;
+ printf("Find middle angle between %f° and %f°\n",ang_start,ang_end);
/* If the other end is inside the object */
- arc_get_point_at_angle(arc,target,mid3);
+ arc_get_point_at_angle(arc,target,mid1);
dist = obj->ops->distance_from(obj, target );
if (dist < 0.001){
- arc_get_point_at_angle(arc,target,mid1);
+ printf("Point at %f°: %f,%f is very close to object: %f, returning it\n",mid1, target->x,
target->y, dist);
return ;
}
do {
arc_get_point_at_angle(arc, target, mid2);
dist = obj->ops->distance_from(obj, target);
- if (dist < 0.0000001) {
- mid1 = mid2;
- } else {
- mid3 = mid2;
- }
- mid2 = (mid1 + mid3) / 2;
-
#ifdef TRACE_DIST
trace[i] = mid2;
disttrace[i] = dist;
#endif
i++;
+
+ if (dist < 0.0000001) {
+ mid3 = mid2;
+ } else {
+ mid1 = mid2;
+ }
+ mid2 = get_middle_arc_angle(mid1,mid3,clockwiseness);
+
} while (i < MAXITER && (dist < 0.0000001 || dist > 0.001));
#ifdef TRACE_DIST
- if (i == MAXITER) {
- for (i = 0; i < MAXITER; i++) {
- printf("%d: %f, %f: %f\n", i, trace[i].x, trace[i].y, disttrace[i]);
+ for (j = 0; j < i; j++) {
+ arc_get_point_at_angle(arc,target,trace[j]);
+ printf("%d: %f ° : %f,%f :%f\n", j, trace[j],target->x,target->y, disttrace[j]);
}
- printf("i = %d, dist = %f\n", i, dist);
- }
#endif
arc_get_point_at_angle(arc,target,mid2);
return ;
@@ -576,10 +604,24 @@
start_cp = arc->connection.endpoint_handles[0].connected_to;
end_cp = arc->connection.endpoint_handles[1].connected_to;
- if (connpoint_is_autogap(start_cp))
- calculate_arc_object_edge(arc, arc->angle1, arc->angle2, start_cp->object, &gaptmp[0]);
- if (connpoint_is_autogap(end_cp))
- calculate_arc_object_edge(arc, arc->angle2, arc->angle1, end_cp->object, &gaptmp[1]);
+ arc_update_data(arc);
+ printf("drawing arc:\n start:%f °:%f,%f \tend:%f °:%f,%f\n",arc->angle1,endpoints[0].x,endpoints[0].y,
arc->angle2,endpoints[1].x,endpoints[1].y);
+
+
+ if (connpoint_is_autogap(start_cp)) {
+ printf("computing start intersection\ncurve_distance: %f\n",arc->curve_distance);
+ if (arc->curve_distance < 0)
+ calculate_arc_object_edge(arc, arc->angle1, arc->angle2, start_cp->object, &gaptmp[0], FALSE);
+ else
+ calculate_arc_object_edge(arc, arc->angle2, arc->angle1, start_cp->object, &gaptmp[0], TRUE);
+ }
+ if (connpoint_is_autogap(end_cp)) {
+ printf("computing end intersection\ncurve_distance: %f\n",arc->curve_distance);
+ if (arc->curve_distance < 0)
+ calculate_arc_object_edge(arc, arc->angle2, arc->angle1, end_cp->object, &gaptmp[1], TRUE);
+ else
+ calculate_arc_object_edge(arc, arc->angle1, arc->angle2, end_cp->object, &gaptmp[1], FALSE);
+ }
/* compute new middle_point */
arc_compute_midpoint(arc, &gaptmp[0], &gaptmp[1], &gaptmp[2]);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]