/** * 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 }
/** * 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_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) { 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; }
/** * 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) { 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; }
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; }
static void test_intersection(void) { ArtVpath vp0[] = { { ART_MOVETO, 10, 10}, { ART_LINETO, 60, 60}, { ART_LINETO, 110, 10}, { ART_LINETO, 10, 10}, { ART_END, 0, 0} }, vp1[]= { {ART_MOVETO, 110,34.999999999999993}, {ART_LINETO, 10,35}, {ART_LINETO, 10,36}, {ART_LINETO, 110,35.999999999999993}, {ART_LINETO, 110,34.999999999999993}, {ART_END, 0,0} }, vp2[]= { {ART_MOVETO, 110,35.999999999999993}, {ART_LINETO, 10,36}, {ART_LINETO, 10,37}, {ART_LINETO, 110,36.999999999999993}, {ART_LINETO, 110,35.999999999999993}, {ART_END, 0,0} }, *vp[] = {vp0, vp1, vp2}; ArtSVP *svp[3], *svpi; int i; for(i=0; i<3; i++) { svp[i]=art_svp_from_vpath(vp[i]); printf("vpath[%d]\n", i); print_vpath(vp[i]); printf("svp[%d]\n", i); print_svp(svp[i]); } for(i=2; i>0; i--) { svpi = art_svp_intersect(svp[i],svp[0]); printf("svp[%d] & svp[0]\n", i); print_svp(svpi); art_svp_free(svpi); } for(i=0; i<3; i++) { art_svp_free(svp[i]); } }
/** * art_svp_union: Compute the union of two sorted vector paths. * @svp1: One sorted vector path. * @svp2: The other sorted vector path. * * Computes the union 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 (or 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 union of @svp1 and @svp2. **/ ArtSVP * art_svp_union (const ArtSVP *svp1, const ArtSVP *svp2) { 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_POSITIVE); #ifdef VERBOSE print_ps_svp (svp4); print_ps_svp (svp_new); #endif art_svp_free (svp4); return svp_new; }
gfxline_t* gfxpoly_circular_to_evenodd(gfxline_t*line, double gridsize) { msg("<verbose> Converting circular-filled gfxline of %d segments to even-odd filled gfxline", gfxline_len(line)); ArtSVP* svp = gfxfillToSVP(line, 1); ArtSVP* svp_rewinded; svp_rewinded = run_intersector(svp, ART_WIND_RULE_NONZERO); if(!svp_rewinded) { art_svp_free(svp); return 0; } gfxline_t* result = gfxline_from_gfxpoly((gfxpoly_t*)svp_rewinded); art_svp_free(svp); art_svp_free(svp_rewinded); 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) { 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; }
gfxpoly_t* gfxpoly_from_fill(gfxline_t*line, double gridsize) { /* I'm not sure whether doing perturbation here is actually a good idea- if that line has been run through the machinery several times already, it might be safer to leave it alone, since it should already be in a format libart can handle */ #ifdef PERTURBATE ArtSVP* svp = gfxfillToSVP(line, 1); #else ArtSVP* svp = gfxfillToSVP(line, 0); #endif #ifdef DEBUG char filename[80]; static int counter = 0; sprintf(filename, "svp%d.ps", counter); write_svp_postscript(filename, svp); sprintf(filename, "gfxline%d.ps", counter); write_gfxline_postscript(filename, line); #endif /* we do xor-filling by default, so dir is always 1 (actually for oddeven rewinding it makes no difference, but it's "cleaner") */ int t; for(t=0; t<svp->n_segs; t++) { svp->segs[t].dir = 1; } /* for some reason, we need to rewind / self-intersect the polygons that gfxfillToSVP returns- art probably uses a different fill mode (circular?) for vpaths */ ArtSVP*svp_uncrossed=0; #ifdef DEBUG sprintf(filename, "svp%d_in.ps", counter); write_svp_postscript(filename, svp); counter++; #endif svp_uncrossed = run_intersector(svp, ART_WIND_RULE_ODDEVEN); art_svp_free(svp); svp=svp_uncrossed; return (gfxpoly_t*)svp; }
/** * 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 }
static void make_testpat (void) { ArtVpath *vpath, *vpath2, *vpath3; ArtSVP *svp, *svp2; ArtSVP *svp3; art_u8 buf[512 * 512 * BYTES_PP]; int i, j; int iter; art_u8 colorimg[256][256][3]; art_u8 rgbaimg[256][256][4]; art_u8 bitimg[16][2]; int x, y; double affine[6]; double affine2[6]; double affine3[6]; ArtAlphaGamma *alphagamma; double dash_data[] = { 20 }; ArtVpathDash dash; dash.offset = 0; dash.n_dash = 1; dash.dash = dash_data; #ifdef TEST_AFFINE test_affine (); exit (0); #endif vpath = randstar (50); svp = art_svp_from_vpath (vpath); art_free (vpath); vpath2 = randstar (50); #if 1 vpath3 = art_vpath_dash (vpath2, &dash); art_free (vpath2); svp2 = art_svp_vpath_stroke (vpath3, ART_PATH_STROKE_JOIN_MITER, ART_PATH_STROKE_CAP_BUTT, 15, 4, 0.5); art_free (vpath3); #else svp2 = art_svp_from_vpath (vpath2); #endif #if 1 svp3 = art_svp_intersect (svp, svp2); #else svp3 = svp2; #endif #if 0 print_svp (svp); #endif for (y = 0; y < 256; y++) for (x = 0; x < 256; x++) { colorimg[y][x][0] = (x + y) >> 1; colorimg[y][x][1] = (x + (255 - y)) >> 1; colorimg[y][x][2] = ((255 - x) + y) >> 1; rgbaimg[y][x][0] = (x + y) >> 1; rgbaimg[y][x][1] = (x + (255 - y)) >> 1; rgbaimg[y][x][2] = ((255 - x) + y) >> 1; rgbaimg[y][x][3] = y; } for (y = 0; y < 16; y++) for (x = 0; x < 2; x++) bitimg[y][x] = (x << 4) | y; affine[0] = 0.5; affine[1] = .2; affine[2] = -.2; affine[3] = 0.5; affine[4] = 64; affine[5] = 64; affine2[0] = 1; affine2[1] = -.2; affine2[2] = .2; affine2[3] = 1; affine2[4] = 128; affine2[5] = 128; affine3[0] = 5; affine3[1] = -.2; affine3[2] = .2; affine3[3] = 5; affine3[4] = 384; affine3[5] = 32; #if 0 alphagamma = art_alphagamma_new (1.8); #else alphagamma = NULL; #endif #ifdef COLOR printf ("P6\n512 512\n255\n"); #else printf ("P5\n512 512\n255\n"); #endif for (iter = 0; iter < NUM_ITERS; iter++) for (j = 0; j < 512; j += TILE_SIZE) for (i = 0; i < 512; i += TILE_SIZE) { #ifdef COLOR art_rgb_svp_aa (svp, i, j, i + TILE_SIZE, j + TILE_SIZE, 0xffe0a0, 0x100040, buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP, alphagamma); art_rgb_svp_alpha (svp2, i, j, i + TILE_SIZE, j + TILE_SIZE, 0xff000080, buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP, alphagamma); art_rgb_svp_alpha (svp3, i, j, i + TILE_SIZE, j + TILE_SIZE, 0x00ff0080, buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP, alphagamma); art_rgb_affine (buf + (j * 512 + i) * BYTES_PP, i, j, i + TILE_SIZE, j + TILE_SIZE, 512 * BYTES_PP, (art_u8 *)colorimg, 256, 256, 256 * 3, affine, ART_FILTER_NEAREST, alphagamma); art_rgb_rgba_affine (buf + (j * 512 + i) * BYTES_PP, i, j, i + TILE_SIZE, j + TILE_SIZE, 512 * BYTES_PP, (art_u8 *)rgbaimg, 256, 256, 256 * 4, affine2, ART_FILTER_NEAREST, alphagamma); art_rgb_bitmap_affine (buf + (j * 512 + i) * BYTES_PP, i, j, i + TILE_SIZE, j + TILE_SIZE, 512 * BYTES_PP, (art_u8 *)bitimg, 16, 16, 2, 0xffff00ff, affine3, ART_FILTER_NEAREST, alphagamma); #else art_gray_svp_aa (svp, i, j, i + TILE_SIZE, j + TILE_SIZE, buf + (j * 512 + i) * BYTES_PP, 512 * BYTES_PP); #endif } art_svp_free (svp2); art_svp_free (svp3); art_svp_free (svp); #if 1 fwrite (buf, 1, 512 * 512 * BYTES_PP, stdout); #endif }
void art_draw_poly(art_buffer_p buffer, art_context_p context, int filled, float *x, float *y, int n, int closed) { ArtVpath *vec, *vec2; ArtSVP *svp; double dash_data[2]; ArtVpathDash dash; ArtDRect drect; ArtIRect irect; int i, mark = 0; vec = art_new(ArtVpath, n + 1 + closed); for(i = 0; i < n; i++) { vec[mark].code = i ? ART_LINETO : ART_MOVETO; if(i == 0 || i == n - 1 || hypot(x[i] - vec[mark - 1].x, (buffer->height - y[i]) - vec[mark - 1].y) > 1.0) { vec[mark].x = x[i]; vec[mark].y = buffer->height - y[i]; mark++; } } n = mark; if(closed) { vec[n].code = ART_LINETO; vec[n].x = vec[0].x; vec[n].y = vec[0].y; } vec[n + closed].code = ART_END; vec[n + closed].x = 0; vec[n + closed].y = 0; if(context->current_dash_on > 0) { dash.offset = 0; dash_data[0] = context->current_dash_on; dash_data[1] = context->current_dash_off; dash.n_dash = 2; dash.dash = dash_data; vec2 = art_vpath_dash(vec, &dash); art_free(vec); vec = vec2; } if(filled) svp = art_svp_from_vpath(vec); else svp = art_svp_vpath_stroke(vec, context->current_jointype, context->current_captype, context->current_linewidth, context->current_miterlimit, context->current_flatness); art_free(vec); art_drect_svp(&drect, svp); art_drect_to_irect(&irect, &drect); if(irect.x1 > buffer->width) irect.x1 = buffer->width; if(irect.y1 > buffer->height) irect.y1 = buffer->height; if(irect.x0 < 0) irect.x0 = 0; if(irect.y0 < 0) irect.y0 = 0; art_rgb_svp_alpha(svp, irect.x0, irect.y0, irect.x1, irect.y1, context->current_color, buffer->buffer + (irect.y0 * buffer->width + irect.x0) * 3, buffer->width * 3, NULL); art_svp_free(svp); }
void finalize_selectregion(void) { GList *itemlist; struct Item *item; ArtVpath *vpath; ArtSVP *lassosvp; int i, n; double *pt; ui.cur_item_type = ITEM_NONE; // build SVP for the lasso path n = ui.cur_path.num_points; vpath = g_malloc((n+2)*sizeof(ArtVpath)); for (i=0; i<n; i++) { vpath[i].x = ui.cur_path.coords[2*i]; vpath[i].y = ui.cur_path.coords[2*i+1]; } vpath[n].x = vpath[0].x; vpath[n].y = vpath[0].y; vpath[0].code = ART_MOVETO; for (i=1; i<=n; i++) vpath[i].code = ART_LINETO; vpath[n+1].code = ART_END; lassosvp = art_svp_from_vpath(vpath); g_free(vpath); // see which items we selected for (itemlist = ui.selection->layer->items; itemlist!=NULL; itemlist = itemlist->next) { item = (struct Item *)itemlist->data; if (hittest_item(lassosvp, item)) { // update the selection bbox if (ui.selection->items==NULL || ui.selection->bbox.left>item->bbox.left) ui.selection->bbox.left = item->bbox.left; if (ui.selection->items==NULL || ui.selection->bbox.right<item->bbox.right) ui.selection->bbox.right = item->bbox.right; if (ui.selection->items==NULL || ui.selection->bbox.top>item->bbox.top) ui.selection->bbox.top = item->bbox.top; if (ui.selection->items==NULL || ui.selection->bbox.bottom<item->bbox.bottom) ui.selection->bbox.bottom = item->bbox.bottom; // add the item ui.selection->items = g_list_append(ui.selection->items, item); } } art_svp_free(lassosvp); if (ui.selection->items == NULL) { // if we clicked inside a text zone or image? pt = ui.cur_path.coords; item = click_is_in_text_or_image(ui.selection->layer, pt[0], pt[1]); if (item!=NULL) { for (i=0; i<n; i++, pt+=2) { if (pt[0]<item->bbox.left || pt[0]>item->bbox.right || pt[1]<item->bbox.top || pt[1]>item->bbox.bottom) { item = NULL; break; } } } if (item!=NULL) { ui.selection->items = g_list_append(ui.selection->items, item); g_memmove(&(ui.selection->bbox), &(item->bbox), sizeof(struct BBox)); } } if (ui.selection->items == NULL) reset_selection(); else { // make a selection rectangle instead of the lasso shape gtk_object_destroy(GTK_OBJECT(ui.selection->canvas_item)); ui.selection->canvas_item = gnome_canvas_item_new(ui.cur_layer->group, gnome_canvas_rect_get_type(), "width-pixels", 1, "outline-color-rgba", 0x000000ff, "fill-color-rgba", 0x80808040, "x1", ui.selection->bbox.left, "x2", ui.selection->bbox.right, "y1", ui.selection->bbox.top, "y2", ui.selection->bbox.bottom, NULL); make_dashed(ui.selection->canvas_item); ui.selection->type = ITEM_SELECTRECT; } update_cursor(); update_copy_paste_enabled(); update_font_button(); }
void gfxpoly_destroy(gfxpoly_t*poly) { ArtSVP*svp = (ArtSVP*)poly; art_svp_free(svp); }