ArtSVP * art_svp_minus (const ArtSVP *svp1, const ArtSVP *svp2) { ArtSVP *svp2_mod; ArtSVP *svp3, *svp_new; ArtSvpWriter *swr; int i; svp2_mod = (ArtSVP *) svp2; /* get rid of the const for a while */ /* First invert svp2 to "turn it inside out" */ for (i = 0; i < svp2_mod->n_segs; i++) svp2_mod->segs[i].dir = !svp2_mod->segs[i].dir; svp3 = art_svp_merge (svp1, svp2_mod); swr = art_svp_writer_rewind_new (ART_WIND_RULE_POSITIVE); art_svp_intersector (svp3, swr); svp_new = art_svp_writer_rewind_reap (swr); art_free (svp3); /* shallow free because svp3 contains shared segments */ /* Flip svp2 back to its original state */ for (i = 0; i < svp2_mod->n_segs; i++) svp2_mod->segs[i].dir = !svp2_mod->segs[i].dir; return svp_new; }
/** * art_svp_diff: Compute the symmetric difference of two sorted vector paths. * @svp1: One sorted vector path. * @svp2: The other sorted vector path. * * Computes the symmetric of the two argument svp's. Given two svp's * with winding numbers of 0 and 1 everywhere, the resulting winding * number will be 1 where either, but not both, of the argument svp's * has a winding number 1, 0 otherwise. The result is newly allocated. * * Currently, this routine has accuracy problems pending the * implementation of the new intersector. * * Return value: The symmetric difference of @svp1 and @svp2. **/ ArtSVP * art_svp_diff (const ArtSVP *svp1, const ArtSVP *svp2) { #ifdef ART_USE_NEW_INTERSECTOR ArtSVP *svp3, *svp_new; ArtSvpWriter *swr; svp3 = art_svp_merge (svp1, svp2); swr = art_svp_writer_rewind_new (ART_WIND_RULE_ODDEVEN); art_svp_intersector (svp3, swr); svp_new = art_svp_writer_rewind_reap (swr); art_free (svp3); /* shallow free because svp3 contains shared segments */ return svp_new; #else ArtSVP *svp3, *svp4, *svp_new; svp3 = art_svp_merge_perturbed (svp1, svp2); svp4 = art_svp_uncross (svp3); art_svp_free (svp3); svp_new = art_svp_rewind_uncrossed (svp4, ART_WIND_RULE_ODDEVEN); art_svp_free (svp4); return svp_new; #endif }
/** * art_svp_intersect: Compute the intersection of two sorted vector paths. * @svp1: One sorted vector path. * @svp2: The other sorted vector path. * * Computes the intersection of the two argument svp's. Given two * svp's with winding numbers of 0 and 1 everywhere, the resulting * winding number will be 1 where both of the argument svp's has a * winding number 1, 0 otherwise. The result is newly allocated. * * Currently, this routine has accuracy problems pending the * implementation of the new intersector. * * Return value: The intersection of @svp1 and @svp2. **/ ArtSVP * art_svp_intersect (const ArtSVP *svp1, const ArtSVP *svp2) { #ifdef ART_USE_NEW_INTERSECTOR ArtSVP *svp3, *svp_new; ArtSvpWriter *swr; #ifdef ROBIN_DEBUG dump_svp("art_svp_intersect svp1", svp1); dump_svp("art_svp_intersect svp2", svp2); #endif svp3 = art_svp_merge (svp1, svp2); swr = art_svp_writer_rewind_new (ART_WIND_RULE_INTERSECT); art_svp_intersector (svp3, swr); svp_new = art_svp_writer_rewind_reap (swr); art_free (svp3); /* shallow free because svp3 contains shared segments */ #ifdef ROBIN_DEBUG dump_svp("art_svp_intersect svp_new", svp_new); #endif return svp_new; #else ArtSVP *svp3, *svp4, *svp_new; svp3 = art_svp_merge_perturbed (svp1, svp2); svp4 = art_svp_uncross (svp3); art_svp_free (svp3); svp_new = art_svp_rewind_uncrossed (svp4, ART_WIND_RULE_INTERSECT); art_svp_free (svp4); return svp_new; #endif }
ArtSVP* run_intersector(ArtSVP*svp, ArtWindRule rule) { ArtSvpWriter * swr = art_svp_writer_rewind_new(rule); double zoom = 1.0; intbbox_t bbox = get_svp_bbox(svp, zoom); art_svp_intersector(svp, swr); ArtSVP*result = art_svp_writer_rewind_reap(swr); clean_svp(result); if(!check_svp(result)) { current_svp = result; art_report_error(); // might set art_error_in_intersector } else { msg("<verbose> Comparing polygon renderings of size %dx%d and %dx%d", bbox.width, bbox.height, bbox.width, bbox.height); unsigned char*data1 = render_svp(svp, &bbox, zoom, rule); unsigned char*data2 = render_svp(result, &bbox, zoom, ART_WIND_RULE_ODDEVEN); if(!compare_bitmaps(&bbox, data1, data2)) { msg("<verbose> Bad SVP rewinding result- polygons don't match"); current_svp = result; art_report_error(); // might set art_error_in_intersector } free(data1); free(data2); } if(art_error_in_intersector) { msg("<verbose> Error in polygon processing"); art_svp_free(result); art_error_in_intersector=0; return 0; } return result; }
/** * art_svp_vpath_stroke: Stroke a vector path. * @vpath: #ArtVPath to stroke. * @join: Join style. * @cap: Cap style. * @line_width: Width of stroke. * @miter_limit: Miter limit. * @flatness: Flatness. * * Computes an svp representing the stroked outline of @vpath. The * width of the stroked line is @line_width. * * Lines are joined according to the @join rule. Possible values are * ART_PATH_STROKE_JOIN_MITER (for mitered joins), * ART_PATH_STROKE_JOIN_ROUND (for round joins), and * ART_PATH_STROKE_JOIN_BEVEL (for bevelled joins). The mitered join * is converted to a bevelled join if the miter would extend to a * distance of more than @miter_limit * @line_width from the actual * join point. * * If there are open subpaths, the ends of these subpaths are capped * according to the @cap rule. Possible values are * ART_PATH_STROKE_CAP_BUTT (squared cap, extends exactly to end * point), ART_PATH_STROKE_CAP_ROUND (rounded half-circle centered at * the end point), and ART_PATH_STROKE_CAP_SQUARE (squared cap, * extending half @line_width past the end point). * * The @flatness parameter controls the accuracy of the rendering. It * is most important for determining the number of points to use to * approximate circular arcs for round lines and joins. In general, the * resulting vector path will be within @flatness pixels of the "ideal" * path containing actual circular arcs. I reserve the right to use * the @flatness parameter to convert bevelled joins to miters for very * small turn angles, as this would reduce the number of points in the * resulting outline path. * * The resulting path is "clean" with respect to self-intersections, i.e. * the winding number is 0 or 1 at each point. * * Return value: Resulting stroked outline in svp format. **/ ArtSVP * art_svp_vpath_stroke (ArtVpath *vpath, ArtPathStrokeJoinType join, ArtPathStrokeCapType cap, double line_width, double miter_limit, double flatness) { #ifdef ART_USE_NEW_INTERSECTOR ArtVpath *vpath_stroke; ArtSVP *svp, *svp2; ArtSvpWriter *swr; vpath_stroke = art_svp_vpath_stroke_raw (vpath, join, cap, line_width, miter_limit, flatness); #ifdef VERBOSE print_ps_vpath (vpath_stroke); #endif svp = art_svp_from_vpath (vpath_stroke); #ifdef VERBOSE print_ps_svp (svp); #endif art_free (vpath_stroke); swr = art_svp_writer_rewind_new (ART_WIND_RULE_NONZERO); art_svp_intersector (svp, swr); svp2 = art_svp_writer_rewind_reap (swr); #ifdef VERBOSE print_ps_svp (svp2); #endif art_svp_free (svp); return svp2; #else ArtVpath *vpath_stroke, *vpath2; ArtSVP *svp, *svp2, *svp3; vpath_stroke = art_svp_vpath_stroke_raw (vpath, join, cap, line_width, miter_limit, flatness); #ifdef VERBOSE print_ps_vpath (vpath_stroke); #endif vpath2 = art_vpath_perturb (vpath_stroke); #ifdef VERBOSE print_ps_vpath (vpath2); #endif art_free (vpath_stroke); svp = art_svp_from_vpath (vpath2); #ifdef VERBOSE print_ps_svp (svp); #endif art_free (vpath2); svp2 = art_svp_uncross (svp); #ifdef VERBOSE print_ps_svp (svp2); #endif art_svp_free (svp); svp3 = art_svp_rewind_uncrossed (svp2, ART_WIND_RULE_NONZERO); #ifdef VERBOSE print_ps_svp (svp3); #endif art_svp_free (svp2); return svp3; #endif }
static void test_intersect (void) { ArtVpath vpath[] = { #if 0 /* two triangles */ { ART_MOVETO, 100, 100 }, { ART_LINETO, 300, 400 }, { ART_LINETO, 400, 200 }, { ART_LINETO, 100, 100 }, { ART_MOVETO, 110, 110 }, { ART_LINETO, 310, 410 }, { ART_LINETO, 410, 210 }, { ART_LINETO, 110, 110 }, #endif #if 0 /* a bowtie */ { ART_MOVETO, 100, 100 }, { ART_LINETO, 400, 400 }, { ART_LINETO, 400, 100 }, { ART_LINETO, 100, 400 }, { ART_LINETO, 100, 100 }, #endif #if 1 /* a square */ { ART_MOVETO, 100, 100 }, { ART_LINETO, 100, 400 }, { ART_LINETO, 400, 400 }, { ART_LINETO, 400, 100 }, { ART_LINETO, 100, 100 }, #endif #if 1 /* another square */ #define XOFF 10 #define YOFF 10 { ART_MOVETO, 100 + XOFF, 100 + YOFF }, { ART_LINETO, 100 + XOFF, 400 + YOFF }, { ART_LINETO, 400 + XOFF, 400 + YOFF }, { ART_LINETO, 400 + XOFF, 100 + YOFF }, { ART_LINETO, 100 + XOFF, 100 + YOFF }, #endif { ART_END, 0, 0} }; ArtSVP *svp, *svp2; ArtSvpWriter *swr; svp = art_svp_from_vpath (vpath); #define RUN_INTERSECT #ifdef RUN_INTERSECT swr = art_svp_writer_rewind_new (ART_WIND_RULE_ODDEVEN); art_svp_intersector (svp, swr); svp2 = art_svp_writer_rewind_reap (swr); #endif #if 0 output_svp_ppm (svp2); #else print_svp (svp2); #endif art_svp_free (svp); #ifdef RUN_INTERSECT art_svp_free (svp2); #endif }