Merge pull request #2259 from efifogel/Set_movable_separability_2-tau
new package: 2D Movable Separability of Sets (2D Casting)
20
.travis.yml
|
|
@ -33,16 +33,16 @@ env:
|
|||
- PACKAGE='Polynomial Polytope_distance_d Principal_component_analysis '
|
||||
- PACKAGE='Profiling_tools QP_solver Random_numbers '
|
||||
- PACKAGE='Ridges_3 Scale_space_reconstruction_3 Segment_Delaunay_graph_2 '
|
||||
- PACKAGE='Segment_Delaunay_graph_Linf_2 Skin_surface_3 Snap_rounding_2 '
|
||||
- PACKAGE='Solver_interface Spatial_searching Spatial_sorting '
|
||||
- PACKAGE='STL_Extension Straight_skeleton_2 Stream_lines_2 '
|
||||
- PACKAGE='Stream_support Subdivision_method_3 Surface_mesh '
|
||||
- PACKAGE='Surface_mesh_deformation Surface_mesher Surface_mesh_parameterization '
|
||||
- PACKAGE='Surface_mesh_segmentation Surface_mesh_shortest_path Surface_mesh_simplification '
|
||||
- PACKAGE='Surface_mesh_skeletonization Sweep_line_2 TDS_2 '
|
||||
- PACKAGE='TDS_3 Three Triangulation '
|
||||
- PACKAGE='Triangulation_2 Triangulation_3 Union_find '
|
||||
- PACKAGE='Visibility_2 Voronoi_diagram_2 '
|
||||
- PACKAGE='Segment_Delaunay_graph_Linf_2 Set_movable_separability_2 Skin_surface_3 '
|
||||
- PACKAGE='Snap_rounding_2 Solver_interface Spatial_searching '
|
||||
- PACKAGE='Spatial_sorting STL_Extension Straight_skeleton_2 '
|
||||
- PACKAGE='Stream_lines_2 Stream_support Subdivision_method_3 '
|
||||
- PACKAGE='Surface_mesh Surface_mesh_deformation Surface_mesher '
|
||||
- PACKAGE='Surface_mesh_parameterization Surface_mesh_segmentation Surface_mesh_shortest_path '
|
||||
- PACKAGE='Surface_mesh_simplification Surface_mesh_skeletonization Sweep_line_2 '
|
||||
- PACKAGE='TDS_2 TDS_3 Three '
|
||||
- PACKAGE='Triangulation Triangulation_2 Triangulation_3 '
|
||||
- PACKAGE='Union_find Visibility_2 Voronoi_diagram_2 '
|
||||
- PACKAGE='Polyhedron_demo'
|
||||
compiler:
|
||||
- clang-3.6
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ Ridges_3
|
|||
Scale_space_reconstruction_3
|
||||
Segment_Delaunay_graph_2
|
||||
Segment_Delaunay_graph_Linf_2
|
||||
Set_movable_separability_2
|
||||
Skin_surface_3
|
||||
Snap_rounding_2
|
||||
Solver_interface
|
||||
|
|
|
|||
|
|
@ -97,6 +97,4 @@ Barycentric_coordinates_2
|
|||
Surface_mesh
|
||||
Surface_mesh_shortest_path
|
||||
Polygon_mesh_processing
|
||||
|
||||
|
||||
|
||||
Set_movable_separability_2
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ h1 {
|
|||
\package_listing{Minkowski_sum_2}
|
||||
\package_listing{Polyline_simplification_2}
|
||||
\package_listing{Visibility_2}
|
||||
\package_listing{Set_movable_separability_2}
|
||||
|
||||
|
||||
\section PartPolyhedra Cell Complexes and Polyhedra
|
||||
|
|
|
|||
|
|
@ -1841,6 +1841,15 @@ ABSTRACT = {We present the first complete, exact and efficient C++ implementatio
|
|||
,update = "97.12 kettner"
|
||||
}
|
||||
|
||||
@inproceedings{ cgal:ss-spfis-16
|
||||
,author = {Shahar Shamai and Dan Halperin}
|
||||
,title = {On the Separation of a Polyhedron from Its Single-Part Mold}
|
||||
,booktitle = {Abstracts 32nd European Workshop Comput. Geom.}
|
||||
,year = {2016}
|
||||
,pages = {99--102}
|
||||
,site = {Lugano}
|
||||
}
|
||||
|
||||
@misc{ cgal:sl-stl-95
|
||||
,author = {Alexander Stepanov and Meng Lee}
|
||||
,title = {The Standard Template Library}
|
||||
|
|
|
|||
|
|
@ -145397,6 +145397,17 @@ of geometric optics."
|
|||
any other by flips."
|
||||
}
|
||||
|
||||
@article{w-sf-76
|
||||
, author = {Neal R. Wagner}
|
||||
, title = {The Sofa Problem}
|
||||
, year = {1976}
|
||||
, journal = {The American Mathematical Monthly}
|
||||
, volume = {83}
|
||||
, number = {3}
|
||||
, pages = {188--189}
|
||||
, doi = {10.2307/2977022}
|
||||
}
|
||||
|
||||
@inproceedings{ww-oedca-00
|
||||
, author = "Uli Wagner and Emo Welzl"
|
||||
, title = "Origin-Embracing Distributions, or A Continuous Analogue of the Upper Bound Theorem"
|
||||
|
|
|
|||
|
|
@ -134,6 +134,13 @@ and <code>src/</code> directories).
|
|||
<div>
|
||||
<p>Release date: April 2018 </p>
|
||||
|
||||
<h3>2D Movable Separability of Sets</h3>
|
||||
<ul>
|
||||
<li><p>A new packaged called "2D Movable Separability of Sets" has been introduced. It handles a class of problems that deal with moving sets of objects in the plane; the challenge is to avoid collisions between the objects while considering different kinds of motions and various definitions of separation.<\p>
|
||||
|
||||
<p>At this point this package consists of the implementations of various predicates and constructions related to castings of polygonal objects. In particular, it can be used to determine whether a feasible mold for a polygonal object does exist. If a mold exists, the package can also be used to compute all possible orientations of the feasible molds and the corresponding motions needed to remove the casted object from the mold.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- Installation (and general changes) -->
|
||||
<!-- New packages -->
|
||||
<!-- Major and breaking changes -->
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2016 GeometryFactory SARL (France).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org); you can redistribute it and/or
|
||||
// modify it under the terms of the GNU Lesser General Public License as
|
||||
// published by the Free Software Foundation; either version 3 of the License,
|
||||
// or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Author(s) : Andreas Fabri
|
||||
//
|
||||
// Warning: this file is generated, see include/CGAL/licence/README.md
|
||||
|
||||
#ifndef CGAL_LICENSE_SET_MOVABLE_SEPARABILITY_2_H
|
||||
#define CGAL_LICENSE_SET_MOVABLE_SEPARABILITY_2_H
|
||||
|
||||
#include <CGAL/config.h>
|
||||
#include <CGAL/license.h>
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef CGAL_SET_MOVABLE_SEPARABILITY_2_COMMERCIAL_LICENSE
|
||||
|
||||
# if CGAL_SET_MOVABLE_SEPARABILITY_2_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE
|
||||
|
||||
# if defined(CGAL_LICENSE_WARNING)
|
||||
|
||||
CGAL_pragma_warning("Your commercial license for CGAL does not cover "
|
||||
"this release of the 2D Movable Separability of Sets package.")
|
||||
# endif
|
||||
|
||||
# ifdef CGAL_LICENSE_ERROR
|
||||
# error "Your commercial license for CGAL does not cover this release \
|
||||
of the 2D Movable Separability of Sets package. \
|
||||
You get this error, as you defined CGAL_LICENSE_ERROR."
|
||||
# endif // CGAL_LICENSE_ERROR
|
||||
|
||||
# endif // CGAL_SET_MOVABLE_SEPARABILITY_2_COMMERCIAL_LICENSE < CGAL_RELEASE_DATE
|
||||
|
||||
#else // no CGAL_SET_MOVABLE_SEPARABILITY_2_COMMERCIAL_LICENSE
|
||||
|
||||
# if defined(CGAL_LICENSE_WARNING)
|
||||
CGAL_pragma_warning("You use the CGAL 2D Movable Separability of Sets package under "
|
||||
"the terms of the GPLv3+.")
|
||||
# endif // CGAL_LICENSE_WARNING
|
||||
|
||||
# ifdef CGAL_LICENSE_ERROR
|
||||
# error "You use the CGAL 2D Movable Separability of Sets package under the terms of \
|
||||
the GPLv3+. You get this error, as you defined CGAL_LICENSE_ERROR."
|
||||
# endif // CGAL_LICENSE_ERROR
|
||||
|
||||
#endif // no CGAL_SET_MOVABLE_SEPARABILITY_2_COMMERCIAL_LICENSE
|
||||
|
||||
#endif // CGAL_LICENSE_CHECK_SET_MOVABLE_SEPARABILITY_2_H
|
||||
|
|
@ -61,6 +61,7 @@ Scale_space_reconstruction_3 Scale-Space Surface Reconstruction
|
|||
SearchStructures dD Range and Segment Trees
|
||||
Segment_Delaunay_graph_2 2D Segment Delaunay Graphs
|
||||
Segment_Delaunay_graph_Linf_2 L Infinity Segment Delaunay Graphs
|
||||
Set_movable_separability_2 2D Movable Separability of Sets
|
||||
Skin_surface_3 3D Skin Surface Meshing
|
||||
Snap_rounding_2 2D Snap Rounding
|
||||
Spatial_searching dD Spatial Searching
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
namespace CGAL {
|
||||
namespace Set_movable_separability_2 {
|
||||
namespace Single_mold_translational_casting {
|
||||
|
||||
/*! \ingroup is_pullout_direction_grp
|
||||
*
|
||||
* Given a simple polygon and a direction, this function determines whether a
|
||||
* cavity (of a mold in the plane) that has the shape of the polygon could be
|
||||
* casted in the mold and then pulled out of the mold in the given direction
|
||||
* without colliding into the mold (but possibly sliding along the mold
|
||||
* surface). If the polygon is not castable at all, the function returns `false`
|
||||
* whatsoever.
|
||||
*
|
||||
* The type that substitutes the template parameter `%CastingTraits_2` must be
|
||||
* a model of the concept `CastingTraits_2`.
|
||||
*
|
||||
* \param polygon the input polygon.
|
||||
* \param d the inspected direction.
|
||||
* \param traits the traits to use.
|
||||
* \return if `polygon` can be pullout in the `d` direction the iterator of the
|
||||
* corresponding top edge, otherwise, `polygon.edges_end()`.
|
||||
* \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple,
|
||||
* and it does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator
|
||||
is_pullout_direction(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
const typename CastingTraits_2::Direction_2& d,
|
||||
const CastingTraits_2& traits = CastingTraits_2());
|
||||
|
||||
/*! \ingroup is_pullout_direction_grp
|
||||
*
|
||||
* Same as above with the additional `orientation` argument.
|
||||
* If the orientation of the polygon is known upon invocation, specify it.
|
||||
* Otherwise, it has to be computed. Note that finding the orientation of a
|
||||
* polygon requires time linear in the number of edges.
|
||||
*
|
||||
* \param polygon the input polygon.
|
||||
* \param d the inspected direction.
|
||||
* \param orientation the orientation of `polygon`.
|
||||
* \param traits the traits to use.
|
||||
* \return if `polygon` can be pullout in the `d` direction the iterator of the
|
||||
* corresponding top edge, otherwise, `polygon.edges_end()`.
|
||||
* \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple,
|
||||
* and it does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator
|
||||
is_pullout_direction(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
const typename CastingTraits_2::Direction_2& d,
|
||||
CGAL::Orientation orientation,
|
||||
const CastingTraits_2& traits = CastingTraits_2());
|
||||
|
||||
/*! \ingroup is_pullout_direction_grp
|
||||
*
|
||||
* Given a simple polygon, an edge of the polygon, and a direction, this
|
||||
* function determines whether a cavity (of a mold in the plane) that has the
|
||||
* shape of the polygon can be used so that the polygon could be casted in the
|
||||
* mold and then pulled out of the mold in the given direction such that the
|
||||
* given edge is used as the top edge without colliding into the mold (but
|
||||
* possibly sliding along the mold surface). Observe, that if polygon can be
|
||||
* pulled out in the given direction, but with a top edge different than the
|
||||
* given one, the function returns `false`.
|
||||
*
|
||||
* The type that substitutes the template parameter `%CastingTraits_2` must be
|
||||
* a model of the concept `CastingTraits_2`.
|
||||
*
|
||||
* \param polygon the input polygon.
|
||||
* \param it an iterator to an edge in polygon.
|
||||
* \param d the tested direction.
|
||||
* \param traits the traits to use.
|
||||
* \return true if `polygon` can be pulled out in the `d` direction with the
|
||||
* edge identified by `i` being the top edge, and `false` otherwise.
|
||||
* \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple,
|
||||
* and it does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
bool is_pullout_direction
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& it,
|
||||
const typename CastingTraits_2::Direction_2& d,
|
||||
const CastingTraits_2& traits = CastingTraits_2());
|
||||
|
||||
/*! \ingroup is_pullout_direction_grp
|
||||
*
|
||||
* Same as above with the additional `orientation` argument.
|
||||
* If the orientation of the polygon is known upon invocation, specify it.
|
||||
* Otherwise, it has to be computed. Note that finding the orientation of a
|
||||
* polygon requires time linear in the number of edges.
|
||||
*
|
||||
* \param polygon the input polygon.
|
||||
* \param it an iterator to an edge in polygon.
|
||||
* \param d the tested direction.
|
||||
* \param orientation the orientation of `polygon`.
|
||||
* \param traits the traits to use.
|
||||
* \return true if `polygon` can be pulled out in the `d` direction with the
|
||||
* edge identified by `i` being the top edge, and `false` otherwise.
|
||||
* \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple,
|
||||
* and it does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
bool is_pullout_direction
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& it,
|
||||
const typename CastingTraits_2::Direction_2& d,
|
||||
CGAL::Orientation orientation,
|
||||
const CastingTraits_2& traits = CastingTraits_2());
|
||||
|
||||
} // namespace Single_mold_translational_casting
|
||||
} // namesapce Set_movable_separability_2
|
||||
} // namesapce CGAL
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
namespace CGAL {
|
||||
namespace Set_movable_separability_2 {
|
||||
namespace Single_mold_translational_casting {
|
||||
|
||||
/*! \ingroup pullout_directions_grp
|
||||
*
|
||||
* Given a simple polygon and an edge of the polygon, this function determines
|
||||
* whether a cavity (of a mold in the plane) that has the shape of the polygon
|
||||
* can be used so that the polygon could be casted in the mold using the input
|
||||
* edge as the top edge and then pulled out of the mold without colliding
|
||||
* into the mold (but possibly sliding along the mold surface). If the polygon
|
||||
* is <em>castable</em> this way, the function computes the closed range of
|
||||
* pullout directions.
|
||||
*
|
||||
* The type that substitutes the template parameter `%CastingTraits_2` must be
|
||||
* a model of the concept `CastingTraits_2`.
|
||||
*
|
||||
* \param polygon the input polygon.
|
||||
* \param it an iterator to an edge in polygon.
|
||||
* \param traits the traits to use.
|
||||
* \return a pair of elements, where the first is a Boolean that indicates
|
||||
* whether the input edge is a valid top edge, and the second
|
||||
* is a closed range of pullout directions represented as a pair
|
||||
* of the extreme directions in the range. If the input edge is not
|
||||
* a valid top edge, the range is nondeterministic.
|
||||
*
|
||||
* \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple,
|
||||
* and it does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
std::pair<bool, std::pair<typename CastingTraits_2::Direction_2,
|
||||
typename CastingTraits_2::Direction_2> >
|
||||
pullout_directions
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& it,
|
||||
CastingTraits_2& traits = CastingTraits_2());
|
||||
|
||||
/*! \ingroup pullout_directions_grp
|
||||
*
|
||||
* Same as above with the additional `orientation` argument.
|
||||
* If the orientation of the polygon is known upon invocation, specify it.
|
||||
* Otherwise, it has to be computed. Note that finding the orientation of a
|
||||
* polygon requires time linear in the number of edges.
|
||||
*
|
||||
* \param polygon the input polygon.
|
||||
* \param it an iterator to an edge in polygon.
|
||||
* \param orientation the orientation of `polygon`.
|
||||
* \param traits the traits to use.
|
||||
* \return a pair of elements, where the first is a Boolean that indicates
|
||||
* whether the input edge is a valid top edge, and the second
|
||||
* is a closed range of pullout directions represented as a pair
|
||||
* of the extreme directions in the range. If the input edge is not
|
||||
* a valid top edge, the range is nondeterministic.
|
||||
*
|
||||
* \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple,
|
||||
* and it does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
std::pair<bool, std::pair<typename CastingTraits_2::Direction_2,
|
||||
typename CastingTraits_2::Direction_2> >
|
||||
pullout_directions
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& it,
|
||||
CGAL::Orientation orientation,
|
||||
CastingTraits_2& traits = CastingTraits_2());
|
||||
|
||||
} // namespace Single_mold_translational_casting
|
||||
} // namesapce Set_movable_separability_2
|
||||
} // namesapce CGAL
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
namespace CGAL {
|
||||
namespace Set_movable_separability_2 {
|
||||
namespace Single_mold_translational_casting {
|
||||
|
||||
/*! \ingroup top_edges_grp
|
||||
*
|
||||
* Given a simple polygon, this function determines whether a cavity (of a mold
|
||||
* in the plane) that has the shape of the polygon can be used so that the
|
||||
* polygon could be casted in the mold and then pulled out of the mold without
|
||||
* colliding into the mold (but possibly sliding along the mold surface). If the
|
||||
* polygon is <em>castable</em>, the function computes the set of top edges of
|
||||
* such cavities and the corresponding closed ranges of pullout directions. Let
|
||||
* \f$n\f$ denote the normal to a top edge \f$e\f$, and let \f$d\f$ denote a
|
||||
* pullout direction of \f$e\f$. Naturally, the angle between \f$n\f$ and
|
||||
* \f$d\f$ must be in the open range (-90°, 90°); that is, \f$n \cdot d
|
||||
* > 0\f$. Each top edge and corresponding range is added to a container
|
||||
* referred to by a given output iterator.
|
||||
*
|
||||
* The type that substitutes the template parameter `%CastingTraits_2` must be
|
||||
* a model of the concept `CastingTraits_2`.
|
||||
*
|
||||
* \param polygon the input polygon.
|
||||
* \param oi the output iterator. Its dereference type is a pair, where
|
||||
* (i) the first element in the pair is an iterator to a top edge,
|
||||
* and
|
||||
* (ii) the second element is a closed range of pullout directions
|
||||
* represented as a pair of the extreme directions in the
|
||||
* range of type `CastingTraits_2::Direction_2`.
|
||||
* \param traits the traits to use.
|
||||
* \return the past-the-end iterator of the output container.
|
||||
* \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple,
|
||||
* and it does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2, typename OutputIterator>
|
||||
OutputIterator top_edges(const CGAL::Polygon_2<CastingTraits>& polygon,
|
||||
OutputIterator oi,
|
||||
CastingTraits_2& traits = CastingTraits_2());
|
||||
|
||||
/*! \ingroup top_edges_grp
|
||||
*
|
||||
* Same as above with the additional `orientation` argument.
|
||||
* If the orientation of the polygon is known upon invocation, specify it.
|
||||
* Otherwise, it has to be computed. Note that finding the orientation of a
|
||||
* polygon requires time linear in the number of edges.
|
||||
*
|
||||
* \param polygon the input polygon.
|
||||
* \param oi the output iterator. Its dereference type is a pair, where
|
||||
* (i) the first element in the pair is an iterator to a top edge,
|
||||
* and
|
||||
* (ii) the second element is a closed range of pullout directions
|
||||
* represented as a pair of the extreme directions in the
|
||||
* range of type `CastingTraits_2::Direction_2`.
|
||||
* \param orientation the orientation of `polygon`.
|
||||
* \param traits the traits to use.
|
||||
* \return the past-the-end iterator of the output container.
|
||||
* \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple,
|
||||
* and it does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2, typename OutputIterator>
|
||||
OutputIterator top_edges(const CGAL::Polygon_2<CastingTraits>& polygon,
|
||||
OutputIterator oi,
|
||||
CGAL::Orientation orientation,
|
||||
CastingTraits_2& traits = CastingTraits_2());
|
||||
|
||||
} // namespace Single_mold_translational_casting
|
||||
} // namesapce Set_movable_separability_2
|
||||
} // namesapce CGAL
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
/*!
|
||||
|
||||
\ingroup PkgSetMovableSeparability2Concepts
|
||||
\cgalConcept
|
||||
|
||||
This concept generalizes the concept of a 2D Kernel.
|
||||
|
||||
\cgalRefines `DefaultConstructible`
|
||||
\cgalRefines `PolygonTraits_2`
|
||||
|
||||
\cgalHasModel Any CGAL kernel, e.g., CGAL::Exact_predicates_exact_constructions_kernel.
|
||||
|
||||
*/
|
||||
|
||||
class CastingTraits_2 {
|
||||
public:
|
||||
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
//! The direction type. Models the concept `Kernel::Direction_2`.
|
||||
typedef unspecified_type Direction_2;
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Functor Types
|
||||
/// @{
|
||||
|
||||
//! Models the concept `Kernel::Counterclockwise_in_between_2`.
|
||||
typedef unspecified_type Counterclockwise_in_between_2;
|
||||
|
||||
//! Models the concept `Kernel::Collinear_2`.
|
||||
typedef unspecified_type Collinear_2;
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Accessing Functor Objects
|
||||
/// @{
|
||||
|
||||
Counterclockwise_in_between_2 counterclockwise_in_between_2_object() const;
|
||||
Collinear_2 collinear_2_object() const;
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
|
||||
|
||||
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Movable Separability of Sets"
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/// \defgroup PkgSetMovableSeparability2 2D Movable Separability of Sets Reference
|
||||
|
||||
/// \defgroup top_edges_grp Top Edges
|
||||
/// These function determine whether a cavity (of a mold in the plane)
|
||||
/// that has the shape of a given polygon could be casted in the mold
|
||||
/// and then pulled out of the mold without colliding into the mold (but
|
||||
/// possibly sliding along the mold boundary).
|
||||
/// \ingroup PkgSetMovableSeparability2
|
||||
|
||||
/// \defgroup is_pullout_direction_grp Is Pullout Direction
|
||||
/// These functions determine whether a cavity (of a mold in the plane)
|
||||
/// that has the shape of a given polygon could be casted in the mold
|
||||
/// and then pulled out of the mold in a given direction without colliding
|
||||
/// into the mold (but possibly sliding along the mold boundary).
|
||||
/// \ingroup PkgSetMovableSeparability2
|
||||
|
||||
/// \defgroup pullout_directions_grp Pullout Directions
|
||||
/// These functions determine whether a cavity (of a mold in the plane)
|
||||
/// that has the shape of a given polygon could be casted in the mold
|
||||
/// using a given edge as the top edge and then pulled out of the mold
|
||||
/// without colliding into the mold (but possibly sliding along the mold
|
||||
/// boundary). If the polygon is <em>castable</em> this way, the function
|
||||
/// computes the closed range of pullout directions.
|
||||
/// \ingroup PkgSetMovableSeparability2
|
||||
|
||||
/// \defgroup PkgSetMovableSeparability2Concepts Concepts
|
||||
/// \ingroup PkgSetMovableSeparability2
|
||||
|
||||
/*!
|
||||
\addtogroup PkgSetMovableSeparability2
|
||||
\cgalPkgDescriptionBegin{2D Movable Separability of Sets,PkgSetMovableSeparability2Summary}
|
||||
\cgalPkgPicture{Casting_2.png}
|
||||
\cgalPkgSummaryBegin
|
||||
\cgalPkgAuthors{Shahar Shamai, Efi Fogel}
|
||||
\cgalPkgDesc{<em>Movable Separability of Sets</em> \cgalCite{t-mss-85} is a
|
||||
class of problems that deal with moving sets of objects, such as polygons in
|
||||
the plane; the challenge is to avoid collisions between the objects
|
||||
while considering different kinds of motions and various definitions
|
||||
of separation.}
|
||||
\cgalPkgManuals{Chapter_SetMovableSeparability2,PkgSetMovableSeparability2}
|
||||
\cgalPkgSummaryEnd
|
||||
\cgalPkgShortInfoBegin
|
||||
\cgalPkgSince{4.12}
|
||||
\cgalPkgDependsOn{\ref PkgPolygon2Summary}
|
||||
\cgalPkgBib{cgal:sf-sms2}
|
||||
\cgalPkgLicense{\ref licensesGPL "GPL"}
|
||||
\cgalPkgShortInfoEnd
|
||||
\cgalPkgDescriptionEnd
|
||||
|
||||
At this point this package consists of the implementations of various predicates and constructions related to castings of polygonal objects. In particular, it can be used to determine whether a feasible mold for a polygonal object does exist. If a mold exists, the package can also be used to compute all possible orientations of the feasible molds and the corresponding motions needed to remove the casted object from the mold.
|
||||
|
||||
\cgalClassifedRefPages
|
||||
|
||||
## Casting Functions ##
|
||||
- `CGAL::Set_movable_separability_2::Single_mold_translational_casting::top_edges()`
|
||||
- `CGAL::Set_movable_separability_2::Single_mold_translational_casting::pullout_directions()`
|
||||
- `CGAL::Set_movable_separability_2::Single_mold_translational_casting::is_pullout_direction()`
|
||||
|
||||
## Casting Concepts ##
|
||||
- `CastingTraits_2`
|
||||
|
||||
*/
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
namespace CGAL {
|
||||
/*!
|
||||
|
||||
\mainpage User Manual
|
||||
\anchor Chapter_SetMovableSeparability2
|
||||
|
||||
\cgalAutoToc
|
||||
\authors Shahar Shamai and Efi Fogel
|
||||
|
||||
\section sms_2_sec_intro Introduction
|
||||
|
||||
<em>Movable Separability of Sets</em> \cgalCite{t-mss-85} is a class
|
||||
of problems that deal with moving sets of objects, such as polygons in
|
||||
the plane; the challenge is to avoid collisions between the objects
|
||||
while considering different kinds of motions and various definitions
|
||||
of separation. The <a
|
||||
href="https://en.wikipedia.org/wiki/Moving_sofa_problem">Moving sofa
|
||||
problem</a> or <em>sofa problem</em> is a classic member of this
|
||||
class. It is a two-dimensional idealisation of real-life
|
||||
furniture-moving problems; it asks for the rigid two-dimensional shape
|
||||
of largest area \f$A\f$ that can be maneuvered through an L-shaped
|
||||
planar region with legs of unit width \cgalCite{w-sf-76}. The area
|
||||
\f$A\f$ thus obtained is referred to as the sofa constant. The exact
|
||||
value of the sofa constant is an open problem; see
|
||||
\cgalFigureRef{sms_2_fig_sofa_problem}. These problems become
|
||||
progressively more challenging as the allowable set of separation
|
||||
motions becomes more complex (have more degrees of freedom), the
|
||||
number of objects involved grows, or the shape of the objects becomes
|
||||
more complicated.
|
||||
|
||||
\cgalFigureBegin{sms_2_fig_sofa_problem,sofa_problem.png} The
|
||||
Hammersley sofa has area 2.2074 but is not the largest solution.
|
||||
\cgalFigureEnd
|
||||
|
||||
At this point this package provides solutions to one subclass of
|
||||
problems related to 2D castings. In particular, each of these
|
||||
solutions handles a single moving polygon and a single stationary
|
||||
polygon, and considers a single translation of the moving polygon.
|
||||
|
||||
\section sms_2_sec_casting Casting
|
||||
|
||||
Casting is a manufacturing process where liquid material is poured
|
||||
into a cavity inside a mold, which has the shape of a desired
|
||||
product. (The mold can take any shape and form as long as it has a
|
||||
cavity of the desired shape.) After the material solidifies, the
|
||||
product is pulled out of the mold. Typically a mold is used to
|
||||
manufacture numerous copies of a product. The challenge is designing a
|
||||
proper mold, such that the solidified product can be separated from
|
||||
its mold without breaking it.
|
||||
|
||||
This package provides a function called
|
||||
`CGAL::Set_movable_separability_2::Single_mold_translational_casting::top_edges()`
|
||||
that, given a simple closed polygon \f$P\f$, determines whether a
|
||||
cavity (of a mold in the plane) that has the shape of \f$P\f$ can be
|
||||
used so that the polygon \f$P\f$ could be pulled out of the mold
|
||||
without colliding into the mold (but possibly sliding along the mold
|
||||
boundary); see \cgalFigureRef{sms_2_fig_polygons} for an
|
||||
illustration. In reality, the mold of a <em>castable</em> polygon must
|
||||
be rotated before the polygon is casted, such that one edge becomes
|
||||
parallel to the \f$x\f$-axis and is located above all other edges;
|
||||
such an edge is referred to as a <em>top edge</em>. A polygon may have
|
||||
up to four edges that can serve as top edges. If the polygon is
|
||||
<em>castable</em>, the function computes the set of top edges of such
|
||||
cavities and the corresponding closed ranges of pullout directions in
|
||||
the plane.
|
||||
|
||||
\cgalFigureBegin{sms_2_fig_polygons,polygons.png}
|
||||
Two castable polygons (light grey) in their molds (darker grey) and
|
||||
valid pullout directions on the left. Two non-castable polygons on the
|
||||
right.
|
||||
\cgalFigureEnd
|
||||
|
||||
The input polygon must satisfy two conditions as follows. First, it
|
||||
has to be simple. Essentially, a simple polygon is topologically
|
||||
equivalent to a disk; see Chapter \ref
|
||||
Chapter_2D_Regularized_Boolean_Set-Operations "2D Regularized Boolean
|
||||
Set-Operations" for the precise definition of simple
|
||||
polygons. Secondly, any consecutive three vertices cannot be
|
||||
collinear. If you suspect that the input polygon may not satisfy the
|
||||
latter condition, pre-process the polygon to elliminate this
|
||||
ill-condition.
|
||||
|
||||
The implementation is based on an algorithm developed by Shamai and
|
||||
Halperin; see \cgalCite{cgal:ss-spfis-16} for the generalization of
|
||||
the algorithm to 3D. The time and space complexities are in \f$O(n)\f$
|
||||
and \f$O(1)\f$, respectively. In order to ensure robustness and
|
||||
correctness you must use a kernel that guarantees exact
|
||||
constructions as well as exact predicates, e,g,.
|
||||
`Exact_predicates_exact_constructions_kernel`.
|
||||
|
||||
The following example computes the top edges and their pullout
|
||||
directions of an input polygon read from a file and reports the results.
|
||||
|
||||
|
||||
\cgalExample{Set_movable_separability_2/top_edges_single_mold_trans_cast.cpp}
|
||||
|
||||
This package provides two additional functions, namely,
|
||||
`CGAL::Set_movable_separability_2::Single_mold_translational_casting::pullout_directions()`
|
||||
and
|
||||
`CGAL::Set_movable_separability_2::Single_mold_translational_casting::is_pullout_direction()`.
|
||||
The former accepts a simple closed polygon \f$P\f$ and an edge \f$e\f$
|
||||
of the polygon \f$P\f$; it determines whether \f$e\f$ is a top edge of
|
||||
\f$P\f$, and if so, it computes the range of pullout directions of
|
||||
\f$e\f$. The latter is overloaded with two versions: The first version
|
||||
accepts a simple closed polygon \f$P\f$ and a direction \f$d\f$; it
|
||||
determines whether \f$d\f$ is a pullout direction of some top edge of
|
||||
\f$P\f$. The other version accepts, in addition, an edge \f$e\f$ of
|
||||
the polygon \f$P\f$; it determines whether \f$d\f$ is a pullout
|
||||
direction of \f$e\f$.
|
||||
|
||||
Overloads of each of the functions above that accept (i) an additional
|
||||
argument that indicates the orientation of the input polygon or (ii) an
|
||||
additional traits argument, or (iii) both, are also provided by the package.
|
||||
|
||||
*/
|
||||
|
||||
} /* namespace CGAL */
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Manual
|
||||
Kernel_23
|
||||
Circulator
|
||||
Number_types
|
||||
Polygon
|
||||
Boolean_set_operations_2
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/*!
|
||||
\example Set_movable_separability_2/is_pullout_direction_single_mold_trans_cast.cpp
|
||||
\example Set_movable_separability_2/pullout_directions_single_mold_trans_cast.cpp
|
||||
\example Set_movable_separability_2/top_edges_single_mold_trans_cast.cpp
|
||||
*/
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
|
@ -0,0 +1,30 @@
|
|||
# Created by the script cgal_create_cmake_script
|
||||
# This is the CMake script for compiling a CGAL application.
|
||||
|
||||
project( Set_movable_separability_2_Examples )
|
||||
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_generalized_initializers has_cpp11)
|
||||
if (has_cpp11 LESS 0)
|
||||
message(STATUS "NOTICE: These examples requires a C++11 compiler and will not be compiled.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Use C++11 for this directory and its sub-directories.
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
|
||||
find_package(CGAL QUIET COMPONENTS )
|
||||
|
||||
if (CGAL_FOUND)
|
||||
include( ${CGAL_USE_FILE} )
|
||||
include( CGAL_CreateSingleSourceCGALProgram )
|
||||
include_directories (BEFORE "../../include")
|
||||
create_single_source_cgal_program( "top_edges_single_mold_trans_cast.cpp" )
|
||||
create_single_source_cgal_program( "is_pullout_direction_single_mold_trans_cast.cpp" )
|
||||
create_single_source_cgal_program( "pullout_directions_single_mold_trans_cast.cpp" )
|
||||
|
||||
else()
|
||||
message(STATUS "This program requires the CGAL library, and will not be compiled.")
|
||||
endif()
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
#include <fstream>
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef Kernel::Vector_2 Vector_2;
|
||||
typedef Kernel::Point_2 Point_2;
|
||||
typedef Kernel::Direction_2 Direction_2;
|
||||
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
||||
|
||||
namespace SMS = CGAL::Set_movable_separability_2;
|
||||
namespace casting = SMS::Single_mold_translational_casting;
|
||||
|
||||
// The main program:
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Polygon_2 polygon;
|
||||
|
||||
const char* filename = (argc > 1) ? argv[1] : "polygon.dat";
|
||||
std::ifstream input_file(filename);
|
||||
if (! input_file.is_open()) {
|
||||
std::cerr << "Failed to open the " << filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
input_file >> polygon;
|
||||
input_file.close();
|
||||
|
||||
// Example for is_pullout_direction_single_mold_translational_casting_2 that
|
||||
// accepts the edge
|
||||
size_t index(0);
|
||||
for (auto e_it = polygon.edges_begin(); e_it != polygon.edges_end(); ++e_it,
|
||||
++index)
|
||||
{
|
||||
auto orientation = polygon.orientation();
|
||||
auto segment_outer_circle =
|
||||
SMS::internal::get_segment_outer_circle<Kernel>(*e_it, orientation);
|
||||
auto d = segment_outer_circle.first;
|
||||
d = d.perpendicular(CGAL::CLOCKWISE);
|
||||
auto res = casting::is_pullout_direction(polygon, e_it, d);
|
||||
std::cout << "The polygon is " << (res ? "" : "not ")
|
||||
<< "castable using edge "
|
||||
<< index << " in vartical translation (" << d << ")" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
std::cout << "-----------------------------------"<< std::endl;
|
||||
|
||||
// Example for is_pullout_direction_single_mold_translational_casting_2 that
|
||||
// do not accepts the edge
|
||||
{
|
||||
Vector_2 v (Point_2(0,0), Point_2(1,0));
|
||||
Direction_2 d(v);
|
||||
auto res = casting::is_pullout_direction(polygon, d);
|
||||
if (res != polygon.edges_end()) {
|
||||
std::cout << "The polygon is castable in direction d (" << d
|
||||
<< ") using edge "<< *res << std::endl;
|
||||
|
||||
}
|
||||
else {
|
||||
std::cout << "The polygon is not castable in direction d (" << d << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
4
|
||||
0 0 1 0 1 1 0 1
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
#include <fstream>
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
||||
|
||||
namespace SMS = CGAL::Set_movable_separability_2;
|
||||
namespace casting = SMS::Single_mold_translational_casting;
|
||||
|
||||
// The main program:
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Polygon_2 polygon;
|
||||
|
||||
const char* filename = (argc > 1) ? argv[1] : "polygon.dat";
|
||||
std::ifstream input_file(filename);
|
||||
if (! input_file.is_open()) {
|
||||
std::cerr << "Failed to open the " << filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
input_file >> polygon;
|
||||
input_file.close();
|
||||
|
||||
// Example for pullout_directions_single_mold_translational_casting_2
|
||||
size_t index(0);
|
||||
for (auto e_it = polygon.edges_begin(); e_it != polygon.edges_end(); ++e_it,
|
||||
++index)
|
||||
{
|
||||
auto res = casting::pullout_directions(polygon, e_it);
|
||||
if (res.first) {
|
||||
std::cout << "The polygon is castable using edge " << index
|
||||
<< " in range " << res.second.first
|
||||
<< " to " << res.second.second << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cout << "The polygon is not castable using edge " << index
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
8
|
||||
-1 0 -7 7 0 1 7 7 1 0 7 -7 0 -1 -7 -7
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#include <list>
|
||||
#include <fstream>
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
||||
typedef Kernel::Direction_2 Direction_2;
|
||||
typedef Kernel::Vector_2 Vector_2;
|
||||
typedef Kernel::Point_2 Point_2;
|
||||
|
||||
// A direction range is a closed range of directions on the unit circle.
|
||||
typedef std::pair<Direction_2, Direction_2> Direction_range;
|
||||
typedef Polygon_2::Edge_const_iterator Edge_iter;
|
||||
|
||||
// A top edge is identified by the index to an edge of a polygon and the
|
||||
// corresponding range of pullout directions.
|
||||
typedef std::pair<Edge_iter, Direction_range> Top_edge;
|
||||
|
||||
namespace SMS = CGAL::Set_movable_separability_2;
|
||||
namespace casting = SMS::Single_mold_translational_casting;
|
||||
|
||||
// The main program:
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Polygon_2 polygon;
|
||||
|
||||
const char* filename = (argc > 1) ? argv[1] : "polygon.dat";
|
||||
std::ifstream input_file(filename);
|
||||
if (! input_file.is_open()) {
|
||||
std::cerr << "Failed to open the " << filename << std::endl;
|
||||
return -1;
|
||||
}
|
||||
input_file >> polygon;
|
||||
input_file.close();
|
||||
|
||||
std::list<Top_edge> top_edges;
|
||||
|
||||
// Example for top_edges_single_mold_translational_casting_2
|
||||
casting::top_edges(polygon, std::back_inserter(top_edges));
|
||||
if (top_edges.empty())
|
||||
std::cout << "The polygon is not castable!" << std::endl;
|
||||
else {
|
||||
std::cout << "There are " << top_edges.size() << " top edges:" << std::endl;
|
||||
for (const auto& top_edge : top_edges) {
|
||||
std::cout
|
||||
<< "\tEdge: " << *top_edge.first<< std::endl
|
||||
<< "\tPullout directions from: " << top_edge.second.first
|
||||
<< " to " << top_edge.second.second
|
||||
<< std::endl << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
4
|
||||
0 -1 1 0 1 1 0 7
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
3
|
||||
0 0 1 0 1 1
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
// Copyright (c) 2016 Tel-Aviv University (Israel).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Author(s): Shahar <shasha94@gmail.com>
|
||||
// Efi Fogel <efif@gmail.com>
|
||||
|
||||
#ifndef CGAL_SMS_2_IS_PULLOUT_DIRECTION_SINGLE_MOLD_TRANSLATIONAL_CASTING_H
|
||||
#define CGAL_SMS_2_IS_PULLOUT_DIRECTION_SINGLE_MOLD_TRANSLATIONAL_CASTING_H
|
||||
|
||||
#include <CGAL/license/Set_movable_separability_2.h>
|
||||
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <CGAL/enum.h>
|
||||
#include <CGAL/Set_movable_separability_2/internal/Utils.h>
|
||||
#include <CGAL/Set_movable_separability_2/internal/Circle_arrangment.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Set_movable_separability_2 {
|
||||
namespace Single_mold_translational_casting {
|
||||
|
||||
/*! Given a simple polygon, an edge of the polygon and a pullout direction (not
|
||||
* rotated) this function determines whether a cavity (of a mold in the plane)
|
||||
* that has the shape of the polygon can be used so that the polygon could be
|
||||
* casted in the mold with the input edge and being the top edge and then pulled
|
||||
* out in the input direction (without rotation) of the mold without colliding
|
||||
* into the mold (but possibly sliding along the mold surface).
|
||||
*
|
||||
* The type that substitutes the template parameter `%CastingTraits_2` must be
|
||||
* a model of the concept `CastingTraits_2`.
|
||||
*
|
||||
* \param[in] pgn the input polygon.
|
||||
* \param[in] it an iterator to an edge in pgn.
|
||||
* \param[in] orientation the orientation of `pgn`.
|
||||
* \param[in] d the pullout direction
|
||||
* \return if the polygon can be pullout through edge i with direction d
|
||||
*
|
||||
* \pre `png` must be non-degenerate (has at least 3 vertices), simple, and
|
||||
* does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
bool is_pullout_direction
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& i,
|
||||
const typename CastingTraits_2::Direction_2& d,
|
||||
CGAL::Orientation orientation, CastingTraits_2& traits)
|
||||
{
|
||||
//NOT CHECKED AT ALL
|
||||
CGAL_precondition(pgn.is_simple());
|
||||
CGAL_precondition(!internal::is_any_edge_colinear(pgn, traits));
|
||||
|
||||
auto e_it = pgn.edges_begin();
|
||||
auto cc_in_between = traits.counterclockwise_in_between_2_object();
|
||||
|
||||
for (; e_it != pgn.edges_end(); ++e_it) {
|
||||
auto segment_outer_circle =
|
||||
internal::get_segment_outer_circle<CastingTraits_2>(*e_it, orientation);
|
||||
bool isordered = !cc_in_between(d, segment_outer_circle.second,
|
||||
segment_outer_circle.first);
|
||||
if (isordered == (e_it == i)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*! Same as above without the traits argument.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
bool is_pullout_direction
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& i,
|
||||
const typename CastingTraits_2::Direction_2& d, CGAL::Orientation orientation)
|
||||
{
|
||||
CastingTraits_2 traits;
|
||||
return is_pullout_direction(pgn, i, d, orientation, traits);
|
||||
}
|
||||
|
||||
/*! Same as above without the orientation and traits arguments.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
bool is_pullout_direction
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& i,
|
||||
const typename CastingTraits_2::Direction_2& d)
|
||||
{
|
||||
CGAL::Orientation orientation = pgn.orientation();
|
||||
CastingTraits_2 traits;
|
||||
return is_pullout_direction(pgn, i, d, orientation, traits);
|
||||
}
|
||||
|
||||
/*! Same as above without the orientation argument.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
bool is_pullout_direction
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& i,
|
||||
const typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits)
|
||||
{
|
||||
CGAL::Orientation orientation = pgn.orientation();
|
||||
return is_pullout_direction(pgn, i, d, orientation, traits);
|
||||
}
|
||||
|
||||
/*! Given a simple polygon, and a pullout direction (not rotated)
|
||||
* this function determines whether a cavity (of a mold in the plane)
|
||||
* that has the shape of the polygon can be used so that the polygon could be
|
||||
* casted in the mold with the input edge and being the top edge and then pulled
|
||||
* out in the input direction (without rotation) of the mold without colliding
|
||||
* into the mold (but possibly sliding along the mold surface).
|
||||
*
|
||||
* The type that substitutes the template parameter `%CastingTraits_2` must be
|
||||
* a model of the concept `CastingTraits_2`.
|
||||
*
|
||||
* \param[in] pgn the input polygon.
|
||||
* \param[in] d the pullout direction
|
||||
* \return if the polygon can be pullout through some edge with direction d
|
||||
* the top edge, otherwise, pgn.edges_end()
|
||||
*
|
||||
* \pre `png` must be non-degenerate (has at least 3 vertices),simple, and
|
||||
* does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator
|
||||
is_pullout_direction(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
typename CastingTraits_2::Direction_2& d,
|
||||
CGAL::Orientation orientation, CastingTraits_2& traits)
|
||||
{
|
||||
//NOT CHECKED AT ALL
|
||||
typedef CGAL::Polygon_2<CastingTraits_2> Polygon_2;
|
||||
typedef typename Polygon_2::Edge_const_iterator Edge_iter;
|
||||
|
||||
CGAL_precondition(pgn.is_simple());
|
||||
CGAL_precondition(!internal::is_any_edge_colinear(pgn, traits));
|
||||
|
||||
Edge_iter e_it = pgn.edges_begin();
|
||||
auto segment_outer_circle =
|
||||
internal::get_segment_outer_circle<CastingTraits_2>(*e_it++, orientation);
|
||||
auto cc_in_between = traits.counterclockwise_in_between_2_object();
|
||||
Edge_iter top_edge= pgn.edges_end();
|
||||
for (; e_it != pgn.edges_end(); ++e_it) {
|
||||
segment_outer_circle =
|
||||
internal::get_segment_outer_circle<CastingTraits_2>(*e_it, orientation);
|
||||
bool isordered = !cc_in_between(d,
|
||||
segment_outer_circle.second,
|
||||
segment_outer_circle.first);
|
||||
if (!isordered) {
|
||||
// unlikely, this if must be true atleast once for any polygon - add ref
|
||||
// to paper
|
||||
if (top_edge== pgn.edges_end()) top_edge=e_it;
|
||||
else return pgn.edges_end();
|
||||
}
|
||||
}
|
||||
CGAL_postcondition(top_edge!=pgn.edges_end());
|
||||
return top_edge;
|
||||
}
|
||||
|
||||
/*! Same as above without the traits argument.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator
|
||||
is_pullout_direction(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
typename CastingTraits_2::Direction_2& d,
|
||||
CGAL::Orientation orientation)
|
||||
{
|
||||
CastingTraits_2 traits;
|
||||
return is_pullout_direction(pgn, d, orientation, traits);
|
||||
}
|
||||
|
||||
/*! Same as above without the orientation argument.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator
|
||||
is_pullout_direction(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
typename CastingTraits_2::Direction_2& d,
|
||||
CastingTraits_2& traits)
|
||||
{
|
||||
CGAL::Orientation orientation = pgn.orientation();
|
||||
return is_pullout_direction(pgn, d, orientation, traits);
|
||||
}
|
||||
|
||||
/*! Same as above without the orientation and traits arguments.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator
|
||||
is_pullout_direction(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
typename CastingTraits_2::Direction_2& d)
|
||||
{
|
||||
CGAL::Orientation orientation = pgn.orientation();
|
||||
CastingTraits_2 traits;
|
||||
return is_pullout_direction(pgn, d, orientation, traits);
|
||||
}
|
||||
|
||||
} // namespace Single_mold_translational_casting
|
||||
} // namesapce Set_movable_separability_2
|
||||
} // namesapce CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
// Copyright (c) 2016 Tel-Aviv University (Israel).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Author(s): Shahar <shasha94@gmail.com>
|
||||
// Efi Fogel <efif@gmail.com>
|
||||
|
||||
#ifndef CGAL_SMS_2_PULLOUT_DIRECTIONS_SINGLE_MOLD_TRANSLATIONAL_CASTING_H
|
||||
#define CGAL_SMS_2_PULLOUT_DIRECTIONS_SINGLE_MOLD_TRANSLATIONAL_CASTING_H
|
||||
|
||||
#include <CGAL/license/Set_movable_separability_2.h>
|
||||
|
||||
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <CGAL/Set_movable_separability_2/internal/Utils.h>
|
||||
#include <CGAL/Set_movable_separability_2/internal/Circle_arrangment.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Set_movable_separability_2 {
|
||||
namespace Single_mold_translational_casting {
|
||||
|
||||
/*! Same as below with the additional traits argument.
|
||||
* \param[in] traits the traits to use.
|
||||
*
|
||||
* algorithm:
|
||||
* this function implements a very simple algorithm... it just keep at any stage the current
|
||||
* intersection in [firstClockwise,secondClockwise].
|
||||
* When a new semicircle appear the possible cases are as such:
|
||||
* (let f:=firstClockwise, s:=secondClockwise, a:=newSemicircleFirstClockwise , b:=newSemicircleSecondClockwise)
|
||||
* REMEBER THAT THIS ARE SEGMENTS ON A CIRCLE! NOT ON A LINE!
|
||||
* 1. [f,s] contained in [a,b]
|
||||
* f s * f s * f s * f s
|
||||
* a b * a b * a b * a b
|
||||
* _________________ * _________________ * _________________* _________________
|
||||
* f s * f s * f s * f s
|
||||
* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
* 2. a contained in (f,s] and b is not / or in other words / s in [a,b) and f is not in [a,b] (it is enough to ask if s is in [a,b] since fs+ab is less than 2*pi)
|
||||
* f s * f s
|
||||
* a b * a b
|
||||
* _________________ * _________________
|
||||
* f s * fs
|
||||
* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
* 3. b contained in [f,s) and a is not / or in other words / f in (a,b] and s is not in [a,b] (it is enough to ask if f is in [a,b] since fs is shorter the ab)
|
||||
* f s * f s
|
||||
* a b * a b
|
||||
* _________________ * _________________
|
||||
* f s * fs
|
||||
* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
* 4. no intersection between [f,s] and [a,b] / case a: or in other words / f,s are not in [a,b]
|
||||
* f s * f s
|
||||
* b a * b a
|
||||
* _________________ * _________________
|
||||
* NO INTERSECTION! * NO INTERSECTION! (the only case in which this is possible is if (f,s) was not changes, and then (f,s) is an open arc)
|
||||
* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
* 5. Illegal cases
|
||||
* f s * f s
|
||||
* a b * b a
|
||||
* __________________* __________________
|
||||
* THIS CASE CANT HAPPEN!! [a,b] is an semicircle, and (f,s) is a semicircle or less
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
std::pair<bool, std::pair<typename CastingTraits_2::Direction_2,
|
||||
typename CastingTraits_2::Direction_2> >
|
||||
pullout_directions
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& i,
|
||||
CGAL::Orientation orientation,
|
||||
CastingTraits_2& traits)
|
||||
{
|
||||
CGAL_precondition(pgn.is_simple());
|
||||
CGAL_precondition(!internal::is_any_edge_colinear(pgn, traits));
|
||||
CGAL_precondition(pgn.edges_end()!=i);
|
||||
|
||||
typedef CastingTraits_2 Casting_traits_2;
|
||||
//the returned range is [clock_first, clock_second]
|
||||
typename Casting_traits_2::Direction_2 clock_first, clock_second;
|
||||
|
||||
|
||||
auto segment_outer_circle =
|
||||
internal::get_segment_outer_circle<Casting_traits_2>(*i, orientation);
|
||||
clock_first = segment_outer_circle.first;
|
||||
clock_second = segment_outer_circle.second;
|
||||
//well theoretically, this is a bug since the current intersection is
|
||||
//currently (clock_first,clock_second) and not [clock_first,clock_second].. but
|
||||
//this edges will surly change since we are in a polygon
|
||||
|
||||
bool is_range_smaller_than_semicircle(false);
|
||||
auto cc_in_between = traits.counterclockwise_in_between_2_object();
|
||||
|
||||
for (auto e_it = pgn.edges_begin(); e_it != pgn.edges_end(); ++e_it) {
|
||||
if (e_it==i) continue;
|
||||
// std::cout << "f " << clock_first << " s " << clock_second << std::endl;
|
||||
auto segment_outer_circle =
|
||||
internal::get_segment_outer_circle<Casting_traits_2>(*e_it, orientation);
|
||||
// std::cout << "a "<< segment_outer_circle.second << " b "
|
||||
// << segment_outer_circle.first<<std::endl;
|
||||
|
||||
// notice that we are interested in the segment_inner_circle
|
||||
// (segment_outer_circle.second,segment_outer_circle.first)
|
||||
if (!is_range_smaller_than_semicircle) {
|
||||
if ((segment_outer_circle.first == clock_second) &&
|
||||
(segment_outer_circle.second == clock_first))
|
||||
{
|
||||
// std::cout<<"case 1b"<<std::endl<<std::endl;
|
||||
// the arc is the range case 1b
|
||||
continue;
|
||||
}
|
||||
if ((segment_outer_circle.first == clock_first) &&
|
||||
(segment_outer_circle.second == clock_second))
|
||||
{
|
||||
// std::cout<<"case 4b"<<std::endl<<std::endl;
|
||||
|
||||
// the arc the opposite of the range case 4b
|
||||
return std::make_pair(false, std::make_pair(clock_first, clock_second));
|
||||
}
|
||||
is_range_smaller_than_semicircle = true;
|
||||
}
|
||||
bool f_between_ab = !cc_in_between(clock_first, segment_outer_circle.second,
|
||||
segment_outer_circle.first);
|
||||
//is true if segment_outer_circle \in [first,clock_first,clock_second]
|
||||
bool s_between_ab = !cc_in_between(clock_second,
|
||||
segment_outer_circle.second,
|
||||
segment_outer_circle.first);
|
||||
//is true if segment_outer_circle \in [first,clock_first,clock_second]
|
||||
if (f_between_ab && s_between_ab) {
|
||||
// std::cout<<"case 1"<<std::endl<<std::endl;
|
||||
// case 1 //surly not case 4b since [f,s] is less then a semicircle
|
||||
continue;
|
||||
}
|
||||
if (!f_between_ab && s_between_ab) {
|
||||
// std::cout<<"case 2"<<std::endl<<std::endl;
|
||||
// case 2 - return a,s
|
||||
clock_first = segment_outer_circle.second;
|
||||
}
|
||||
else if(f_between_ab && !s_between_ab) {
|
||||
// std::cout<<"case 3"<<std::endl<<std::endl;
|
||||
// case 3 - return f,b
|
||||
clock_second = segment_outer_circle.first;
|
||||
}
|
||||
else {
|
||||
// std::cout<<"case 4a"<<std::endl<<std::endl;
|
||||
//case 4a
|
||||
return std::make_pair(false, std::make_pair(clock_first, clock_second));
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_pair(true, std::make_pair(clock_first, clock_second));
|
||||
}
|
||||
|
||||
/*! Given a simple polygon and an edge of the polygon, this function determines
|
||||
* whether a cavity (of a mold in the plane) that has the shape of the polygon
|
||||
* can be used so that the polygon could be casted in the mold with the input
|
||||
* edge being the top edge and then pulled out of the mold without colliding
|
||||
* into the mold (but possibly sliding along the mold surface). If the polygon
|
||||
* is <em>castable</em> this way, the function computes the closed range of pull
|
||||
* directions.
|
||||
*
|
||||
* The type that substitutes the template parameter `%CastingTraits_2` must be
|
||||
* a model of the concept `CastingTraits_2`.
|
||||
*
|
||||
* \param[in] pgn the input polygon.
|
||||
* \param[in] i the iterator of an edge in pgn.
|
||||
* \return a pair of elements, where the first is a Boolean that indicates
|
||||
* whether the input edge is a valid top edge, and the second
|
||||
* is a closed range of pull-out directions represented as a pair
|
||||
* of the extreme directions in the range. If the input edge is not
|
||||
* a valid top edge, the range is nondeterministic.
|
||||
* a pair of Directions is build this way [firstClockwise,secondClockwise]
|
||||
*
|
||||
* \pre `png` must be non-degenerate (has at least 3 vertices), simple, and
|
||||
* does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
std::pair<bool, std::pair<typename CastingTraits_2::Direction_2,
|
||||
typename CastingTraits_2::Direction_2> >
|
||||
pullout_directions
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& it,
|
||||
CGAL::Orientation orientation)
|
||||
{
|
||||
CastingTraits_2 traits;
|
||||
return pullout_directions(pgn, it, orientation, traits);
|
||||
}
|
||||
|
||||
/*! Same as above with the orientation argument.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
std::pair<bool, std::pair<typename CastingTraits_2::Direction_2,
|
||||
typename CastingTraits_2::Direction_2> >
|
||||
pullout_directions
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& it,
|
||||
CastingTraits_2& traits)
|
||||
{
|
||||
CGAL::Orientation orientation = pgn.orientation();
|
||||
return pullout_directions(pgn, it, orientation, traits);
|
||||
}
|
||||
|
||||
/*! Same as above with the orientation and traits arguments.
|
||||
*/
|
||||
template <typename CastingTraits_2>
|
||||
std::pair<bool, std::pair<typename CastingTraits_2::Direction_2,
|
||||
typename CastingTraits_2::Direction_2> >
|
||||
pullout_directions
|
||||
(const CGAL::Polygon_2<CastingTraits_2>& pgn,
|
||||
const typename CGAL::Polygon_2<CastingTraits_2>::Edge_const_iterator& it)
|
||||
{
|
||||
CGAL::Orientation orientation = pgn.orientation();
|
||||
CastingTraits_2 traits;
|
||||
return pullout_directions(pgn, it, orientation, traits);
|
||||
}
|
||||
|
||||
} // namespace Single_mold_translational_casting
|
||||
} // namespace Set_movable_separability_2
|
||||
} // namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright (c) 2016 Tel-Aviv University (Israel).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Author(s): Shahar <shasha94@gmail.com>
|
||||
// Efi Fogel <efif@gmail.com>
|
||||
|
||||
#ifndef CGAL_SMS_2_TOP_EDGES_SINGLE_MOLD_TRANSLATIONAL_CASTING_H
|
||||
#define CGAL_SMS_2_TOP_EDGES_SINGLE_MOLD_TRANSLATIONAL_CASTING_H
|
||||
|
||||
#include <CGAL/license/Set_movable_separability_2.h>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <CGAL/enum.h>
|
||||
#include <CGAL/Set_movable_separability_2/internal/Circle_arrangment.h>
|
||||
#include <CGAL/Set_movable_separability_2/internal/Utils.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Set_movable_separability_2 {
|
||||
namespace Single_mold_translational_casting {
|
||||
|
||||
/* Legend:
|
||||
* point = Represented as Direction_2. It is the intersection between the
|
||||
* fitting Direction_2 and the unit circle
|
||||
*
|
||||
* Arc = Represented as A pair of point. clockwise arc between the first
|
||||
* point and the second point. (each of its sides might be open or closed)
|
||||
*
|
||||
* SegmentOuterCircle = Arc that represent all the directions that points
|
||||
* out from the polygon if it start from the
|
||||
* fitting segment. This arc is always open half circle.
|
||||
*/
|
||||
|
||||
/*! \ingroup PkgSetMovableSeparability2Funcs
|
||||
*
|
||||
* Same as above with the additional `orientation` argument.
|
||||
* If the orientation of the polygon is known upon invocation, specify it.
|
||||
* Otherwise, it has to be computed. Note that finding the orientation of a
|
||||
* polygon requires time linear in the number of edges.
|
||||
*
|
||||
* \param polygon the input polygon.
|
||||
* \param oi the output iterator. Its value type is a pair, where
|
||||
* (i) the first element in the pair is an iterator to a top edge, and
|
||||
* (ii) the second element is a closed range of pullout directions
|
||||
* represented as a pair of the extreme directions in the range
|
||||
* of type `CastingTraits::Direction_2`.
|
||||
* \param orientation the orientation of `polygon`.
|
||||
* \param traits the traits to use.
|
||||
* \return the past-the-end iterator of the output container.
|
||||
* \pre `polygon` must be non-degenerate (has at least 3 vertices), simple, and
|
||||
* does not have three consecutive collinear vertices.
|
||||
*/
|
||||
template <typename CastingTraits_2, typename OutputIterator>
|
||||
OutputIterator top_edges(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
OutputIterator oi,
|
||||
CGAL::Orientation orientation,
|
||||
CastingTraits_2& traits)
|
||||
{
|
||||
/* Legend
|
||||
* point = Represented as Direction_2. It is the intersection between the
|
||||
* fitting Direction_2 and the unit circle
|
||||
*
|
||||
* arc = Represented as A pair of point. clockwise arc between the first
|
||||
* point and the second point. (each of its sides might be open or closed)
|
||||
*/
|
||||
typedef CastingTraits_2 Traits;
|
||||
|
||||
CGAL_precondition(polygon.is_simple());
|
||||
CGAL_precondition(!internal::is_any_edge_colinear(polygon, traits));
|
||||
|
||||
auto e_it = polygon.edges_begin();
|
||||
auto segment_outer_circle =
|
||||
internal::get_segment_outer_circle<Traits>(*e_it++, orientation);
|
||||
typedef internal::Circle_arrangment<Traits> Circle_arrangment;
|
||||
Circle_arrangment circle_arrangment(traits,
|
||||
segment_outer_circle,polygon.edges_begin());
|
||||
|
||||
for (; e_it != polygon.edges_end(); ++e_it) {
|
||||
segment_outer_circle =
|
||||
internal::get_segment_outer_circle<Traits>(*e_it, orientation);
|
||||
circle_arrangment.add_segment_outer_circle(segment_outer_circle, e_it);
|
||||
if (circle_arrangment.all_is_covered_twice()) return oi;
|
||||
}
|
||||
circle_arrangment.get_all_1_edges(oi);
|
||||
return oi;
|
||||
}
|
||||
|
||||
/*! \fn OutputIterator top_edges(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
* OutputIterator oi, CastingTraits_2& traits)
|
||||
* \param polygon the input polygon that we want to check if is castable or not.
|
||||
* \param oi the output iterator to put the top edges in
|
||||
* \param traits the traits to use.
|
||||
* \return all the possible top edges of the polygon and there pullout direction
|
||||
* a pair of Directions is build this way [firstClockwise,secondClockwise]
|
||||
* (with no rotation)
|
||||
*/
|
||||
template <typename CastingTraits_2, typename OutputIterator>
|
||||
OutputIterator top_edges(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
OutputIterator oi, CastingTraits_2& traits)
|
||||
{
|
||||
CGAL::Orientation orientation = polygon.orientation();
|
||||
return top_edges(polygon, oi, orientation, traits);
|
||||
}
|
||||
|
||||
/*! \fn OutputIterator top_edges(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
* OutputIterator oi)
|
||||
* \param polygon the input polygon that we want to check if is castable or not.
|
||||
* \param oi the output iterator to put the top edges in
|
||||
* \param orientation the orientation of `polygon`.
|
||||
* \return all the possible top edges of the polygon and there pullout direction
|
||||
* a pair of Directions is build this way [firstClockwise,secondClockwise]
|
||||
* (with no rotation)
|
||||
*/
|
||||
template <typename CastingTraits_2, typename OutputIterator>
|
||||
OutputIterator top_edges(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
OutputIterator oi, CGAL::Orientation orientation)
|
||||
{
|
||||
CastingTraits_2 traits;
|
||||
return top_edges(polygon, oi, orientation, traits);
|
||||
}
|
||||
|
||||
/*! \fn OutputIterator top_edges(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
* OutputIterator oi)
|
||||
* \param polygon the input polygon that we want to check if is castable or not.
|
||||
* \param oi the output iterator to put the top edges in
|
||||
* \return all the possible top edges of the polygon and there pullout direction
|
||||
* a pair of Directions is build this way [firstClockwise,secondClockwise]
|
||||
* (with no rotation)
|
||||
*/
|
||||
template <typename CastingTraits_2, typename OutputIterator>
|
||||
OutputIterator top_edges(const CGAL::Polygon_2<CastingTraits_2>& polygon,
|
||||
OutputIterator oi)
|
||||
{
|
||||
CGAL::Orientation orientation = polygon.orientation();
|
||||
CastingTraits_2 traits;
|
||||
return top_edges(polygon, oi, orientation, traits);
|
||||
}
|
||||
|
||||
} // namespace Single_mold_translational_casting
|
||||
} // namespace Set_movable_separability_2
|
||||
} // namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
// Copyright (c) 2005,2006,2007,2008,2009,2010,2011 Tel-Aviv University (Israel).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Author(s): Shahar <shasha94@gmail.com>
|
||||
// Efi Fogel <efif@gmail.com>
|
||||
|
||||
#ifndef CGAL_SET_MOVABLE_SEPARABILITY_2_INTERNAL_CIRCLE_ARRANGMENT_H
|
||||
#define CGAL_SET_MOVABLE_SEPARABILITY_2_INTERNAL_CIRCLE_ARRANGMENT_H
|
||||
|
||||
#include <CGAL/license/Set_movable_separability_2.h>
|
||||
|
||||
|
||||
#include <CGAL/enum.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
/* Legend:
|
||||
* point = Represented as Direction_2. It is the intersection between the
|
||||
* fitting Direction_2 and the unit circle
|
||||
*
|
||||
* Arc = Represented as A pair of point. clockwise arc between the first
|
||||
* point and the second point. (each of its sides might be open or closed)
|
||||
*
|
||||
* SegmentOuterCircle = Arc that represent all the directions that points
|
||||
* out from the polygon if it start from the
|
||||
* fitting segment. This arc is always open half circle.
|
||||
*/
|
||||
|
||||
/*! \Circle_arrangment
|
||||
* \brief This class represents an subdivision of the unit-circle into cells of
|
||||
* depth 0,1,2+ where depth is the number of inserted open half-circles inserted
|
||||
* that covers this cell in addition this class contains some static functions
|
||||
* that are in this class inorder of sharing its typedefs all the circle is
|
||||
* always covered by some cell. there can't be an hole
|
||||
*/
|
||||
|
||||
namespace CGAL {
|
||||
namespace Set_movable_separability_2 {
|
||||
namespace internal {
|
||||
|
||||
template <typename Kernel>
|
||||
class Circle_arrangment {
|
||||
typedef typename Kernel::Direction_2 Point;
|
||||
typedef std::pair<Point, Point> Arc;
|
||||
typedef typename CGAL::Polygon_2<Kernel>::Edge_const_iterator Edge_iter;
|
||||
|
||||
/* Legend:
|
||||
* Point = Represented as Direction_2. It is the intersection between the
|
||||
* fitting Direction_2 and the unit circle
|
||||
*
|
||||
* Arc = Represented as a pair of points. clockwise arc between the first
|
||||
* point and the second point. (each of its sides might be open or closed)
|
||||
*/
|
||||
|
||||
/*! \fn bool is_open_direction_contained_in_arc(point p, bool is_counterclockwise, Arc A)
|
||||
* Checks whether an open epsilon area clockwise/counterclockwise from a point
|
||||
* p is contained in an arc s.
|
||||
* \param[in] p a point .
|
||||
* \param[in] is_counterclockwise true: we care about the counterclockwise
|
||||
* epsilon area of p. false: same with clockwise
|
||||
* \param[in] A an Arc that should contain the epsilon area
|
||||
*/
|
||||
bool is_open_direction_contained_in_arc(const Point p,
|
||||
const bool is_counterclockwise,
|
||||
const Arc A) const
|
||||
{
|
||||
if ((is_counterclockwise && (p == A.second)) ||
|
||||
(!is_counterclockwise && (p == A.first)))
|
||||
return false;
|
||||
auto cc_in_between = m_kernel.counterclockwise_in_between_2_object();
|
||||
return !cc_in_between(p, A.first, A.second);
|
||||
}
|
||||
|
||||
/*! \fn bool is_a_contained_in_b(bool is_a_start_closed,bool is_a_end_closed, arc A, arc B)
|
||||
* \brief checks whether an arc A is contained in an arc B
|
||||
* \param[in] is_a_start_closed - do A contains its start point (clockwise)
|
||||
* \param[in] is_a_end_closed - do A contains its end point (clockwise)
|
||||
* \param[in] A - an arc
|
||||
* \param[in] B - an *open* arc
|
||||
*/
|
||||
bool is_a_contained_in_b(const bool is_a_start_closed,
|
||||
const bool is_a_end_closed,
|
||||
const Arc A,const Arc B) const
|
||||
{
|
||||
//A is closed, B is open and they share an vertex -> A not contained in B
|
||||
if ((is_a_start_closed &&(A.first == B.first)) ||
|
||||
(is_a_end_closed && (A.second == B.second)))
|
||||
return false;
|
||||
if ((A.first == B.second) || (B.first == A.second)) return false;
|
||||
auto cc_in_between = m_kernel.counterclockwise_in_between_2_object();
|
||||
return (!cc_in_between(A.first, B.first, B.second) &&
|
||||
!cc_in_between(A.second, B.first, B.second) &&
|
||||
!cc_in_between(A.first, B.first, A.second));
|
||||
}
|
||||
|
||||
/*! \Circle_arrangment_edge
|
||||
* This class represents a cells (a point or an arc) of depth 0,1,2+ in the
|
||||
* Circle_arrangment where depth the number of inserted open half-circles
|
||||
* inserted that cover this cell
|
||||
* This edge (cell) is described by the first point of the edge (clockwise).
|
||||
* The last point can be deduced by the next instance of
|
||||
* Circle_arrangment_edge in the list in Circle_arrangment
|
||||
* this class also keeps the cell depth.
|
||||
*/
|
||||
class Circle_arrangment_edge {
|
||||
public:
|
||||
bool m_start_is_closed;
|
||||
|
||||
Point m_edge_start_angle; // the end is the start of the next edge
|
||||
|
||||
uint8_t m_count; // no. of outer circles that cover the edge (0/1/2+)
|
||||
|
||||
Edge_iter m_edge_iter; // the iterator of the polygon edge the open
|
||||
// half-circle of which covers this cell.
|
||||
// only relevant if m_count ==1
|
||||
|
||||
/*! \ctor Circle_arrangment_edge(point edge_start_angle, const Edge_iter edge_iter, bool start_is_closed,bool set_count_to_one=true)
|
||||
* Creates a new edge (Arc), this edge count must be 0 or 1
|
||||
* \param[in] edge_start_angle the first point of the arc (clockwise)
|
||||
* \param[in] edge_iter the iterator of the polygon edge who's open
|
||||
* half-circle covers this cell - only relevant if m_count == 1
|
||||
* \param[in] start_is_closed - is the point edge_start_angle contained in
|
||||
* this cell
|
||||
* \param[in] set_count_to_one to set the m_count to one (or zero if this
|
||||
* var is false)
|
||||
*/
|
||||
Circle_arrangment_edge(const Point edge_start_angle,
|
||||
const Edge_iter edge_iter,
|
||||
const bool start_is_closed,
|
||||
const bool set_count_to_one = true)
|
||||
{
|
||||
this->m_start_is_closed = start_is_closed;
|
||||
this->m_edge_start_angle = edge_start_angle;
|
||||
this->m_count = (int) set_count_to_one;
|
||||
this->m_edge_iter = edge_iter;
|
||||
}
|
||||
|
||||
/*! \fn void plusplus(const Edge_iter edge_ite)
|
||||
* Adds new polygon edge who's open half-circle covers this cell
|
||||
* \param[in] edge_ite - the iterator of this edge
|
||||
* increase the edge m_count by one (if it is 2+, it will stay 2+)
|
||||
* set this new edge to be the one covers the cell if the m_count was zero
|
||||
* before. (only relevant if now m_count == 1)
|
||||
*/
|
||||
void plusplus(const Edge_iter edge_iter)
|
||||
{
|
||||
if (this->m_count ==0) {
|
||||
this->m_edge_iter = edge_iter;
|
||||
this->m_count = 1;
|
||||
}
|
||||
else if(this->m_count ==1) this->m_count = 2;
|
||||
}
|
||||
bool is_covered() { return m_count == 2; }
|
||||
};
|
||||
|
||||
typedef typename std::list<Circle_arrangment_edge> Circle_edges;
|
||||
|
||||
//! The kernel to use.
|
||||
const Kernel& m_kernel;
|
||||
|
||||
Circle_edges m_edges;
|
||||
|
||||
/*! \fn void insert_if_legal(const Circle_edge_iterator cur_it,
|
||||
* const Circle_edge_iterator next_it,
|
||||
* const Circle_arrangment_edge &edge)
|
||||
* Adds new edge to the arrangement if it won't create some empty edges
|
||||
* \param[in] cur_it iterator to the edge before where the new edge should be
|
||||
* inserted
|
||||
* \param[in] next_it iterator to the edge after where the new edge should be
|
||||
* inserted
|
||||
* \param[in] edge the new edge that should be inserted
|
||||
*
|
||||
* Notice that next_it is redundant since it can be deduced from cur_it.
|
||||
* But it was easier for me to just send it as well.
|
||||
*/
|
||||
template <typename InputIterator>
|
||||
void insert_if_legal(const InputIterator cur_it,
|
||||
InputIterator next_it,
|
||||
const Circle_arrangment_edge& edge)
|
||||
{
|
||||
if (((edge.m_start_is_closed && !next_it->m_start_is_closed) ||
|
||||
(edge.m_edge_start_angle != next_it->m_edge_start_angle)) &&
|
||||
((cur_it->m_start_is_closed && !edge.m_start_is_closed) ||
|
||||
(edge.m_edge_start_angle != cur_it->m_edge_start_angle)))
|
||||
{
|
||||
m_edges.insert(next_it, edge);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*! \fn void merge_adjacent_2_edges_and_remove_empty()
|
||||
* \brief merge all the arcs that are adjacent and of depth 2+
|
||||
* it doesn't merge the first and last ones since it is easier this way.
|
||||
*/
|
||||
void merge_adjacent_2_edges_and_remove_empty()
|
||||
{
|
||||
bool in_two_edge(false);
|
||||
for (auto it = m_edges.begin(); it != m_edges.end();) {
|
||||
if (it->is_covered()) {
|
||||
if (in_two_edge) {
|
||||
it = m_edges.erase(it);
|
||||
continue;
|
||||
}
|
||||
in_two_edge = true;
|
||||
}
|
||||
else {
|
||||
in_two_edge = false;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/*! \ctor Circle_arrangment(arc first_segment_outer_circle)
|
||||
* Creates an arrangement on circle with two edges the one covered by
|
||||
* first_segment_outer_circle and the other one
|
||||
* \param[in] first_segment_outer_circle the outer circle of the first segment
|
||||
* of the polygon.
|
||||
* Notice that you might consider implementing the ctor as an full circle of
|
||||
* depth 0, but it was much easier for me to ignore the case where the all
|
||||
* circle is a single arc, so I choose this implementation.
|
||||
*/
|
||||
Circle_arrangment(const Kernel& kernel, const Arc first_segment_outer_circle,
|
||||
const Edge_iter edge_iter) :
|
||||
m_kernel(kernel)
|
||||
{
|
||||
m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first,
|
||||
edge_iter, false));
|
||||
m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second,
|
||||
edge_iter, true, false));
|
||||
}
|
||||
|
||||
/*! \fn add_segment_outer_circle(arc segment_outer_circle, const Edge_iter edge_ite)
|
||||
* Updates the arrangement in respect to a new segment outer open circle
|
||||
* \param[in] segment_outer_circle - the outer circle of the current segment of
|
||||
* the polygon.
|
||||
* \param[in] edge_ite this segment iterator
|
||||
* This is the main funtion of this code. It separates the cells in which the
|
||||
* endpoints of the new arc is contained to two parts and increase m_count
|
||||
* for all the cells that the new arc covers. In the end the function
|
||||
* merge_adjacent_2_edges_and_remove_empty is called to remove redundant cells
|
||||
*/
|
||||
void add_segment_outer_circle(const Arc segment_outer_circle,
|
||||
const Edge_iter edge_iter)
|
||||
{
|
||||
Arc edge;
|
||||
bool is_start_closed_segment = m_edges.begin()->m_start_is_closed;
|
||||
bool is_end_closed_segment ;
|
||||
edge.first = m_edges.begin()->m_edge_start_angle;
|
||||
//edge.second ;
|
||||
auto next_it = m_edges.begin();
|
||||
auto it = m_edges.begin();
|
||||
bool done = false;
|
||||
while (!done) {
|
||||
it = next_it;
|
||||
next_it = it;
|
||||
++next_it;
|
||||
if (next_it == m_edges.end()) {
|
||||
done = true;
|
||||
next_it = m_edges.begin();
|
||||
}
|
||||
|
||||
is_start_closed_segment =it->m_start_is_closed;
|
||||
is_end_closed_segment = !next_it->m_start_is_closed;
|
||||
edge.first = it->m_edge_start_angle;
|
||||
edge.second =next_it->m_edge_start_angle;
|
||||
|
||||
if (it->m_count == 2) continue;
|
||||
if (is_a_contained_in_b(is_start_closed_segment, is_end_closed_segment,
|
||||
edge, segment_outer_circle))
|
||||
{
|
||||
it->plusplus(edge_iter);
|
||||
continue;
|
||||
}
|
||||
bool is_start_contained =
|
||||
is_open_direction_contained_in_arc(segment_outer_circle.first, true,
|
||||
edge);
|
||||
bool is_end_contained =
|
||||
is_open_direction_contained_in_arc(segment_outer_circle.second, false,
|
||||
edge);
|
||||
// o~~~~~~~~~~~~o = new arc
|
||||
// ?------------? = "old" arc (the edge from the array)
|
||||
if (is_start_contained) {
|
||||
if (is_end_contained) {
|
||||
auto cc_in_between = m_kernel.counterclockwise_in_between_2_object();
|
||||
bool isordered = !cc_in_between(segment_outer_circle.second,
|
||||
segment_outer_circle.first,
|
||||
edge.second);
|
||||
if (isordered) {
|
||||
// o~~~~~~~~~~~~o
|
||||
// ?-----------------------?
|
||||
// __________________________
|
||||
// ?----c
|
||||
// o~-~-~-~-~-~-o
|
||||
// c-----?
|
||||
Circle_arrangment_edge edge2 = *it;
|
||||
edge2.m_start_is_closed = false;
|
||||
edge2.m_edge_start_angle = segment_outer_circle.first;
|
||||
edge2.plusplus(edge_iter);
|
||||
this->insert_if_legal(it, next_it, edge2);
|
||||
Circle_arrangment_edge edge3 = *it;
|
||||
edge3.m_start_is_closed = true;
|
||||
edge3.m_edge_start_angle = segment_outer_circle.second;
|
||||
this->insert_if_legal(it,next_it,edge3);
|
||||
}
|
||||
else {
|
||||
// ...~~~~~~~~~o o~~~~~~~~~~... (round)
|
||||
// ?-----------?
|
||||
// __________________________
|
||||
// ?~-~o
|
||||
// c---c
|
||||
// o-~-?
|
||||
Circle_arrangment_edge edge2 = *it;
|
||||
edge2.m_start_is_closed = true;
|
||||
edge2.m_edge_start_angle = segment_outer_circle.second;
|
||||
this->insert_if_legal(it, next_it, edge2);
|
||||
Circle_arrangment_edge edge3 = *it;
|
||||
edge3.m_start_is_closed = false;
|
||||
edge3.m_edge_start_angle = segment_outer_circle.first;
|
||||
edge3.plusplus(edge_iter);
|
||||
this->insert_if_legal(it, next_it, edge3);
|
||||
it->plusplus(edge_iter);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// o~~~~~~~~~~~~o
|
||||
// ?-----------?
|
||||
//_____________________
|
||||
// ?----c
|
||||
// o-~-~-~?
|
||||
Circle_arrangment_edge edge2 = *it;
|
||||
edge2.m_start_is_closed = false;
|
||||
edge2.m_edge_start_angle = segment_outer_circle.first;
|
||||
edge2.plusplus(edge_iter);
|
||||
this->insert_if_legal(it, next_it, edge2);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (is_end_contained) {
|
||||
// o~~~~~~~~~~~~o
|
||||
// ?------------?
|
||||
//_____________________
|
||||
// ?-~-~-~-o
|
||||
// c----?
|
||||
Circle_arrangment_edge edge2 = *it;
|
||||
edge2.m_start_is_closed = true;
|
||||
edge2.m_edge_start_angle = segment_outer_circle.second;
|
||||
it->plusplus(edge_iter);
|
||||
this->insert_if_legal(it, next_it, edge2);
|
||||
}
|
||||
//else - no intersection, do noting
|
||||
}
|
||||
}
|
||||
merge_adjacent_2_edges_and_remove_empty();
|
||||
}
|
||||
|
||||
#if 0
|
||||
// debug function
|
||||
void printArrangement()
|
||||
{
|
||||
for (auto it = m_edges.begin(); it != m_edges.end(); ++it) {
|
||||
if (it->m_start_is_closed) std::cout<<")[";
|
||||
else std::cout << "](";
|
||||
std::cout << it->m_edge_start_angle;
|
||||
std::cout << ","<<(int)it->m_count;
|
||||
}
|
||||
std::cout << "\n\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! \fn void get_all_1_edges(OutputIterator oi)
|
||||
* Insert to oi all the cells in depth 1 i.e. the cells that represent legal
|
||||
* pullout directions
|
||||
* \param[in, out] oi the output iterator to put the cells in
|
||||
* Puts in oi var of type pair<size_t, std::pair<Kernel::Direction_2,
|
||||
* Kernel::Direction_2 > > foreach valid top edge.
|
||||
* Should only be called after all of the polygon edges where inserted.
|
||||
*/
|
||||
template <typename OutputIterator>
|
||||
OutputIterator get_all_1_edges(OutputIterator oi)
|
||||
{
|
||||
for (auto it = m_edges.begin(); it != m_edges.end();) {
|
||||
if ((*it).m_count == 1) {
|
||||
std::pair<Edge_iter, Arc> edge;
|
||||
edge.first = (*it).m_edge_iter;
|
||||
edge.second.first = (*it).m_edge_start_angle;
|
||||
++it;
|
||||
edge.second.second =
|
||||
(*((it == m_edges.end()) ? m_edges.begin() : (it))).m_edge_start_angle;
|
||||
*oi++ = edge;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return oi;
|
||||
}
|
||||
|
||||
/*! \fn bool all_is_covered_twice()
|
||||
* Before running this run merge_adjacent_2_edges_and_remove_empty() or
|
||||
* add_segment_outer_circle() which calls
|
||||
* merge_adjacent_2_edges_and_remove_empty().
|
||||
*
|
||||
* The funtions checks that the whole circle is a single cell, which can
|
||||
* happen only if this cell is of depth 2, so there is no need to check the
|
||||
* depth as well.
|
||||
* \return if all of the arrangement is in depth 2+
|
||||
*/
|
||||
bool all_is_covered_twice() { return m_edges.size() == 1; }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Set_movable_separability_2
|
||||
} // namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright (c) 2005,2006,2007,2008,2009,2010,2011 Tel-Aviv University (Israel).
|
||||
// All rights reserved.
|
||||
//
|
||||
// This file is part of CGAL (www.cgal.org).
|
||||
// You can redistribute it and/or modify it under the terms of the GNU
|
||||
// General Public License as published by the Free Software Foundation,
|
||||
// either version 3 of the License, or (at your option) any later version.
|
||||
//
|
||||
// Licensees holding a valid commercial license may use this file in
|
||||
// accordance with the commercial license agreement provided with the software.
|
||||
//
|
||||
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
||||
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
//
|
||||
// Author(s): Shahar <shasha94@gmail.com>
|
||||
// Efi Fogel <efif@gmail.com>
|
||||
|
||||
#ifndef CGAL_SET_MOVABLE_SEPARABILITY_2_INTERNAL_UTILS_H
|
||||
#define CGAL_SET_MOVABLE_SEPARABILITY_2_INTERNAL_UTILS_H
|
||||
|
||||
#include <CGAL/license/Set_movable_separability_2.h>
|
||||
|
||||
|
||||
#include <CGAL/enum.h>
|
||||
#include <CGAL/Polygon_2.h>
|
||||
|
||||
namespace CGAL {
|
||||
namespace Set_movable_separability_2 {
|
||||
namespace internal {
|
||||
|
||||
/*! \fn std::pair<typename Kernel::Direction_2,typename Kernel::Direction_2> get_segment_outer_circle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation)
|
||||
* \param[in] seg the polygon segment
|
||||
* \param[in] orientation the orientation of the segment (and the polygon).
|
||||
* if CLOCKWISE then the outer half circle is to the left.
|
||||
* \return the open outer half-circle of the edge.
|
||||
*/
|
||||
template <typename Kernel>
|
||||
inline std::pair<typename Kernel::Direction_2, typename Kernel::Direction_2>
|
||||
get_segment_outer_circle(const typename Kernel::Segment_2 seg,
|
||||
const CGAL::Orientation orientation)
|
||||
{
|
||||
typename Kernel::Direction_2 forward( seg);
|
||||
typename Kernel::Direction_2 backward(-forward);
|
||||
return (orientation == CGAL::CLOCKWISE) ?
|
||||
std::make_pair(backward, forward) : std::make_pair(forward, backward);
|
||||
}
|
||||
|
||||
template <typename Kernel>
|
||||
bool is_any_edge_colinear(const CGAL::Polygon_2<Kernel>& pgn, Kernel& kernel)
|
||||
{
|
||||
typedef typename Kernel::Point_2 Point_2;
|
||||
typedef typename CGAL::Polygon_2<Kernel> Polygon_2;
|
||||
typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator;
|
||||
auto collinear = kernel.collinear_2_object();
|
||||
Vertex_const_iterator vci = pgn.vertices_begin();
|
||||
Point_2 firstVar = *(vci++);
|
||||
Point_2 secondVar = *(vci++);
|
||||
Point_2 thirdVar = *(vci++);
|
||||
for (; vci != pgn.vertices_end(); ++vci) {
|
||||
firstVar = secondVar;
|
||||
secondVar = thirdVar;
|
||||
thirdVar = *vci;
|
||||
if (collinear(firstVar, secondVar, thirdVar)) return true;
|
||||
}
|
||||
vci = pgn.vertices_begin();
|
||||
firstVar = secondVar;
|
||||
secondVar = thirdVar;
|
||||
thirdVar = *(vci++);
|
||||
if(collinear(firstVar, secondVar, thirdVar)) return true;
|
||||
|
||||
firstVar = secondVar;
|
||||
secondVar = thirdVar;
|
||||
thirdVar = *(vci++);
|
||||
if (collinear(firstVar, secondVar, thirdVar)) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Set_movable_separability_2
|
||||
} // namespace CGAL
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1 @@
|
|||
Tel-Aviv University (Israel).
|
||||
|
|
@ -0,0 +1 @@
|
|||
Various predicates and operations that solves movable-separability problems of sets in the plane. At this point only predicates and operations related to catings of planar objects, such as given a polygonal object, is there a mold for it from which is can be pulled out.
|
||||
|
|
@ -0,0 +1 @@
|
|||
GPL (v3 or later)
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
Movable Separability of Sets is a class of problems that deal with moving sets of objects, such as polygons in the plane; the challange is to avoid collisions between the objects while considering different kinds of motions and various definitions of separation. At this point this package provides solutions to one subclass of problems related to 2D castings. In particular, each of these solutions handles a single moving polygon and a single stationary polygon, and considers a single translation of the moving polygon.
|
||||
|
||||
The casting process is a form of manufacturing, where liquid material is poured into a mold, it solidifies, and then the object is pulled from the mold. The mold has to be designed in such a way that the object can be removed without breaking the mold. This is not always possible (e.g., a circle).
|
||||
|
||||
This package consists of the implementations of various predicates and operations related to castings of polygonal objects. In particular, it can be used to determine whether a mold for a polygonal object does exist. If a mold exists, the package can also used to compute all possible orientations of the feasible molds and the corresponding motions needed to remove the casted object from the mold.
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Shahar Shamai <shasha94@gmail.com>
|
||||
Efi Fogel <efif@post.tau.ac.il>
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
# Created by the script cgal_create_cmake_script
|
||||
# This is the CMake script for compiling a CGAL application.
|
||||
|
||||
project( Set_movable_separability_2_Tests )
|
||||
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
if (RUNNING_CGAL_AUTO_TEST)
|
||||
# Just to avoid a warning from CMake when that variable is set on the command line...
|
||||
endif()
|
||||
if (CGAL_DIR)
|
||||
# Just to avoid a warning from CMake when that variable is set on the command line...
|
||||
endif()
|
||||
|
||||
list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_generalized_initializers has_cpp11)
|
||||
if (has_cpp11 LESS 0)
|
||||
message(STATUS "NOTICE: These examples requires a C++11 compiler and will not be compiled.")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Use C++11 for this directory and its sub-directories.
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
|
||||
|
||||
find_package(CGAL QUIET COMPONENTS )
|
||||
|
||||
if (CGAL_FOUND)
|
||||
include( ${CGAL_USE_FILE} )
|
||||
include( CGAL_CreateSingleSourceCGALProgram )
|
||||
include_directories (BEFORE "../../include")
|
||||
create_single_source_cgal_program( "test_top_edges_single_mold_trans_cast.cpp" )
|
||||
create_single_source_cgal_program( "test_is_pullout_directions_single_mold_trans_cast.cpp" )
|
||||
|
||||
else()
|
||||
message(STATUS "This program requires the CGAL library, and will not be compiled.")
|
||||
endif()
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
#! /bin/sh
|
||||
|
||||
# This is a script for the CGAL test suite. Such a script must obey
|
||||
# the following rules:
|
||||
#
|
||||
# - the name of the script is cgal_test_with_cmake
|
||||
# - for every target two one line messages are written to the file 'error.txt'
|
||||
# the first one indicates if the compilation was successful
|
||||
# the second one indicates if the execution was successful
|
||||
# if one of the two was not successful, the line should start with 'ERROR:'
|
||||
# - running the script should not require any user interaction
|
||||
# - the script should clean up object files and executables
|
||||
|
||||
ERRORFILE=error.txt
|
||||
DO_RUN=y
|
||||
if [ -z "${MAKE_CMD}" ]; then
|
||||
MAKE_CMD=make
|
||||
fi
|
||||
NEED_CLEAN=
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
# configure
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
configure()
|
||||
{
|
||||
echo "Configuring... "
|
||||
|
||||
if eval 'cmake "$CMAKE_GENERATOR" -DRUNNING_CGAL_AUTO_TEST=TRUE \
|
||||
-DCGAL_DIR="$CGAL_DIR" \
|
||||
.' ; then
|
||||
|
||||
echo " successful configuration" >> $ERRORFILE
|
||||
else
|
||||
echo " ERROR: configuration" >> $ERRORFILE
|
||||
fi
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
# compile_and_run <target>
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
compile_and_run()
|
||||
{
|
||||
echo "Compiling $1 ... "
|
||||
SUCCESS="y"
|
||||
|
||||
if eval '${MAKE_CMD} VERBOSE=ON -fMakefile $1' ; then
|
||||
echo " successful compilation of $1" >> $ERRORFILE
|
||||
else
|
||||
echo " ERROR: compilation of $1" >> $ERRORFILE
|
||||
SUCCESS=""
|
||||
fi
|
||||
|
||||
if [ -n "$DO_RUN" ] ; then
|
||||
if [ -n "${SUCCESS}" ] ; then
|
||||
OUTPUTFILE=ProgramOutput.$1.$PLATFORM
|
||||
rm -f $OUTPUTFILE
|
||||
COMMAND="./$1"
|
||||
if [ -f $1.cmd ] ; then
|
||||
COMMAND="$COMMAND `cat $1.cmd`"
|
||||
fi
|
||||
if [ -f $1.cin ] ; then
|
||||
COMMAND="cat $1.cin | $COMMAND"
|
||||
fi
|
||||
echo "Executing $1 ... "
|
||||
echo
|
||||
ulimit -t 3600 2> /dev/null
|
||||
if eval $COMMAND > $OUTPUTFILE 2>&1 ; then
|
||||
echo " successful execution of $1" >> $ERRORFILE
|
||||
else
|
||||
echo " ERROR: execution of $1" >> $ERRORFILE
|
||||
fi
|
||||
else
|
||||
echo " ERROR: not executed $1" >> $ERRORFILE
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
# remove the previous error file
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
rm -f $ERRORFILE
|
||||
touch $ERRORFILE
|
||||
|
||||
#---------------------------------------------------------------------#
|
||||
# configure, compile and run the tests
|
||||
#---------------------------------------------------------------------#
|
||||
|
||||
configure
|
||||
|
||||
if [ $# -ne 0 ] ; then
|
||||
for file in $* ; do
|
||||
compile_and_run $file
|
||||
done
|
||||
else
|
||||
echo "Run all tests."
|
||||
if ${MAKE_CMD} -f Makefile help | grep -E "test_top_edges_single_mold_trans_cast$" > /dev/null; then
|
||||
compile_and_run test_top_edges_single_mold_trans_cast
|
||||
NEED_CLEAN=y
|
||||
fi
|
||||
if ${MAKE_CMD} -f Makefile help | grep -E "test_is_pullout_directions_single_mold_trans_cast$" > /dev/null; then
|
||||
compile_and_run test_is_pullout_directions_single_mold_trans_cast
|
||||
NEED_CLEAN=y
|
||||
fi
|
||||
fi
|
||||
|
||||
#
|
||||
# The clean target generated by CMake under cygwin
|
||||
# always fails for some reason
|
||||
#
|
||||
if [ -n "${NEED_CLEAN}" ]; then
|
||||
if ! ( uname | grep -q "CYGWIN" ) ; then
|
||||
${MAKE_CMD} -fMakefile clean
|
||||
fi
|
||||
fi
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
4
|
||||
0 0 1 0 1 1 0 1
|
||||
4
|
||||
0 0 -1 0 -1
|
||||
1 1 0 1 0
|
||||
2 0 1 0 1
|
||||
3 -1 0 -1 0
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
./data/test01.txt
|
||||
# ./data/test02.txt
|
||||
# ./data/test03.txt
|
||||
# ./data/test04.txt
|
||||
# ./data/test05.txt
|
||||
# ./data/test06.txt
|
||||
# ./data/test07.txt
|
||||
# ./data/test08.txt
|
||||
# ./data/test09.txt
|
||||
# ./data/test10.txt
|
||||
# ./data/test11.txt
|
||||
# ./data/test12.txt
|
||||
# ./data/test13.txt
|
||||
# ./data/test14.txt
|
||||
# ./data/test15.txt
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
#include <string>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <cctype>
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h>
|
||||
#include <CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
||||
typedef Kernel::Direction_2 Direction_2;
|
||||
typedef Kernel::Point_2 Point_2;
|
||||
|
||||
typedef std::pair<Direction_2, Direction_2> Direction_range;
|
||||
typedef Polygon_2::Edge_const_iterator Edge_iter;
|
||||
typedef std::pair<Edge_iter, Direction_range> Top_edge;
|
||||
|
||||
namespace SMS = CGAL::Set_movable_separability_2;
|
||||
namespace casting = SMS::Single_mold_translational_casting;
|
||||
|
||||
bool test_one_file(std::ifstream& inp)
|
||||
{
|
||||
Polygon_2 pgn;
|
||||
inp >> pgn;
|
||||
// std::cout << pgn << std::endl;
|
||||
|
||||
std::vector<Top_edge> top_edges;
|
||||
casting::top_edges(pgn, std::back_inserter(top_edges));
|
||||
|
||||
for (auto it = top_edges.begin(); it != top_edges.end(); ++it) {
|
||||
auto facet = it->first;
|
||||
const auto& d1 = it->second.first;
|
||||
const auto& d2 = it->second.second;
|
||||
|
||||
if (! casting::is_pullout_direction(pgn, facet, d1)) return false;
|
||||
if (! casting::is_pullout_direction(pgn, facet, d2)) return false;
|
||||
|
||||
auto od1 = CGAL::opposite(d1);
|
||||
if (casting::is_pullout_direction(pgn, facet, od1)) return false;
|
||||
auto od2 = CGAL::opposite(d2);
|
||||
if (casting::is_pullout_direction(pgn, facet, od2)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
std::cerr << "Missing input file" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int success = 0;
|
||||
for (size_t i = 1; i < static_cast<size_t>(argc); ++i) {
|
||||
std::string str(argv[i]);
|
||||
if (str.empty()) continue;
|
||||
|
||||
auto itr = str.end();
|
||||
--itr;
|
||||
while (itr != str.begin()) {
|
||||
auto tmp = itr;
|
||||
--tmp;
|
||||
if (!isspace(*itr)) break;
|
||||
str.erase(itr);
|
||||
itr = tmp;
|
||||
}
|
||||
if (str.size() <= 1) continue;
|
||||
std::ifstream inp(str.c_str());
|
||||
if (!inp.is_open()) {
|
||||
std::cerr << "Failed to open " << str << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (! test_one_file(inp)) {
|
||||
std::cout << str << ": ERROR" << std::endl;
|
||||
++success;
|
||||
}
|
||||
else std::cout << str << ": succeeded" << std::endl;
|
||||
inp.close();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
./data/test01.txt
|
||||
# ./data/test02.txt
|
||||
# ./data/test03.txt
|
||||
# ./data/test04.txt
|
||||
# ./data/test05.txt
|
||||
# ./data/test06.txt
|
||||
# ./data/test07.txt
|
||||
# ./data/test08.txt
|
||||
# ./data/test09.txt
|
||||
# ./data/test10.txt
|
||||
# ./data/test11.txt
|
||||
# ./data/test12.txt
|
||||
# ./data/test13.txt
|
||||
# ./data/test14.txt
|
||||
# ./data/test15.txt
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
#include <string>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <cctype>
|
||||
#include <iterator>
|
||||
|
||||
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
|
||||
#include <CGAL/Polygon_2.h>
|
||||
#include <CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h>
|
||||
|
||||
typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
|
||||
typedef CGAL::Polygon_2<Kernel> Polygon_2;
|
||||
typedef Kernel::Direction_2 Direction_2;
|
||||
typedef Kernel::Point_2 Point_2;
|
||||
|
||||
typedef std::pair<Direction_2, Direction_2> Direction_range;
|
||||
typedef Polygon_2::Edge_const_iterator Edge_iter;
|
||||
typedef std::pair<Edge_iter, Direction_range> Top_edge;
|
||||
|
||||
namespace SMS = CGAL::Set_movable_separability_2;
|
||||
namespace casting = SMS::Single_mold_translational_casting;
|
||||
|
||||
struct Top_edge_comparer {
|
||||
bool operator()(const Top_edge& a, const Top_edge& b)
|
||||
{
|
||||
if (a.first < b.first) return true;
|
||||
if (a.first > b.first) return false;
|
||||
if (a.second.first < b.second.first) return true;
|
||||
if (a.second.first > b.second.first) return false;
|
||||
return a.second.second < b.second.second;
|
||||
}
|
||||
};
|
||||
|
||||
bool test_one_file(std::ifstream& inp)
|
||||
{
|
||||
Polygon_2 pgn;
|
||||
inp >> pgn;
|
||||
// std::cout << pgn << std::endl;
|
||||
|
||||
std::vector<Top_edge> top_edges;
|
||||
casting::top_edges(pgn, std::back_inserter(top_edges));
|
||||
|
||||
size_t exp_num_top_edges;
|
||||
inp >> exp_num_top_edges;
|
||||
// std::cout << "Exp. no. of top facets: " << exp_num_top_edges << std::endl;
|
||||
std::vector<Top_edge> exp_top_edges(exp_num_top_edges);
|
||||
for (auto& top_edge : exp_top_edges) {
|
||||
size_t facet;
|
||||
Direction_2 d1, d2;
|
||||
inp >> facet >> d1 >> d2;
|
||||
// std::cout << facet << " " << d1 << " " << d2 << std::endl;
|
||||
Edge_iter it(pgn.edges_begin());
|
||||
std::advance(it, facet);
|
||||
top_edge = std::make_pair(it, std::make_pair(d1, d2));
|
||||
}
|
||||
|
||||
std::sort(top_edges.begin(), top_edges.end(), Top_edge_comparer());
|
||||
std::sort(exp_top_edges.begin(), exp_top_edges.end(), Top_edge_comparer());
|
||||
|
||||
if (top_edges.size() != exp_top_edges.size()) {
|
||||
std::cerr << "Number of facets: "
|
||||
<< "obtain: " << top_edges.size()
|
||||
<< ", expected: " << exp_top_edges.size()
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
auto exp_it = exp_top_edges.begin();
|
||||
size_t i(0);
|
||||
for (auto it = top_edges.begin(); it != top_edges.end(); ++it, ++exp_it) {
|
||||
auto facet = it->first;
|
||||
auto fid = std::distance(pgn.edges_begin(), facet);
|
||||
const auto& d1 = it->second.first;
|
||||
const auto& d2 = it->second.second;
|
||||
auto exp_facet = exp_it->first;
|
||||
auto exp_fid = std::distance(pgn.edges_begin(), exp_facet);
|
||||
const auto& exp_d1 = exp_it->second.first;
|
||||
const auto& exp_d2 = exp_it->second.second;
|
||||
if ((fid != exp_fid) || (d1 != exp_d1) || (d2 != exp_d2)) {
|
||||
std::cerr << "Top edge[" << i++ << "]: "
|
||||
<< "obtained: " << fid << " " << d1 << " " << d2
|
||||
<< ", expected: " << exp_fid << " " << exp_d1 << " " << exp_d2
|
||||
<< std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
if (argc < 2) {
|
||||
std::cerr << "Missing input file" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int success = 0;
|
||||
for (size_t i = 1; i < static_cast<size_t>(argc); ++i) {
|
||||
std::string str(argv[i]);
|
||||
if (str.empty()) continue;
|
||||
|
||||
auto itr = str.end();
|
||||
--itr;
|
||||
while (itr != str.begin()) {
|
||||
auto tmp = itr;
|
||||
--tmp;
|
||||
if (!isspace(*itr)) break;
|
||||
str.erase(itr);
|
||||
itr = tmp;
|
||||
}
|
||||
if (str.size() <= 1) continue;
|
||||
std::ifstream inp(str.c_str());
|
||||
if (!inp.is_open()) {
|
||||
std::cerr << "Failed to open " << str << std::endl;
|
||||
return -1;
|
||||
}
|
||||
if (! test_one_file(inp)) {
|
||||
std::cout << str << ": ERROR" << std::endl;
|
||||
++success;
|
||||
}
|
||||
else std::cout << str << ": succeeded" << std::endl;
|
||||
inp.close();
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||