/* 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 2 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, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/* 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;
gint ix;
gint 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;
}
#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);
art_free (svp1_p);
art_free (svp2_p);
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
}