Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/libart_lgpl/art_svp_ops.c
diff options
context:
space:
mode:
authorBruno Coudoin <bruno.coudoin@free.fr>2009-07-04 18:15:47 (GMT)
committer Bruno Coudoin <bruno.coudoin@free.fr>2009-07-04 18:15:47 (GMT)
commitdc4f522a1b1faacd0a825409054647feaaef0ae4 (patch)
treefd1e14b5828a14305f9e5bf95bee1eb970b83b58 /src/libart_lgpl/art_svp_ops.c
parent6d69994dd8125f36462b96ec2fe7a0d2652ccf2f (diff)
Integrated gnomecanvas and libart_lgpl to make it easier to compile GCompris
on different platforms. This is similar to the way GCompris 8.4.X is provided.
Diffstat (limited to 'src/libart_lgpl/art_svp_ops.c')
-rw-r--r--src/libart_lgpl/art_svp_ops.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/src/libart_lgpl/art_svp_ops.c b/src/libart_lgpl/art_svp_ops.c
new file mode 100644
index 0000000..57d4b93
--- /dev/null
+++ b/src/libart_lgpl/art_svp_ops.c
@@ -0,0 +1,400 @@
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998-2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ * Boston, MA 02111-1307, USA.
+ */
+
+#define noVERBOSE
+
+/* Vector path set operations, over sorted vpaths. */
+
+#include "config.h"
+#include "art_svp_ops.h"
+
+#include "art_misc.h"
+
+#include "art_svp.h"
+#include "art_vpath.h"
+#include "art_svp_vpath.h"
+#include "art_svp.h"
+#ifdef ART_USE_NEW_INTERSECTOR
+#include "art_svp_intersect.h"
+#else
+#include "art_svp_wind.h"
+#endif
+#include "art_vpath_svp.h"
+
+/* Merge the segments of the two svp's. The resulting svp will share
+ segments with args passed in, so be super-careful with the
+ allocation. */
+/**
+ * art_svp_merge: Merge the segments of two svp's.
+ * @svp1: One svp to merge.
+ * @svp2: The other svp to merge.
+ *
+ * Merges the segments of two SVP's into a new one. The resulting
+ * #ArtSVP data structure will share the segments of the argument
+ * svp's, so it is probably a good idea to free it shallowly,
+ * especially if the arguments will be freed with art_svp_free().
+ *
+ * Return value: The merged #ArtSVP.
+ **/
+static ArtSVP *
+art_svp_merge (const ArtSVP *svp1, const ArtSVP *svp2)
+{
+ ArtSVP *svp_new;
+ int ix;
+ int ix1, ix2;
+
+ svp_new = (ArtSVP *)art_alloc (sizeof(ArtSVP) +
+ (svp1->n_segs + svp2->n_segs - 1) *
+ sizeof(ArtSVPSeg));
+ ix1 = 0;
+ ix2 = 0;
+ for (ix = 0; ix < svp1->n_segs + svp2->n_segs; ix++)
+ {
+ if (ix1 < svp1->n_segs &&
+ (ix2 == svp2->n_segs ||
+ art_svp_seg_compare (&svp1->segs[ix1], &svp2->segs[ix2]) < 1))
+ svp_new->segs[ix] = svp1->segs[ix1++];
+ else
+ svp_new->segs[ix] = svp2->segs[ix2++];
+ }
+
+ svp_new->n_segs = ix;
+ return svp_new;
+}
+
+#ifdef VERBOSE
+
+#define XOFF 50
+#define YOFF 700
+
+static void
+print_ps_vpath (ArtVpath *vpath)
+{
+ int i;
+
+ printf ("gsave %d %d translate 1 -1 scale\n", XOFF, YOFF);
+ for (i = 0; vpath[i].code != ART_END; i++)
+ {
+ switch (vpath[i].code)
+ {
+ case ART_MOVETO:
+ printf ("%g %g moveto\n", vpath[i].x, vpath[i].y);
+ break;
+ case ART_LINETO:
+ printf ("%g %g lineto\n", vpath[i].x, vpath[i].y);
+ break;
+ default:
+ break;
+ }
+ }
+ printf ("stroke grestore showpage\n");
+}
+
+#define DELT 4
+
+static void
+print_ps_svp (ArtSVP *vpath)
+{
+ int i, j;
+
+ printf ("%% begin\n");
+ for (i = 0; i < vpath->n_segs; i++)
+ {
+ printf ("%g setgray\n", vpath->segs[i].dir ? 0.7 : 0);
+ for (j = 0; j < vpath->segs[i].n_points; j++)
+ {
+ printf ("%g %g %s\n",
+ XOFF + vpath->segs[i].points[j].x,
+ YOFF - vpath->segs[i].points[j].y,
+ j ? "lineto" : "moveto");
+ }
+ printf ("%g %g moveto %g %g lineto %g %g lineto %g %g lineto stroke\n",
+ XOFF + vpath->segs[i].points[0].x - DELT,
+ YOFF - DELT - vpath->segs[i].points[0].y,
+ XOFF + vpath->segs[i].points[0].x - DELT,
+ YOFF - vpath->segs[i].points[0].y,
+ XOFF + vpath->segs[i].points[0].x + DELT,
+ YOFF - vpath->segs[i].points[0].y,
+ XOFF + vpath->segs[i].points[0].x + DELT,
+ YOFF - DELT - vpath->segs[i].points[0].y);
+ printf ("%g %g moveto %g %g lineto %g %g lineto %g %g lineto stroke\n",
+ XOFF + vpath->segs[i].points[j - 1].x - DELT,
+ YOFF + DELT - vpath->segs[i].points[j - 1].y,
+ XOFF + vpath->segs[i].points[j - 1].x - DELT,
+ YOFF - vpath->segs[i].points[j - 1].y,
+ XOFF + vpath->segs[i].points[j - 1].x + DELT,
+ YOFF - vpath->segs[i].points[j - 1].y,
+ XOFF + vpath->segs[i].points[j - 1].x + DELT,
+ YOFF + DELT - vpath->segs[i].points[j - 1].y);
+ printf ("stroke\n");
+ }
+
+ printf ("showpage\n");
+}
+#endif
+
+#ifndef ART_USE_NEW_INTERSECTOR
+static ArtSVP *
+art_svp_merge_perturbed (const ArtSVP *svp1, const ArtSVP *svp2)
+{
+ ArtVpath *vpath1, *vpath2;
+ ArtVpath *vpath1_p, *vpath2_p;
+ ArtSVP *svp1_p, *svp2_p;
+ ArtSVP *svp_new;
+
+ vpath1 = art_vpath_from_svp (svp1);
+ vpath1_p = art_vpath_perturb (vpath1);
+ art_free (vpath1);
+ svp1_p = art_svp_from_vpath (vpath1_p);
+ art_free (vpath1_p);
+
+ vpath2 = art_vpath_from_svp (svp2);
+ vpath2_p = art_vpath_perturb (vpath2);
+ art_free (vpath2);
+ svp2_p = art_svp_from_vpath (vpath2_p);
+ art_free (vpath2_p);
+
+ svp_new = art_svp_merge (svp1_p, svp2_p);
+#ifdef VERBOSE
+ print_ps_svp (svp1_p);
+ print_ps_svp (svp2_p);
+ print_ps_svp (svp_new);
+#endif
+ art_free (svp1_p);
+ art_free (svp2_p);
+
+ return svp_new;
+}
+#endif
+
+/* Compute the union of two vector paths.
+
+ Status of this routine:
+
+ Basic correctness: Seems to work.
+
+ Numerical stability: We cheat (adding random perturbation). Thus,
+ it seems very likely that no numerical stability problems will be
+ seen in practice.
+
+ Speed: Would be better if we didn't go to unsorted vector path
+ and back to add the perturbation.
+
+ Precision: The perturbation fuzzes the coordinates slightly. In
+ cases of butting segments, razor thin long holes may appear.
+
+*/
+/**
+ * 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)
+{
+#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_POSITIVE);
+ 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_POSITIVE);
+#ifdef VERBOSE
+ print_ps_svp (svp4);
+ print_ps_svp (svp_new);
+#endif
+ art_svp_free (svp4);
+ return svp_new;
+#endif
+}
+
+/* Compute the intersection of two vector paths.
+
+ Status of this routine:
+
+ Basic correctness: Seems to work.
+
+ Numerical stability: We cheat (adding random perturbation). Thus,
+ it seems very likely that no numerical stability problems will be
+ seen in practice.
+
+ Speed: Would be better if we didn't go to unsorted vector path
+ and back to add the perturbation.
+
+ Precision: The perturbation fuzzes the coordinates slightly. In
+ cases of butting segments, razor thin long isolated segments may
+ appear.
+
+*/
+
+/**
+ * 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;
+
+ 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 */
+
+ 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
+}
+
+/* Compute the symmetric difference of two vector paths.
+
+ Status of this routine:
+
+ Basic correctness: Seems to work.
+
+ Numerical stability: We cheat (adding random perturbation). Thus,
+ it seems very likely that no numerical stability problems will be
+ seen in practice.
+
+ Speed: We could do a lot better by scanning through the svp
+ representations and culling out any segments that are exactly
+ identical. It would also be better if we didn't go to unsorted
+ vector path and back to add the perturbation.
+
+ Precision: Awful. In the case of inputs which are similar (the
+ common case for canvas display), the entire outline is "hairy." In
+ addition, the perturbation fuzzes the coordinates slightly. It can
+ be used as a conservative approximation.
+
+*/
+
+/**
+ * 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
+}
+
+#ifdef ART_USE_NEW_INTERSECTOR
+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;
+}
+#endif /* ART_USE_NEW_INTERSECTOR */