aboutsummaryrefslogblamecommitdiffstats
path: root/libart_lgpl/art_svp_ops.c
blob: 9c5d461bfdf7b64ce5b500caaa78e0dfbbd89371 (plain) (tree)


















                                                                    




































                                                                    

                



















                                                                         





















                                                                






                    




































                                                                          
                              






















                                                                           
/* 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
}