Boost-Geometry-Utils

 view release on metacpan or  search on metacpan

src/medial_axis.hpp  view on Meta::CPAN

      color_(0) {
    if (is_linear)
      color_ |= BIT_IS_LINEAR;
    if (is_primary)
      color_ |= BIT_IS_PRIMARY;
  }

  medial_axis_cell_type* cell() { return cell_; }
  const medial_axis_cell_type* cell() const { return cell_; }
  void cell(medial_axis_cell_type* c) { cell_ = c; }

  medial_axis_vertex_type* vertex0() { return vertex_; }
  const medial_axis_vertex_type* vertex0() const { return vertex_; }
  void vertex0(medial_axis_vertex_type* v) { vertex_ = v; }

  medial_axis_vertex_type* vertex1() { return twin_->vertex0(); }
  const medial_axis_vertex_type* vertex1() const { return twin_->vertex0(); }

  medial_axis_edge_type* twin() { return twin_; }
  const medial_axis_edge_type* twin() const { return twin_; }
  void twin(medial_axis_edge_type* e) { twin_ = e; }

  medial_axis_edge_type* next() { return next_; }
  const medial_axis_edge_type* next() const { return next_; }
  void next(medial_axis_edge_type* e) { next_ = e; }

  medial_axis_edge_type* prev() { return prev_; }
  const medial_axis_edge_type* prev() const { return prev_; }
  void prev(medial_axis_edge_type* e) { prev_ = e; }

  // Returns a pointer to the rotation next edge
  // over the starting point of the half-edge.
  medial_axis_edge_type* rot_next() { return prev_->twin(); }
  const medial_axis_edge_type* rot_next() const { return prev_->twin(); }

  // Returns a pointer to the rotation prev edge
  // over the starting point of the half-edge.
  medial_axis_edge_type* rot_prev() { return twin_->next(); }
  const medial_axis_edge_type* rot_prev() const { return twin_->next(); }

  // Returns true if the edge is finite (segment, parabolic arc).
  // Returns false if the edge is infinite (ray, line).
  bool is_finite() const { return vertex0() && vertex1(); }

  // Returns true if the edge is infinite (ray, line).
  // Returns false if the edge is finite (segment, parabolic arc).
  bool is_infinite() const { return !vertex0() || !vertex1(); }

  // Returns true if the edge is linear (segment, ray, line).
  // Returns false if the edge is curved (parabolic arc).
  bool is_linear() const {
    return (color_ & BIT_IS_LINEAR) ? true : false;
  }

  // Returns true if the edge is curved (parabolic arc).
  // Returns false if the edge is linear (segment, ray, line).
  bool is_curved() const {
    return (color_ & BIT_IS_LINEAR) ? false : true;
  }

  // Returns false if edge goes through the endpoint of the segment.
  // Returns true else.
  bool is_primary() const {
    return (color_ & BIT_IS_PRIMARY) ? true : false;
  }

  // Returns true if edge goes through the endpoint of the segment.
  // Returns false else.
  bool is_secondary() const {
    return (color_ & BIT_IS_PRIMARY) ? false : true;
  }

  color_type color() const { return color_ >> BITS_SHIFT; }
  void color(color_type color) const {
    color_ &= BITS_MASK;
    color_ |= color << BITS_SHIFT;
  }
  
  // foot: where radius from vertex0 touches source segment at a 90 degree angle
  const detail::point_2d<default_voronoi_builder::int_type>* foot() const { 
    if (!footset_) {return NULL;}
    return &foot_;
  }
  void foot(coordinate_type x, coordinate_type y) {
    footset_ = true;
    foot_.x(x);
    foot_.y(y);
  }

 private:
  // 5 color bits are reserved.
  enum Bits {
    BIT_IS_LINEAR = 0x1,  // linear is opposite to curved
    BIT_IS_PRIMARY = 0x2,  // primary is opposite to secondary

    BITS_SHIFT = 0x5,
    BITS_MASK = 0x1F
  };

  medial_axis_cell_type* cell_;
  medial_axis_vertex_type* vertex_;
  medial_axis_edge_type* twin_;
  medial_axis_edge_type* next_;
  medial_axis_edge_type* prev_;
  mutable color_type color_;
  mutable detail::point_2d<default_voronoi_builder::int_type> foot_;
  bool footset_;
  mutable detail::point_2d<default_voronoi_builder::int_type> p1_;

};

template <typename T>
struct medial_axis_traits {
  typedef T coordinate_type;
  typedef medial_axis_cell<coordinate_type> cell_type;
  typedef medial_axis_vertex<coordinate_type> vertex_type;
  typedef medial_axis_edge<coordinate_type> edge_type;
  typedef class {
   public:
    enum { ULPS = 128 };
    bool operator()(const vertex_type& v1, const vertex_type& v2) const {
      return (ulp_cmp(v1.x(), v2.x(), ULPS) ==
              detail::ulp_comparison<T>::EQUAL) &&
             (ulp_cmp(v1.y(), v2.y(), ULPS) ==
              detail::ulp_comparison<T>::EQUAL);
    }
   private:

src/medial_axis.hpp  view on Meta::CPAN

event_log_ += "x1=\""+to_str(edge->vertex0()->x())+"\" y1=\""+to_str(edge->vertex0()->y())+"\" ";
event_log_ += "x2=\""+to_str(edge->vertex1()->x())+"\" y2=\""+to_str(edge->vertex1()->y())+"\" />\n";
if (edge->is_primary()) {
event_log_ += "<line style=\"stroke-width:200000;stroke:orange;\" ";
event_log_ += "x1=\""+to_str(edge->vertex0()->x())+"\" y1=\""+to_str(edge->vertex0()->y())+"\" ";
event_log_ += "x2=\""+to_str(edge->vertex1()->x())+"\" y2=\""+to_str(edge->vertex1()->y())+"\" />\n";
} else if (!edge->is_primary()) {
event_log_ += "<line style=\"stroke-width:200000;stroke:aqua;\" ";
event_log_ += "x1=\""+to_str(edge->vertex0()->x())+"\" y1=\""+to_str(edge->vertex0()->y())+"\" ";
event_log_ += "x2=\""+to_str(edge->vertex1()->x())+"\" y2=\""+to_str(edge->vertex1()->y())+"\" />\n";
}
}
}
}

    // Now all edges within the polygon have color() == 0 and all edges
    // outside of the polygon or inside holes in the polygon have 
    // color() == 1.

    /////////////
    // At this point we modify the half edge graph to better represent the 
    // the medial axis.
    // The main thing to do is update next() and prev() pointers to follow
    // along the primary edges that represent the medial axis, instead
    // of having them point just to the next/prev within each Voronoi cell.

    // Get the edge corresponding to the first polygon input segment
    // so the first loop we traverse is the outer polygon loop.
    // Currently it doesn't matter that we process that first, but we
    // may want to enhance the output data structure later to reflect 
    // inside vs outside/in-concavity/in-hole medial axis edge collections.

    edge_type * start_edge = NULL;
    for (edge_iterator it = edges_.begin(); it != edges_.end(); ++it) {
      if (it->cell()->source_index() == 0
          && it->color() == 0
          && it->is_primary()
         ) {
        start_edge = &(*it);
        break;
      }
    }

    // Walk the edge references and modify to represent medial axis.
    while (start_edge != NULL) {
      edge_type * edge = start_edge;
      //start_edge->color(2);
      do {
        // mark visited internal edges (will restore to 0 afterward)
        edge->color(2);

        // if next edge is within polygon
        if (edge->next()->color() == 0 || edge->next()->color() == 2) {
          if (edge->next()->is_primary()) { 
            // go to next edge within same cell 
            edge = edge->next();
          } else { 
            // skip over a non-primary edge to the primary edge that follows it
            edge_type* prev = edge;
            edge = edge->next()->twin()->next();
            // get foot from non-primary endpoint and
            // mirror foot info from the non-primary to the twin
            if (prev->twin()->vertex0() && prev->twin()->vertex1() && prev->next()->vertex1()) {
              // The reflect about line case is simple:
              double x = prev->next()->vertex1()->x();
              double y = prev->next()->vertex1()->y();
              
              if (!edge->foot()) {
                edge->foot(x, y);
              }
              
              double x0 = prev->twin()->vertex0()->x();
              double y0 = prev->twin()->vertex0()->y();
              double x1, y1;
              // would like to already have foot in place
              // but not quite there yet, and this performs well
              if (true || !prev->twin()->foot()) {
                if (!prev->twin()->is_curved()) {
                  double x1 = prev->twin()->vertex1()->x() + 0;
                  double y1 = prev->twin()->vertex1()->y() + 0;
                  reflect(x, y, x0, y0, x1, y1);
                  prev->twin()->foot(x, y);
                  //printf("reflect foot to line\n");
                } else {
                  // The case for a curved edge isn't as simple, but 
                  // it seems most feet in this case are already properly
                  // calculated by the event-processing code.
                  // It may be that we never get to, or should never need to 
                  // get into this else{}. Maybe eliminate this after foot-finding
                  // in the event-processing has been fully understood and
                  // implemented.
                  // ... "reflect foot for parabola" still happens a lot -
                  //     still depending on it
                  if (!prev->twin()->prev()->is_primary()) {
                    //printf("from prev twin prev non-primary\n");
                    prev->twin()->foot(prev->twin()->prev()->vertex0()->x(),
                                       prev->twin()->prev()->vertex0()->y()
                                      );       
                  }
                  else {
                    double x = prev->next()->vertex1()->x();
                    double y = prev->next()->vertex1()->y();
                    if (!edge->is_curved()) {
                      double x0 = edge->vertex0()->x();
                      double y0 = edge->vertex0()->y();
                      double x1 = edge->vertex1()->x();
                      double y1 = edge->vertex1()->y();
                      reflect(x, y, x0, y0, x1, y1);
                      prev->twin()->foot(x, y);
                      //printf("reflect foot for parabola\n");
                    }                  
                  }
                }
              }
            }
            // first make the clipped-out edges ahead link to themselves
            prev->next()->twin()->next(prev->next());
            prev->next()->prev(prev->next()->twin());
            // now link this to new next
            prev->next(edge);
            edge->prev(prev);

src/medial_axis.hpp  view on Meta::CPAN

        );
      if (it->vertex0()) {
        printf("[%f , %f , %f]",
          it->vertex0()->x(),
          it->vertex0()->y(),
          it->vertex0()->r()
        );
      }
      else {printf("no vert0");}
      printf("\n");
      }
    }
    */
  }

 private:
  typedef typename cell_container_type::iterator cell_iterator;
  typedef typename vertex_container_type::iterator vertex_iterator;
  typedef typename edge_container_type::iterator edge_iterator;
  typedef typename TRAITS::vertex_equality_predicate_type
    vertex_equality_predicate_type;

  template <typename SEvent>
  bool is_primary_edge(const SEvent& site1, const SEvent& site2) const {
    bool flag1 = site1.is_segment();
    bool flag2 = site2.is_segment();
    if (flag1 && !flag2) {
      return (site1.point0() != site2.point0()) &&
             (site1.point1() != site2.point0());
    }
    if (!flag1 && flag2) {
      return (site2.point0() != site1.point0()) &&
             (site2.point1() != site1.point0());
    }
    return true;
  }

  template <typename SEvent>
  bool is_linear_edge(const SEvent& site1, const SEvent& site2) const {
    if (!is_primary_edge(site1, site2)) {
      return true;
    }
    return !(site1.is_segment() ^ site2.is_segment());
  }

  // Remove degenerate edge.
  void remove_edge(edge_type* edge) {
    
    // Are these two ifs necessary?
    // Put these in for debugging, where the problem was something else,
    // but these do fill in/transfer some missing feet.
    // After revising the foot-finding (trying to do it all in the sweepline
    // event processing), see if these are still needed.
    if (edge->foot() && !edge->next()->foot()) {
      edge->next()->foot(edge->foot()->x(), edge->foot()->y());
    }
    if (edge->twin()->foot() && !edge->twin()->next()->foot()) {
      edge->twin()->next()->foot(edge->twin()->foot()->x(), edge->twin()->foot()->y());
    }

    // Update the endpoints of the incident edges to the second vertex.
    vertex_type* vertex = edge->vertex0();
    edge_type* updated_edge = edge->twin()->rot_next();
    while (updated_edge != edge->twin()) {
      updated_edge->vertex0(vertex);
      updated_edge = updated_edge->rot_next();
    }
    
    edge_type* edge1 = edge;
    edge_type* edge2 = edge->twin();

    edge_type* edge1_rot_prev = edge1->rot_prev();
    edge_type* edge1_rot_next = edge1->rot_next();

    edge_type* edge2_rot_prev = edge2->rot_prev();
    edge_type* edge2_rot_next = edge2->rot_next();

    // Update prev/next pointers for the incident edges.
    edge1_rot_next->twin()->next(edge2_rot_prev);
    edge2_rot_prev->prev(edge1_rot_next->twin());
    edge1_rot_prev->prev(edge2_rot_next->twin());
    edge2_rot_next->twin()->next(edge1_rot_prev);

  }

  void mark_exterior(edge_type* edge) {
    if (edge->color() == 1) {
      return;
    }
    edge->color(1);
    edge->twin()->color(1);
    edge->cell()->color(1);
    edge->twin()->cell()->color(1);
    vertex_type* v = edge->vertex1();
    if (!v) {v = edge->vertex0();}
    if (v == NULL || !edge->is_primary()) {
      return;
    }
    v->color(1);
    edge_type* e = v->incident_edge();
    do {
      mark_exterior(e);
      e = e->rot_next();
    } while (e != v->incident_edge());
  }

  void mark_interior(edge_type* edge, bool backward = false) {
    // This function seems to work as intended, though it's still
    // on probation. The conditionals in the do {} while(); might not all be
    // correct or necessary (or they might be). 
    edge->color(0);
    edge->twin()->color(0);
    vertex_type* v = edge->vertex0();
    edge_type* e;
    if (edge->is_curved()) {
      edge_type* start_e = (edge->cell()->contains_point()) ? edge : edge->twin();
      e = start_e;
      do {
        if (!e->is_primary()) { 
          e->color(0);
          e->twin()->color(0);



( run in 0.436 second using v1.01-cache-2.11-cpan-483215c6ad5 )