static void message_update_data(Message *message) { Connection *conn = &message->connection; DiaObject *obj = &conn->object; Rectangle rect; if (connpoint_is_autogap(conn->endpoint_handles[0].connected_to) || connpoint_is_autogap(conn->endpoint_handles[1].connected_to)) { connection_adjust_for_autogap(conn); } obj->position = conn->endpoints[0]; message->text_handle.pos = message->text_pos; connection_update_handles(conn); connection_update_boundingbox(conn); message->text_width = dia_font_string_width(message->text, message->font, message->font_height); /* Add boundingbox for text: */ rect.left = message->text_pos.x-message->text_width/2; rect.right = rect.left + message->text_width; rect.top = message->text_pos.y - dia_font_ascent(message->text, message->font, message->font_height); rect.bottom = rect.top + message->font_height; rectangle_union(&obj->bounding_box, &rect); }
static void bezierline_save(Bezierline *bezierline, ObjectNode obj_node, DiaContext *ctx) { if (connpoint_is_autogap(bezierline->bez.object.handles[0]->connected_to) || connpoint_is_autogap(bezierline->bez.object.handles[3*(bezierline->bez.bezier.num_points-1)]->connected_to) || bezierline->absolute_start_gap || bezierline->absolute_end_gap) { Point gap_points[4]; compute_gap_points(bezierline, gap_points); exchange_bez_gap_points(&bezierline->bez,gap_points); bezierconn_update_boundingbox(&bezierline->bez); exchange_bez_gap_points(&bezierline->bez,gap_points); } bezierconn_save(&bezierline->bez, obj_node, ctx); if (!color_equals(&bezierline->line_color, &color_black)) data_add_color(new_attribute(obj_node, "line_color"), &bezierline->line_color, ctx); if (bezierline->line_width != 0.1) data_add_real(new_attribute(obj_node, PROP_STDNAME_LINE_WIDTH), bezierline->line_width, ctx); if (bezierline->line_style != LINESTYLE_SOLID) data_add_enum(new_attribute(obj_node, "line_style"), bezierline->line_style, ctx); if (bezierline->line_style != LINESTYLE_SOLID && bezierline->dashlength != DEFAULT_LINESTYLE_DASHLEN) data_add_real(new_attribute(obj_node, "dashlength"), bezierline->dashlength, ctx); if (bezierline->line_join != LINEJOIN_MITER) data_add_enum(new_attribute(obj_node, "line_join"), bezierline->line_join, ctx); if (bezierline->line_caps != LINECAPS_BUTT) data_add_enum(new_attribute(obj_node, "line_caps"), bezierline->line_caps, ctx); if (bezierline->start_arrow.type != ARROW_NONE) { save_arrow(obj_node, &bezierline->start_arrow, "start_arrow", "start_arrow_length", "start_arrow_width", ctx); } if (bezierline->end_arrow.type != ARROW_NONE) { save_arrow(obj_node, &bezierline->end_arrow, "end_arrow", "end_arrow_length", "end_arrow_width", ctx); } if (bezierline->absolute_start_gap) data_add_real(new_attribute(obj_node, "absolute_start_gap"), bezierline->absolute_start_gap, ctx); if (bezierline->absolute_end_gap) data_add_real(new_attribute(obj_node, "absolute_end_gap"), bezierline->absolute_end_gap, ctx); }
static void constraint_update_data(Constraint *constraint) { Connection *conn = &constraint->connection; DiaObject *obj = &conn->object; Rectangle rect; LineBBExtras *extra; if ((constraint->text) && (constraint->text[0] == '{')) { /* we might have a string loaded from an older dia. Clean it up. */ g_free(constraint->brtext); constraint->brtext = constraint->text; constraint->text = bracketted_to_string(constraint->text,"{","}"); } else if (!constraint->brtext) { constraint->brtext = string_to_bracketted(constraint->text, "{", "}"); } if (connpoint_is_autogap(conn->endpoint_handles[0].connected_to) || connpoint_is_autogap(conn->endpoint_handles[1].connected_to)) { connection_adjust_for_autogap(conn); } obj->position = conn->endpoints[0]; constraint->text_width = dia_font_string_width(constraint->brtext, constraint->font, constraint->font_height); constraint->text_handle.pos = constraint->text_pos; connection_update_handles(conn); /* Boundingbox: */ extra = &conn->extra_spacing; extra->start_long = extra->start_trans = extra->end_long = constraint->line_width/2.0; extra->end_trans = MAX(constraint->line_width,CONSTRAINT_ARROWLEN)/2.0; connection_update_boundingbox(conn); /* Add boundingbox for text: */ rect.left = constraint->text_pos.x; rect.right = rect.left + constraint->text_width; rect.top = constraint->text_pos.y - dia_font_ascent(constraint->brtext, constraint->font, constraint->font_height); rect.bottom = rect.top + constraint->font_height; rectangle_union(&obj->bounding_box, &rect); }
/** Adjust one end of an orthconn for gaps, if autogap is on for the connpoint. * @param pos Point of the end of the line. * @param dir Which of the four cardinal directions the line goes from pos. * @param cp The connectionpoint the line is connected to. * @returns Where the line should end to be on the correct edge of the * object, if cp has autogap on. */ static Point autolayout_adjust_for_gap(Point *pos, int dir, ConnectionPoint *cp) { DiaObject *object; Point dir_other; /* Do absolute gaps here, once it's defined */ if (!connpoint_is_autogap(cp)) { return *pos; } object = cp->object; dir_other.x = pos->x; dir_other.y = pos->y; switch (dir) { case DIR_NORTH: dir_other.y += 2 * (object->bounding_box.top - pos->y); break; case DIR_SOUTH: dir_other.y += 2 * (object->bounding_box.bottom - pos->y); break; case DIR_EAST: dir_other.x += 2 * (object->bounding_box.right - pos->x); break; case DIR_WEST: dir_other.x += 2 * (object->bounding_box.left - pos->x); break; default: g_warning("Impossible direction %d\n", dir); } return calculate_object_edge(pos, &dir_other, object); }
static real bezierline_distance_from(Bezierline *bezierline, Point *point) { BezierConn *bez = &bezierline->bez; if (connpoint_is_autogap(bez->object.handles[0]->connected_to) || connpoint_is_autogap(bez->object.handles[3*(bez->bezier.num_points-1)]->connected_to) || bezierline->absolute_start_gap || bezierline->absolute_end_gap) { Point gap_points[4]; real distance; compute_gap_points(bezierline, gap_points); exchange_bez_gap_points(bez,gap_points); distance = bezierconn_distance_from(bez, point, bezierline->line_width); exchange_bez_gap_points(bez,gap_points); return distance; } else { return bezierconn_distance_from(bez, point, bezierline->line_width); } }
static void annotation_update_data(Annotation *annotation) { Connection *conn = &annotation->connection; DiaObject *obj = &conn->object; Rectangle textrect; if (connpoint_is_autogap(conn->endpoint_handles[0].connected_to) || connpoint_is_autogap(conn->endpoint_handles[1].connected_to)) { connection_adjust_for_autogap(conn); } obj->position = conn->endpoints[0]; annotation->text_handle.pos = annotation->text->position; connection_update_handles(conn); connection_update_boundingbox(conn); text_calc_boundingbox(annotation->text,&textrect); rectangle_union(&obj->bounding_box, &textrect); }
static void flow_update_data(Flow *flow) { Connection *conn = &flow->connection; DiaObject *obj = &conn->object; Rectangle rect; Color* color = NULL; if (connpoint_is_autogap(flow->connection.endpoint_handles[0].connected_to) || connpoint_is_autogap(flow->connection.endpoint_handles[1].connected_to)) { connection_adjust_for_autogap(conn); } obj->position = conn->endpoints[0]; switch (flow->type) { case FLOW_ENERGY: color = &flow_color_energy ; break ; case FLOW_MATERIAL: color = &flow_color_material ; break ; case FLOW_SIGNAL: color = &flow_color_signal ; break ; } text_set_color( flow->text, color ) ; flow->text->position = flow->textpos; flow->text_handle.pos = flow->textpos; connection_update_handles(conn); /* Boundingbox: */ connection_update_boundingbox(conn); /* Add boundingbox for text: */ text_calc_boundingbox(flow->text, &rect) ; rectangle_union(&obj->bounding_box, &rect); }
void polyline_calculate_gap_endpoints(Polyline *polyline, Point *gap_endpoints) { Point start_vec, end_vec; ConnectionPoint *start_cp, *end_cp; int n = polyline->poly.numpoints; gap_endpoints[0] = polyline->poly.points[0]; gap_endpoints[1] = polyline->poly.points[n-1]; start_cp = (polyline->poly.object.handles[0])->connected_to; end_cp = (polyline->poly.object.handles[polyline->poly.object.num_handles-1])->connected_to; if (connpoint_is_autogap(start_cp)) { gap_endpoints[0] = calculate_object_edge(&gap_endpoints[0], &polyline->poly.points[1], start_cp->object); } if (connpoint_is_autogap(end_cp)) { gap_endpoints[1] = calculate_object_edge(&gap_endpoints[1], &polyline->poly.points[n-2], end_cp->object); } start_vec = gap_endpoints[0]; point_sub(&start_vec, &polyline->poly.points[0]); point_normalize(&start_vec); end_vec = gap_endpoints[1]; point_sub(&end_vec, &polyline->poly.points[n-1]); point_normalize(&end_vec); /* add absolute gap */ point_add_scaled(&gap_endpoints[0], &start_vec, polyline->absolute_start_gap); point_add_scaled(&gap_endpoints[1], &end_vec, polyline->absolute_end_gap); }
static void wanlink_update_data(WanLink *wanlink) { Connection *conn = &wanlink->connection; DiaObject *obj = (DiaObject *) wanlink; Point v, vhat; Point *endpoints; real width, width_2; real len, angle; Point origin; int i; Matrix m; width = wanlink->width; width_2 = width / 2.0; if (connpoint_is_autogap(conn->endpoint_handles[0].connected_to) || connpoint_is_autogap(conn->endpoint_handles[1].connected_to)) { connection_adjust_for_autogap(conn); } endpoints = &conn->endpoints[0]; obj->position = endpoints[0]; v = endpoints[1]; point_sub(&v, &endpoints[0]); if ((fabs(v.x) == 0.0) && (fabs(v.y)==0.0)) { v.x += 0.01; } vhat = v; point_normalize(&vhat); connection_update_boundingbox(conn); /** compute the polygon **/ origin = wanlink->connection.endpoints [0]; len = point_len (&v); angle = atan2 (vhat.y, vhat.x) - M_PI_2; /* The case of the wanlink */ wanlink->poly[0].x = (width * 0.50) - width_2; wanlink->poly[0].y = (len * 0.00); wanlink->poly[1].x = (width * 0.50) - width_2; wanlink->poly[1].y = (len * 0.45); wanlink->poly[2].x = (width * 0.94) - width_2; wanlink->poly[2].y = (len * 0.45); wanlink->poly[3].x = (width * 0.50) - width_2; wanlink->poly[3].y = (len * 1.00); wanlink->poly[4].x = (width * 0.50) - width_2; wanlink->poly[4].y = (len * 0.55); wanlink->poly[5].x = (width * 0.06) - width_2; wanlink->poly[5].y = (len * 0.55); /* rotate */ _identity_matrix (m); _rotate_matrix (m, angle); obj->bounding_box.top = origin.y; obj->bounding_box.left = origin.x; obj->bounding_box.bottom = conn->endpoints[1].y; obj->bounding_box.right = conn->endpoints[1].x; for (i = 0; i < WANLINK_POLY_LEN; i++) { Point new_pt; _transform_point (m, &wanlink->poly[i], &new_pt); point_add (&new_pt, &origin); wanlink->poly[i] = new_pt; } /* calculate bounding box */ { PolyBBExtras bbex = {0, 0, wanlink->width/2, 0, 0 }; polyline_bbox (&wanlink->poly[0], WANLINK_POLY_LEN, &bbex, TRUE, &obj->bounding_box); } connection_update_handles(conn); }
static void line_update_data(Line *line) { Connection *conn = &line->connection; DiaObject *obj = &conn->object; LineBBExtras *extra = &conn->extra_spacing; Point start, end; extra->start_trans = extra->end_trans = extra->start_long = extra->end_long = (line->line_width / 2.0); if (connpoint_is_autogap(line->connection.endpoint_handles[0].connected_to) || connpoint_is_autogap(line->connection.endpoint_handles[1].connected_to)) { connection_adjust_for_autogap(conn); } if (line->absolute_start_gap || line->absolute_end_gap ) { Point gap_endpoints[2]; line_adjust_for_absolute_gap(line, gap_endpoints); line_bbox(&gap_endpoints[0],&gap_endpoints[1], &conn->extra_spacing,&conn->object.bounding_box); start = gap_endpoints[0]; end = gap_endpoints[1]; } else { connection_update_boundingbox(conn); start = conn->endpoints[0]; end = conn->endpoints[1]; } if (line->start_arrow.type != ARROW_NONE) { Rectangle bbox; Point move_arrow, move_line; Point to = start; Point from = end; calculate_arrow_point(&line->start_arrow, &to, &from, &move_arrow, &move_line, line->line_width); /* move them */ point_sub(&to, &move_arrow); point_sub(&from, &move_line); arrow_bbox (&line->start_arrow, line->line_width, &to, &from, &bbox); rectangle_union (&obj->bounding_box, &bbox); } if (line->end_arrow.type != ARROW_NONE) { Rectangle bbox; Point move_arrow, move_line; Point to = end; Point from = start; calculate_arrow_point(&line->end_arrow, &to, &from, &move_arrow, &move_line, line->line_width); /* move them */ point_sub(&to, &move_arrow); point_sub(&from, &move_line); arrow_bbox (&line->end_arrow, line->line_width, &to, &from, &bbox); rectangle_union (&obj->bounding_box, &bbox); } obj->position = conn->endpoints[0]; connpointline_update(line->cpl); connpointline_putonaline(line->cpl, &start, &end, DIR_ALL); connection_update_handles(conn); }
static void bezierline_update_data(Bezierline *bezierline) { BezierConn *bez = &bezierline->bez; DiaObject *obj = &bez->object; PolyBBExtras *extra = &bez->extra_spacing; bezierconn_update_data(bez); extra->start_trans = extra->start_long = extra->middle_trans = extra->end_trans = extra->end_long = (bezierline->line_width / 2.0); obj->position = bez->bezier.points[0].p1; if (connpoint_is_autogap(bez->object.handles[0]->connected_to) || connpoint_is_autogap(bez->object.handles[3*(bez->bezier.num_points-1)]->connected_to) || bezierline->absolute_start_gap || bezierline->absolute_end_gap || bezierline->start_arrow.type != ARROW_NONE || bezierline->end_arrow.type != ARROW_NONE) { Point gap_points[4]; Rectangle bbox_union = {bez->bezier.points[0].p1.x, bez->bezier.points[0].p1.y, bez->bezier.points[0].p1.x, bez->bezier.points[0].p1.y}; compute_gap_points(bezierline, gap_points); exchange_bez_gap_points(bez,gap_points); /* further modifying the points data, accounts for corrcet arrow and bezier bounding box */ if (bezierline->start_arrow.type != ARROW_NONE) { Rectangle bbox; Point move_arrow, move_line; Point to = bez->bezier.points[0].p1, from = bez->bezier.points[1].p1; calculate_arrow_point(&bezierline->start_arrow, &to, &from, &move_arrow, &move_line, bezierline->line_width); point_sub(&to, &move_arrow); point_sub(&bez->bezier.points[0].p1, &move_line); arrow_bbox (&bezierline->start_arrow, bezierline->line_width, &to, &from, &bbox); rectangle_union (&bbox_union, &bbox); } if (bezierline->end_arrow.type != ARROW_NONE) { Rectangle bbox; Point move_arrow, move_line; int num_points = bez->bezier.num_points; Point to = bez->bezier.points[num_points-1].p3, from = bez->bezier.points[num_points-1].p2; calculate_arrow_point(&bezierline->end_arrow, &to, &from, &move_arrow, &move_line, bezierline->line_width); point_sub(&to, &move_arrow); point_sub(&bez->bezier.points[num_points-1].p3, &move_line); arrow_bbox (&bezierline->end_arrow, bezierline->line_width, &to, &from, &bbox); rectangle_union (&bbox_union, &bbox); } bezierconn_update_boundingbox(bez); rectangle_union (&obj->bounding_box, &bbox_union); exchange_bez_gap_points(bez,gap_points); } else { bezierconn_update_boundingbox(bez); } /* add control points to the bounding box, needed to make them visible when showing all * and to remove traces from them */ { int i, num_points = bez->bezier.num_points; g_assert (obj->enclosing_box != NULL); *obj->enclosing_box = obj->bounding_box; /* starting with the second point, the first one is MOVE_TO */ for (i = 1; i < num_points; ++i) { if (bez->bezier.points[i].type != BEZ_CURVE_TO) continue; rectangle_add_point(obj->enclosing_box, &bez->bezier.points[i].p1); rectangle_add_point(obj->enclosing_box, &bez->bezier.points[i].p2); } } }
static void bezierline_draw(Bezierline *bezierline, DiaRenderer *renderer) { Point gap_points[4]; /* two first and two last bez points */ BezierConn *bez = &bezierline->bez; DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer); renderer_ops->set_linewidth(renderer, bezierline->line_width); renderer_ops->set_linestyle(renderer, bezierline->line_style, bezierline->dashlength); renderer_ops->set_linejoin(renderer, bezierline->line_join); renderer_ops->set_linecaps(renderer, bezierline->line_caps); if (connpoint_is_autogap(bez->object.handles[0]->connected_to) || connpoint_is_autogap(bez->object.handles[3*(bez->bezier.num_points-1)]->connected_to) || bezierline->absolute_start_gap || bezierline->absolute_end_gap) { compute_gap_points(bezierline,gap_points); exchange_bez_gap_points(bez,gap_points); renderer_ops->draw_bezier_with_arrows(renderer, bez->bezier.points, bez->bezier.num_points, bezierline->line_width, &bezierline->line_color, &bezierline->start_arrow, &bezierline->end_arrow); exchange_bez_gap_points(bez,gap_points); } else { renderer_ops->draw_bezier_with_arrows(renderer, bez->bezier.points, bez->bezier.num_points, bezierline->line_width, &bezierline->line_color, &bezierline->start_arrow, &bezierline->end_arrow); } #if 0 renderer_ops->draw_bezier(renderer, bez->bezier.points, bez->bezier.num_points, &bezierline->line_color); if (bezierline->start_arrow.type != ARROW_NONE) { arrow_draw(renderer, bezierline->start_arrow.type, &bez->bezier.points[0].p1, &bez->bezier.points[1].p1, bezierline->start_arrow.length, bezierline->start_arrow.width, bezierline->line_width, &bezierline->line_color, &color_white); } if (bezierline->end_arrow.type != ARROW_NONE) { arrow_draw(renderer, bezierline->end_arrow.type, &bez->bezier.points[bez->bezier.num_points-1].p3, &bez->bezier.points[bez->bezier.num_points-1].p2, bezierline->end_arrow.length, bezierline->end_arrow.width, bezierline->line_width, &bezierline->line_color, &color_white); } #endif /* Only display lines while selected. Calling dia_object_is_selected() * every time may take a little long. Some time can be saved by storing * whether the object is currently selected in bezierline_select, and * only checking while selected. But we'll do that if needed. */ if (renderer->is_interactive && dia_object_is_selected(&bezierline->bez.object)) { bezier_draw_control_lines(bezierline->bez.bezier.num_points, bezierline->bez.bezier.points, renderer); } }
static void compute_gap_points(Bezierline *bezierline, Point *gap_points) { real bez_length; BezierConn *bez = &bezierline->bez; Point vec_start, vec_end; gap_points[0] = bez->bezier.points[0].p1; gap_points[1] = bez->bezier.points[1].p1; gap_points[2] = bez->bezier.points[bez->bezier.num_points-1].p2; gap_points[3] = bez->bezier.points[bez->bezier.num_points-1].p3; point_copy(&vec_start, &gap_points[1]); point_sub(&vec_start, &gap_points[0]); point_normalize(&vec_start); /* unit vector pointing from first point */ point_copy(&vec_end, &gap_points[2]); point_sub(&vec_end, &gap_points[3]); point_normalize(&vec_end); /* unit vector pointing from last point */ bez_length = approx_bez_length(bez) ; if (connpoint_is_autogap(bez->object.handles[0]->connected_to) && (bez->object.handles[0])->connected_to != NULL && (bez->object.handles[0])->connected_to->object != NULL ) { Point end; point_copy(&end, &gap_points[0]); point_add_scaled(&end, &vec_start, bez_length); /* far away on the same slope */ end = calculate_object_edge(&gap_points[0], &end, (bez->object.handles[0])->connected_to->object); point_sub(&end, &gap_points[0]); /* vector from old start to new start */ /* move points */ point_add(&gap_points[0], &end); point_add(&gap_points[1], &end); } if (connpoint_is_autogap(bez->object.handles[3*(bez->bezier.num_points-1)]->connected_to) && (bez->object.handles[3*(bez->bezier.num_points-1)])->connected_to != NULL && (bez->object.handles[3*(bez->bezier.num_points-1)])->connected_to->object != NULL) { Point end; point_copy(&end, &gap_points[3]); point_add_scaled(&end, &vec_end, bez_length); /* far away on the same slope */ end = calculate_object_edge(&gap_points[3], &end, (bez->object.handles[3*(bez->bezier.num_points-1)])->connected_to->object); point_sub(&end, &gap_points[3]); /* vector from old end to new end */ /* move points */ point_add(&gap_points[3], &end); point_add(&gap_points[2], &end); } /* adds the absolute start gap according to the slope at the first point */ point_add_scaled(&gap_points[0], &vec_start, bezierline->absolute_start_gap); point_add_scaled(&gap_points[1], &vec_start, bezierline->absolute_start_gap); /* adds the absolute end gap according to the slope at the last point */ point_add_scaled(&gap_points[2], &vec_end, bezierline->absolute_end_gap); point_add_scaled(&gap_points[3], &vec_end, bezierline->absolute_end_gap); }
static void arc_draw(Arc *arc, DiaRenderer *renderer) { DiaRendererClass *renderer_ops = DIA_RENDERER_GET_CLASS (renderer); Point *endpoints; Point gaptmp[3]; ConnectionPoint *start_cp, *end_cp; assert(arc != NULL); assert(renderer != NULL); endpoints = &arc->connection.endpoints[0]; gaptmp[0] = endpoints[0]; gaptmp[1] = endpoints[1]; start_cp = arc->connection.endpoint_handles[0].connected_to; end_cp = arc->connection.endpoint_handles[1].connected_to; TRACE(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)) { TRACE(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)) { TRACE(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]); renderer_ops->set_linewidth(renderer, arc->line_width); renderer_ops->set_linestyle(renderer, arc->line_style); renderer_ops->set_dashlength(renderer, arc->dashlength); renderer_ops->set_linecaps(renderer, arc->line_caps); /* Special case when almost line: */ if (arc_is_line (arc)) { TRACE(printf("drawing like a line\n")); renderer_ops->draw_line_with_arrows(renderer, &gaptmp[0], &gaptmp[1], arc->line_width, &arc->arc_color, &arc->start_arrow, &arc->end_arrow); return; } renderer_ops->draw_arc_with_arrows(renderer, &gaptmp[0], &gaptmp[1], &gaptmp[2], arc->line_width, &arc->arc_color, &arc->start_arrow, &arc->end_arrow); if (renderer->is_interactive && dia_object_is_selected(&arc->connection.object)) { /* draw the central angle */ Color line_color = { 0.0, 0.0, 0.6, 1.0 }; renderer_ops->set_linewidth(renderer, 0); renderer_ops->set_linestyle(renderer, LINESTYLE_DOTTED); renderer_ops->set_dashlength(renderer, 1); renderer_ops->set_linejoin(renderer, LINEJOIN_MITER); renderer_ops->set_linecaps(renderer, LINECAPS_BUTT); renderer_ops->draw_line(renderer, &endpoints[0], &arc->center, &line_color); renderer_ops->draw_line(renderer, &endpoints[1], &arc->center, &line_color); } }