Skip to content

File GeometrySet.h

File List > detail > GeometrySet.h

Go to the documentation of this file

// Copyright (c) 2012-2013, IGN France.
// Copyright (c) 2012-2022, Oslandia.
// SPDX-License-Identifier: LGPL-2.0-or-later

#ifndef _SFCGAL_DETAIL_GEOMETRY_SET_H_
#define _SFCGAL_DETAIL_GEOMETRY_SET_H_

#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/variant.hpp>

#include "SFCGAL/config.h"

#include "SFCGAL/Kernel.h"
#include "SFCGAL/detail/TypeForDimension.h"

#include <CGAL/Bbox_2.h>
#include <CGAL/Bbox_3.h>
#include <CGAL/Box_intersection_d/Box_with_handle_d.h>

// comparison operator on segments, for use in a std::set
bool
operator<(const CGAL::Segment_2<SFCGAL::Kernel> &sega,
          const CGAL::Segment_2<SFCGAL::Kernel> &segb);
bool
operator<(const CGAL::Segment_3<SFCGAL::Kernel> &sega,
          const CGAL::Segment_3<SFCGAL::Kernel> &segb);

namespace SFCGAL {
class Geometry;
namespace detail {

enum PrimitiveType {
  PrimitivePoint   = 0,
  PrimitiveSegment = 1,
  PrimitiveSurface = 2,
  PrimitiveVolume  = 3
};

template <int Dim>
struct PrimitiveHandle {
  //
  // We use boost::variant here for convenience, whereas it is needed
  typedef boost::variant<const typename Point_d<Dim>::Type *,
                         const typename Segment_d<Dim>::Type *,
                         const typename Surface_d<Dim>::Type *,
                         const typename Volume_d<Dim>::Type *>
       Type;
  Type handle;

  template <class T>
  PrimitiveHandle(const T *p) : handle(p)
  {
  }

  template <class T>
  inline const T *
  as() const
  {
    return boost::get<const T *>(handle);
  }
};

template <int Dim>
struct PrimitiveBox {
  typedef CGAL::Box_intersection_d::Box_with_handle_d<double, Dim,
                                                      PrimitiveHandle<Dim> *>
      Type;
};

template <int Dim>
struct BoxCollection {
  typedef std::vector<typename PrimitiveBox<Dim>::Type> Type;
};

template <int Dim>
struct HandleCollection {
  typedef std::list<PrimitiveHandle<Dim>> Type;
};

enum ElementFlag {
  // the polyhedron is planar => build a triangle or a polygon
  FLAG_IS_PLANAR = 1
};

template <class Primitive>
class CollectionElement {
public:
  int
  flags() const
  {
    return _flags;
  }
  void
  setFlags(int flags)
  {
    _flags = flags;
  }

  Primitive &
  primitive()
  {
    return _primitive;
  }
  const Primitive &
  primitive() const
  {
    return _primitive;
  }

  // constructor from Primitive
  CollectionElement() : _flags(0) {}
  CollectionElement(const Primitive &p) : _primitive(p), _flags(0) {}
  CollectionElement(const Primitive &p, int f) : _primitive(p), _flags(f) {}

  CollectionElement(const CollectionElement &other)
      : _primitive(other._primitive), _flags(other._flags)
  {
  }
  bool
  operator<(const CollectionElement &other) const
  {
    return _primitive < other._primitive;
  }

private:
  Primitive _primitive;
  int       _flags;
};

template <class Primitive>
std::ostream &
operator<<(std::ostream &ostr, const CollectionElement<Primitive> &p)
{
  ostr << p.primitive() << " flags: " << p.flags();
  return ostr;
}

template <int Dim>
class GeometrySet {
public:
  // Points are stored in an ordered set
  typedef std::set<CollectionElement<typename Point_d<Dim>::Type>>
      PointCollection;
  // Segments are stored in an ordered set
  typedef std::set<CollectionElement<typename Segment_d<Dim>::Type>>
      SegmentCollection;
  typedef std::list<CollectionElement<typename Surface_d<Dim>::Type>>
      SurfaceCollection;
  typedef std::list<CollectionElement<typename Volume_d<Dim>::Type>>
      VolumeCollection;

  GeometrySet();

  GeometrySet(const Geometry &g);

  GeometrySet(const typename TypeForDimension<Dim>::Point &g, int flags = 0);

  GeometrySet(const typename TypeForDimension<Dim>::Segment &g, int flags = 0);

  GeometrySet(const typename TypeForDimension<Dim>::Surface &g, int flags = 0);

  GeometrySet(const typename TypeForDimension<Dim>::Volume &g, int flags = 0);

  void
  merge(const GeometrySet<Dim> &g);

  void
  addGeometry(const Geometry &g);

  void
  addPrimitive(const PrimitiveHandle<Dim> &p);

  void
  addPrimitive(const CGAL::Object &o, bool pointsAsRing = false);

  void
  addPrimitive(const typename TypeForDimension<Dim>::Point &g, int flags = 0);
  template <class IT>
  void
  addPoints(IT ibegin, IT iend)
  {
    std::copy(ibegin, iend, std::inserter(_points, _points.end()));
  }

  void
  collectPoints(const PrimitiveHandle<Dim> &b);

  void
  addPrimitive(const typename TypeForDimension<Dim>::Segment &g, int flags = 0);
  template <class IT>
  void
  addSegments(IT ibegin, IT iend)
  {
    std::copy(ibegin, iend, std::inserter(_segments, _segments.end()));
  }

  void
  addPrimitive(const typename TypeForDimension<Dim>::Surface &g, int flags = 0);
  template <class IT>
  void
  addSurfaces(IT ibegin, IT iend)
  {
    std::copy(ibegin, iend, std::back_inserter(_surfaces));
  }

  void
  addPrimitive(const typename TypeForDimension<Dim>::Volume &g, int flags = 0);
  template <class IT>
  void
  addVolumes(IT ibegin, IT iend)
  {
    std::copy(ibegin, iend, std::back_inserter(_volumes));
  }

  int
  dimension() const;

  void
  addBoundary(const typename TypeForDimension<Dim>::Surface &surface);

  void
  addBoundary(const typename TypeForDimension<Dim>::Volume &volume);

  void
  computeBoundingBoxes(typename HandleCollection<Dim>::Type &handles,
                       typename BoxCollection<Dim>::Type    &boxes) const;

  inline PointCollection &
  points()
  {
    return _points;
  }
  inline const PointCollection &
  points() const
  {
    return _points;
  }

  inline SegmentCollection &
  segments()
  {
    return _segments;
  }
  inline const SegmentCollection &
  segments() const
  {
    return _segments;
  }

  inline SurfaceCollection &
  surfaces()
  {
    return _surfaces;
  }
  inline const SurfaceCollection &
  surfaces() const
  {
    return _surfaces;
  }

  inline VolumeCollection &
  volumes()
  {
    return _volumes;
  }
  inline const VolumeCollection &
  volumes() const
  {
    return _volumes;
  }

  bool
  hasPoints() const;
  bool
  hasSegments() const;
  bool
  hasSurfaces() const;
  bool
  hasVolumes() const;

  std::unique_ptr<Geometry>
  recompose() const;

  void
  filterCovered(GeometrySet<Dim> &output) const;

private:
  void
  _decompose(const Geometry &g);

  PointCollection   _points;
  SegmentCollection _segments;
  SurfaceCollection _surfaces;
  VolumeCollection  _volumes;
};

SFCGAL_API std::ostream            &
operator<<(std::ostream &, const GeometrySet<2> &g);
SFCGAL_API std::ostream            &
operator<<(std::ostream &, const GeometrySet<3> &g);

// bbox of a 'volume' for 2D, will never be called
inline CGAL::Bbox_2
compute_solid_bbox(const NoVolume &, dim_t<2>)
{
  return CGAL::Bbox_2();
}

inline CGAL::Bbox_3
compute_solid_bbox(const TypeForDimension<3>::Volume &vol, dim_t<3>)
{
  BOOST_ASSERT(vol.size_of_vertices());
  MarkedPolyhedron::Point_const_iterator pit = vol.points_begin();
  CGAL::Bbox_3                           ret(pit->bbox());
  ++pit;

  for (; pit != vol.points_end(); ++pit) {
    ret = ret + pit->bbox();
  }

  return ret;
}
} // namespace detail
} // namespace SFCGAL

#endif