Handle * beziershape_closest_handle(BezierShape *bezier, Point *point) { int i, hn; real dist = G_MAXDOUBLE; Handle *closest = NULL; for (i = 1, hn = 0; i < bezier->numpoints; i++, hn++) { real new_dist; new_dist = distance_point_point( point, &bezier->points[i].p1); if (new_dist < dist) { dist = new_dist; closest = bezier->object.handles[hn]; } hn++; new_dist = distance_point_point( point, &bezier->points[i].p2); if (new_dist < dist) { dist = new_dist; closest = bezier->object.handles[hn]; } hn++; new_dist = distance_point_point( point, &bezier->points[i].p3); if (new_dist < dist) { dist = new_dist; closest = bezier->object.handles[hn]; } } return closest; }
static real arc_distance_from(Arc *arc, Point *point) { Point *endpoints; Point from_center; real angle; real d, d2; endpoints = &arc->connection.endpoints[0]; from_center = *point; point_sub(&from_center, &arc->center); angle = -atan2(from_center.y, from_center.x)*180.0/M_PI; if (angle<0) angle+=360.0; if (in_angle(angle, arc->angle1, arc->angle2)) { d = fabs(sqrt(point_dot(&from_center, &from_center)) - arc->radius); d -= arc->line_width/2.0; if (d<0) d = 0.0; return d; } else { d = distance_point_point(&endpoints[0], point); d2 = distance_point_point(&endpoints[1], point); return MIN(d,d2); } }
/*! * \brief Calculate BezCornerType just from the _BezPoint * * The bezier line/shape is fully described just with the array of BezPoint. * For convenience and editing there also is an BezierConn::corner_types. * This function adjust the corner types in the given array to match * the bezier points. */ static void bezier_calc_corner_types (BezierCommon *bezier) { int i; int num = bezier->num_points; const real tolerance = 0.00001; /* EPSILON */ g_return_if_fail (bezier->num_points > 1); bezier->corner_types = g_realloc (bezier->corner_types, bezier->num_points * sizeof(BezCornerType)); bezier->corner_types[0] = BEZ_CORNER_CUSP; bezier->corner_types[num-1] = BEZ_CORNER_CUSP; for (i = 0; i < num - 2; ++i) { const Point *start = &bezier->points[i].p2; const Point *major = &bezier->points[i].p3; const Point *end = &bezier->points[i+1].p2; if (bezier->points[i].type != BEZ_LINE_TO || bezier->points[i+1].type != BEZ_CURVE_TO) bezier->corner_types[i+1] = BEZ_CORNER_CUSP; else if (distance_point_point (start, end) < tolerance) /* last resort */ bezier->corner_types[i+1] = BEZ_CORNER_CUSP; else if (distance_line_point (start, end, 0, major) > tolerance) bezier->corner_types[i+1] = BEZ_CORNER_CUSP; else if (fabs ( distance_point_point (start, major) - distance_point_point (end, major) > tolerance)) bezier->corner_types[i+1] = BEZ_CORNER_SMOOTH; else bezier->corner_types[i+1] = BEZ_CORNER_SYMMETRIC; } }
/*! * \brief Move one of the objects handles * \memberof Outline */ static ObjectChange* outline_move_handle (Outline *outline, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { DiaObject *obj = &outline->object; Point start = obj->position; Point end = outline->ink_rect[2]; real dist, old_dist = distance_point_point (&start, &end); Point norm = end; point_sub (&norm, &start); point_normalize (&norm); /* we use this to modify angle and scale */ switch (handle->id) { case HANDLE_RESIZE_NW : start = *to; break; case HANDLE_RESIZE_SE : end = *to; break; default : g_warning ("Outline unknown handle"); } dist = distance_point_point (&start, &end); /* disallow everything below a certain level, otherwise the font-size could become invalid */ if (dist > 0.1) { obj->position = start; outline->font_height *= (dist / old_dist); outline_update_data (outline); } return NULL; }
static int cpl_get_pointbefore(ConnPointLine *cpl, Point *clickedpoint) { int i, pos = -1; GSList *elem; ConnectionPoint *cp; real dist = 65536.0; real tmpdist; if (!clickedpoint) return 0; for (i=0,elem=cpl->connections; i<cpl->num_connections; i++,elem=g_slist_next(elem)) { cp = (ConnectionPoint *)(elem->data); tmpdist = distance_point_point(&cp->pos,clickedpoint); if (tmpdist < dist) { dist = tmpdist; pos = i; } } tmpdist = distance_point_point(&cpl->end,clickedpoint); if (tmpdist < dist) { /*dist = tmpdist; */ pos = -1; } return pos; }
/*! * \brief Find the next sub path to connect * * Ignores the crossing point of the Split, but just looks at the * start and end of the given sub path. */ static gboolean _find_split (GArray *splits, Point *pt, gboolean outside, Split **next) { int i; for (i = 0; i < splits->len; ++i) { Split *sp = &g_array_index (splits, Split, i); /* one of two splits - prefer the one matching in start point */ BezierSegment *bs = &g_array_index (sp->path, BezierSegment, 0); if ( !sp->used && (sp->outside == outside) && distance_point_point (&bs->p0, pt) < 1.4142 * EPSILON) { *next = sp; sp->used = TRUE; return TRUE; } } /* but also deliver segments ending in pt */ for (i = 0; i < splits->len; ++i) { Split *sp = &g_array_index (splits, Split, i); BezierSegment *bs = &g_array_index (sp->path, BezierSegment, sp->path->len - 1); if ( !sp->used && (sp->outside == outside) && distance_point_point (&bs->p3, pt) < 1.4142 * EPSILON) { *next = sp; sp->used = TRUE; return TRUE; } } return FALSE; }
/*! * \brief Return the handle closest to a given point. * @param bezier A bezier object * @param point A point to find distances from * @return The handle on `bezier' closest to `point'. * * \memberof _BezierConn */ Handle * bezierconn_closest_handle (BezierConn *bezier, Point *point) { int i, hn; real dist; Handle *closest; closest = bezier->object.handles[0]; dist = distance_point_point( point, &closest->pos); for (i = 1, hn = 1; i < bezier->bezier.num_points; i++, hn++) { real new_dist; new_dist = distance_point_point(point, &bezier->bezier.points[i].p1); if (new_dist < dist) { dist = new_dist; closest = bezier->object.handles[hn]; } hn++; new_dist = distance_point_point(point, &bezier->bezier.points[i].p2); if (new_dist < dist) { dist = new_dist; closest = bezier->object.handles[hn]; } hn++; new_dist = distance_point_point(point, &bezier->bezier.points[i].p3); if (new_dist < dist) { dist = new_dist; closest = bezier->object.handles[hn]; } } return closest; }
static GArray * _path_to_segments (const GArray *path) { GArray *segs = g_array_new (FALSE, FALSE, sizeof(BezierSegment)); BezierSegment bs; int i; BezPoint *last_move = &g_array_index (path, BezPoint, 0); for (i = 1; i < path->len; ++i) { if (g_array_index (path, BezPoint, i).type == BEZ_MOVE_TO) last_move = &g_array_index (path, BezPoint, i); if (_segment_from_path (&bs, path, i)) g_array_append_val (segs, bs); } /* if the path is not closed do an explicit line-to */ if (distance_point_point (&last_move->p1, &bs.p3) < EPSILON) { /* if the error is small enough just modify the last point */ BezierSegment *e = &g_array_index (segs, BezierSegment, segs->len - 1); if (_segment_is_lineto (e)) e->p1 = e->p2 = e->p3 = last_move->p1; else e->p3 = last_move->p1; } else { bs.p0 = bs.p3; bs.p1 = bs.p2 = bs.p3 = last_move->p1; g_array_append_val (segs, bs); } return segs; }
int three_point_circle (const Point *p1, const Point *p2, const Point *p3, Point* center, real* radius) { const real epsilon = 1e-4; real x1 = p1->x; real y1 = p1->y; real x2 = p2->x; real y2 = p2->y; real x3 = p3->x; real y3 = p3->y; real ma, mb; if (fabs(x2 - x1) < epsilon) return 0; if (fabs(x3 - x2) < epsilon) return 0; ma = (y2 - y1) / (x2 - x1); mb = (y3 - y2) / (x3 - x2); if (fabs (mb - ma) < epsilon) return 0; center->x = (ma*mb*(y1-y3)+mb*(x1+x2)-ma*(x2+x3))/(2*(mb-ma)); if (fabs(ma)>epsilon) center->y = -1/ma*(center->x - (x1+x2)/2.0) + (y1+y2)/2.0; else if (fabs(mb)>epsilon) center->y = -1/mb*(center->x - (x2+x3)/2.0) + (y2+y3)/2.0; else return 0; *radius = distance_point_point(center, p1); return 1; }
static void draw_dot(DiaRenderer *renderer, Point *end, Point *vect, Color *col) { DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer); Point vv,vp,vt,pt; real vlen; vv = *end; point_sub(&vv,vect); vlen = distance_point_point(vect,end); if (vlen < 1E-7) return; point_scale(&vv,1/vlen); vp.y = vv.x; vp.x = -vv.y; pt = *end; vt = vp; point_scale(&vt,ARROW_DOT_WOFFSET); point_add(&pt,&vt); vt = vv; point_scale(&vt,-ARROW_DOT_LOFFSET); point_add(&pt,&vt); renderer_ops->set_fillstyle(renderer,FILLSTYLE_SOLID); renderer_ops->fill_ellipse(renderer,&pt, ARROW_DOT_RADIUS,ARROW_DOT_RADIUS, col); }
uint16_t path_astar_heuristic_callback (uint8_t node) { /* TODO: a better and faster heuristic can be found, considering that * movement is only allowed on the grid. */ vect_t pos; path_pos (node, &pos); return distance_point_point (&pos, &path.endpoints[0]); }
Handle * polyconn_closest_handle(PolyConn *poly, Point *point) { int i; real dist; Handle *closest; closest = poly->object.handles[0]; dist = distance_point_point( point, &closest->pos); for (i=1;i<poly->numpoints;i++) { real new_dist; new_dist = distance_point_point( point, &poly->points[i]); if (new_dist < dist) { dist = new_dist; closest = poly->object.handles[i]; } } return closest; }
static Point _append_segments (GArray *path, GArray *segs) { BezPoint bp; int i; gboolean flip; BezPoint *ebp = &g_array_index (path, BezPoint, path->len - 1); const BezierSegment *sseg = &g_array_index (segs, BezierSegment, 0); const BezierSegment *eseg = &g_array_index (segs, BezierSegment, segs->len - 1); /* always try to join with what we have */ if (distance_point_point (&sseg->p0, ebp->type == BEZ_CURVE_TO ? &ebp->p3 : &ebp->p1) < EPSILON) { /* matching in given direction */ flip = FALSE; } else if (distance_point_point (&eseg->p3, ebp->type == BEZ_CURVE_TO ? &ebp->p3 : &ebp->p1) < EPSILON) { /* change direction of segments */ flip = TRUE; } else { /* neither matches so we can use any direction but should add a move-to */ bp.type = BEZ_MOVE_TO; bp.p1 = sseg->p0; g_array_append_val (path, bp); } if (flip) { for (i = segs->len - 1; i >= 0; --i) { /* counting down - backwards append */ _curve_from_segment (&bp, &g_array_index (segs, BezierSegment, i), flip); if (bp.type != BEZ_MOVE_TO) /* just ignore move-to here */ g_array_append_val (path, bp); } } else { for (i = 0; i < segs->len; ++i) { /* preserve original direction */ _curve_from_segment (&bp, &g_array_index (segs, BezierSegment, i), flip); if (bp.type != BEZ_MOVE_TO) g_array_append_val (path, bp); } } ebp = &g_array_index (path, BezPoint, path->len - 1); return ebp->type == BEZ_CURVE_TO ? ebp->p3 : ebp->p1; }
static gboolean point_projection_is_between (const Point *c, const Point *a, const Point *b) { real len = distance_point_point (a, b); if (len > 0) { real r = ((a->y - c->y) * (a->y - b->y) - (a->x - c->x) * (b->x - a->x)) / (len * len); return (r >= 0 && r <= 1.0); } /* identity of three points ? */ return (c->x == a->x && c->y == a->y); }
static void annotation_draw(Annotation *annotation, DiaRenderer *renderer) { Point *endpoints; Point vect,rvect,v1,v2; Point pts[4]; real vlen; DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer); assert(annotation != NULL); assert(renderer != NULL); endpoints = &annotation->connection.endpoints[0]; renderer_ops->set_linewidth(renderer, ANNOTATION_LINE_WIDTH); renderer_ops->set_linestyle(renderer, LINESTYLE_SOLID); renderer_ops->set_linecaps(renderer, LINECAPS_BUTT); vect = annotation->connection.endpoints[1]; point_sub(&vect,&annotation->connection.endpoints[0]); vlen = distance_point_point(&annotation->connection.endpoints[0], &annotation->connection.endpoints[1]); if (vlen > 0.0) { /* draw the squiggle */ point_scale(&vect,1/vlen); rvect.y = vect.x; rvect.x = -vect.y; pts[0] = annotation->connection.endpoints[0]; pts[1] = annotation->connection.endpoints[0]; v1 = vect; point_scale(&v1,.5*vlen); point_add(&pts[1],&v1); pts[2] = pts[1]; /* pts[1] and pts[2] are currently both at the middle of (pts[0],pts[3]) */ v1 = vect; point_scale(&v1,ANNOTATION_ZLEN); v2 = rvect; point_scale(&v2,ANNOTATION_ZLEN); point_sub(&v1,&v2); point_add(&pts[1],&v1); point_sub(&pts[2],&v1); pts[3] = annotation->connection.endpoints[1]; renderer_ops->draw_polyline(renderer, pts, sizeof(pts) / sizeof(pts[0]), &color_black); } text_draw(annotation->text,renderer); }
static ObjectChange* radiocell_move_handle(RadioCell *radiocell, Handle *handle, Point *to, ConnectionPoint *cp, HandleMoveReason reason, ModifierKeys modifiers) { real distance; gboolean larger; /* prevent flicker for "negative" resizing */ if ((handle->id == HANDLE_CUSTOM1 && to->x < radiocell->center.x) || (handle->id == HANDLE_CUSTOM4 && to->x > radiocell->center.x) || ((handle->id == HANDLE_CUSTOM2 || handle->id == HANDLE_CUSTOM3) && to->y < radiocell->center.y) || ((handle->id == HANDLE_CUSTOM5 || handle->id == HANDLE_CUSTOM6) && to->y > radiocell->center.y)) { return NULL; } /* prevent flicker for "diagonal" resizing */ if (handle->id == HANDLE_CUSTOM1 || handle->id == HANDLE_CUSTOM4) { to->y = handle->pos.y; } else { to->x = handle->pos.x; } distance = distance_point_point(&handle->pos, to); larger = distance_point_point(&handle->pos, &radiocell->center) < distance_point_point(to, &radiocell->center); radiocell->radius += distance * (larger? 1: -1); if (radiocell->radius < 1.) radiocell->radius = 1.; radiocell_update_data(radiocell); return NULL; }
static real implements_distance_from(Implements *implements, Point *point) { Point *endpoints; real dist1, dist2; endpoints = &implements->connection.endpoints[0]; dist1 = distance_line_point( &endpoints[0], &endpoints[1], IMPLEMENTS_WIDTH, point); dist2 = distance_point_point( &implements->circle_center, point) - implements->circle_diameter/2.0; if (dist2<0) dist2 = 0; return MIN(dist1, dist2); }
/*! Not in the object interface but very important anyway. Used to recalculate the object data after a change */ static void measure_update_data (Measure *measure) { Connection *conn = &measure->connection; DiaObject *obj = &measure->connection.object; real value; Point *ends = measure->connection.endpoints; LineBBExtras *extra = &conn->extra_spacing; Rectangle bbox; Arrow arrow = MEASURE_ARROW(measure); real ascent, width; g_return_if_fail (obj->handles != NULL); connection_update_handles(conn); extra->start_trans = extra->end_trans = extra->start_long = extra->end_long = (measure->line_width / 2.0); g_free (measure->name); value = distance_point_point (&ends[0], &ends[1]); value *= measure->scale; value *= (28.346457 / units[measure->unit].factor); measure->name = g_strdup_printf ("%.*g %s", measure->precision, value, units[measure->unit].unit); ascent = dia_font_ascent (measure->name, measure->font, measure->font_height); width = dia_font_string_width (measure->name, measure->font, measure->font_height); measure->text_pos.x = (ends[0].x + ends[1].x) / 2; measure->text_pos.y = (ends[0].y + ends[1].y) / 2; /* for horizontal we could try to center over the line */ line_bbox (&ends[0], &ends[0], &conn->extra_spacing,&conn->object.bounding_box); arrow_bbox (&arrow, measure->line_width, &ends[0], &ends[1], &bbox); rectangle_union(&obj->bounding_box, &bbox); arrow_bbox (&arrow, measure->line_width, &ends[1], &ends[0], &bbox); rectangle_union(&obj->bounding_box, &bbox); bbox.left = measure->text_pos.x; bbox.top = measure->text_pos.y - ascent; bbox.bottom = bbox.top + measure->font_height; bbox.right = bbox.left + width; rectangle_union(&obj->bounding_box, &bbox); obj->position = conn->endpoints[0]; }
static void draw_tunnel(DiaRenderer *renderer, Point *end, Point *vect, Color *col) { DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer); Point vv,vp,vt1,vt2; BezPoint curve1[2]; BezPoint curve2[2]; real vlen; vv = *end; point_sub(&vv,vect); vlen = distance_point_point(vect,end); if (vlen < 1E-7) return; point_scale(&vv,1/vlen); vp.y = vv.x; vp.x = -vv.y; curve1[0].type = curve2[0].type = BEZ_MOVE_TO; curve1[0].p1 = curve2[0].p1 = *end; vt1 = vv; point_scale(&vt1,-ARROW_PARENS_LOFFSET - (.5*ARROW_PARENS_LENGTH)); point_add(&curve1[0].p1,&vt1); point_add(&curve2[0].p1,&vt1); /* gcc, work for me, please. */ vt2 = vp; point_scale(&vt2,ARROW_PARENS_WOFFSET); point_add(&curve1[0].p1,&vt2); point_sub(&curve2[0].p1,&vt2); vt2 = vp; vt1 = vv; point_scale(&vt1,2.0*ARROW_PARENS_LENGTH / 6.0); point_scale(&vt2,ARROW_PARENS_LENGTH / 6.0); curve1[1].type = curve2[1].type = BEZ_CURVE_TO; curve1[1].p1 = curve1[0].p1; curve2[1].p1 = curve2[0].p1; point_add(&curve1[1].p1,&vt1); point_add(&curve2[1].p1,&vt1); point_add(&curve1[1].p1,&vt2); point_sub(&curve2[1].p1,&vt2); curve1[1].p2 = curve1[1].p1; curve2[1].p2 = curve2[1].p1; point_add(&curve1[1].p2,&vt1); point_add(&curve2[1].p2,&vt1); curve1[1].p3 = curve1[1].p2; curve2[1].p3 = curve2[1].p2; point_add(&curve1[1].p3,&vt1); point_add(&curve2[1].p3,&vt1); point_sub(&curve1[1].p3,&vt2); point_add(&curve2[1].p3,&vt2); renderer_ops->draw_bezier(renderer,curve1,2,col); renderer_ops->draw_bezier(renderer,curve2,2,col); }
/*! * \brief Gap calculation for _Line * * Calculate the absolute gap -- this gap is 'transient', in that * the actual end of the line is not moved, but it is made to look like * it is shorter. * * \protected \memberof Line */ static void line_adjust_for_absolute_gap(Line *line, Point *gap_endpoints) { Point endpoints[2]; real line_length; endpoints[0] = line->connection.endpoints[0]; endpoints[1] = line->connection.endpoints[1]; line_length = distance_point_point(&endpoints[0], &endpoints[1]); /* puts new 0 to x% of 0->1 */ point_convex(&gap_endpoints[0], &endpoints[0], &endpoints[1], 1 - line->absolute_start_gap/line_length); /* puts new 1 to x% of 1->0 */ point_convex(&gap_endpoints[1], &endpoints[1], &endpoints[0], 1 - line->absolute_end_gap/line_length); }
static const Handle * _path_closest_corner_handle (StdPath *sp, const Point *pt) { int i, j; real dist = G_MAXDOUBLE; Handle *closest = NULL; int corners[] = {0, 2, 5, 7}; for (j = 0; j < 4; ++j) { real new_dist; i = corners[j]; new_dist = distance_point_point (&sp->handles[i].pos, pt); if (new_dist < dist) { closest = &sp->handles[i]; dist = new_dist; } } return closest; }
static gboolean _segment_from_path (BezierSegment *a, const GArray *p1, int i) { const BezPoint *abp0 = &g_array_index (p1, BezPoint, i-1); const BezPoint *abp1 = &g_array_index (p1, BezPoint, i); a->p0 = abp0->type == BEZ_CURVE_TO ? abp0->p3 : abp0->p1; switch (abp1->type) { case BEZ_CURVE_TO : a->p1 = abp1->p1; a->p2 = abp1->p2; a->p3 = abp1->p3; break; case BEZ_LINE_TO : if (distance_point_point (&a->p0, &abp1->p1) < EPSILON) return FALSE; /* avoid a zero length line-to for confusion with move-to */ a->p1 = a->p2 = a->p3 = abp1->p1; break; case BEZ_MOVE_TO : a->p0 = a->p1 = a->p2 = a->p3 = abp1->p1; break; } return TRUE; }
int aadlbox_point_near_port(Aadlbox *aadlbox, Point *p) { int i, min; real dist = 1000.0; real d; min = -1; for (i=0;i<aadlbox->num_ports;i++) { d = distance_point_point(&aadlbox->ports[i]->handle->pos, p); if (d < dist) { dist = d; min = i; } } if (dist < 0.5) return min; else return -1; }
static int aadlbox_point_near_connection(Aadlbox *aadlbox, Point *p) { int i, min; real dist = 1000.0; real d; min = -1; for (i=0;i<aadlbox->num_connections;i++) { d = distance_point_point(&aadlbox->connections[i]->pos, p); if (d < dist) { dist = d; min = i; } } if (dist < 0.5) return min; else return -1; }
/** Return 1 if the direct path between a and b nodes is blocked, also compute * distance. */ static uint8_t path_blocking (uint8_t a, uint8_t b, int16_t *dp) { uint8_t i; vect_t va; vect_t vb; uint8_t escape_factor = 0; uint8_t factor = 1; uint8_t blocking = 0; if (a == PATH_SRC_NODE_INDEX || b == PATH_SRC_NODE_INDEX) escape_factor = path.escape_factor; path_pos (a, &va); path_pos (b, &vb); /* Test for green zone. */ uint8_t a_green, b_green; a_green = va.x < PG_GREEN_WIDTH_MM || va.x > PG_WIDTH - PG_GREEN_WIDTH_MM; b_green = vb.x < PG_GREEN_WIDTH_MM || vb.x > PG_WIDTH - PG_GREEN_WIDTH_MM; if ((va.x < BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM && vb.x > BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM) || (va.x > BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM && vb.x < BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM) || (va.x > PG_WIDTH - BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM && vb.x < PG_WIDTH - BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM) || (va.x < PG_WIDTH - BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM && vb.x > PG_WIDTH - BOT_GREEN_ELEMENT_PLACE_DISTANCE_MM)) return 1; if (a_green && b_green) return 1; if (a_green || b_green) factor = 4; /* Test for protected zone. */ if (va.y <= 350 && va.x > PG_WIDTH / 2 - 350 && va.y < PG_WIDTH / 2 + 350 && (vb.x < PG_WIDTH / 2 - 350 || vb.x > PG_WIDTH / 2 + 350)) return 1; if (vb.y <= 350 && vb.x > PG_WIDTH / 2 - 350 && vb.y < PG_WIDTH / 2 + 350 && (va.x < PG_WIDTH / 2 - 350 || va.x > PG_WIDTH / 2 + 350)) return 1; /* Test for a blocking obstacle. */ for (i = 0; i < PATH_OBSTACLES_NB && !blocking; i++) { if (path.obstacles[i].valid) { uint16_t d = distance_segment_point (&va, &vb, &path.obstacles[i].c); if (d < path.obstacles[i].r) blocking = 1; } } /* Compute distance. */ int16_t d = distance_point_point (&va, &vb); if (d == 0) { *dp = 0; return 0; } /* Test for a blocking element. */ if (element_blocking_path (va, vb, d, path.escape_factor)) blocking = 1; /* Handle escaping. */ if (blocking) { if (escape_factor) { *dp = d * escape_factor; return 0; } else return 1; } /* No blocking. */ *dp = d * factor; return 0; }
static DiaObject * arc_load(ObjectNode obj_node, int version,DiaContext *ctx) { Arc *arc; Connection *conn; DiaObject *obj; AttributeNode attr; arc = g_malloc0(sizeof(Arc)); conn = &arc->connection; obj = &conn->object; obj->type = &arc_type; obj->ops = &arc_ops; connection_load(conn, obj_node, ctx); arc->arc_color = color_black; attr = object_find_attribute(obj_node, "arc_color"); if (attr != NULL) data_color(attribute_first_data(attr), &arc->arc_color, ctx); arc->curve_distance = 0.1; attr = object_find_attribute(obj_node, "curve_distance"); if (attr != NULL) arc->curve_distance = data_real(attribute_first_data(attr), ctx); arc->line_width = 0.1; attr = object_find_attribute(obj_node, PROP_STDNAME_LINE_WIDTH); if (attr != NULL) arc->line_width = data_real(attribute_first_data(attr), ctx); arc->line_style = LINESTYLE_SOLID; attr = object_find_attribute(obj_node, "line_style"); if (attr != NULL) arc->line_style = data_enum(attribute_first_data(attr), ctx); arc->dashlength = DEFAULT_LINESTYLE_DASHLEN; attr = object_find_attribute(obj_node, "dashlength"); if (attr != NULL) arc->dashlength = data_real(attribute_first_data(attr), ctx); arc->line_caps = LINECAPS_BUTT; attr = object_find_attribute(obj_node, "line_caps"); if (attr != NULL) arc->line_caps = data_enum(attribute_first_data(attr), ctx); load_arrow(obj_node, &arc->start_arrow, "start_arrow", "start_arrow_length", "start_arrow_width", ctx); load_arrow(obj_node, &arc->end_arrow, "end_arrow", "end_arrow_length", "end_arrow_width", ctx); connection_init(conn, 4, 0); _arc_setup_handles (arc); /* older versions did not prohibit everything reduced to a single point * and afterwards failed on all the calculations producing nan. */ if (distance_point_point (&arc->connection.endpoints[0], &arc->connection.endpoints[1]) < 0.02) { arc->curve_distance = 0.0; arc->connection.endpoints[0].x -= 0.01; arc->connection.endpoints[1].x += 0.01; arc_update_handles (arc); } arc_update_data(arc); return &arc->connection.object; }
/*! * \brief Calculate crossing points of two bezier segments * * Beware two bezier segments can intersect more than once, but this * function only returns the first or no intersection. It is the * responsibility of the caller to further split segments until there * is no intersection left. */ static gboolean bezier_bezier_intersection (GArray *crossing, const BezierSegment *a, const BezierSegment *b, int depth, real asplit, real bsplit) { Rectangle abox, bbox; PolyBBExtras extra = { 0, }; gboolean small_a, small_b; /* Avoid intersection overflow: if start and end are on the other segment * assume full overlap and no crossing. */ if ( (_segment_has_point (a, &b->p0) && _segment_has_point (a, &b->p3)) || (_segment_has_point (b, &a->p0) && _segment_has_point (b, &a->p3))) return FALSE; /* XXX: more variants pending, partial overlap */ /* With very similar segments we would create a lot of points with not * a very deep recursion (test with ying-yang symbol). * Just comparing the segments on depth=1 is not good enough, so for * now we are limiting the number of intersections */ if (crossing->len > 127) { /* XXX: arbitrary limit */ g_warning ("Crossing limit (%d) reached", crossing->len); return FALSE; } bicubicbezier2D_bbox (&a->p0, &a->p1, &a->p2, &a->p3, &extra, &abox); bicubicbezier2D_bbox (&b->p0, &b->p1, &b->p2, &b->p3, &extra, &bbox); if (!rectangle_intersects (&abox, &bbox)) return FALSE; small_a = (abox.right - abox.left) < EPSILON && (abox.bottom - abox.top) < EPSILON; small_b = (bbox.right - bbox.left) < EPSILON && (bbox.bottom - bbox.top) < EPSILON; /* if the boxes are small enough we can calculate the point */ if (small_a && small_b) { /* intersecting and both small, should not matter which one is used */ Point pt = { (abox.right + abox.left + bbox.right + bbox.left) / 4, (abox.bottom + abox.top + bbox.bottom + bbox.top) / 4 }; Intersection is; int i; for (i = 0; i < crossing->len; ++i) { /* if it's already included we are done */ if (distance_point_point (&g_array_index (crossing, Intersection, i).pt, &pt) < 1.4142*EPSILON) return TRUE; /* although we did not add it */ } is.split_one = asplit; is.split_two = bsplit; is.pt = pt; g_print ("d=%d; as=%g; bs=%g; ", depth, asplit, bsplit); g_array_append_val (crossing, is); return TRUE; } else { /* further splitting of a and b; it could be smart to only search in the * intersection of a-box and b-box ... */ BezierSegment a1, a2; BezierSegment b1, b2; real ofs = 1.0/(1<<(depth+1)); gboolean ret = FALSE; bezier_split (a, &a1, &a2); bezier_split (b, &b1, &b2); ret |= bezier_bezier_intersection (crossing, &a1, &b1, depth+1, asplit-ofs, bsplit-ofs); ret |= bezier_bezier_intersection (crossing, &a2, &b1, depth+1, asplit+ofs, bsplit-ofs); ret |= bezier_bezier_intersection (crossing, &a1, &b2, depth+1, asplit-ofs, bsplit+ofs); ret |= bezier_bezier_intersection (crossing, &a2, &b2, depth+1, asplit+ofs, bsplit+ofs); /* XXX: check !ret case, not sure if it should happen */ return ret; } }
static void ellipse_update_data(Ellipse *ellipse, AnchorShape horiz, AnchorShape vert) { Element *elem = &ellipse->element; ElementBBExtras *extra = &elem->extra_spacing; DiaObject *obj = &elem->object; Point center, bottom_right; Point p, c; real dw, dh; real width, height; real radius1, radius2; int i; /* save starting points */ center = bottom_right = elem->corner; center.x += elem->width/2; bottom_right.x += elem->width; center.y += elem->height/2; bottom_right.y += elem->height; text_calc_boundingbox(ellipse->text, NULL); width = ellipse->text->max_width + 2 * ellipse->padding; height = ellipse->text->height * ellipse->text->numlines + 2 * ellipse->padding; /* stop ellipse from getting infinite width/height */ if (elem->width / elem->height > 4) elem->width = elem->height * 4; else if (elem->height / elem->width > 4) elem->height = elem->width * 4; c.x = elem->corner.x + elem->width / 2; c.y = elem->corner.y + elem->height / 2; p.x = c.x - width / 2; p.y = c.y - height / 2; radius1 = ellipse_radius(ellipse, p.x, p.y) - ellipse->border_width/2; radius2 = distance_point_point(&c, &p); if ( radius1 < radius2 && ( ellipse->text_fitting == TEXTFIT_ALWAYS || ellipse->text_fitting == TEXTFIT_WHEN_NEEDED)) { /* increase size of the ellipse while keeping its aspect ratio */ elem->width *= radius2 / radius1; elem->height *= radius2 / radius1; } /* move shape if necessary ... */ switch (horiz) { case ANCHOR_MIDDLE: elem->corner.x = center.x - elem->width/2; break; case ANCHOR_END: elem->corner.x = bottom_right.x - elem->width; break; default: break; } switch (vert) { case ANCHOR_MIDDLE: elem->corner.y = center.y - elem->height/2; break; case ANCHOR_END: elem->corner.y = bottom_right.y - elem->height; break; default: break; } p = elem->corner; p.x += elem->width / 2.0; p.y += elem->height / 2.0 - ellipse->text->height*ellipse->text->numlines/2 + ellipse->text->ascent; switch (ellipse->text->alignment) { case ALIGN_LEFT: p.x -= (elem->width - 2*(ellipse->padding + ellipse->border_width))/2; break; case ALIGN_RIGHT: p.x += (elem->width - 2*(ellipse->padding + ellipse->border_width))/2; break; case ALIGN_CENTER: break; } text_set_position(ellipse->text, &p); /* Update connections: */ c.x = elem->corner.x + elem->width / 2; c.y = elem->corner.y + elem->height / 2; dw = elem->width / 2.0; dh = elem->height / 2.0; for (i = 0; i < NUM_CONNECTIONS-1; i++) { real theta = M_PI / 8.0 * i; real costheta = cos(theta); real sintheta = sin(theta); connpoint_update(&ellipse->connections[i], c.x + dw * costheta, c.y - dh * sintheta, (costheta > .5?DIR_EAST:(costheta < -.5?DIR_WEST:0))| (sintheta > .5?DIR_NORTH:(sintheta < -.5?DIR_SOUTH:0))); } connpoint_update(&ellipse->connections[16], c.x, c.y, DIR_ALL); extra->border_trans = ellipse->border_width / 2.0; element_update_boundingbox(elem); obj->position = elem->corner; element_update_handles(elem); }
/** Return 1 if the direct path between a and b nodes is blocked, also compute * distance. */ static uint8_t path_blocking (uint8_t a, uint8_t b, int16_t *dp) { uint8_t i; vect_t va; vect_t vb; uint8_t escape_factor = 0; if (a == PATH_SRC_NODE_INDEX || b == PATH_SRC_NODE_INDEX) escape_factor = path.escape_factor; path_pos (a, &va); path_pos (b, &vb); /* Test for a blocking obstacle. */ for (i = 0; i < PATH_OBSTACLES_NB; i++) { if (path.obstacles[i].valid) { uint16_t d = distance_segment_point (&va, &vb, &path.obstacles[i].c); if (d < path.obstacles[i].r) { if (escape_factor) { int16_t d = distance_point_point (&va, &vb); *dp = d * escape_factor; return 0; } else return 1; } } } /* Test for a blocking food. */ int16_t d = distance_point_point (&va, &vb); if (d == 0) { *dp = 0; return 0; } else if (food_blocking_path (va, vb, d)) { if (escape_factor) { *dp = d * escape_factor; return 0; } else return 1; } /* Test for the wall. */ if (va.x < BOT_SIZE_RADIUS || va.x >= PG_WIDTH - BOT_SIZE_RADIUS || vb.x < BOT_SIZE_RADIUS || vb.x >= PG_WIDTH - BOT_SIZE_RADIUS) { int16_t dx = va.x - vb.x; int16_t dy = va.y - vb.y; /* Do not authorise path going parallel to the wall. */ if (UTILS_ABS (dx) < UTILS_ABS (dy)) { if (escape_factor) { *dp = d * escape_factor; return 0; } else return 1; } } /* No blocking. */ *dp = d; return 0; }
static DiaObject * fig_read_arc(FILE *file, DiaContext *ctx) { int sub_type; int line_style; int thickness; int pen_color; int fill_color; int depth; int pen_style; int area_fill; real style_val; int cap_style; int direction; int forward_arrow, backward_arrow; Arrow *forward_arrow_info = NULL, *backward_arrow_info = NULL; DiaObject *newobj = NULL; real center_x, center_y; int x1, y1; int x2, y2; int x3, y3; char* old_locale; Point p2, pm; real distance; old_locale = setlocale(LC_NUMERIC, "C"); if (fscanf(file, "%d %d %d %d %d %d %d %d %lf %d %d %d %d %lf %lf %d %d %d %d %d %d\n", &sub_type, &line_style, &thickness, &pen_color, &fill_color, &depth, &pen_style, &area_fill, &style_val, &cap_style, &direction, &forward_arrow, &backward_arrow, ¢er_x, ¢er_y, &x1, &y1, &x2, &y2, &x3, &y3) != 21) { dia_context_add_message_with_errno(ctx, errno, _("Couldn't read arc info.")); goto exit; } if (forward_arrow == 1) { forward_arrow_info = fig_read_arrow(file, ctx); } if (backward_arrow == 1) { backward_arrow_info = fig_read_arrow(file, ctx); } p2.x = x2/FIG_UNIT; p2.y = y2/FIG_UNIT; pm.x = (x1+x3)/(2*FIG_UNIT); pm.y = (y1+y3)/(2*FIG_UNIT); distance = distance_point_point (&p2, &pm); switch (sub_type) { case 0: case 1: case 2: /* We can't do pie-wedge properly yet */ newobj = create_standard_arc(x1/FIG_UNIT, y1/FIG_UNIT, x3/FIG_UNIT, y3/FIG_UNIT, direction ? distance : -distance, forward_arrow_info, backward_arrow_info); if (newobj == NULL) goto exit; if (sub_type == 2) { /* set new fill property on arc? */ dia_context_add_message(ctx, _("Filled arc treated as unfilled")); } break; default: dia_context_add_message(ctx, _("Unknown polyline arc: %d\n"), sub_type); goto exit; } fig_simple_properties(newobj, line_style, style_val, thickness, pen_color, fill_color, area_fill, ctx); /* Pen style field (not used) */ /* Style_val (size of dots and dashes) in 1/80 inch*/ /* Join style */ /* Cap style */ /* Depth field */ add_at_depth(newobj, depth, ctx); exit: setlocale(LC_NUMERIC, old_locale); g_free(forward_arrow_info); g_free(backward_arrow_info); return newobj; }