/*! * \brief Calculate the distance of the whole object to the given point * \memberof StdPath */ static real stdpath_distance_from (StdPath *stdpath, Point *point) { real lw = stdpath->stroke_or_fill & PDO_STROKE ? stdpath->line_width : 0.0; if (stdpath->stroke_or_fill & PDO_FILL) return distance_bez_shape_point (stdpath->points, stdpath->num_points, lw, point); else return distance_bez_line_point (stdpath->points, stdpath->num_points, lw, point); }
real beziershape_distance_from(BezierShape *bezier, Point *point, real line_width) { return distance_bez_shape_point(bezier->points, bezier->numpoints, line_width, point); }
/*! * Given the original segments and splits apply * all segment splits and create unique segment index. * * Split.seg is the index to the segment to split before this function. * After the splits are applied every split.seq is unique. */ static void _split_segments (GArray *segs, GArray *splits, const GArray *other) { int i, sofs = 0; GArray *pending; /* splits must be sorted for the algorithm below */ g_array_sort (splits, _compare_split); for (i = 0; i < splits->len; ++i) { int j, to; int from = i; int from_seg = g_array_index (splits, Split, i).seg; BezierSegment bs; real t = 0; g_return_if_fail (from_seg + sofs < segs->len); bs = g_array_index (segs, BezierSegment, from_seg + sofs); while (i < splits->len - 1 && from_seg == g_array_index (splits, Split, i+1).seg) ++i; /* advance while segment reference is the same */ to = i; for (j = from; j <= to; j++) { BezierSegment left, right; /* scale t to split the right segment */ real tL = g_array_index (splits, Split, j).split; real tR = (tL - t) / (1.0 - t); bezier_split_at (&bs, &left, &right, tR); bs = right; t = tL; /* overwrite the exisiting */ g_return_if_fail (from_seg + sofs < segs->len); g_array_index (segs, BezierSegment, from_seg + sofs) = left; sofs += 1; /* increment segment offset for every segment added */ /* insert a new one behind that ... */ g_array_insert_val (segs, from_seg + sofs, right); /* ... potentially overwritten */ /* adjust the segment reference */ g_array_index (splits, Split, j).seg = from_seg + sofs; } } pending = g_array_new (FALSE, FALSE, sizeof(BezierSegment)); /* for every sub-path determine if it is inside the full other path */ for (i = 0; i < splits->len; ++i) { Split *sp = &g_array_index (splits, Split, i); BezierSegment *bs = &g_array_index (segs, BezierSegment, sp->seg); BezierSegment left, right; int to, j; if (i == 0 && sp->seg > 0) g_array_append_vals (pending, &g_array_index (segs, BezierSegment, 0), sp->seg); bezier_split (bs, &left, &right); sp->outside = distance_bez_shape_point (&g_array_index (other, BezPoint, 0), other->len, 0 /* line width */, &right.p0) > 0.0; /* also remember the sub-path */ to = g_array_index (splits, Split, (i+1)%splits->len).seg; sp->path = g_array_new (FALSE, FALSE, sizeof(BezierSegment)); if (to < sp->seg) { g_array_append_vals (sp->path, bs, segs->len - sp->seg); #if 0 /* XXX: this is only correct if there is no move-to within the segments */ g_array_append_vals (sp->path, &g_array_index (segs, BezierSegment, 0), to); #else g_array_append_vals (sp->path, &g_array_index (pending, BezierSegment, 0), pending->len); g_array_set_size (pending, 0); #endif } else { for (j = sp->seg; j < to; ++j) { if (_segment_is_moveto (bs)) { g_array_append_vals (sp->path, &g_array_index (pending, BezierSegment, 0), pending->len); g_array_set_size (pending, 0); break; } g_array_append_val (sp->path, *bs); bs++; } for (/* remains */; j < to; ++j) { g_array_append_val (pending, *bs); bs++; } } } g_array_free (pending, TRUE); }