From a02348c9f2af63e54ba9d2970a912508bd9e0655 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 31 May 2016 14:26:06 +0300 Subject: [PATCH 01/90] 1st revision --- Casting_2/package_info/Casting_2/copyright | 1 + Casting_2/package_info/Casting_2/description.txt | 1 + Casting_2/package_info/Casting_2/license.txt | 1 + Casting_2/package_info/Casting_2/long_description.txt | 3 +++ Casting_2/package_info/Casting_2/maintainer | 2 ++ 5 files changed, 8 insertions(+) create mode 100644 Casting_2/package_info/Casting_2/copyright create mode 100644 Casting_2/package_info/Casting_2/description.txt create mode 100644 Casting_2/package_info/Casting_2/license.txt create mode 100644 Casting_2/package_info/Casting_2/long_description.txt create mode 100644 Casting_2/package_info/Casting_2/maintainer diff --git a/Casting_2/package_info/Casting_2/copyright b/Casting_2/package_info/Casting_2/copyright new file mode 100644 index 00000000000..930771b9d2c --- /dev/null +++ b/Casting_2/package_info/Casting_2/copyright @@ -0,0 +1 @@ +Tel-Aviv University (Israel). diff --git a/Casting_2/package_info/Casting_2/description.txt b/Casting_2/package_info/Casting_2/description.txt new file mode 100644 index 00000000000..04c8be96802 --- /dev/null +++ b/Casting_2/package_info/Casting_2/description.txt @@ -0,0 +1 @@ +Various 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. diff --git a/Casting_2/package_info/Casting_2/license.txt b/Casting_2/package_info/Casting_2/license.txt new file mode 100644 index 00000000000..8bb8efcb72b --- /dev/null +++ b/Casting_2/package_info/Casting_2/license.txt @@ -0,0 +1 @@ +GPL (v3 or later) diff --git a/Casting_2/package_info/Casting_2/long_description.txt b/Casting_2/package_info/Casting_2/long_description.txt new file mode 100644 index 00000000000..94858c8ac33 --- /dev/null +++ b/Casting_2/package_info/Casting_2/long_description.txt @@ -0,0 +1,3 @@ +The casting ptocess 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 catings of planar 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. diff --git a/Casting_2/package_info/Casting_2/maintainer b/Casting_2/package_info/Casting_2/maintainer new file mode 100644 index 00000000000..3385b879fc6 --- /dev/null +++ b/Casting_2/package_info/Casting_2/maintainer @@ -0,0 +1,2 @@ +Shahar Shamai +Efi Fogel From 46be5b04703d2e51dcaa4eb7f820181db83a893a Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 1 Jun 2016 18:53:10 +0300 Subject: [PATCH 02/90] Fixed typo --- Casting_2/package_info/Casting_2/long_description.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Casting_2/package_info/Casting_2/long_description.txt b/Casting_2/package_info/Casting_2/long_description.txt index 94858c8ac33..c8b96a75c22 100644 --- a/Casting_2/package_info/Casting_2/long_description.txt +++ b/Casting_2/package_info/Casting_2/long_description.txt @@ -1,3 +1,3 @@ -The casting ptocess 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). +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 catings of planar 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. +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. From 7e600dbb12a51cbcf4d26a8fc6b51b1c913daa9a Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 1 Jun 2016 20:01:58 +0300 Subject: [PATCH 03/90] 1st revision --- Casting_2/examples/Casting_2/CMakeLists.txt | 28 ++++++++++++ ...nd_single_mold_translational_casting_2.cpp | 43 +++++++++++++++++++ ...find_single_mold_translational_casting_2.h | 34 +++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 Casting_2/examples/Casting_2/CMakeLists.txt create mode 100644 Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp create mode 100644 Casting_2/include/CGAL/find_single_mold_translational_casting_2.h diff --git a/Casting_2/examples/Casting_2/CMakeLists.txt b/Casting_2/examples/Casting_2/CMakeLists.txt new file mode 100644 index 00000000000..e6c74082648 --- /dev/null +++ b/Casting_2/examples/Casting_2/CMakeLists.txt @@ -0,0 +1,28 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + + +project( Casting_2_example ) + +cmake_minimum_required(VERSION 2.8.10) + +find_package(CGAL QUIET COMPONENTS Core ) + +if ( CGAL_FOUND ) + + include( ${CGAL_USE_FILE} ) + + include( CGAL_CreateSingleSourceCGALProgram ) + + include_directories (BEFORE "../../include") + + create_single_source_cgal_program( "find_single_mold_translational_casting_2.cpp" ) + if (CMAKE_COMPILER_IS_GNUCXX) + add_definitions(-std=c++11) + endif() + +else() + + message(STATUS "This program requires the CGAL library, and will not be compiled.") + +endif() diff --git a/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp b/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp new file mode 100644 index 00000000000..04ad3e2ee33 --- /dev/null +++ b/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp @@ -0,0 +1,43 @@ +/*! \file find_single_mold_translational_casting_2.cpp + * . + */ + +#include + +#include +#include +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef CGAL::Polygon_2 Polygon_2; +typedef Kernel::Direction_2 Direction_2; +typedef Kernel::Point_2 Point_2; + +typedef std::pair Direction_range; +typedef std::pair Top_edge; + +// The main program: +int main() +{ + Polygon_2 pgn; + pgn.push_back(Point_2(0, 0)); + pgn.push_back(Point_2(1, 0)); + pgn.push_back(Point_2(1, 1)); + pgn.push_back(Point_2(0, 1)); + + std::list top_edges; + find_single_mold_translational_casting_2(pgn, 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 << top_edge.first << ", (" + << top_edge.second.first << "," << top_edge.second.second + << ")" << std::endl; + } + } + + return 0; +} diff --git a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h new file mode 100644 index 00000000000..6005a9a1068 --- /dev/null +++ b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h @@ -0,0 +1,34 @@ +// 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. +// +// $URL$ +// $Id$ +// +// +// Author(s): Shahar +// Efi Fogel + +#ifndef CGAL_FIND_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#define CGAL_FIND_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H + +/*! + */ +template +OutputIterator +find_single_mold_translational_casting_2(const Polygon& pgn, OutputIterator oi) +{ + return oi; +} + +#endif From 19f0c6bb61da680fb3694a473e30792d6b2fcaa4 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Wed, 8 Jun 2016 17:23:28 +0300 Subject: [PATCH 04/90] 2D casting with bug --- ...nd_single_mold_translational_casting_2.cpp | 24 +- ...find_single_mold_translational_casting_2.h | 334 +++++++++++++++++- 2 files changed, 349 insertions(+), 9 deletions(-) diff --git a/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp b/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp index 04ad3e2ee33..00f15e82b99 100644 --- a/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp +++ b/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp @@ -20,11 +20,27 @@ typedef std::pair Top_edge; int main() { Polygon_2 pgn; - pgn.push_back(Point_2(0, 0)); - pgn.push_back(Point_2(1, 0)); - pgn.push_back(Point_2(1, 1)); - pgn.push_back(Point_2(0, 1)); +// pgn.push_back(Point_2(0, 0)); +// pgn.push_back(Point_2(1, 0)); +// pgn.push_back(Point_2(1, 1)); +// pgn.push_back(Point_2(0, 1)); + +// pgn.push_back(Point_2(0, 7)); +// pgn.push_back(Point_2(1, 0)); +// pgn.push_back(Point_2(1, 1)); +// pgn.push_back(Point_2(0, 1)); + typename Kernel::Segment_2 s1(Point_2(0, 1),Point_2(1, 0)); + typename Kernel::Segment_2 s2(Point_2(0, 1),Point_2(1, 12)); +Direction_2 d1(s1); +Direction_2 d2(s2); + +std::cout< top_edges; find_single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); diff --git a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h index 6005a9a1068..db3a8296b08 100644 --- a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h +++ b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h @@ -21,14 +21,338 @@ #ifndef CGAL_FIND_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H #define CGAL_FIND_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H - +#include +#include /*! */ -template -OutputIterator -find_single_mold_translational_casting_2(const Polygon& pgn, OutputIterator oi) +/* + typedef Kernel::Direction_2 Direction_2; + typedef std::pair Direction_range; + typedef std::pair Top_edge; + + */ +#include +#include +template +inline std::pair getSegmentOuterCircle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) { - return oi; + typename Kernel::Direction_2 forward( seg); + typename Kernel::Direction_2 backward(-forward); + if(orientation ==CGAL::Orientation::CLOCKWISE) + return std::pair (backward,forward); + return std::pair (forward,backward); + } +template +class CircleArrangmentEdge +{ +public : + bool startIsClosed; + typename Kernel::Direction_2 edgeStartEngle; //the end is the start of the next edge + char count; //number of outer circles that cover the edge (0/1/2+) + size_t edgeIndex; + CircleArrangmentEdge(typename Kernel::Direction_2 edgeStartEngle,size_t edgeIndex,bool startIsClosed,bool setCountToZero=false) + { + this->startIsClosed=startIsClosed; + this->edgeStartEngle= edgeStartEngle; + if(setCountToZero) + { + this->count = 0; + } + else + { + this->count = 1; + this->edgeIndex = edgeIndex; + } + } + void plusplus(size_t edgeIndex) + { + if(this->count ==0) + { + this->edgeIndex = edgeIndex; + this->count = 1; + } + else if(this->count ==1) + { + this->count =2; + } + + } + bool isCovered(){return count ==2;} + +}; +//only one segment can be closed so if B is closed and A isnt, we dont care + +//template +//inline bool isOpenDirectionContainedInSegment(bool isFirstDirection,bool isStartClosed,bool isEndClosed,typename Kernel::Direction_2 d, std::pair s) +//{ +// if(!isEndClosed) +// { +// if( isFirstDirection && (d == s.second)) +// return false; +// } +// if(!isStartClosed) +// { +// if( !isFirstDirection && (d == s.first)) +// return false;; +// } +// return !d.counterclockwise_in_between(s.first,s.second); +// +//} +template +inline bool isOpenDirectionContainedInSegment(typename Kernel::Direction_2 d, std::pair s) +{ + return !d.counterclockwise_in_between(s.first,s.second); + +} +template +inline bool isAcontainedInB(bool isAStartClosed,bool isAEndClosed,std::pair A, std::pair B) +{ + //A is closed, B is open and they share an vertex -> A not contained in B + if( ( isAStartClosed &&A.first == B.first )|| (isAEndClosed && A.second == B.second)) + return false; + if(!A.first.counterclockwise_in_between(B.first,B.second) && !A.second.counterclockwise_in_between(B.first,B.second) && + !A.first.counterclockwise_in_between(B.first,A.second)) + { + return true; + } + return false; +} +template +class CircleArrangment +{ + std::list >edges; + +public : + CircleArrangment(std::pair firstSegmentOuterCircle) +{ + edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.first,0,false)); + edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.second,0,true,true)); +} + void addSegmentOuterCircle(std::pair segmentOuterCircle, size_t edge_index) + { + std::pair edge; + bool isStartClosedSegment=edges.begin()->startIsClosed; + bool isEndClosedSegment=edges.begin()->startIsClosed; + edge.first = edges.begin()->edgeStartEngle; + edge.second = edges.begin()->edgeStartEngle; + + typename std::list >::iterator nextIt=edges.begin(); + typename std::list >::iterator it=edges.begin(); + bool done = false; + while(!done) + { + it = nextIt; + nextIt=it; + nextIt++; + // std::cout<<"len "<count == 2) + { + + continue; + } + std::cout<startIsClosed; + edge.first = edge.second; + edge.second =nextIt->edgeStartEngle; + if( isAcontainedInB(isStartClosedSegment,isEndClosedSegment,edge,segmentOuterCircle)) + { + std::cout<<"O<\n"; + + it->plusplus(edge_index); + continue; + } + bool isStartContained = isOpenDirectionContainedInSegment(segmentOuterCircle.first,edge); + bool isEndContained = isOpenDirectionContainedInSegment(segmentOuterCircle.second,edge); + // o~~~~~~~~~~~~o = new segment + // ?------------? = "old" segment (the edge from the array + if(isStartContained) + { + if(isEndContained) + { + bool isordered = !segmentOuterCircle.second.counterclockwise_in_between(segmentOuterCircle.first,edge.second); + if(isordered) + { + std::cout<<"A<\n"; + // o~~~~~~~~~~~~o + // ?-----------------------? + // __________________________ + // ?----c + // o~-~-~-~-~-~-o + // c-----? + struct CircleArrangmentEdge< Kernel> edge2 = *it; + edge2.startIsClosed=false; + edge2.edgeStartEngle=segmentOuterCircle.first; + edge2.plusplus(edge_index); + edges.insert(nextIt,edge2); + struct CircleArrangmentEdge< Kernel> edge3 = *it; + edge3.startIsClosed=true; + edge3.edgeStartEngle=segmentOuterCircle.second; + edges.insert(nextIt,edge3); + + + } + else + { + std::cout<<"B<\n"; + + // ...~~~~~~~~~o o~~~~~~~~~~... (round) + // ?------------? + // __________________________ + // ?~-~o + // c----c + // o-~-? + + struct CircleArrangmentEdge< Kernel> edge2 = *it; + edge2.startIsClosed=true; + edge2.edgeStartEngle=segmentOuterCircle.second; + edges.insert(nextIt,edge2); + struct CircleArrangmentEdge< Kernel> edge3 = *it; + edge3.startIsClosed=false; + edge3.edgeStartEngle=segmentOuterCircle.first; + edge3.plusplus(edge_index); + edges.insert(nextIt,edge3); + it->plusplus(edge_index); + + } + } + else + { + // o~~~~~~~~~~~~o + // ?-----------? + //_____________________ + // ?----c + // o-~-~-~? + std::cout<<"C<\n"; + + struct CircleArrangmentEdge< Kernel> edge2 = *it; + edge2.startIsClosed=false; + edge2.edgeStartEngle=segmentOuterCircle.first; + edge2.plusplus(edge_index); + edges.insert(nextIt,edge2); + + } + } + else + { + if(isEndContained) + { + // o~~~~~~~~~~~~o + // ?------------? + //_____________________ + // ?-~-~-~-o + // c----? + std::cout<<"D\n"; + + struct CircleArrangmentEdge< Kernel> edge2 = *it; + edge2.startIsClosed=true; + edge2.edgeStartEngle=segmentOuterCircle.second; + it->plusplus(edge_index); + edges.insert(nextIt,edge2); + } + //else// no intersection, do noting + + + } + } + + } + + + void mergeAdjacent2EdgesAndRemoveEmpty() + { +// bool inTwoEdge=false; +// for(typename std::list >::iterator it=edges.begin();it!=edges.end();) +// { +// +// +// if(it->isCovered()) +// { +// if(inTwoEdge) +// { +// it= edges.erase(it); +// continue; +// } +// inTwoEdge = true; +// } +// else +// { +// inTwoEdge = false; +// } +// it++; +// } + } + // debug function + void printArrangement() + { + for(typename std::list >::iterator it=edges.begin();it!=edges.end();++it) + { + if(it->startIsClosed) + std::cout<<")["; + else + std::cout<<"]("; + std::cout<edgeStartEngle; + std::cout<<","<<(int)it->count; + + } + std::cout<<"\n\n"; + + } + template< typename OutputIterator> + void getAll1Edges(OutputIterator oi) + { + for(typename std::list >::iterator it=edges.begin();it!=edges.end();) + { + + if((*it).count == 1) + { + std::pair > edge; + edge.first = (*it).edgeIndex; + edge.second.first = (*it).edgeStartEngle; + it++; + edge.second.second = (*((it == edges.end())?edges.begin():(it))).edgeStartEngle; + oi=(edge); + } + else + { + it++; + } + } + } + bool allIsCoveredTwice(){return edges.size()==1;} +}; + +template +OutputIterator +find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) +{ + typename CGAL::Polygon_2::Edge_const_iterator e_it = pgn.edges_begin(); + size_t edge_index =0; + CGAL::Orientation poly_orientation =pgn.orientation(); + std::pair segmentOuterCircle = getSegmentOuterCircle(*e_it++,poly_orientation); + CircleArrangment circleArrangment(segmentOuterCircle); + edge_index++; + circleArrangment.printArrangement(); + + for(;e_it!= pgn.edges_end();e_it++,edge_index++) + { + segmentOuterCircle = getSegmentOuterCircle(*e_it,poly_orientation); + circleArrangment.addSegmentOuterCircle(segmentOuterCircle,edge_index); + circleArrangment.mergeAdjacent2EdgesAndRemoveEmpty(); + circleArrangment.printArrangement(); + if(circleArrangment.allIsCoveredTwice()) + return oi; + } + circleArrangment.getAll1Edges(oi); + return oi; +} #endif From 595abea38cc257fb51a5d6d0baa26616c54d5558 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Fri, 10 Jun 2016 11:14:50 +0300 Subject: [PATCH 05/90] first working code. not documented. not deeply tested. the returned directions might be the exact mirror of the real directions --- ...nd_single_mold_translational_casting_2.cpp | 12 +- ...find_single_mold_translational_casting_2.h | 297 ++++++++---------- 2 files changed, 139 insertions(+), 170 deletions(-) diff --git a/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp b/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp index 00f15e82b99..7908ab33f76 100644 --- a/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp +++ b/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp @@ -30,14 +30,10 @@ int main() // pgn.push_back(Point_2(1, 0)); // pgn.push_back(Point_2(1, 1)); // pgn.push_back(Point_2(0, 1)); - typename Kernel::Segment_2 s1(Point_2(0, 1),Point_2(1, 0)); - typename Kernel::Segment_2 s2(Point_2(0, 1),Point_2(1, 12)); -Direction_2 d1(s1); -Direction_2 d2(s2); + pgn.push_back(Point_2(-1, 7)); + pgn.push_back(Point_2(0, 6)); -std::cout< #include -/*! - */ -/* - typedef Kernel::Direction_2 Direction_2; - typedef std::pair Direction_range; - typedef std::pair Top_edge; - */ #include #include template -inline std::pair getSegmentOuterCircle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) -{ - typename Kernel::Direction_2 forward( seg); - typename Kernel::Direction_2 backward(-forward); - if(orientation ==CGAL::Orientation::CLOCKWISE) - return std::pair (backward,forward); - return std::pair (forward,backward); -} - -template -class CircleArrangmentEdge -{ -public : - bool startIsClosed; - typename Kernel::Direction_2 edgeStartEngle; //the end is the start of the next edge - char count; //number of outer circles that cover the edge (0/1/2+) - size_t edgeIndex; - CircleArrangmentEdge(typename Kernel::Direction_2 edgeStartEngle,size_t edgeIndex,bool startIsClosed,bool setCountToZero=false) - { - this->startIsClosed=startIsClosed; - this->edgeStartEngle= edgeStartEngle; - if(setCountToZero) - { - this->count = 0; - } - else - { - this->count = 1; - this->edgeIndex = edgeIndex; - } - } - void plusplus(size_t edgeIndex) - { - if(this->count ==0) - { - this->edgeIndex = edgeIndex; - this->count = 1; - } - else if(this->count ==1) - { - this->count =2; - } - - } - bool isCovered(){return count ==2;} - -}; -//only one segment can be closed so if B is closed and A isnt, we dont care - -//template -//inline bool isOpenDirectionContainedInSegment(bool isFirstDirection,bool isStartClosed,bool isEndClosed,typename Kernel::Direction_2 d, std::pair s) -//{ -// if(!isEndClosed) -// { -// if( isFirstDirection && (d == s.second)) -// return false; -// } -// if(!isStartClosed) -// { -// if( !isFirstDirection && (d == s.first)) -// return false;; -// } -// return !d.counterclockwise_in_between(s.first,s.second); -// -//} -template -inline bool isOpenDirectionContainedInSegment(typename Kernel::Direction_2 d, std::pair s) -{ - return !d.counterclockwise_in_between(s.first,s.second); - -} -template -inline bool isAcontainedInB(bool isAStartClosed,bool isAEndClosed,std::pair A, std::pair B) -{ - //A is closed, B is open and they share an vertex -> A not contained in B - if( ( isAStartClosed &&A.first == B.first )|| (isAEndClosed && A.second == B.second)) - return false; - if(!A.first.counterclockwise_in_between(B.first,B.second) && !A.second.counterclockwise_in_between(B.first,B.second) && - !A.first.counterclockwise_in_between(B.first,A.second)) - { - return true; - } - return false; -} template class CircleArrangment { - std::list >edges; + + typedef typename Kernel::Direction_2 Direction_2; + + inline static bool isOpenDirectionContainedInSegment(Direction_2 d,bool isDIsLeftClockwise, std::pair s) + { + if((isDIsLeftClockwise && d==s.second )||(!isDIsLeftClockwise && d==s.first )) + return false; + return !d.counterclockwise_in_between(s.first,s.second); + + } + //only one segment can be closed so if B is closed and A isnt, we dont care + inline static bool isAcontainedInB(bool isAStartClosed,bool isAEndClosed,std::pair A, std::pair B) + { + //A is closed, B is open and they share an vertex -> A not contained in B + if( ( isAStartClosed &&A.first == B.first )|| (isAEndClosed && A.second == B.second)) + return false; + if((A.first == B.second ||B.first == A.second)&& A.first != A.second) + return false; + + return (!A.first.counterclockwise_in_between(B.first,B.second)&& + !A.second.counterclockwise_in_between(B.first,B.second)&& + !A.first.counterclockwise_in_between(B.first,A.second)); + } + + class CircleArrangmentEdge + { + public : + bool startIsClosed; + Direction_2 edgeStartEngle; //the end is the start of the next edge + char count; //number of outer circles that cover the edge (0/1/2+) + size_t edgeIndex; + CircleArrangmentEdge(Direction_2 edgeStartEngle,size_t edgeIndex,bool startIsClosed,bool setCountToZero=false) + { + this->startIsClosed=startIsClosed; + this->edgeStartEngle= edgeStartEngle; + if(setCountToZero) + { + this->count = 0; + } + else + { + this->count = 1; + this->edgeIndex = edgeIndex; + } + } + void plusplus(size_t edgeIndex) + { + if(this->count ==0) + { + this->edgeIndex = edgeIndex; + this->count = 1; + } + else if(this->count ==1) + { + this->count =2; + } + + } + bool isCovered(){return count ==2;} + + }; + typedef typename std::list::iterator CircleEdgeIterator; + + std::listedges; + + void insertIfLegal(const CircleEdgeIterator curIt,const CircleEdgeIterator nextIt,const struct CircleArrangmentEdge &edge) + { + if(( edge.startIsClosed && !nextIt->startIsClosed) || edge.edgeStartEngle != nextIt->edgeStartEngle) + if(( curIt->startIsClosed && !edge.startIsClosed) || edge.edgeStartEngle != curIt->edgeStartEngle) + edges.insert(nextIt,edge); + } public : - CircleArrangment(std::pair firstSegmentOuterCircle) -{ - edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.first,0,false)); - edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.second,0,true,true)); -} - void addSegmentOuterCircle(std::pair segmentOuterCircle, size_t edge_index) + CircleArrangment(std::pair firstSegmentOuterCircle) { - std::pair edge; + edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.first,0,false)); + edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.second,0,true,true)); + } + + void addSegmentOuterCircle(std::pair segmentOuterCircle, size_t edge_index) + { + std::pair edge; bool isStartClosedSegment=edges.begin()->startIsClosed; bool isEndClosedSegment=edges.begin()->startIsClosed; edge.first = edges.begin()->edgeStartEngle; edge.second = edges.begin()->edgeStartEngle; - - typename std::list >::iterator nextIt=edges.begin(); - typename std::list >::iterator it=edges.begin(); + CircleEdgeIterator nextIt=edges.begin(); + CircleEdgeIterator it=edges.begin(); bool done = false; while(!done) { it = nextIt; nextIt=it; nextIt++; - // std::cout<<"len "<startIsClosed; + edge.first = edge.second; + edge.second =nextIt->edgeStartEngle; + if(it->count == 2) { continue; } - std::cout<startIsClosed; - edge.first = edge.second; - edge.second =nextIt->edgeStartEngle; - if( isAcontainedInB(isStartClosedSegment,isEndClosedSegment,edge,segmentOuterCircle)) + if( isAcontainedInB(isStartClosedSegment,isEndClosedSegment,edge,segmentOuterCircle)) { - std::cout<<"O<\n"; - it->plusplus(edge_index); continue; } - bool isStartContained = isOpenDirectionContainedInSegment(segmentOuterCircle.first,edge); - bool isEndContained = isOpenDirectionContainedInSegment(segmentOuterCircle.second,edge); + bool isStartContained = isOpenDirectionContainedInSegment(segmentOuterCircle.first,true,edge); + bool isEndContained = isOpenDirectionContainedInSegment(segmentOuterCircle.second,false,edge); // o~~~~~~~~~~~~o = new segment // ?------------? = "old" segment (the edge from the array if(isStartContained) @@ -182,29 +156,26 @@ public : bool isordered = !segmentOuterCircle.second.counterclockwise_in_between(segmentOuterCircle.first,edge.second); if(isordered) { - std::cout<<"A<\n"; // o~~~~~~~~~~~~o // ?-----------------------? // __________________________ // ?----c // o~-~-~-~-~-~-o // c-----? - struct CircleArrangmentEdge< Kernel> edge2 = *it; + struct CircleArrangmentEdge edge2 = *it; edge2.startIsClosed=false; edge2.edgeStartEngle=segmentOuterCircle.first; edge2.plusplus(edge_index); - edges.insert(nextIt,edge2); - struct CircleArrangmentEdge< Kernel> edge3 = *it; + this->insertIfLegal(it,nextIt,edge2); + struct CircleArrangmentEdge edge3 = *it; edge3.startIsClosed=true; edge3.edgeStartEngle=segmentOuterCircle.second; - edges.insert(nextIt,edge3); + this->insertIfLegal(it,nextIt,edge3); } else { - std::cout<<"B<\n"; - // ...~~~~~~~~~o o~~~~~~~~~~... (round) // ?------------? // __________________________ @@ -212,17 +183,16 @@ public : // c----c // o-~-? - struct CircleArrangmentEdge< Kernel> edge2 = *it; + struct CircleArrangmentEdge edge2 = *it; edge2.startIsClosed=true; edge2.edgeStartEngle=segmentOuterCircle.second; - edges.insert(nextIt,edge2); - struct CircleArrangmentEdge< Kernel> edge3 = *it; + this->insertIfLegal(it,nextIt,edge2); + struct CircleArrangmentEdge edge3 = *it; edge3.startIsClosed=false; edge3.edgeStartEngle=segmentOuterCircle.first; edge3.plusplus(edge_index); - edges.insert(nextIt,edge3); + this->insertIfLegal(it,nextIt,edge3); it->plusplus(edge_index); - } } else @@ -232,13 +202,11 @@ public : //_____________________ // ?----c // o-~-~-~? - std::cout<<"C<\n"; - - struct CircleArrangmentEdge< Kernel> edge2 = *it; + struct CircleArrangmentEdge edge2 = *it; edge2.startIsClosed=false; edge2.edgeStartEngle=segmentOuterCircle.first; edge2.plusplus(edge_index); - edges.insert(nextIt,edge2); + this->insertIfLegal(it,nextIt,edge2); } } @@ -251,15 +219,13 @@ public : //_____________________ // ?-~-~-~-o // c----? - std::cout<<"D\n"; - - struct CircleArrangmentEdge< Kernel> edge2 = *it; + struct CircleArrangmentEdge edge2 = *it; edge2.startIsClosed=true; edge2.edgeStartEngle=segmentOuterCircle.second; it->plusplus(edge_index); - edges.insert(nextIt,edge2); + this->insertIfLegal(it,nextIt,edge2); } - //else// no intersection, do noting + //else - no intersection, do noting } @@ -270,31 +236,31 @@ public : void mergeAdjacent2EdgesAndRemoveEmpty() { -// bool inTwoEdge=false; -// for(typename std::list >::iterator it=edges.begin();it!=edges.end();) -// { -// -// -// if(it->isCovered()) -// { -// if(inTwoEdge) -// { -// it= edges.erase(it); -// continue; -// } -// inTwoEdge = true; -// } -// else -// { -// inTwoEdge = false; -// } -// it++; -// } + bool inTwoEdge=false; + for(CircleEdgeIterator it=edges.begin();it!=edges.end();) + { + + + if(it->isCovered()) + { + if(inTwoEdge) + { + it= edges.erase(it); + continue; + } + inTwoEdge = true; + } + else + { + inTwoEdge = false; + } + it++; + } } // debug function void printArrangement() { - for(typename std::list >::iterator it=edges.begin();it!=edges.end();++it) + for(CircleEdgeIterator it=edges.begin();it!=edges.end();++it) { if(it->startIsClosed) std::cout<<")["; @@ -310,12 +276,12 @@ public : template< typename OutputIterator> void getAll1Edges(OutputIterator oi) { - for(typename std::list >::iterator it=edges.begin();it!=edges.end();) + for(CircleEdgeIterator it=edges.begin();it!=edges.end();) { if((*it).count == 1) { - std::pair > edge; + std::pair > edge; edge.first = (*it).edgeIndex; edge.second.first = (*it).edgeStartEngle; it++; @@ -330,7 +296,14 @@ public : } bool allIsCoveredTwice(){return edges.size()==1;} }; +inline std::pair getSegmentOuterCircle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) +{ + typename Kernel::Direction_2 forward( seg); + typename Kernel::Direction_2 backward(-forward); + return (orientation ==CGAL::Orientation::CLOCKWISE)? + std::make_pair(backward, forward) : std::make_pair(forward, backward); +} template OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) @@ -341,14 +314,14 @@ find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, Out std::pair segmentOuterCircle = getSegmentOuterCircle(*e_it++,poly_orientation); CircleArrangment circleArrangment(segmentOuterCircle); edge_index++; - circleArrangment.printArrangement(); + //circleArrangment.printArrangement(); for(;e_it!= pgn.edges_end();e_it++,edge_index++) { segmentOuterCircle = getSegmentOuterCircle(*e_it,poly_orientation); circleArrangment.addSegmentOuterCircle(segmentOuterCircle,edge_index); circleArrangment.mergeAdjacent2EdgesAndRemoveEmpty(); - circleArrangment.printArrangement(); + // circleArrangment.printArrangement(); if(circleArrangment.allIsCoveredTwice()) return oi; } From b2dae4076820f207adcd2a28d3d822524f07b837 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Fri, 10 Jun 2016 11:17:12 +0300 Subject: [PATCH 06/90] same as last commit --- .../include/CGAL/find_single_mold_translational_casting_2.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h index e267b550c60..039e34c4e52 100644 --- a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h +++ b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h @@ -26,7 +26,6 @@ #include #include -template template class CircleArrangment @@ -295,7 +294,10 @@ public : } } bool allIsCoveredTwice(){return edges.size()==1;} + }; +template + inline std::pair getSegmentOuterCircle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) { typename Kernel::Direction_2 forward( seg); From 42bfeaffce2509bb404b6e54ea463c58ca26f8e4 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Fri, 10 Jun 2016 15:59:10 +0300 Subject: [PATCH 07/90] added comments and cleaned code --- ...nd_single_mold_translational_casting_2.cpp | 5 +- ...find_single_mold_translational_casting_2.h | 257 +++++++++++++----- 2 files changed, 199 insertions(+), 63 deletions(-) diff --git a/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp b/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp index 7908ab33f76..102a45775b3 100644 --- a/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp +++ b/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp @@ -30,13 +30,14 @@ int main() // pgn.push_back(Point_2(1, 0)); // pgn.push_back(Point_2(1, 1)); // pgn.push_back(Point_2(0, 1)); - pgn.push_back(Point_2(-1, 7)); - pgn.push_back(Point_2(0, 6)); pgn.push_back(Point_2(3, 8)); pgn.push_back(Point_2(1, 1)); pgn.push_back(Point_2(1, 0)); pgn.push_back(Point_2(0, 0)); + pgn.push_back(Point_2(0, 1)); + pgn.push_back(Point_2(-3, 8)); + std::list top_edges; find_single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); diff --git a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h index 039e34c4e52..d298338e7c4 100644 --- a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h +++ b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h @@ -27,21 +27,60 @@ #include #include +/* + * Terms: + * 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. + */ + +/*! \CircleArrangment + \brief This class represents an partition of the unit-circle in to cells of depth 0,1,2+ + \ where depth 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 + */ template class CircleArrangment { - typedef typename Kernel::Direction_2 Direction_2; + typedef typename Kernel::Direction_2 point; + typedef std::pair arc; + /* + * Reminder: + * 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) + */ - inline static bool isOpenDirectionContainedInSegment(Direction_2 d,bool isDIsLeftClockwise, std::pair s) + /*! \fn bool isOpenDirectionContainedInArc(point p,bool isCounterClockwise, arc a) + \brief checks whether an open epsilon area clockwise/counterclockwise from a point p is contained in an arc s + \param p - a point . + \param isCounterClockwise - true: we care about the counterclockwise epsilon area of p. false: same with clockwise + \param a - an arc that should contain the epsilon area + */ + inline static bool isOpenDirectionContainedInArc(point p,bool isCounterClockwise, arc a) { - if((isDIsLeftClockwise && d==s.second )||(!isDIsLeftClockwise && d==s.first )) + if((isCounterClockwise && p==a.second )||(!isCounterClockwise && p==a.first )) return false; - return !d.counterclockwise_in_between(s.first,s.second); + return !p.counterclockwise_in_between(a.first,a.second); } - //only one segment can be closed so if B is closed and A isnt, we dont care - inline static bool isAcontainedInB(bool isAStartClosed,bool isAEndClosed,std::pair A, std::pair B) + /*! \fn bool isAcontainedInB(bool isAStartClosed,bool isAEndClosed,arc A, arc B) + \brief checks whether an arc A is contained in an arc B + \param isAStartClosed - do A contains its start point (clockwise) + \param isAEndClosed - do A contains its end point (clockwise) + \param A - an arc + \param B - an *open* arc + */ + inline static bool isAcontainedInB(bool isAStartClosed,bool isAEndClosed,arc A, arc B) { //A is closed, B is open and they share an vertex -> A not contained in B if( ( isAStartClosed &&A.first == B.first )|| (isAEndClosed && A.second == B.second)) @@ -54,27 +93,44 @@ class CircleArrangment !A.first.counterclockwise_in_between(B.first,A.second)); } + /*! \CircleArrangmentEdge + \brief This class represents a cells (a point or an arc) of depth 0,1,2+ in the CircleArrangment + \ 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 CircleArrangmentEdge in the list in CircleArrangment + + this class also keeps the cell depth. + */ class CircleArrangmentEdge { public : bool startIsClosed; - Direction_2 edgeStartEngle; //the end is the start of the next edge + point edgeStartEngle; //the end is the start of the next edge char count; //number of outer circles that cover the edge (0/1/2+) - size_t edgeIndex; - CircleArrangmentEdge(Direction_2 edgeStartEngle,size_t edgeIndex,bool startIsClosed,bool setCountToZero=false) + size_t edgeIndex; // the index of the polygon edge who's open half-circle covers this cell - only relevant if count ==1 + + /*! \ctor CircleArrangmentEdge(point edgeStartEngle,size_t edgeIndex,bool startIsClosed,bool setCountToOne=true) + \brief create a new edge (Arc), this edge count must be 0 or 1 + \param edgeStartEngle - the first point of the arc (clockwise) + \param edgeIndex - the index of the polygon edge who's open half-circle covers this cell - only relevant if count == 1 + \param startIsClosed - is the point edgeStartEngle contained in this cell + \param setCountToOne - to set the count to one (or zero if this var is false) + */ + CircleArrangmentEdge(point edgeStartEngle,size_t edgeIndex,bool startIsClosed,bool setCountToOne=true) { this->startIsClosed=startIsClosed; this->edgeStartEngle= edgeStartEngle; - if(setCountToZero) - { - this->count = 0; - } - else - { - this->count = 1; - this->edgeIndex = edgeIndex; - } + this->count = (int) setCountToOne; + this->edgeIndex = edgeIndex; } + + /*! \fn void plusplus(size_t edgeIndex) + \brief add new polygon edge who's open half-circle covers this cell + \param edgeIndex - the index of this edge + increase the edge count by one (if it is 2+, it will stay 2+) + set this new edge to be the one covers the cell if the count was zero before. (only relevant if now count == 1) + */ void plusplus(size_t edgeIndex) { if(this->count ==0) @@ -95,23 +151,80 @@ class CircleArrangment std::listedges; + + /*! \fn void insertIfLegal(const CircleEdgeIterator curIt,const CircleEdgeIterator nextIt,const struct CircleArrangmentEdge &edge) + \brief add new edge to the arrangement if it won't create some empty edges + \param curIt - iterator to the edge before where the new edge should be inserted + \param nextIt - iterator to the edge after where the new edge should be inserted + \param edge - the new edge that should be inserted + + Notice that nextIt is redundant since it can be deduced from curIt. + But it was easier for me to just send it as well. + + */ void insertIfLegal(const CircleEdgeIterator curIt,const CircleEdgeIterator nextIt,const struct CircleArrangmentEdge &edge) { if(( edge.startIsClosed && !nextIt->startIsClosed) || edge.edgeStartEngle != nextIt->edgeStartEngle) if(( curIt->startIsClosed && !edge.startIsClosed) || edge.edgeStartEngle != curIt->edgeStartEngle) edges.insert(nextIt,edge); } + /*! \fn void mergeAdjacent2EdgesAndRemoveEmpty() + \brief merge all the arcs that are adjacent and of depth 2+ -public : - CircleArrangment(std::pair firstSegmentOuterCircle) + it doesn't merge the first and last ones since it is easier this way. + */ + void mergeAdjacent2EdgesAndRemoveEmpty() { - edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.first,0,false)); - edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.second,0,true,true)); + bool inTwoEdge=false; + for(CircleEdgeIterator it=edges.begin();it!=edges.end();) + { + if(it->isCovered()) + { + if(inTwoEdge) + { + it= edges.erase(it); + continue; + } + inTwoEdge = true; + } + else + { + inTwoEdge = false; + } + it++; + } } - void addSegmentOuterCircle(std::pair segmentOuterCircle, size_t edge_index) +public : + /*! \ctor CircleArrangment(arc firstSegmentOuterCircle) + \brief creates an arrangement on circle with two edges the one covered by firstSegmentOuterCircle and the other one + \param firstSegmentOuterCircle - 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. + + */ + CircleArrangment(arc firstSegmentOuterCircle) { - std::pair edge; + edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.first,0,false)); + edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.second,0,true,false)); + } + /*! \fn addSegmentOuterCircle(arc segmentOuterCircle, size_t edge_index) + \brief updates the arrangement in respect to a new segment outer open circle + \param segmentOuterCircle - the outer circle of the current segment of the polygon. + \param edge_index - this segment id + + 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 count + for all the cells that the new arc covers. + + In the end the function mergeAdjacent2EdgesAndRemoveEmpty is called to remove redundant cells + + */ + void addSegmentOuterCircle(arc segmentOuterCircle, size_t edge_index) + { + arc edge; bool isStartClosedSegment=edges.begin()->startIsClosed; bool isEndClosedSegment=edges.begin()->startIsClosed; edge.first = edges.begin()->edgeStartEngle; @@ -144,10 +257,10 @@ public : it->plusplus(edge_index); continue; } - bool isStartContained = isOpenDirectionContainedInSegment(segmentOuterCircle.first,true,edge); - bool isEndContained = isOpenDirectionContainedInSegment(segmentOuterCircle.second,false,edge); - // o~~~~~~~~~~~~o = new segment - // ?------------? = "old" segment (the edge from the array + bool isStartContained = isOpenDirectionContainedInArc(segmentOuterCircle.first,true,edge); + bool isEndContained = isOpenDirectionContainedInArc(segmentOuterCircle.second,false,edge); + // o~~~~~~~~~~~~o = new arc + // ?------------? = "old" arc (the edge from the array) if(isStartContained) { if(isEndContained) @@ -229,33 +342,10 @@ public : } } - + mergeAdjacent2EdgesAndRemoveEmpty(); } - - void mergeAdjacent2EdgesAndRemoveEmpty() - { - bool inTwoEdge=false; - for(CircleEdgeIterator it=edges.begin();it!=edges.end();) - { - - - if(it->isCovered()) - { - if(inTwoEdge) - { - it= edges.erase(it); - continue; - } - inTwoEdge = true; - } - else - { - inTwoEdge = false; - } - it++; - } - } +#if 0 // debug function void printArrangement() { @@ -272,6 +362,18 @@ public : std::cout<<"\n\n"; } +#endif + + + /*! \fn void getAll1Edges(OutputIterator oi) + \brief insert to oi all the cells in depth 1 i.e. the cells that represent legal pullout directions + \param oi - the output iterator to put the cells in + + Puts in oi var of type pair > + foreach valid top edge. + Should only be called after all of the polygon edges where inserted. + */ + template< typename OutputIterator> void getAll1Edges(OutputIterator oi) { @@ -280,7 +382,7 @@ public : if((*it).count == 1) { - std::pair > edge; + std::pair edge; edge.first = (*it).edgeIndex; edge.second.first = (*it).edgeStartEngle; it++; @@ -293,11 +395,29 @@ public : } } } + /*! \fn bool allIsCoveredTwice() + \brief returns if all of the arrangement is in depth 2+ + + Before running this run mergeAdjacent2EdgesAndRemoveEmpty() or addSegmentOuterCircle() which calls + mergeAdjacent2EdgesAndRemoveEmpty(). + + 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. + + */ bool allIsCoveredTwice(){return edges.size()==1;} }; -template +/*! \fn std::pair getSegmentOuterCircle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) + * \fn arc getSegmentOuterCircle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) + \brief returns the open outer half-circle of the edge. + \param seg - the polygon segment + \param orientation - the orientation of the segment (and the polygon). + if CLOCKWISE then the outer half circle is to the left. + */ + +template inline std::pair getSegmentOuterCircle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) { typename Kernel::Direction_2 forward( seg); @@ -306,24 +426,39 @@ inline std::pair getS std::make_pair(backward, forward) : std::make_pair(forward, backward); } + + + +/*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) + \brief returns all the possible top edges of the polygon and there pullout direction (with no rotation) + \param pgn - the input polygon that we want to check if is castable or not. + \param oi - the output iterator to put the top edges in + */ template OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) { - typename CGAL::Polygon_2::Edge_const_iterator e_it = pgn.edges_begin(); + typedef typename CGAL::Polygon_2::Edge_const_iterator PolygonEdgeIterator; + typedef typename Kernel::Direction_2 point; + typedef std::pair arc; + /* + * Reminder: + * 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) + */ + + PolygonEdgeIterator e_it = pgn.edges_begin(); size_t edge_index =0; CGAL::Orientation poly_orientation =pgn.orientation(); - std::pair segmentOuterCircle = getSegmentOuterCircle(*e_it++,poly_orientation); + arc segmentOuterCircle = getSegmentOuterCircle(*e_it++,poly_orientation); CircleArrangment circleArrangment(segmentOuterCircle); edge_index++; - //circleArrangment.printArrangement(); - for(;e_it!= pgn.edges_end();e_it++,edge_index++) { segmentOuterCircle = getSegmentOuterCircle(*e_it,poly_orientation); circleArrangment.addSegmentOuterCircle(segmentOuterCircle,edge_index); - circleArrangment.mergeAdjacent2EdgesAndRemoveEmpty(); - // circleArrangment.printArrangement(); if(circleArrangment.allIsCoveredTwice()) return oi; } From a00c7ae050a826700f1ce7b667cda320d26a92c7 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Sat, 11 Jun 2016 18:01:34 +0300 Subject: [PATCH 09/90] Applied conventions --- ...find_single_mold_translational_casting_2.h | 787 +++++++++--------- 1 file changed, 383 insertions(+), 404 deletions(-) diff --git a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h index d298338e7c4..3de6883c5a1 100644 --- a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h +++ b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h @@ -12,10 +12,6 @@ // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // -// $URL$ -// $Id$ -// -// // Author(s): Shahar // Efi Fogel @@ -27,442 +23,425 @@ #include #include -/* - * Terms: - * point = Represented as Direction_2. It is the intersection between the fitting Direction_2 and the unit circle +/* 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) + * 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. + * 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. */ -/*! \CircleArrangment - \brief This class represents an partition of the unit-circle in to cells of depth 0,1,2+ - \ where depth 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 +/*! \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 */ template -class CircleArrangment -{ +class Circle_arrangment { + typedef typename Kernel::Direction_2 Point; + typedef std::pair Arc; + /* 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) + */ - typedef typename Kernel::Direction_2 point; - typedef std::pair arc; - /* - * Reminder: - * 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) - */ + /*! \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 p a point . + * \param is_counterclockwise true: we care about the counterclockwise epsilon + * area of p. false: same with clockwise + * \param a an arc that should contain the epsilon area + */ + static bool is_open_direction_contained_in_arc(Point p, + bool is_counterclockwise, + Arc a) + { + if ((is_counterclockwise && p == a.second) || + (!is_counterclockwise && p == a.first)) + return false; + return !p.counterclockwise_in_between(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 is_a_start_closed - do A contains its start point (clockwise) + * \param is_a_end_closed - do A contains its end point (clockwise) + * \param A - an arc + * \param B - an *open* arc + */ + static bool is_a_contained_in_b(bool is_a_start_closed, + bool is_a_end_closed, + Arc A, Arc B) + { + //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)) && + (A.first != A.second)) + return false; - /*! \fn bool isOpenDirectionContainedInArc(point p,bool isCounterClockwise, arc a) - \brief checks whether an open epsilon area clockwise/counterclockwise from a point p is contained in an arc s - \param p - a point . - \param isCounterClockwise - true: we care about the counterclockwise epsilon area of p. false: same with clockwise - \param a - an arc that should contain the epsilon area - */ - inline static bool isOpenDirectionContainedInArc(point p,bool isCounterClockwise, arc a) - { - if((isCounterClockwise && p==a.second )||(!isCounterClockwise && p==a.first )) - return false; - return !p.counterclockwise_in_between(a.first,a.second); + return (!A.first.counterclockwise_in_between(B.first, B.second) && + !A.second.counterclockwise_in_between(B.first, B.second) && + !A.first.counterclockwise_in_between(B.first, A.second)); + } - } - /*! \fn bool isAcontainedInB(bool isAStartClosed,bool isAEndClosed,arc A, arc B) - \brief checks whether an arc A is contained in an arc B - \param isAStartClosed - do A contains its start point (clockwise) - \param isAEndClosed - do A contains its end point (clockwise) - \param A - an arc - \param B - an *open* arc - */ - inline static bool isAcontainedInB(bool isAStartClosed,bool isAEndClosed,arc A, arc B) - { - //A is closed, B is open and they share an vertex -> A not contained in B - if( ( isAStartClosed &&A.first == B.first )|| (isAEndClosed && A.second == B.second)) - return false; - if((A.first == B.second ||B.first == A.second)&& A.first != A.second) - return false; + /*! \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 start_is_closed; + Point edge_start_angle; // the end is the start of the next edge + char count; // no. of outer circles that cover the edge (0/1/2+) + size_t edge_index; // the index of the polygon edge the open + // half-circle of which covers this cell. + // only relevant if count ==1 - return (!A.first.counterclockwise_in_between(B.first,B.second)&& - !A.second.counterclockwise_in_between(B.first,B.second)&& - !A.first.counterclockwise_in_between(B.first,A.second)); - } + /*! \ctor Circle_arrangment_edge(point edge_start_angle, size_t edge_index, bool start_is_closed,bool set_count_to_one=true) + * Creates a new edge (Arc), this edge count must be 0 or 1 + * \param edge_start_angle - the first point of the arc (clockwise) + * \param edge_index - the index of the polygon edge who's open half-circle + * covers this cell - only relevant if count == 1 + * \param start_is_closed - is the point edge_start_angle contained in this + * cell + * \param set_count_to_one - to set the count to one (or zero if this var is + * false) + */ + Circle_arrangment_edge(Point edge_start_angle, size_t edge_index, + bool start_is_closed, bool set_count_to_one = true) + { + this->start_is_closed = start_is_closed; + this->edge_start_angle = edge_start_angle; + this->count = (int) set_count_to_one; + this->edge_index = edge_index; + } - /*! \CircleArrangmentEdge - \brief This class represents a cells (a point or an arc) of depth 0,1,2+ in the CircleArrangment - \ where depth the number of inserted open half-circles inserted that cover this cell + /*! \fn void plusplus(size_t edge_index) + * Adds new polygon edge who's open half-circle covers this cell + * \param edge_index - the index of this edge + * increase the edge count by one (if it is 2+, it will stay 2+) + * set this new edge to be the one covers the cell if the count was zero + * before. (only relevant if now count == 1) + */ + void plusplus(size_t edge_index) { + if (this->count ==0) { + this->edge_index = edge_index; + this->count = 1; + } + else if(this->count ==1) this->count = 2; + } + bool is_covered() { return count == 2; } + }; - This edge (cell) is described by the first point of the edge (clockwise). - The last point can be deduced by the next instance of CircleArrangmentEdge in the list in CircleArrangment + typedef typename std::list Circle_edges; - this class also keeps the cell depth. - */ - class CircleArrangmentEdge - { - public : - bool startIsClosed; - point edgeStartEngle; //the end is the start of the next edge - char count; //number of outer circles that cover the edge (0/1/2+) - size_t edgeIndex; // the index of the polygon edge who's open half-circle covers this cell - only relevant if count ==1 + Circle_edges edges; - /*! \ctor CircleArrangmentEdge(point edgeStartEngle,size_t edgeIndex,bool startIsClosed,bool setCountToOne=true) - \brief create a new edge (Arc), this edge count must be 0 or 1 - \param edgeStartEngle - the first point of the arc (clockwise) - \param edgeIndex - the index of the polygon edge who's open half-circle covers this cell - only relevant if count == 1 - \param startIsClosed - is the point edgeStartEngle contained in this cell - \param setCountToOne - to set the count to one (or zero if this var is false) - */ - CircleArrangmentEdge(point edgeStartEngle,size_t edgeIndex,bool startIsClosed,bool setCountToOne=true) - { - this->startIsClosed=startIsClosed; - this->edgeStartEngle= edgeStartEngle; - this->count = (int) setCountToOne; - this->edgeIndex = edgeIndex; - } + /*! \fn void insert_if_legal(const Circle_edge_iterator cur_it,const Circle_edge_iterator next_it,const struct Circle_arrangment_edge &edge) + * Adds new edge to the arrangement if it won't create some empty edges + * \param cur_it iterator to the edge before where the new edge should be + * inserted + * \param next_it - iterator to the edge after where the new edge should be + * inserted + * \param 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 + void insert_if_legal(const InputIterator cur_it, + const InputIterator next_it, + const struct Circle_arrangment_edge& edge) + { + if ((edge.start_is_closed && !next_it->start_is_closed) || + edge.edge_start_angle != next_it->edge_start_angle) + if ((cur_it->start_is_closed && !edge.start_is_closed) || + edge.edge_start_angle != cur_it->edge_start_angle) + edges.insert(next_it, edge); + } - /*! \fn void plusplus(size_t edgeIndex) - \brief add new polygon edge who's open half-circle covers this cell - \param edgeIndex - the index of this edge - increase the edge count by one (if it is 2+, it will stay 2+) - set this new edge to be the one covers the cell if the count was zero before. (only relevant if now count == 1) - */ - void plusplus(size_t edgeIndex) - { - if(this->count ==0) - { - this->edgeIndex = edgeIndex; - this->count = 1; - } - else if(this->count ==1) - { - this->count =2; - } + /*! \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 = edges.begin(); it != edges.end();) { + if (it->is_covered()) { + if (in_two_edge) { + it = edges.erase(it); + continue; + } + in_two_edge = true; + } + else { + in_two_edge = false; + } + ++it; + } + } - } - bool isCovered(){return count ==2;} +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 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(Arc first_segment_outer_circle) + { + edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, 0, + false)); + edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, 0, + true,false)); + } - }; - typedef typename std::list::iterator CircleEdgeIterator; + /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) + * Updates the arrangement in respect to a new segment outer open circle + * \param segment_outer_circle - the outer circle of the current segment of + * the polygon. + * \param edge_index - this segment id + * 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 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(Arc segment_outer_circle, size_t edge_index) + { + Arc edge; + bool is_start_closed_segment = edges.begin()->start_is_closed; + bool is_end_closed_segment = edges.begin()->start_is_closed; + edge.first = edges.begin()->edge_start_angle; + edge.second = edges.begin()->edge_start_angle; + auto next_it = edges.begin(); + auto it = edges.begin(); + bool done = false; + while (!done) { + it = next_it; + next_it = it; + next_it++; + if (next_it == edges.end()) { + done = true; + next_it = edges.begin(); + } - std::listedges; + is_start_closed_segment = !is_end_closed_segment; + is_end_closed_segment = !next_it->start_is_closed; + edge.first = edge.second; + edge.second =next_it->edge_start_angle; - - /*! \fn void insertIfLegal(const CircleEdgeIterator curIt,const CircleEdgeIterator nextIt,const struct CircleArrangmentEdge &edge) - \brief add new edge to the arrangement if it won't create some empty edges - \param curIt - iterator to the edge before where the new edge should be inserted - \param nextIt - iterator to the edge after where the new edge should be inserted - \param edge - the new edge that should be inserted - - Notice that nextIt is redundant since it can be deduced from curIt. - But it was easier for me to just send it as well. - - */ - void insertIfLegal(const CircleEdgeIterator curIt,const CircleEdgeIterator nextIt,const struct CircleArrangmentEdge &edge) - { - if(( edge.startIsClosed && !nextIt->startIsClosed) || edge.edgeStartEngle != nextIt->edgeStartEngle) - if(( curIt->startIsClosed && !edge.startIsClosed) || edge.edgeStartEngle != curIt->edgeStartEngle) - edges.insert(nextIt,edge); - } - /*! \fn void mergeAdjacent2EdgesAndRemoveEmpty() - \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 mergeAdjacent2EdgesAndRemoveEmpty() - { - bool inTwoEdge=false; - for(CircleEdgeIterator it=edges.begin();it!=edges.end();) - { - if(it->isCovered()) - { - if(inTwoEdge) - { - it= edges.erase(it); - continue; - } - inTwoEdge = true; - } - else - { - inTwoEdge = false; - } - it++; - } - } - -public : - /*! \ctor CircleArrangment(arc firstSegmentOuterCircle) - \brief creates an arrangement on circle with two edges the one covered by firstSegmentOuterCircle and the other one - \param firstSegmentOuterCircle - 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. - - */ - CircleArrangment(arc firstSegmentOuterCircle) - { - edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.first,0,false)); - edges.push_back(CircleArrangmentEdge(firstSegmentOuterCircle.second,0,true,false)); - } - /*! \fn addSegmentOuterCircle(arc segmentOuterCircle, size_t edge_index) - \brief updates the arrangement in respect to a new segment outer open circle - \param segmentOuterCircle - the outer circle of the current segment of the polygon. - \param edge_index - this segment id - - 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 count - for all the cells that the new arc covers. - - In the end the function mergeAdjacent2EdgesAndRemoveEmpty is called to remove redundant cells - - */ - void addSegmentOuterCircle(arc segmentOuterCircle, size_t edge_index) - { - arc edge; - bool isStartClosedSegment=edges.begin()->startIsClosed; - bool isEndClosedSegment=edges.begin()->startIsClosed; - edge.first = edges.begin()->edgeStartEngle; - edge.second = edges.begin()->edgeStartEngle; - CircleEdgeIterator nextIt=edges.begin(); - CircleEdgeIterator it=edges.begin(); - bool done = false; - while(!done) - { - it = nextIt; - nextIt=it; - nextIt++; - if(nextIt==edges.end()) { - done =true; - nextIt= edges.begin(); - } - - isStartClosedSegment = !isEndClosedSegment; - isEndClosedSegment = !nextIt->startIsClosed; - edge.first = edge.second; - edge.second =nextIt->edgeStartEngle; - - if(it->count == 2) - { - - continue; - } - if( isAcontainedInB(isStartClosedSegment,isEndClosedSegment,edge,segmentOuterCircle)) - { - it->plusplus(edge_index); - continue; - } - bool isStartContained = isOpenDirectionContainedInArc(segmentOuterCircle.first,true,edge); - bool isEndContained = isOpenDirectionContainedInArc(segmentOuterCircle.second,false,edge); - // o~~~~~~~~~~~~o = new arc - // ?------------? = "old" arc (the edge from the array) - if(isStartContained) - { - if(isEndContained) - { - bool isordered = !segmentOuterCircle.second.counterclockwise_in_between(segmentOuterCircle.first,edge.second); - if(isordered) - { - // o~~~~~~~~~~~~o - // ?-----------------------? - // __________________________ - // ?----c - // o~-~-~-~-~-~-o - // c-----? - struct CircleArrangmentEdge edge2 = *it; - edge2.startIsClosed=false; - edge2.edgeStartEngle=segmentOuterCircle.first; - edge2.plusplus(edge_index); - this->insertIfLegal(it,nextIt,edge2); - struct CircleArrangmentEdge edge3 = *it; - edge3.startIsClosed=true; - edge3.edgeStartEngle=segmentOuterCircle.second; - this->insertIfLegal(it,nextIt,edge3); - - - } - else - { - // ...~~~~~~~~~o o~~~~~~~~~~... (round) - // ?------------? - // __________________________ - // ?~-~o - // c----c - // o-~-? - - struct CircleArrangmentEdge edge2 = *it; - edge2.startIsClosed=true; - edge2.edgeStartEngle=segmentOuterCircle.second; - this->insertIfLegal(it,nextIt,edge2); - struct CircleArrangmentEdge edge3 = *it; - edge3.startIsClosed=false; - edge3.edgeStartEngle=segmentOuterCircle.first; - edge3.plusplus(edge_index); - this->insertIfLegal(it,nextIt,edge3); - it->plusplus(edge_index); - } - } - else - { - // o~~~~~~~~~~~~o - // ?-----------? - //_____________________ - // ?----c - // o-~-~-~? - struct CircleArrangmentEdge edge2 = *it; - edge2.startIsClosed=false; - edge2.edgeStartEngle=segmentOuterCircle.first; - edge2.plusplus(edge_index); - this->insertIfLegal(it,nextIt,edge2); - - } - } - else - { - if(isEndContained) - { - // o~~~~~~~~~~~~o - // ?------------? - //_____________________ - // ?-~-~-~-o - // c----? - struct CircleArrangmentEdge edge2 = *it; - edge2.startIsClosed=true; - edge2.edgeStartEngle=segmentOuterCircle.second; - it->plusplus(edge_index); - this->insertIfLegal(it,nextIt,edge2); - } - //else - no intersection, do noting - - - } - } - mergeAdjacent2EdgesAndRemoveEmpty(); - } + if (it->count == 2) continue; + if (is_a_contained_in_b(is_start_closed_segment, is_end_closed_segment, + edge, segment_outer_circle)) + { + it->plusplus(edge_index); + 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) { + bool isordered = + !segment_outer_circle.second.counterclockwise_in_between(segment_outer_circle.first, edge.second); + if (isordered) { + // o~~~~~~~~~~~~o + // ?-----------------------? + // __________________________ + // ?----c + // o~-~-~-~-~-~-o + // c-----? + struct Circle_arrangment_edge edge2 = *it; + edge2.start_is_closed = false; + edge2.edge_start_angle = segment_outer_circle.first; + edge2.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + struct Circle_arrangment_edge edge3 = *it; + edge3.start_is_closed = true; + edge3.edge_start_angle = segment_outer_circle.second; + this->insert_if_legal(it,next_it,edge3); + } + else { + // ...~~~~~~~~~o o~~~~~~~~~~... (round) + // ?------------? + // __________________________ + // ?~-~o + // c----c + // o-~-? + struct Circle_arrangment_edge edge2 = *it; + edge2.start_is_closed = true; + edge2.edge_start_angle = segment_outer_circle.second; + this->insert_if_legal(it, next_it, edge2); + struct Circle_arrangment_edge edge3 = *it; + edge3.start_is_closed = false; + edge3.edge_start_angle = segment_outer_circle.first; + edge3.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge3); + it->plusplus(edge_index); + } + } + else { + // o~~~~~~~~~~~~o + // ?-----------? + //_____________________ + // ?----c + // o-~-~-~? + struct Circle_arrangment_edge edge2 = *it; + edge2.start_is_closed = false; + edge2.edge_start_angle = segment_outer_circle.first; + edge2.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + } + } + else { + if (is_end_contained) { + // o~~~~~~~~~~~~o + // ?------------? + //_____________________ + // ?-~-~-~-o + // c----? + struct Circle_arrangment_edge edge2 = *it; + edge2.start_is_closed = true; + edge2.edge_start_angle = segment_outer_circle.second; + it->plusplus(edge_index); + 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(CircleEdgeIterator it=edges.begin();it!=edges.end();++it) - { - if(it->startIsClosed) - std::cout<<")["; - else - std::cout<<"]("; - std::cout<edgeStartEngle; - std::cout<<","<<(int)it->count; - - } - std::cout<<"\n\n"; - - } + // debug function + void printArrangement() + { + for (auto it = edges.begin(); it != edges.end(); ++it) { + if (it->start_is_closed) std::cout<<")["; + else std::cout << "]("; + std::cout << it->edge_start_angle; + std::cout << ","<<(int)it->count; + } + std::cout << "\n\n"; + } #endif - /*! \fn void getAll1Edges(OutputIterator oi) - \brief insert to oi all the cells in depth 1 i.e. the cells that represent legal pullout directions - \param oi - the output iterator to put the cells in - - Puts in oi var of type pair > - foreach valid top edge. - Should only be called after all of the polygon edges where inserted. - */ - - template< typename OutputIterator> - void getAll1Edges(OutputIterator oi) - { - for(CircleEdgeIterator it=edges.begin();it!=edges.end();) - { - - if((*it).count == 1) - { - std::pair edge; - edge.first = (*it).edgeIndex; - edge.second.first = (*it).edgeStartEngle; - it++; - edge.second.second = (*((it == edges.end())?edges.begin():(it))).edgeStartEngle; - oi=(edge); - } - else - { - it++; - } - } - } - /*! \fn bool allIsCoveredTwice() - \brief returns if all of the arrangement is in depth 2+ - - Before running this run mergeAdjacent2EdgesAndRemoveEmpty() or addSegmentOuterCircle() which calls - mergeAdjacent2EdgesAndRemoveEmpty(). - - 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. - - */ - bool allIsCoveredTwice(){return edges.size()==1;} + /*! \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 oithe output iterator to put the cells in + * Puts in oi var of type pair > foreach valid top edge. + * Should only be called after all of the polygon edges where inserted. + */ + template + OutputIterator get_all_1_edges(OutputIterator oi) + { + for (auto it = edges.begin(); it != edges.end();) { + if ((*it).count == 1) { + std::pair edge; + edge.first = (*it).edge_index; + edge.second.first = (*it).edge_start_angle; + it++; + edge.second.second = + (*((it == edges.end()) ? edges.begin() : (it))).edge_start_angle; + *oi++ = edge; + } + else + { + it++; + } + } + } + /*! \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 edges.size() == 1; } }; -/*! \fn std::pair getSegmentOuterCircle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) - * \fn arc getSegmentOuterCircle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) - \brief returns the open outer half-circle of the edge. - \param seg - the polygon segment - \param orientation - the orientation of the segment (and the polygon). - if CLOCKWISE then the outer half circle is to the left. +/*! \fn std::pair 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 -inline std::pair getSegmentOuterCircle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) +inline std::pair +get_segment_outer_circle(typename Kernel::Segment_2 seg, + CGAL::Orientation orientation) { - typename Kernel::Direction_2 forward( seg); - typename Kernel::Direction_2 backward(-forward); - return (orientation ==CGAL::Orientation::CLOCKWISE)? - std::make_pair(backward, forward) : std::make_pair(forward, backward); - + typename Kernel::Direction_2 forward( seg); + typename Kernel::Direction_2 backward(-forward); + return (orientation == CGAL::Orientation::CLOCKWISE) ? + std::make_pair(backward, forward) : std::make_pair(forward, backward); } - - /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) - \brief returns all the possible top edges of the polygon and there pullout direction (with no rotation) - \param pgn - 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[in] pgn the input polygon that we want to check if is castable or not. + * \param[in] oi the output iterator to put the top edges in + * \return all the possible top edges of the polygon and there pullout direction + * (with no rotation) */ template OutputIterator -find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) +find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, + OutputIterator oi) { - typedef typename CGAL::Polygon_2::Edge_const_iterator PolygonEdgeIterator; - typedef typename Kernel::Direction_2 point; - typedef std::pair arc; - /* - * Reminder: - * 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) - */ - - PolygonEdgeIterator e_it = pgn.edges_begin(); - size_t edge_index =0; - CGAL::Orientation poly_orientation =pgn.orientation(); - arc segmentOuterCircle = getSegmentOuterCircle(*e_it++,poly_orientation); - CircleArrangment circleArrangment(segmentOuterCircle); - edge_index++; - for(;e_it!= pgn.edges_end();e_it++,edge_index++) - { - segmentOuterCircle = getSegmentOuterCircle(*e_it,poly_orientation); - circleArrangment.addSegmentOuterCircle(segmentOuterCircle,edge_index); - if(circleArrangment.allIsCoveredTwice()) - return oi; - } - circleArrangment.getAll1Edges(oi); - return oi; + /* 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) + */ + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + auto poly_orientation = pgn.orientation(); + auto segment_outer_circle = + get_segment_outer_circle(*e_it++, poly_orientation); + Circle_arrangment circle_arrangment(segment_outer_circle); + edge_index++; + for (; e_it!= pgn.edges_end(); e_it++,edge_index++) { + segment_outer_circle = + get_segment_outer_circle(*e_it, poly_orientation); + circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); + if (circle_arrangment.all_is_covered_twice()) return oi; + } + circle_arrangment.get_all_1_edges(oi); + return oi; } #endif From 12e992a5f5e4aabcfde5f712759fcd8a6207169c Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Mon, 13 Jun 2016 11:38:52 +0300 Subject: [PATCH 10/90] Added missing return statement --- .../include/CGAL/find_single_mold_translational_casting_2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h index 3de6883c5a1..9382c5b374e 100644 --- a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h +++ b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h @@ -378,6 +378,7 @@ public: it++; } } + return oi; } /*! \fn bool all_is_covered_twice() From 836bed8b876883bfceb19aebe9dc13dfa202c6f8 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Mon, 13 Jun 2016 22:47:08 +0300 Subject: [PATCH 11/90] added most of my todo list --- ...find_single_mold_translational_casting_2.h | 219 +++++++++--------- 1 file changed, 111 insertions(+), 108 deletions(-) diff --git a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h index 9382c5b374e..f811efc25ff 100644 --- a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h +++ b/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h @@ -54,37 +54,37 @@ class Circle_arrangment { * 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) + /*! \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 p a point . - * \param is_counterclockwise true: we care about the counterclockwise epsilon + * \param[in] p a point . + * \param[in] is_counterclockwise true: we care about the counterclockwise epsilon * area of p. false: same with clockwise - * \param a an arc that should contain the epsilon area + * \param[in] A an Arc that should contain the epsilon area */ - static bool is_open_direction_contained_in_arc(Point p, - bool is_counterclockwise, - Arc a) + static bool is_open_direction_contained_in_arc(const Point p, + const bool is_counterclockwise, + const Arc A) { - if ((is_counterclockwise && p == a.second) || - (!is_counterclockwise && p == a.first)) + if ((is_counterclockwise && (p == A.second)) || + (!is_counterclockwise && (p == A.first))) return false; - return !p.counterclockwise_in_between(a.first,a.second); + return !p.counterclockwise_in_between(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 is_a_start_closed - do A contains its start point (clockwise) - * \param is_a_end_closed - do A contains its end point (clockwise) - * \param A - an arc - * \param B - an *open* arc + * \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 */ - static bool is_a_contained_in_b(bool is_a_start_closed, - bool is_a_end_closed, - Arc A, Arc B) + static bool is_a_contained_in_b(const bool is_a_start_closed, + const bool is_a_end_closed, + const Arc A,const Arc B) { //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)) + 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)) && (A.first != A.second)) @@ -106,74 +106,77 @@ class Circle_arrangment { */ class Circle_arrangment_edge { public: - bool start_is_closed; - Point edge_start_angle; // the end is the start of the next edge - char count; // no. of outer circles that cover the edge (0/1/2+) - size_t edge_index; // the index of the polygon edge the open + 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+) + + size_t m_edge_index; // the index of the polygon edge the open // half-circle of which covers this cell. - // only relevant if count ==1 + // only relevant if m_count ==1 /*! \ctor Circle_arrangment_edge(point edge_start_angle, size_t edge_index, bool start_is_closed,bool set_count_to_one=true) * Creates a new edge (Arc), this edge count must be 0 or 1 - * \param edge_start_angle - the first point of the arc (clockwise) - * \param edge_index - the index of the polygon edge who's open half-circle - * covers this cell - only relevant if count == 1 - * \param start_is_closed - is the point edge_start_angle contained in this + * \param[in] edge_start_angle - the first point of the arc (clockwise) + * \param[in] edge_index - the index 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 set_count_to_one - to set the count to one (or zero if this var is + * \param[in] set_count_to_one - to set the m_count to one (or zero if this var is * false) */ - Circle_arrangment_edge(Point edge_start_angle, size_t edge_index, - bool start_is_closed, bool set_count_to_one = true) + Circle_arrangment_edge(const Point edge_start_angle,const size_t edge_index, + const bool start_is_closed,const bool set_count_to_one = true) { - this->start_is_closed = start_is_closed; - this->edge_start_angle = edge_start_angle; - this->count = (int) set_count_to_one; - this->edge_index = edge_index; + 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_index = edge_index; } /*! \fn void plusplus(size_t edge_index) * Adds new polygon edge who's open half-circle covers this cell - * \param edge_index - the index of this edge - * increase the edge count by one (if it is 2+, it will stay 2+) - * set this new edge to be the one covers the cell if the count was zero - * before. (only relevant if now count == 1) + * \param[in] edge_index - the index 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(size_t edge_index) { - if (this->count ==0) { - this->edge_index = edge_index; - this->count = 1; + void plusplus(const size_t edge_index) { + if (this->m_count ==0) { + this->m_edge_index = edge_index; + this->m_count = 1; } - else if(this->count ==1) this->count = 2; + else if(this->m_count ==1) this->m_count = 2; } - bool is_covered() { return count == 2; } + bool is_covered() { return m_count == 2; } }; typedef typename std::list Circle_edges; - Circle_edges edges; + Circle_edges m_edges; /*! \fn void insert_if_legal(const Circle_edge_iterator cur_it,const Circle_edge_iterator next_it,const struct Circle_arrangment_edge &edge) * Adds new edge to the arrangement if it won't create some empty edges - * \param cur_it iterator to the edge before where the new edge should be + * \param[in] cur_it iterator to the edge before where the new edge should be * inserted - * \param next_it - iterator to the edge after where the new edge should be + * \param[in] next_it - iterator to the edge after where the new edge should be * inserted - * \param edge - the new edge that 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 void insert_if_legal(const InputIterator cur_it, - const InputIterator next_it, + InputIterator next_it, const struct Circle_arrangment_edge& edge) { - if ((edge.start_is_closed && !next_it->start_is_closed) || - edge.edge_start_angle != next_it->edge_start_angle) - if ((cur_it->start_is_closed && !edge.start_is_closed) || - edge.edge_start_angle != cur_it->edge_start_angle) - edges.insert(next_it, edge); + if ((edge.m_start_is_closed && !next_it->m_start_is_closed) || + (edge.m_edge_start_angle != next_it->m_edge_start_angle)) + if ((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); } /*! \fn void merge_adjacent_2_edges_and_remove_empty() @@ -183,10 +186,10 @@ class Circle_arrangment { void merge_adjacent_2_edges_and_remove_empty() { bool in_two_edge(false); - for (auto it = edges.begin(); it != edges.end();) { + for (auto it = m_edges.begin(); it != m_edges.end();) { if (it->is_covered()) { if (in_two_edge) { - it = edges.erase(it); + it = m_edges.erase(it); continue; } in_two_edge = true; @@ -202,55 +205,55 @@ 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 first_segment_outer_circle - the outer circle of the first segment + * \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(Arc first_segment_outer_circle) + Circle_arrangment(const Arc first_segment_outer_circle) { - edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, 0, + m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, 0, false)); - edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, 0, + m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, 0, true,false)); } /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) * Updates the arrangement in respect to a new segment outer open circle - * \param segment_outer_circle - the outer circle of the current segment of + * \param[in] segment_outer_circle - the outer circle of the current segment of * the polygon. - * \param edge_index - this segment id + * \param[in] edge_index - this segment id * 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 count + * 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(Arc segment_outer_circle, size_t edge_index) + void add_segment_outer_circle(const Arc segment_outer_circle,const size_t edge_index) { Arc edge; - bool is_start_closed_segment = edges.begin()->start_is_closed; - bool is_end_closed_segment = edges.begin()->start_is_closed; - edge.first = edges.begin()->edge_start_angle; - edge.second = edges.begin()->edge_start_angle; - auto next_it = edges.begin(); - auto it = edges.begin(); + bool is_start_closed_segment = m_edges.begin()->m_start_is_closed; + bool is_end_closed_segment = m_edges.begin()->m_start_is_closed; + edge.first = m_edges.begin()->m_edge_start_angle; + edge.second = m_edges.begin()->m_edge_start_angle; + 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 == edges.end()) { + ++next_it; + if (next_it == m_edges.end()) { done = true; - next_it = edges.begin(); + next_it = m_edges.begin(); } is_start_closed_segment = !is_end_closed_segment; - is_end_closed_segment = !next_it->start_is_closed; + is_end_closed_segment = !next_it->m_start_is_closed; edge.first = edge.second; - edge.second =next_it->edge_start_angle; + edge.second =next_it->m_edge_start_angle; - if (it->count == 2) continue; + if (it->m_count == 2) continue; if (is_a_contained_in_b(is_start_closed_segment, is_end_closed_segment, edge, segment_outer_circle)) { @@ -277,13 +280,13 @@ public: // o~-~-~-~-~-~-o // c-----? struct Circle_arrangment_edge edge2 = *it; - edge2.start_is_closed = false; - edge2.edge_start_angle = segment_outer_circle.first; + edge2.m_start_is_closed = false; + edge2.m_edge_start_angle = segment_outer_circle.first; edge2.plusplus(edge_index); this->insert_if_legal(it, next_it, edge2); struct Circle_arrangment_edge edge3 = *it; - edge3.start_is_closed = true; - edge3.edge_start_angle = segment_outer_circle.second; + edge3.m_start_is_closed = true; + edge3.m_edge_start_angle = segment_outer_circle.second; this->insert_if_legal(it,next_it,edge3); } else { @@ -294,12 +297,12 @@ public: // c----c // o-~-? struct Circle_arrangment_edge edge2 = *it; - edge2.start_is_closed = true; - edge2.edge_start_angle = segment_outer_circle.second; + edge2.m_start_is_closed = true; + edge2.m_edge_start_angle = segment_outer_circle.second; this->insert_if_legal(it, next_it, edge2); struct Circle_arrangment_edge edge3 = *it; - edge3.start_is_closed = false; - edge3.edge_start_angle = segment_outer_circle.first; + edge3.m_start_is_closed = false; + edge3.m_edge_start_angle = segment_outer_circle.first; edge3.plusplus(edge_index); this->insert_if_legal(it, next_it, edge3); it->plusplus(edge_index); @@ -312,8 +315,8 @@ public: // ?----c // o-~-~-~? struct Circle_arrangment_edge edge2 = *it; - edge2.start_is_closed = false; - edge2.edge_start_angle = segment_outer_circle.first; + edge2.m_start_is_closed = false; + edge2.m_edge_start_angle = segment_outer_circle.first; edge2.plusplus(edge_index); this->insert_if_legal(it, next_it, edge2); } @@ -326,8 +329,8 @@ public: // ?-~-~-~-o // c----? struct Circle_arrangment_edge edge2 = *it; - edge2.start_is_closed = true; - edge2.edge_start_angle = segment_outer_circle.second; + edge2.m_start_is_closed = true; + edge2.m_edge_start_angle = segment_outer_circle.second; it->plusplus(edge_index); this->insert_if_legal(it, next_it, edge2); } @@ -341,11 +344,11 @@ public: // debug function void printArrangement() { - for (auto it = edges.begin(); it != edges.end(); ++it) { - if (it->start_is_closed) std::cout<<")["; + 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->edge_start_angle; - std::cout << ","<<(int)it->count; + std::cout << it->m_edge_start_angle; + std::cout << ","<<(int)it->m_count; } std::cout << "\n\n"; } @@ -355,7 +358,7 @@ public: /*! \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 oithe output iterator to put the cells in + * \param[in, out] oi the output iterator to put the cells in * Puts in oi var of type pair > foreach valid top edge. * Should only be called after all of the polygon edges where inserted. @@ -363,19 +366,19 @@ public: template OutputIterator get_all_1_edges(OutputIterator oi) { - for (auto it = edges.begin(); it != edges.end();) { - if ((*it).count == 1) { + for (auto it = m_edges.begin(); it != m_edges.end();) { + if ((*it).m_count == 1) { std::pair edge; - edge.first = (*it).edge_index; - edge.second.first = (*it).edge_start_angle; - it++; + edge.first = (*it).m_edge_index; + edge.second.first = (*it).m_edge_start_angle; + ++it; edge.second.second = - (*((it == edges.end()) ? edges.begin() : (it))).edge_start_angle; + (*((it == m_edges.end()) ? m_edges.begin() : (it))).m_edge_start_angle; *oi++ = edge; } else { - it++; + ++it; } } return oi; @@ -391,7 +394,7 @@ public: * depth as well. * \return if all of the arrangement is in depth 2+ */ - bool all_is_covered_twice() { return edges.size() == 1; } + bool all_is_covered_twice() { return m_edges.size() == 1; } }; /*! \fn std::pair get_segment_outer_circle(typename Kernel::Segment_2 seg, CGAL::Orientation orientation) @@ -402,8 +405,8 @@ public: */ template inline std::pair -get_segment_outer_circle(typename Kernel::Segment_2 seg, - CGAL::Orientation orientation) +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); @@ -413,7 +416,7 @@ get_segment_outer_circle(typename Kernel::Segment_2 seg, /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) * \param[in] pgn the input polygon that we want to check if is castable or not. - * \param[in] oi the output iterator to put the top edges in + * \param[in,out] oi the output iterator to put the top edges in * \return all the possible top edges of the polygon and there pullout direction * (with no rotation) */ @@ -431,12 +434,12 @@ find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, */ auto e_it = pgn.edges_begin(); size_t edge_index = 0; - auto poly_orientation = pgn.orientation(); + CGAL::Orientation poly_orientation = pgn.orientation(); auto segment_outer_circle = get_segment_outer_circle(*e_it++, poly_orientation); Circle_arrangment circle_arrangment(segment_outer_circle); - edge_index++; - for (; e_it!= pgn.edges_end(); e_it++,edge_index++) { + ++edge_index; + for (; e_it!= pgn.edges_end(); ++e_it,++edge_index) { segment_outer_circle = get_segment_outer_circle(*e_it, poly_orientation); circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); From 88f275c2a0702c04b97bffa1aee7b355dd7d4274 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 22 Jun 2016 11:32:35 +0300 Subject: [PATCH 12/90] Documentation skeleton --- Casting_2/doc/Casting_2/Casting_2.txt | 17 ++++++++++ Casting_2/doc/Casting_2/Doxyfile.in | 3 ++ .../doc/Casting_2/PackageDescription.txt | 33 +++++++++++++++++++ Casting_2/doc/Casting_2/examples.txt | 3 ++ 4 files changed, 56 insertions(+) create mode 100644 Casting_2/doc/Casting_2/Casting_2.txt create mode 100644 Casting_2/doc/Casting_2/Doxyfile.in create mode 100644 Casting_2/doc/Casting_2/PackageDescription.txt create mode 100644 Casting_2/doc/Casting_2/examples.txt diff --git a/Casting_2/doc/Casting_2/Casting_2.txt b/Casting_2/doc/Casting_2/Casting_2.txt new file mode 100644 index 00000000000..3df5af13dd3 --- /dev/null +++ b/Casting_2/doc/Casting_2/Casting_2.txt @@ -0,0 +1,17 @@ +namespace CGAL { +/*! + +\mainpage User Manual +\anchor Chapter_Casting_of_polygons + +\anchor chapterEnvelope2 + +\cgalAutoToc +\authors Shahar Shamai and Efif Fogel + +\section casting_sec_intro Introduction + +\cgalExample{Casting_2/single_mold_translational_casting.cpp} + +*/ +} /* namespace CGAL */ diff --git a/Casting_2/doc/Casting_2/Doxyfile.in b/Casting_2/doc/Casting_2/Doxyfile.in new file mode 100644 index 00000000000..bd25d8dafda --- /dev/null +++ b/Casting_2/doc/Casting_2/Doxyfile.in @@ -0,0 +1,3 @@ +@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} + +PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Castings" diff --git a/Casting_2/doc/Casting_2/PackageDescription.txt b/Casting_2/doc/Casting_2/PackageDescription.txt new file mode 100644 index 00000000000..8e5e4aa60a2 --- /dev/null +++ b/Casting_2/doc/Casting_2/PackageDescription.txt @@ -0,0 +1,33 @@ +/// \defgroup PkgCasting2 2D Castings Reference +/// \defgroup PkgCasting2Concepts Concepts +/// \ingroup PkgCasting2 +/*! +\addtogroup PkgCasting2 +\todo check generated documentation +\cgalPkgDescriptionBegin{2D Castings,PkgCasting2Summary} +\cgalPkgPicture{Casting_2/fig/Casting_2.png} +\cgalPkgSummaryBegin +\cgalPkgAuthors{Shahar Shamai, Efi Fogel} +\cgalPkgDesc{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.} +\cgalPkgManuals{Chapter_Castings_of_polygons,PkgCasting2} +\cgalPkgSummaryEnd +\cgalPkgShortInfoBegin +\cgalPkgSince{4.10} +\cgalPkgDependsOn{\ref PkgCasting2Summary} +\cgalPkgBib{cgal:sf-casting2} +\cgalPkgLicense{\ref licensesGPL "GPL"} +\cgalPkgShortInfoEnd +\cgalPkgDescriptionEnd + +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. + +\cgalClassifedRefPages + +## Functions ## +- `CGAL::single_mold_translational_casting_2` + +## Concepts ## + +## Classes ## + +*/ diff --git a/Casting_2/doc/Casting_2/examples.txt b/Casting_2/doc/Casting_2/examples.txt new file mode 100644 index 00000000000..dda045ca521 --- /dev/null +++ b/Casting_2/doc/Casting_2/examples.txt @@ -0,0 +1,3 @@ +/*! +\example Casting_2/single_mold_translational_casting.cpp +*/ From aaa14948a9929a4a4bb64b2bd4c61cfb970daeab Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 12 Jul 2016 23:52:44 +0300 Subject: [PATCH 13/90] First test --- Casting_2/test/Casting_2/CMakeLists.txt | 29 ++++ Casting_2/test/Casting_2/cgal_test_with_cmake | 113 ++++++++++++++++ Casting_2/test/Casting_2/data/test01.txt | 7 + ...test_single_mold_translational_casting.cmd | 15 +++ ...test_single_mold_translational_casting.cpp | 125 ++++++++++++++++++ 5 files changed, 289 insertions(+) create mode 100644 Casting_2/test/Casting_2/CMakeLists.txt create mode 100755 Casting_2/test/Casting_2/cgal_test_with_cmake create mode 100644 Casting_2/test/Casting_2/data/test01.txt create mode 100644 Casting_2/test/Casting_2/test_single_mold_translational_casting.cmd create mode 100644 Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp diff --git a/Casting_2/test/Casting_2/CMakeLists.txt b/Casting_2/test/Casting_2/CMakeLists.txt new file mode 100644 index 00000000000..0e39af47ec3 --- /dev/null +++ b/Casting_2/test/Casting_2/CMakeLists.txt @@ -0,0 +1,29 @@ +# Created by the script cgal_create_cmake_script +# This is the CMake script for compiling a CGAL application. + + +project( Casting_2_test ) + +cmake_minimum_required(VERSION 2.8.10) + +find_package(CGAL QUIET COMPONENTS Core ) + +if ( CGAL_FOUND ) + + include( ${CGAL_USE_FILE} ) + + include( CGAL_CreateSingleSourceCGALProgram ) + + include_directories (BEFORE "../../include") + + if (CMAKE_COMPILER_IS_GNUCXX) + add_definitions(-std=c++11) + endif() + +create_single_source_cgal_program( "test_single_mold_translational_casting.cpp" ) + +else() + + message(STATUS "This program requires the CGAL library, and will not be compiled.") + +endif() diff --git a/Casting_2/test/Casting_2/cgal_test_with_cmake b/Casting_2/test/Casting_2/cgal_test_with_cmake new file mode 100755 index 00000000000..f89576f0cdb --- /dev/null +++ b/Casting_2/test/Casting_2/cgal_test_with_cmake @@ -0,0 +1,113 @@ +#! /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 +#---------------------------------------------------------------------# + +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_single_mold_translational_casting$" > /dev/null; then + compile_and_run test_single_mold_translational_casting + 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 diff --git a/Casting_2/test/Casting_2/data/test01.txt b/Casting_2/test/Casting_2/data/test01.txt new file mode 100644 index 00000000000..f46664e34c8 --- /dev/null +++ b/Casting_2/test/Casting_2/data/test01.txt @@ -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 diff --git a/Casting_2/test/Casting_2/test_single_mold_translational_casting.cmd b/Casting_2/test/Casting_2/test_single_mold_translational_casting.cmd new file mode 100644 index 00000000000..e8f30c0cf64 --- /dev/null +++ b/Casting_2/test/Casting_2/test_single_mold_translational_casting.cmd @@ -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 diff --git a/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp b/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp new file mode 100644 index 00000000000..11c33dfe2af --- /dev/null +++ b/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef CGAL::Polygon_2 Polygon_2; +typedef Kernel::Direction_2 Direction_2; +typedef Kernel::Point_2 Point_2; + +typedef std::pair Direction_range; +typedef std::pair Top_edge; + +struct Top_edge_comparer { + bool operator()(const Top_edge& a, const Top_edge& b) + { + auto facet_a = a.first; + const auto& d1_a = a.second.first; + const auto& d2_a = a.second.second; + auto facet_b = b.first; + const auto& d1_b = b.second.first; + const auto& d2_b = b.second.second; + + 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_edges; + CGAL::single_mold_translational_casting_2(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 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; + top_edge = std::make_pair(facet, 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; + const auto& d1 = it->second.first; + const auto& d2 = it->second.second; + auto exp_facet = exp_it->first; + const auto& exp_d1 = exp_it->second.first; + const auto& exp_d2 = exp_it->second.second; + if ((facet != exp_facet) || (d1 != exp_d1) || (d2 != exp_d2)) { + std::cerr << "Top edge[" << i++ << "]: " + << "obtained: " << facet << " " << d1 << " " << d2 + << ", expected: " << exp_facet << " " << 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 < 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 (*itr == 't') 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; +} From 27c3a6a4ce9f46691a612a382b5bee3f0e33f4d2 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 12 Jul 2016 23:57:53 +0300 Subject: [PATCH 14/90] Renamed find_single_mold_translational_casting_2() to single_mold_translational_casting_2() --- Casting_2/examples/Casting_2/CMakeLists.txt | 2 +- ...cpp => single_mold_translational_casting.cpp} | 4 ++-- ...2.h => single_mold_translational_casting_2.h} | 16 +++++++++++----- .../test_single_mold_translational_casting.cpp | 2 +- 4 files changed, 15 insertions(+), 9 deletions(-) rename Casting_2/examples/Casting_2/{find_single_mold_translational_casting_2.cpp => single_mold_translational_casting.cpp} (91%) rename Casting_2/include/CGAL/{find_single_mold_translational_casting_2.h => single_mold_translational_casting_2.h} (98%) diff --git a/Casting_2/examples/Casting_2/CMakeLists.txt b/Casting_2/examples/Casting_2/CMakeLists.txt index e6c74082648..de1af6b046d 100644 --- a/Casting_2/examples/Casting_2/CMakeLists.txt +++ b/Casting_2/examples/Casting_2/CMakeLists.txt @@ -16,7 +16,7 @@ if ( CGAL_FOUND ) include_directories (BEFORE "../../include") - create_single_source_cgal_program( "find_single_mold_translational_casting_2.cpp" ) + create_single_source_cgal_program( "single_mold_translational_casting.cpp" ) if (CMAKE_COMPILER_IS_GNUCXX) add_definitions(-std=c++11) endif() diff --git a/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp b/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp similarity index 91% rename from Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp rename to Casting_2/examples/Casting_2/single_mold_translational_casting.cpp index 102a45775b3..1da9d1dd10c 100644 --- a/Casting_2/examples/Casting_2/find_single_mold_translational_casting_2.cpp +++ b/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; @@ -39,7 +39,7 @@ int main() pgn.push_back(Point_2(-3, 8)); std::list top_edges; - find_single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); + CGAL::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); if (top_edges.empty()) std::cout << "The polygon is not castable!" << std::endl; diff --git a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h b/Casting_2/include/CGAL/single_mold_translational_casting_2.h similarity index 98% rename from Casting_2/include/CGAL/find_single_mold_translational_casting_2.h rename to Casting_2/include/CGAL/single_mold_translational_casting_2.h index f811efc25ff..ee1a901893f 100644 --- a/Casting_2/include/CGAL/find_single_mold_translational_casting_2.h +++ b/Casting_2/include/CGAL/single_mold_translational_casting_2.h @@ -15,13 +15,16 @@ // Author(s): Shahar // Efi Fogel -#ifndef CGAL_FIND_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H -#define CGAL_FIND_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#ifndef CGAL_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#define CGAL_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H + #include #include #include -#include +#include + +namespace CGAL { /* Legend: * point = Represented as Direction_2. It is the intersection between the @@ -422,8 +425,8 @@ get_segment_outer_circle(const typename Kernel::Segment_2 seg, */ template OutputIterator -find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, - OutputIterator oi) +single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, + OutputIterator oi) { /* Legend * point = Represented as Direction_2. It is the intersection between the @@ -448,4 +451,7 @@ find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, circle_arrangment.get_all_1_edges(oi); return oi; } + +} + #endif diff --git a/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp b/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp index 11c33dfe2af..f5aa81dffe0 100644 --- a/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp +++ b/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp @@ -7,7 +7,7 @@ #include #include -#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; From eddd6cdde6e57928c55eff40a213ad6492092145 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Wed, 20 Jul 2016 20:08:47 +0300 Subject: [PATCH 15/90] Extended the example,added preconditions, moved circle_arrangment. Changed example to read from file. Added multiple polygons files. added preconditions is_simple, no colinear edge --- .../single_mold_translational_casting.cpp | 60 ++- .../CGAL/Casting_2/Circle_arrangment.h | 403 +++++++++++++++ .../single_mold_translational_casting_2.h | 458 +++--------------- 3 files changed, 498 insertions(+), 423 deletions(-) create mode 100644 Casting_2/include/CGAL/Casting_2/Circle_arrangment.h diff --git a/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp b/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp index 1da9d1dd10c..948917e6c30 100644 --- a/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp +++ b/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp @@ -3,7 +3,7 @@ */ #include - +#include #include #include #include @@ -17,40 +17,36 @@ typedef std::pair Direction_range; typedef std::pair Top_edge; // The main program: -int main() +int main(int argc, char *argv[]) { - Polygon_2 pgn; -// pgn.push_back(Point_2(0, 0)); -// pgn.push_back(Point_2(1, 0)); -// pgn.push_back(Point_2(1, 1)); -// pgn.push_back(Point_2(0, 1)); + Polygon_2 pgn; + 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 <> pgn; -// pgn.push_back(Point_2(0, 7)); -// pgn.push_back(Point_2(1, 0)); -// pgn.push_back(Point_2(1, 1)); -// pgn.push_back(Point_2(0, 1)); + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + ++edge_index; + std::list top_edges; + CGAL::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); - pgn.push_back(Point_2(3, 8)); - pgn.push_back(Point_2(1, 1)); - pgn.push_back(Point_2(1, 0)); - pgn.push_back(Point_2(0, 0)); - pgn.push_back(Point_2(0, 1)); - pgn.push_back(Point_2(-3, 8)); + 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 <<"Edge number: "< top_edges; - CGAL::single_mold_translational_casting_2(pgn, 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 < +// Efi Fogel + +#ifndef CGAL_CIRCLE_ARRANGMENT_CASTING_2_H +#define CGAL_CIRCLE_ARRANGMENT_CASTING_2_H + +#include + +#include +#include + +/* 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 INNER_CASTING_2 { + +template +class Circle_arrangment { + typedef typename Kernel::Direction_2 Point; + typedef std::pair Arc; + /* 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 + */ + static bool is_open_direction_contained_in_arc(const Point p, + const bool is_counterclockwise, + const Arc A) + { + if ((is_counterclockwise && (p == A.second)) || + (!is_counterclockwise && (p == A.first))) + return false; + return !p.counterclockwise_in_between(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 + */ + static bool is_a_contained_in_b(const bool is_a_start_closed, + const bool is_a_end_closed, + const Arc A,const Arc B) + { + //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; + return (!A.first.counterclockwise_in_between(B.first, B.second) && + !A.second.counterclockwise_in_between(B.first, B.second) && + !A.first.counterclockwise_in_between(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+) + + size_t m_edge_index; // the index 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, size_t edge_index, 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_index - the index 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 size_t edge_index, + 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_index = edge_index; + } + + /*! \fn void plusplus(size_t edge_index) + * Adds new polygon edge who's open half-circle covers this cell + * \param[in] edge_index - the index 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 size_t edge_index) { + if (this->m_count ==0) { + this->m_edge_index = edge_index; + 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_edges; + + Circle_edges m_edges; + + /*! \fn void insert_if_legal(const Circle_edge_iterator cur_it,const Circle_edge_iterator next_it,const struct 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 + void insert_if_legal(const InputIterator cur_it, + InputIterator next_it, + const struct 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 Arc first_segment_outer_circle) +{ + m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, 0, + false)); + m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, 0, + true,false)); +} + + /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) + * 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_index - this segment id + * 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 size_t edge_index) + { + 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_index); + 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) { + bool isordered = + !segment_outer_circle.second.counterclockwise_in_between(segment_outer_circle.first, edge.second); + if (isordered) { + // o~~~~~~~~~~~~o + // ?-----------------------? + // __________________________ + // ?----c + // o~-~-~-~-~-~-o + // c-----? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = false; + edge2.m_edge_start_angle = segment_outer_circle.first; + edge2.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + struct 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-~-? + struct 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); + struct Circle_arrangment_edge edge3 = *it; + edge3.m_start_is_closed = false; + edge3.m_edge_start_angle = segment_outer_circle.first; + edge3.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge3); + it->plusplus(edge_index); + } + } + else { + // o~~~~~~~~~~~~o + // ?-----------? + //_____________________ + // ?----c + // o-~-~-~? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = false; + edge2.m_edge_start_angle = segment_outer_circle.first; + edge2.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + } + } + else { + if (is_end_contained) { + // o~~~~~~~~~~~~o + // ?------------? + //_____________________ + // ?-~-~-~-o + // c----? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = true; + edge2.m_edge_start_angle = segment_outer_circle.second; + it->plusplus(edge_index); + 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 > foreach valid top edge. + * Should only be called after all of the polygon edges where inserted. + */ + template + 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; + edge.first = (*it).m_edge_index; + 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; } +}; +} +#endif diff --git a/Casting_2/include/CGAL/single_mold_translational_casting_2.h b/Casting_2/include/CGAL/single_mold_translational_casting_2.h index ee1a901893f..207a2c7d2bf 100644 --- a/Casting_2/include/CGAL/single_mold_translational_casting_2.h +++ b/Casting_2/include/CGAL/single_mold_translational_casting_2.h @@ -23,7 +23,7 @@ #include #include - +#include "Casting_2/Circle_arrangment.h" namespace CGAL { /* Legend: @@ -38,368 +38,6 @@ namespace CGAL { * 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 - */ -template -class Circle_arrangment { - typedef typename Kernel::Direction_2 Point; - typedef std::pair Arc; - /* 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 - */ - static bool is_open_direction_contained_in_arc(const Point p, - const bool is_counterclockwise, - const Arc A) - { - if ((is_counterclockwise && (p == A.second)) || - (!is_counterclockwise && (p == A.first))) - return false; - return !p.counterclockwise_in_between(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 - */ - static bool is_a_contained_in_b(const bool is_a_start_closed, - const bool is_a_end_closed, - const Arc A,const Arc B) - { - //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)) && - (A.first != A.second)) - return false; - - return (!A.first.counterclockwise_in_between(B.first, B.second) && - !A.second.counterclockwise_in_between(B.first, B.second) && - !A.first.counterclockwise_in_between(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+) - - size_t m_edge_index; // the index 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, size_t edge_index, 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_index - the index 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 size_t edge_index, - 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_index = edge_index; - } - - /*! \fn void plusplus(size_t edge_index) - * Adds new polygon edge who's open half-circle covers this cell - * \param[in] edge_index - the index 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 size_t edge_index) { - if (this->m_count ==0) { - this->m_edge_index = edge_index; - 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_edges; - - Circle_edges m_edges; - - /*! \fn void insert_if_legal(const Circle_edge_iterator cur_it,const Circle_edge_iterator next_it,const struct 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 - void insert_if_legal(const InputIterator cur_it, - InputIterator next_it, - const struct 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)) - if ((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); - } - - /*! \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 Arc first_segment_outer_circle) - { - m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, 0, - false)); - m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, 0, - true,false)); - } - - /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) - * 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_index - this segment id - * 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 size_t edge_index) - { - Arc edge; - bool is_start_closed_segment = m_edges.begin()->m_start_is_closed; - bool is_end_closed_segment = m_edges.begin()->m_start_is_closed; - edge.first = m_edges.begin()->m_edge_start_angle; - edge.second = m_edges.begin()->m_edge_start_angle; - 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 = !is_end_closed_segment; - is_end_closed_segment = !next_it->m_start_is_closed; - edge.first = edge.second; - 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_index); - 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) { - bool isordered = - !segment_outer_circle.second.counterclockwise_in_between(segment_outer_circle.first, edge.second); - if (isordered) { - // o~~~~~~~~~~~~o - // ?-----------------------? - // __________________________ - // ?----c - // o~-~-~-~-~-~-o - // c-----? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = false; - edge2.m_edge_start_angle = segment_outer_circle.first; - edge2.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - struct 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-~-? - struct 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); - struct Circle_arrangment_edge edge3 = *it; - edge3.m_start_is_closed = false; - edge3.m_edge_start_angle = segment_outer_circle.first; - edge3.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge3); - it->plusplus(edge_index); - } - } - else { - // o~~~~~~~~~~~~o - // ?-----------? - //_____________________ - // ?----c - // o-~-~-~? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = false; - edge2.m_edge_start_angle = segment_outer_circle.first; - edge2.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - } - } - else { - if (is_end_contained) { - // o~~~~~~~~~~~~o - // ?------------? - //_____________________ - // ?-~-~-~-o - // c----? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = true; - edge2.m_edge_start_angle = segment_outer_circle.second; - it->plusplus(edge_index); - 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 > foreach valid top edge. - * Should only be called after all of the polygon edges where inserted. - */ - template - 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; - edge.first = (*it).m_edge_index; - 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; } -}; - /*! \fn std::pair 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). @@ -409,14 +47,46 @@ public: template inline std::pair get_segment_outer_circle(const typename Kernel::Segment_2 seg, - const CGAL::Orientation orientation) + const CGAL::Orientation orientation) + { + typename Kernel::Direction_2 forward( seg); + typename Kernel::Direction_2 backward(-forward); + return (orientation == CGAL::Orientation::CLOCKWISE) ? + std::make_pair(backward, forward) : std::make_pair(forward, backward); + } + +template +bool isAnyEdgeColinear(const CGAL::Polygon_2& pgn) { - typename Kernel::Direction_2 forward( seg); - typename Kernel::Direction_2 backward(-forward); - return (orientation == CGAL::Orientation::CLOCKWISE) ? - std::make_pair(backward, forward) : std::make_pair(forward, backward); + typedef typename CGAL::Point_2 Point_2; + typedef typename CGAL::Polygon_2 Polygon_2; + typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; + 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(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; + } + vci = pgn.vertices_begin(); + firstVar=secondVar; + secondVar=thirdVar; + thirdVar = *(vci++); + if(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; + + firstVar=secondVar; + secondVar=thirdVar; + thirdVar = *(vci++); + if(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; + + return false; } + /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) * \param[in] pgn the input polygon that we want to check if is castable or not. * \param[in,out] oi the output iterator to put the top edges in @@ -426,32 +96,38 @@ get_segment_outer_circle(const typename Kernel::Segment_2 seg, template OutputIterator single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, - OutputIterator oi) + OutputIterator oi) { - /* 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) - */ - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); - Circle_arrangment circle_arrangment(segment_outer_circle); - ++edge_index; - for (; e_it!= pgn.edges_end(); ++e_it,++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); - if (circle_arrangment.all_is_covered_twice()) return oi; - } - circle_arrangment.get_all_1_edges(oi); - return oi; + /* 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) + */ + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!isAnyEdgeColinear(pgn)); + + + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + get_segment_outer_circle(*e_it++, poly_orientation); + INNER_CASTING_2::Circle_arrangment circle_arrangment(segment_outer_circle); + + ++edge_index; + for (; e_it!= pgn.edges_end(); ++e_it,++edge_index) { + segment_outer_circle = + get_segment_outer_circle(*e_it, poly_orientation); + circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); + if (circle_arrangment.all_is_covered_twice()) return oi; + } + circle_arrangment.get_all_1_edges(oi); + return oi; } + } #endif From 65bae54a6302fcb2e7b0f8c9a9ee51262248e39a Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 3 Aug 2016 01:16:30 +0300 Subject: [PATCH 16/90] Updated manual --- .../single_mold_translational_casting_2.h | 11 ++ Casting_2/doc/Casting_2/Casting_2.txt | 6 +- .../doc/Casting_2/PackageDescription.txt | 15 +- Casting_2/doc/Casting_2/dependencies | 5 + Casting_2/doc/Casting_2/fig/Casting_2.png | Bin 0 -> 4506 bytes Casting_2/doc/Casting_2/fig/Casting_3.png | Bin 0 -> 43970 bytes Casting_2/examples/Casting_2/polygon.dat | 2 + .../single_mold_translational_casting.cpp | 55 +++---- .../single_mold_translational_casting_2.h | 149 +++++++++--------- ...test_single_mold_translational_casting.cpp | 3 +- Documentation/doc/Documentation/packages.txt | 1 + 11 files changed, 139 insertions(+), 108 deletions(-) create mode 100644 Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h create mode 100644 Casting_2/doc/Casting_2/dependencies create mode 100644 Casting_2/doc/Casting_2/fig/Casting_2.png create mode 100644 Casting_2/doc/Casting_2/fig/Casting_3.png create mode 100644 Casting_2/examples/Casting_2/polygon.dat diff --git a/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h b/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h new file mode 100644 index 00000000000..3f2ee7df5a5 --- /dev/null +++ b/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h @@ -0,0 +1,11 @@ +namespace CGAL { + +/*! + * \ingroup PkgCasting2Funcs + */ +template +OutputIterator +single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, + OutputIterator oi); + +} /* end namesapce CGAL */ diff --git a/Casting_2/doc/Casting_2/Casting_2.txt b/Casting_2/doc/Casting_2/Casting_2.txt index 3df5af13dd3..d470d7984f6 100644 --- a/Casting_2/doc/Casting_2/Casting_2.txt +++ b/Casting_2/doc/Casting_2/Casting_2.txt @@ -2,7 +2,7 @@ namespace CGAL { /*! \mainpage User Manual -\anchor Chapter_Casting_of_polygons +\anchor Chapter_Castings_of_polygons \anchor chapterEnvelope2 @@ -11,6 +11,10 @@ namespace CGAL { \section casting_sec_intro Introduction +Casting is a manufacturing process where liquid material is poured +into a mold having the shape of a desired product. After the material +solidifies, the product is pulled out of the mold. + \cgalExample{Casting_2/single_mold_translational_casting.cpp} */ diff --git a/Casting_2/doc/Casting_2/PackageDescription.txt b/Casting_2/doc/Casting_2/PackageDescription.txt index 8e5e4aa60a2..2b11dc4394b 100644 --- a/Casting_2/doc/Casting_2/PackageDescription.txt +++ b/Casting_2/doc/Casting_2/PackageDescription.txt @@ -1,21 +1,26 @@ /// \defgroup PkgCasting2 2D Castings Reference + /// \defgroup PkgCasting2Concepts Concepts /// \ingroup PkgCasting2 + +/// \defgroup PkgCasting2Funcs Free Functions +/// \ingroup PkgCasting2 + /*! \addtogroup PkgCasting2 \todo check generated documentation \cgalPkgDescriptionBegin{2D Castings,PkgCasting2Summary} -\cgalPkgPicture{Casting_2/fig/Casting_2.png} +\cgalPkgPicture{Casting_2.png} \cgalPkgSummaryBegin \cgalPkgAuthors{Shahar Shamai, Efi Fogel} -\cgalPkgDesc{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.} +\cgalPkgDesc{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 be used to compute all possible orientations of the feasible molds and the corresponding motions needed to remove the casted object from the mold.} \cgalPkgManuals{Chapter_Castings_of_polygons,PkgCasting2} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin \cgalPkgSince{4.10} -\cgalPkgDependsOn{\ref PkgCasting2Summary} +\cgalPkgDependsOn{\ref PkgPolygon2Summary} \cgalPkgBib{cgal:sf-casting2} -\cgalPkgLicense{\ref licensesGPL "GPL"} +\cgalPkgLicense{\ref licensesGPL "GPL"} \cgalPkgShortInfoEnd \cgalPkgDescriptionEnd @@ -24,7 +29,7 @@ This package consists of the implementations of various predicates and operation \cgalClassifedRefPages ## Functions ## -- `CGAL::single_mold_translational_casting_2` +- `CGAL::single_mold_translational_casting_2()` ## Concepts ## diff --git a/Casting_2/doc/Casting_2/dependencies b/Casting_2/doc/Casting_2/dependencies new file mode 100644 index 00000000000..88ebc77ecb2 --- /dev/null +++ b/Casting_2/doc/Casting_2/dependencies @@ -0,0 +1,5 @@ +Manual +Kernel_23 +Circulator +Number_types +Polygon diff --git a/Casting_2/doc/Casting_2/fig/Casting_2.png b/Casting_2/doc/Casting_2/fig/Casting_2.png new file mode 100644 index 0000000000000000000000000000000000000000..244a4e790f158eae7150b6ca39b1a2f2fef9e6f4 GIT binary patch literal 4506 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 literal 0 HcmV?d00001 diff --git a/Casting_2/doc/Casting_2/fig/Casting_3.png b/Casting_2/doc/Casting_2/fig/Casting_3.png new file mode 100644 index 0000000000000000000000000000000000000000..13f39312e843139d72e32bb39d430c2c78268a6e GIT binary patch literal 43970 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 Direction_range; typedef std::pair Top_edge; // The main program: -int main(int argc, char *argv[]) +int main(int argc, char* argv[]) { - Polygon_2 pgn; + Polygon_2 pgn; - 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 <> pgn; + 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 >> pgn; - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - ++edge_index; - std::list top_edges; - CGAL::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); + auto e_it = pgn.edges_begin(); + size_t edge_index(0); + auto poly_orientation = pgn.orientation(); + ++edge_index; + std::list top_edges; + CGAL::single_mold_translational_casting_2(pgn, 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 <<"Edge number: "< -inline std::pair -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::Orientation::CLOCKWISE) ? - std::make_pair(backward, forward) : std::make_pair(forward, backward); - } + template + inline std::pair + 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::Orientation::CLOCKWISE) ? + std::make_pair(backward, forward) : std::make_pair(forward, backward); + } -template -bool isAnyEdgeColinear(const CGAL::Polygon_2& pgn) -{ - typedef typename CGAL::Point_2 Point_2; - typedef typename CGAL::Polygon_2 Polygon_2; - typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; - 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(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; - } - vci = pgn.vertices_begin(); - firstVar=secondVar; - secondVar=thirdVar; - thirdVar = *(vci++); - if(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; + template + bool isAnyEdgeColinear(const CGAL::Polygon_2& pgn) + { + typedef typename CGAL::Point_2 Point_2; + typedef typename CGAL::Polygon_2 Polygon_2; + typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; + 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(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; + } + vci = pgn.vertices_begin(); + firstVar=secondVar; + secondVar=thirdVar; + thirdVar = *(vci++); + if(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; - firstVar=secondVar; - secondVar=thirdVar; - thirdVar = *(vci++); - if(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; + firstVar=secondVar; + secondVar=thirdVar; + thirdVar = *(vci++); + if(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; - return false; -} + return false; + } -/*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) - * \param[in] pgn the input polygon that we want to check if is castable or not. - * \param[in,out] oi the output iterator to put the top edges in - * \return all the possible top edges of the polygon and there pullout direction - * (with no rotation) - */ -template -OutputIterator -single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, - OutputIterator oi) -{ - /* 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) - */ - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!isAnyEdgeColinear(pgn)); + /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) + * \param[in] pgn the input polygon that we want to check if is castable or not. + * \param[in,out] oi the output iterator to put the top edges in + * \return all the possible top edges of the polygon and there pullout direction + * (with no rotation) + */ + template + OutputIterator + single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, + OutputIterator oi) + { + /* 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) + */ + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!isAnyEdgeColinear(pgn)); - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); - INNER_CASTING_2::Circle_arrangment circle_arrangment(segment_outer_circle); + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + get_segment_outer_circle(*e_it++, poly_orientation); + INNER_CASTING_2::Circle_arrangment + circle_arrangment(segment_outer_circle); - ++edge_index; - for (; e_it!= pgn.edges_end(); ++e_it,++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); - if (circle_arrangment.all_is_covered_twice()) return oi; - } - circle_arrangment.get_all_1_edges(oi); - return oi; -} + ++edge_index; + for (; e_it!= pgn.edges_end(); ++e_it,++edge_index) { + segment_outer_circle = + get_segment_outer_circle(*e_it, poly_orientation); + circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); + if (circle_arrangment.all_is_covered_twice()) return oi; + } + circle_arrangment.get_all_1_edges(oi); + return oi; + } } diff --git a/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp b/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp index f5aa81dffe0..451fc730611 100644 --- a/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp +++ b/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -103,7 +104,7 @@ int main(int argc, char* argv[]) while (itr != str.begin()) { auto tmp = itr; --tmp; - if (*itr == 't') break; + if (!isspace(*itr)) break; str.erase(itr); itr = tmp; } diff --git a/Documentation/doc/Documentation/packages.txt b/Documentation/doc/Documentation/packages.txt index dbca0235571..7a80652122b 100644 --- a/Documentation/doc/Documentation/packages.txt +++ b/Documentation/doc/Documentation/packages.txt @@ -23,6 +23,7 @@ h1 { \package_listing{Matrix_search} \package_listing{QP_solver} +\package_listing{Casting_2} \section PartKernels Geometry Kernels From 282a3c1a031fdecd02d62f630857a52dc079c52d Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 3 Aug 2016 01:17:49 +0300 Subject: [PATCH 17/90] Removed --- Casting_2/doc/Casting_2/fig/Casting_3.png | Bin 43970 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Casting_2/doc/Casting_2/fig/Casting_3.png diff --git a/Casting_2/doc/Casting_2/fig/Casting_3.png b/Casting_2/doc/Casting_2/fig/Casting_3.png deleted file mode 100644 index 13f39312e843139d72e32bb39d430c2c78268a6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43970 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 Date: Wed, 3 Aug 2016 12:08:46 +0300 Subject: [PATCH 18/90] Enhanced the doc --- .../CGAL/single_mold_translational_casting_2.h | 8 ++++++++ Casting_2/doc/Casting_2/Casting_2.txt | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h b/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h index 3f2ee7df5a5..c19683b4d52 100644 --- a/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h +++ b/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h @@ -2,6 +2,14 @@ namespace CGAL { /*! * \ingroup PkgCasting2Funcs + * This function computes all top edges of a simple polygon. + * \param pgn[in] the input polygon. + * \param oi[out] the output iterator. Its value type is a pair. + * a closed range of pull-out directions represented as a pair of the + * extreme directions in the + * \return the past-the-end iterator of the output container. + * \pre the polygon must be non-degenerate (has at least 3 vertices), simple, + * and does not have three consecutive collinear vertices. */ template OutputIterator diff --git a/Casting_2/doc/Casting_2/Casting_2.txt b/Casting_2/doc/Casting_2/Casting_2.txt index d470d7984f6..d08f50d19d2 100644 --- a/Casting_2/doc/Casting_2/Casting_2.txt +++ b/Casting_2/doc/Casting_2/Casting_2.txt @@ -15,6 +15,16 @@ Casting is a manufacturing process where liquid material is poured into a mold having the shape of a desired product. After the material solidifies, the product is pulled out of the mold. +This package provides a function that .... +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, not consecuitive three vertices can be linear. If +you suspect that the input polygon may not satisfy the latter +condition, pre-process the polygon to elliminate this ill-condition. + \cgalExample{Casting_2/single_mold_translational_casting.cpp} */ From 1a1875043af9c94adbbec811e1d11bbd8e9d90dc Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 9 Aug 2016 13:53:16 +0300 Subject: [PATCH 19/90] Completed the documentation --- .../single_mold_translational_casting_2.h | 31 +++++++++++----- Casting_2/doc/Casting_2/Casting_2.txt | 34 +++++++++++++++--- .../doc/Casting_2/PackageDescription.txt | 7 ---- Casting_2/doc/Casting_2/fig/mold.png | Bin 0 -> 16164 bytes 4 files changed, 52 insertions(+), 20 deletions(-) create mode 100644 Casting_2/doc/Casting_2/fig/mold.png diff --git a/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h b/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h index c19683b4d52..6ead48e8eaf 100644 --- a/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h +++ b/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h @@ -1,15 +1,28 @@ namespace CGAL { -/*! - * \ingroup PkgCasting2Funcs - * This function computes all top edges of a simple polygon. - * \param pgn[in] the input polygon. - * \param oi[out] the output iterator. Its value type is a pair. - * a closed range of pull-out directions represented as a pair of the - * extreme directions in the +/*! \ingroup PkgCasting2Funcs + * + * 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 castable, the function computes the set of top edges of + * such cavities and the corresponding closed ranges of pull directions. + * Assuming the top edge normal is parallel to the \f$y\f$-axis, every direction + * in a range must have a positive component in the positive + * \f$y\f$-direction. Each top edge and corresponding range is added to a + * container referred to by a given output iterator. + * + * \param[in] pgn the input polygon. + * \param[out] oi the output iterator. Its value type is a pair, where + * (i) the first element in the pair identifies a valid top edge and + * represented as a type convertible to `size_t`, and + * (ii) the second element is a closed range of pull-out directions + * represented as a pair of the extreme directions in the + * range of type `Kernel::Direction_2`. * \return the past-the-end iterator of the output container. - * \pre the polygon must be non-degenerate (has at least 3 vertices), simple, - * and does not have three consecutive collinear vertices. + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. */ template OutputIterator diff --git a/Casting_2/doc/Casting_2/Casting_2.txt b/Casting_2/doc/Casting_2/Casting_2.txt index d08f50d19d2..c62334deedd 100644 --- a/Casting_2/doc/Casting_2/Casting_2.txt +++ b/Casting_2/doc/Casting_2/Casting_2.txt @@ -7,15 +7,41 @@ namespace CGAL { \anchor chapterEnvelope2 \cgalAutoToc -\authors Shahar Shamai and Efif Fogel +\authors Shahar Shamai and Efi Fogel \section casting_sec_intro Introduction Casting is a manufacturing process where liquid material is poured -into a mold having the shape of a desired product. After the material -solidifies, the product is pulled out of the mold. +into a cavity inside a mold, which has the shape of a desired +product. After the material solidifies, the product is pulled out of +the mold. Typically a mold is used to manufacture numerous copies of a +product, in which case we need to make sure that the solidified +product can be separated from its mold without breaking it. The +challenge of designing a proper mold belongs to a larger topic termed +\emph{Movable Separability of Sets}; see \cgalCite{t-mss-85} +These problems become progressively more challenging as the allowable +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. + +This package provides a function called +`single_mold_translational_casting_2()` that given a simple polygon +\f$P\f$ it 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 surface); see +\cgalFigureRef{casting_2_fig_mold} for an illustration. If the polygon +is castable, the function computes the set of top edges of +such cavities and the corresponding closed ranges of pull +directions. Assuming the top edge normal is parallel to the +\f$y\f$-axis, every direction in a range must have a positive +component in the positive \f$y\f$-direction. + +\cgalFigureBegin{casting_2_fig_mold,mold.png} +Polygons (light grey) in their molds (darker grey) and valid pull-out +directions. +\cgalFigureEnd -This package provides a function that .... 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 diff --git a/Casting_2/doc/Casting_2/PackageDescription.txt b/Casting_2/doc/Casting_2/PackageDescription.txt index 2b11dc4394b..4bea2df2c5c 100644 --- a/Casting_2/doc/Casting_2/PackageDescription.txt +++ b/Casting_2/doc/Casting_2/PackageDescription.txt @@ -1,8 +1,5 @@ /// \defgroup PkgCasting2 2D Castings Reference -/// \defgroup PkgCasting2Concepts Concepts -/// \ingroup PkgCasting2 - /// \defgroup PkgCasting2Funcs Free Functions /// \ingroup PkgCasting2 @@ -31,8 +28,4 @@ This package consists of the implementations of various predicates and operation ## Functions ## - `CGAL::single_mold_translational_casting_2()` -## Concepts ## - -## Classes ## - */ diff --git a/Casting_2/doc/Casting_2/fig/mold.png b/Casting_2/doc/Casting_2/fig/mold.png new file mode 100644 index 0000000000000000000000000000000000000000..3672678f75c59f0ff1b0b5159121ca26ed51cb53 GIT binary patch literal 16164 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 literal 0 HcmV?d00001 From ee7722b4067b7db99dc60e5115e1e83ece76fa8f Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 9 Aug 2016 14:06:30 +0300 Subject: [PATCH 20/90] Indicated that the polygon is closed --- Casting_2/doc/Casting_2/Casting_2.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Casting_2/doc/Casting_2/Casting_2.txt b/Casting_2/doc/Casting_2/Casting_2.txt index c62334deedd..b960f76917b 100644 --- a/Casting_2/doc/Casting_2/Casting_2.txt +++ b/Casting_2/doc/Casting_2/Casting_2.txt @@ -25,11 +25,11 @@ freedom), the number of objects involved grows, or the shape of the objects becomes more complicated. This package provides a function called -`single_mold_translational_casting_2()` that given a simple polygon -\f$P\f$ it 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 surface); see +`single_mold_translational_casting_2()` that given a simple closed +polygon \f$P\f$ it 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 surface); see \cgalFigureRef{casting_2_fig_mold} for an illustration. If the polygon is castable, the function computes the set of top edges of such cavities and the corresponding closed ranges of pull From e4038276c5f9f6dc1b073a35c08060c0bb38967c Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 11 Aug 2016 16:55:52 +0300 Subject: [PATCH 21/90] Added namespaces and cleaned up --- .../single_mold_translational_casting.cpp | 9 +- .../CGAL/Casting_2/Circle_arrangment.h | 678 +++++++++--------- .../single_mold_translational_casting_2.h | 176 ++--- ...test_single_mold_translational_casting.cpp | 4 +- 4 files changed, 441 insertions(+), 426 deletions(-) diff --git a/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp b/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp index e13720e1a03..8bd0377a18c 100644 --- a/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp +++ b/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp @@ -1,9 +1,6 @@ -/*! \file find_single_mold_translational_casting_2.cpp - * . - */ - #include #include + #include #include #include @@ -16,6 +13,8 @@ typedef Kernel::Point_2 Point_2; typedef std::pair Direction_range; typedef std::pair Top_edge; +namespace CC = CGAL::Casting_2; + // The main program: int main(int argc, char* argv[]) { @@ -34,7 +33,7 @@ int main(int argc, char* argv[]) auto poly_orientation = pgn.orientation(); ++edge_index; std::list top_edges; - CGAL::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); + CC::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); if (top_edges.empty()) std::cout << "The polygon is not castable!" << std::endl; diff --git a/Casting_2/include/CGAL/Casting_2/Circle_arrangment.h b/Casting_2/include/CGAL/Casting_2/Circle_arrangment.h index 04869515c91..2ce36bbf42b 100644 --- a/Casting_2/include/CGAL/Casting_2/Circle_arrangment.h +++ b/Casting_2/include/CGAL/Casting_2/Circle_arrangment.h @@ -42,362 +42,374 @@ * 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 INNER_CASTING_2 { + +namespace CGAL { +namespace Casting_2 { +namespace internal { template class Circle_arrangment { - typedef typename Kernel::Direction_2 Point; - typedef std::pair Arc; - /* 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) - */ + typedef typename Kernel::Direction_2 Point; + typedef std::pair Arc; - /*! \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 - */ - static bool is_open_direction_contained_in_arc(const Point p, - const bool is_counterclockwise, - const Arc A) - { - if ((is_counterclockwise && (p == A.second)) || - (!is_counterclockwise && (p == A.first))) - return false; - return !p.counterclockwise_in_between(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 - */ - static bool is_a_contained_in_b(const bool is_a_start_closed, - const bool is_a_end_closed, - const Arc A,const Arc B) - { - //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; - return (!A.first.counterclockwise_in_between(B.first, B.second) && - !A.second.counterclockwise_in_between(B.first, B.second) && - !A.first.counterclockwise_in_between(B.first, A.second)); - } + /* 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) + */ - /*! \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; + /*! \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 + */ + static bool is_open_direction_contained_in_arc(const Point p, + const bool is_counterclockwise, + const Arc A) + { + if ((is_counterclockwise && (p == A.second)) || + (!is_counterclockwise && (p == A.first))) + return false; + return !p.counterclockwise_in_between(A.first,A.second); + } - Point m_edge_start_angle; // the end is the start of the next edge + /*! \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 + */ + static bool is_a_contained_in_b(const bool is_a_start_closed, + const bool is_a_end_closed, + const Arc A,const Arc B) + { + //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; + return (!A.first.counterclockwise_in_between(B.first, B.second) && + !A.second.counterclockwise_in_between(B.first, B.second) && + !A.first.counterclockwise_in_between(B.first, A.second)); + } - uint8_t m_count; // no. of outer circles that cover the edge (0/1/2+) + /*! \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; - size_t m_edge_index; // the index of the polygon edge the open - // half-circle of which covers this cell. - // only relevant if m_count ==1 + Point m_edge_start_angle; // the end is the start of the next edge - /*! \ctor Circle_arrangment_edge(point edge_start_angle, size_t edge_index, 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_index - the index 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 size_t edge_index, - 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_index = edge_index; - } + uint8_t m_count; // no. of outer circles that cover the edge (0/1/2+) - /*! \fn void plusplus(size_t edge_index) - * Adds new polygon edge who's open half-circle covers this cell - * \param[in] edge_index - the index 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 size_t edge_index) { - if (this->m_count ==0) { - this->m_edge_index = edge_index; - this->m_count = 1; - } - else if(this->m_count ==1) this->m_count = 2; - } - bool is_covered() { return m_count == 2; } - }; + size_t m_edge_index; // the index of the polygon edge the open + // half-circle of which covers this cell. + // only relevant if m_count ==1 - typedef typename std::list Circle_edges; + /*! \ctor Circle_arrangment_edge(point edge_start_angle, size_t edge_index, 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_index the index 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 size_t edge_index, + 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_index = edge_index; + } - Circle_edges m_edges; + /*! \fn void plusplus(size_t edge_index) + * Adds new polygon edge who's open half-circle covers this cell + * \param[in] edge_index - the index 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 size_t edge_index) + { + if (this->m_count ==0) { + this->m_edge_index = edge_index; + this->m_count = 1; + } + else if(this->m_count ==1) this->m_count = 2; + } + bool is_covered() { return m_count == 2; } + }; - /*! \fn void insert_if_legal(const Circle_edge_iterator cur_it,const Circle_edge_iterator next_it,const struct 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 - void insert_if_legal(const InputIterator cur_it, - InputIterator next_it, - const struct 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; - } - } + typedef typename std::list Circle_edges; - /*! \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; - } - } + Circle_edges m_edges; + + /*! \fn void insert_if_legal(const Circle_edge_iterator cur_it,const Circle_edge_iterator next_it,const struct 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 + void insert_if_legal(const InputIterator cur_it, + InputIterator next_it, + const struct 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 Arc first_segment_outer_circle) -{ - m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, 0, - false)); - m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, 0, - true,false)); -} + /*! \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 Arc first_segment_outer_circle) + { + m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, + 0, false)); + m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, + 0, true, false)); + } - /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) - * 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_index - this segment id - * 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 size_t edge_index) - { - 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(); - } + /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) + * 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_index this segment id + * 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 size_t edge_index) + { + 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; + 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_index); - 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) { - bool isordered = - !segment_outer_circle.second.counterclockwise_in_between(segment_outer_circle.first, edge.second); - if (isordered) { - // o~~~~~~~~~~~~o - // ?-----------------------? - // __________________________ - // ?----c - // o~-~-~-~-~-~-o - // c-----? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = false; - edge2.m_edge_start_angle = segment_outer_circle.first; - edge2.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - struct 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-~-? - struct 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); - struct Circle_arrangment_edge edge3 = *it; - edge3.m_start_is_closed = false; - edge3.m_edge_start_angle = segment_outer_circle.first; - edge3.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge3); - it->plusplus(edge_index); - } - } - else { - // o~~~~~~~~~~~~o - // ?-----------? - //_____________________ - // ?----c - // o-~-~-~? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = false; - edge2.m_edge_start_angle = segment_outer_circle.first; - edge2.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - } - } - else { - if (is_end_contained) { - // o~~~~~~~~~~~~o - // ?------------? - //_____________________ - // ?-~-~-~-o - // c----? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = true; - edge2.m_edge_start_angle = segment_outer_circle.second; - it->plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - } - //else - no intersection, do noting - } - } - merge_adjacent_2_edges_and_remove_empty(); - } + 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_index); + 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) { + bool isordered = + !segment_outer_circle.second. + counterclockwise_in_between(segment_outer_circle.first, edge.second); + if (isordered) { + // o~~~~~~~~~~~~o + // ?-----------------------? + // __________________________ + // ?----c + // o~-~-~-~-~-~-o + // c-----? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = false; + edge2.m_edge_start_angle = segment_outer_circle.first; + edge2.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + struct 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-~-? + struct 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); + struct Circle_arrangment_edge edge3 = *it; + edge3.m_start_is_closed = false; + edge3.m_edge_start_angle = segment_outer_circle.first; + edge3.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge3); + it->plusplus(edge_index); + } + } + else { + // o~~~~~~~~~~~~o + // ?-----------? + //_____________________ + // ?----c + // o-~-~-~? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = false; + edge2.m_edge_start_angle = segment_outer_circle.first; + edge2.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + } + } + else { + if (is_end_contained) { + // o~~~~~~~~~~~~o + // ?------------? + //_____________________ + // ?-~-~-~-o + // c----? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = true; + edge2.m_edge_start_angle = segment_outer_circle.second; + it->plusplus(edge_index); + 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"; - } + // 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 > foreach valid top edge. + * Should only be called after all of the polygon edges where inserted. + */ + template + 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; + edge.first = (*it).m_edge_index; + 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 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 > foreach valid top edge. - * Should only be called after all of the polygon edges where inserted. - */ - template - 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; - edge.first = (*it).m_edge_index; - 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; } + /*! \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; } }; -} + +} // end of namespace internal +} // end of namespace Casting_2 +} // end of namespace CGAL + #endif diff --git a/Casting_2/include/CGAL/single_mold_translational_casting_2.h b/Casting_2/include/CGAL/single_mold_translational_casting_2.h index 7db0b42dce2..8ef04eb363e 100644 --- a/Casting_2/include/CGAL/single_mold_translational_casting_2.h +++ b/Casting_2/include/CGAL/single_mold_translational_casting_2.h @@ -18,14 +18,18 @@ #ifndef CGAL_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H #define CGAL_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#include +#include + #include #include -#include -#include #include "Casting_2/Circle_arrangment.h" + namespace CGAL { +namespace Casting_2 { + /* Legend: * point = Represented as Direction_2. It is the intersection between the * fitting Direction_2 and the unit circle @@ -44,91 +48,89 @@ namespace CGAL { * if CLOCKWISE then the outer half circle is to the left. * \return the open outer half-circle of the edge. */ - template - inline std::pair - 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::Orientation::CLOCKWISE) ? - std::make_pair(backward, forward) : std::make_pair(forward, backward); - } - - template - bool isAnyEdgeColinear(const CGAL::Polygon_2& pgn) - { - typedef typename CGAL::Point_2 Point_2; - typedef typename CGAL::Polygon_2 Polygon_2; - typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; - 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(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; - } - vci = pgn.vertices_begin(); - firstVar=secondVar; - secondVar=thirdVar; - thirdVar = *(vci++); - if(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; - - firstVar=secondVar; - secondVar=thirdVar; - thirdVar = *(vci++); - if(CGAL::collinear(firstVar,secondVar,thirdVar)) return true; - - return false; - } - - - /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) - * \param[in] pgn the input polygon that we want to check if is castable or not. - * \param[in,out] oi the output iterator to put the top edges in - * \return all the possible top edges of the polygon and there pullout direction - * (with no rotation) - */ - template - OutputIterator - single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, - OutputIterator oi) - { - /* 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) - */ - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!isAnyEdgeColinear(pgn)); - - - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); - INNER_CASTING_2::Circle_arrangment - circle_arrangment(segment_outer_circle); - - ++edge_index; - for (; e_it!= pgn.edges_end(); ++e_it,++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); - if (circle_arrangment.all_is_covered_twice()) return oi; - } - circle_arrangment.get_all_1_edges(oi); - return oi; - } - - +template +inline std::pair +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::Orientation::CLOCKWISE) ? + std::make_pair(backward, forward) : std::make_pair(forward, backward); } +template +bool is_any_edge_colinear(const CGAL::Polygon_2& pgn) +{ + typedef typename CGAL::Point_2 Point_2; + typedef typename CGAL::Polygon_2 Polygon_2; + typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; + 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 (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + } + vci = pgn.vertices_begin(); + firstVar = secondVar; + secondVar = thirdVar; + thirdVar = *(vci++); + if(CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + + firstVar = secondVar; + secondVar = thirdVar; + thirdVar = *(vci++); + if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + + return false; +} + +/*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) + * \param[in] pgn the input polygon that we want to check if is castable or not. + * \param[in,out] oi the output iterator to put the top edges in + * \return all the possible top edges of the polygon and there pullout direction + * (with no rotation) + */ +template +OutputIterator +single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, + OutputIterator oi) +{ + /* 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) + */ + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!is_any_edge_colinear(pgn)); + + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + get_segment_outer_circle(*e_it++, poly_orientation); + internal::Circle_arrangment + circle_arrangment(segment_outer_circle); + + ++edge_index; + for (; e_it!= pgn.edges_end(); ++e_it,++edge_index) { + segment_outer_circle = + get_segment_outer_circle(*e_it, poly_orientation); + circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); + if (circle_arrangment.all_is_covered_twice()) return oi; + } + circle_arrangment.get_all_1_edges(oi); + return oi; +} + +} // end of namespace Casting_2 + +} // end of namespace CGAL + #endif diff --git a/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp b/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp index 451fc730611..ccebbe74488 100644 --- a/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp +++ b/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp @@ -18,6 +18,8 @@ typedef Kernel::Point_2 Point_2; typedef std::pair Direction_range; typedef std::pair Top_edge; +namespace CC = CGAL::Casting_2; + struct Top_edge_comparer { bool operator()(const Top_edge& a, const Top_edge& b) { @@ -43,7 +45,7 @@ bool test_one_file(std::ifstream& inp) // std::cout << pgn << std::endl; std::vector top_edges; - CGAL::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); + CC::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); size_t exp_num_top_edges; inp >> exp_num_top_edges; From 62208e134d4a14e7fb8bb4e99d10e18b39c2ebe8 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 11 Aug 2016 17:31:37 +0300 Subject: [PATCH 22/90] Added Separation of a Polyhedron from Its Single-Part Mold --- Documentation/doc/biblio/cgal_manual.bib | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/doc/biblio/cgal_manual.bib b/Documentation/doc/biblio/cgal_manual.bib index b034702490a..ef02c3f6e9f 100644 --- a/Documentation/doc/biblio/cgal_manual.bib +++ b/Documentation/doc/biblio/cgal_manual.bib @@ -371,7 +371,7 @@ Boissonnat} @article{ cgal:cht-oacov-90 ,author = {M. Chang and N. Huang and C. Tang} - ,title = {An optimal algorithm for constructing oriented Voronoi diagrams + ,title = {An optimal algorithm for constructing oriented Voronoi diagrams and geographic neighborhood graphs} ,journal = "Information Processing Letters" ,volume = 35 @@ -1834,6 +1834,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} From 7b4188231139af23827a0a80d56a9b7bedf500e3 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 11 Aug 2016 17:31:58 +0300 Subject: [PATCH 23/90] Added complexity and other meta info. --- Casting_2/doc/Casting_2/Casting_2.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Casting_2/doc/Casting_2/Casting_2.txt b/Casting_2/doc/Casting_2/Casting_2.txt index b960f76917b..5040cb20826 100644 --- a/Casting_2/doc/Casting_2/Casting_2.txt +++ b/Casting_2/doc/Casting_2/Casting_2.txt @@ -18,7 +18,7 @@ the mold. Typically a mold is used to manufacture numerous copies of a product, in which case we need to make sure that the solidified product can be separated from its mold without breaking it. The challenge of designing a proper mold belongs to a larger topic termed -\emph{Movable Separability of Sets}; see \cgalCite{t-mss-85} +Movable Separability of Sets; see \cgalCite{t-mss-85} These problems become progressively more challenging as the allowable separation motions becomes more complex (have more degrees of freedom), the number of objects involved grows, or the shape of the @@ -51,6 +51,13 @@ polygons. Secondly, not consecuitive three vertices can be linear. 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 are adviced to use a kernel that guarantees exact +constructions as well as exact predicates. + \cgalExample{Casting_2/single_mold_translational_casting.cpp} */ From 11f6ca3645651c2cfa2ef71639a394474f225a41 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 11 Aug 2016 17:32:18 +0300 Subject: [PATCH 24/90] Reworded --- .../Casting_2/CGAL/single_mold_translational_casting_2.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h b/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h index 6ead48e8eaf..de231f92703 100644 --- a/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h +++ b/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h @@ -1,4 +1,5 @@ namespace CGAL { +namespace Casting_2 { /*! \ingroup PkgCasting2Funcs * @@ -15,8 +16,9 @@ namespace CGAL { * * \param[in] pgn the input polygon. * \param[out] oi the output iterator. Its value type is a pair, where - * (i) the first element in the pair identifies a valid top edge and - * represented as a type convertible to `size_t`, and + * (i) the first element in the pair identifies a valid top edge + * represented by its index the type of which is convertible to + `size_t`, and * (ii) the second element is a closed range of pull-out directions * represented as a pair of the extreme directions in the * range of type `Kernel::Direction_2`. @@ -29,4 +31,5 @@ OutputIterator single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi); +} /* end namesapce Casting_2 */ } /* end namesapce CGAL */ From dcfdafc78e30805d5537381224e62058b2199e65 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 28 Sep 2016 16:54:28 +0300 Subject: [PATCH 25/90] Renamed Casting_2 => Set_movable_separability_2 --- .../CGAL/single_mold_translational_casting_2.h | 0 .../doc/Casting_2/Casting_2.txt | 0 .../doc/Casting_2/Doxyfile.in | 0 .../doc/Casting_2/PackageDescription.txt | 0 .../doc/Casting_2/dependencies | 0 .../doc/Casting_2/examples.txt | 0 .../doc/Casting_2/fig/Casting_2.png | Bin .../doc/Casting_2/fig/mold.png | Bin .../examples/Casting_2/CMakeLists.txt | 0 .../examples/Casting_2/polygon.dat | 0 .../Casting_2/single_mold_translational_casting.cpp | 0 .../include/CGAL/Casting_2/Circle_arrangment.h | 0 .../CGAL/single_mold_translational_casting_2.h | 0 .../package_info/Casting_2/copyright | 0 .../package_info/Casting_2/description.txt | 0 .../package_info/Casting_2/license.txt | 0 .../package_info/Casting_2/long_description.txt | 0 .../package_info/Casting_2/maintainer | 0 .../test/Casting_2/CMakeLists.txt | 0 .../test/Casting_2/cgal_test_with_cmake | 0 .../test/Casting_2/data/test01.txt | 0 .../test_single_mold_translational_casting.cmd | 0 .../test_single_mold_translational_casting.cpp | 0 23 files changed, 0 insertions(+), 0 deletions(-) rename {Casting_2 => Set_movable_separability_2}/doc/Casting_2/CGAL/single_mold_translational_casting_2.h (100%) rename {Casting_2 => Set_movable_separability_2}/doc/Casting_2/Casting_2.txt (100%) rename {Casting_2 => Set_movable_separability_2}/doc/Casting_2/Doxyfile.in (100%) rename {Casting_2 => Set_movable_separability_2}/doc/Casting_2/PackageDescription.txt (100%) rename {Casting_2 => Set_movable_separability_2}/doc/Casting_2/dependencies (100%) rename {Casting_2 => Set_movable_separability_2}/doc/Casting_2/examples.txt (100%) rename {Casting_2 => Set_movable_separability_2}/doc/Casting_2/fig/Casting_2.png (100%) rename {Casting_2 => Set_movable_separability_2}/doc/Casting_2/fig/mold.png (100%) rename {Casting_2 => Set_movable_separability_2}/examples/Casting_2/CMakeLists.txt (100%) rename {Casting_2 => Set_movable_separability_2}/examples/Casting_2/polygon.dat (100%) rename {Casting_2 => Set_movable_separability_2}/examples/Casting_2/single_mold_translational_casting.cpp (100%) rename {Casting_2 => Set_movable_separability_2}/include/CGAL/Casting_2/Circle_arrangment.h (100%) rename {Casting_2 => Set_movable_separability_2}/include/CGAL/single_mold_translational_casting_2.h (100%) rename {Casting_2 => Set_movable_separability_2}/package_info/Casting_2/copyright (100%) rename {Casting_2 => Set_movable_separability_2}/package_info/Casting_2/description.txt (100%) rename {Casting_2 => Set_movable_separability_2}/package_info/Casting_2/license.txt (100%) rename {Casting_2 => Set_movable_separability_2}/package_info/Casting_2/long_description.txt (100%) rename {Casting_2 => Set_movable_separability_2}/package_info/Casting_2/maintainer (100%) rename {Casting_2 => Set_movable_separability_2}/test/Casting_2/CMakeLists.txt (100%) rename {Casting_2 => Set_movable_separability_2}/test/Casting_2/cgal_test_with_cmake (100%) rename {Casting_2 => Set_movable_separability_2}/test/Casting_2/data/test01.txt (100%) rename {Casting_2 => Set_movable_separability_2}/test/Casting_2/test_single_mold_translational_casting.cmd (100%) rename {Casting_2 => Set_movable_separability_2}/test/Casting_2/test_single_mold_translational_casting.cpp (100%) diff --git a/Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h similarity index 100% rename from Casting_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h rename to Set_movable_separability_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h diff --git a/Casting_2/doc/Casting_2/Casting_2.txt b/Set_movable_separability_2/doc/Casting_2/Casting_2.txt similarity index 100% rename from Casting_2/doc/Casting_2/Casting_2.txt rename to Set_movable_separability_2/doc/Casting_2/Casting_2.txt diff --git a/Casting_2/doc/Casting_2/Doxyfile.in b/Set_movable_separability_2/doc/Casting_2/Doxyfile.in similarity index 100% rename from Casting_2/doc/Casting_2/Doxyfile.in rename to Set_movable_separability_2/doc/Casting_2/Doxyfile.in diff --git a/Casting_2/doc/Casting_2/PackageDescription.txt b/Set_movable_separability_2/doc/Casting_2/PackageDescription.txt similarity index 100% rename from Casting_2/doc/Casting_2/PackageDescription.txt rename to Set_movable_separability_2/doc/Casting_2/PackageDescription.txt diff --git a/Casting_2/doc/Casting_2/dependencies b/Set_movable_separability_2/doc/Casting_2/dependencies similarity index 100% rename from Casting_2/doc/Casting_2/dependencies rename to Set_movable_separability_2/doc/Casting_2/dependencies diff --git a/Casting_2/doc/Casting_2/examples.txt b/Set_movable_separability_2/doc/Casting_2/examples.txt similarity index 100% rename from Casting_2/doc/Casting_2/examples.txt rename to Set_movable_separability_2/doc/Casting_2/examples.txt diff --git a/Casting_2/doc/Casting_2/fig/Casting_2.png b/Set_movable_separability_2/doc/Casting_2/fig/Casting_2.png similarity index 100% rename from Casting_2/doc/Casting_2/fig/Casting_2.png rename to Set_movable_separability_2/doc/Casting_2/fig/Casting_2.png diff --git a/Casting_2/doc/Casting_2/fig/mold.png b/Set_movable_separability_2/doc/Casting_2/fig/mold.png similarity index 100% rename from Casting_2/doc/Casting_2/fig/mold.png rename to Set_movable_separability_2/doc/Casting_2/fig/mold.png diff --git a/Casting_2/examples/Casting_2/CMakeLists.txt b/Set_movable_separability_2/examples/Casting_2/CMakeLists.txt similarity index 100% rename from Casting_2/examples/Casting_2/CMakeLists.txt rename to Set_movable_separability_2/examples/Casting_2/CMakeLists.txt diff --git a/Casting_2/examples/Casting_2/polygon.dat b/Set_movable_separability_2/examples/Casting_2/polygon.dat similarity index 100% rename from Casting_2/examples/Casting_2/polygon.dat rename to Set_movable_separability_2/examples/Casting_2/polygon.dat diff --git a/Casting_2/examples/Casting_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Casting_2/single_mold_translational_casting.cpp similarity index 100% rename from Casting_2/examples/Casting_2/single_mold_translational_casting.cpp rename to Set_movable_separability_2/examples/Casting_2/single_mold_translational_casting.cpp diff --git a/Casting_2/include/CGAL/Casting_2/Circle_arrangment.h b/Set_movable_separability_2/include/CGAL/Casting_2/Circle_arrangment.h similarity index 100% rename from Casting_2/include/CGAL/Casting_2/Circle_arrangment.h rename to Set_movable_separability_2/include/CGAL/Casting_2/Circle_arrangment.h diff --git a/Casting_2/include/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h similarity index 100% rename from Casting_2/include/CGAL/single_mold_translational_casting_2.h rename to Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h diff --git a/Casting_2/package_info/Casting_2/copyright b/Set_movable_separability_2/package_info/Casting_2/copyright similarity index 100% rename from Casting_2/package_info/Casting_2/copyright rename to Set_movable_separability_2/package_info/Casting_2/copyright diff --git a/Casting_2/package_info/Casting_2/description.txt b/Set_movable_separability_2/package_info/Casting_2/description.txt similarity index 100% rename from Casting_2/package_info/Casting_2/description.txt rename to Set_movable_separability_2/package_info/Casting_2/description.txt diff --git a/Casting_2/package_info/Casting_2/license.txt b/Set_movable_separability_2/package_info/Casting_2/license.txt similarity index 100% rename from Casting_2/package_info/Casting_2/license.txt rename to Set_movable_separability_2/package_info/Casting_2/license.txt diff --git a/Casting_2/package_info/Casting_2/long_description.txt b/Set_movable_separability_2/package_info/Casting_2/long_description.txt similarity index 100% rename from Casting_2/package_info/Casting_2/long_description.txt rename to Set_movable_separability_2/package_info/Casting_2/long_description.txt diff --git a/Casting_2/package_info/Casting_2/maintainer b/Set_movable_separability_2/package_info/Casting_2/maintainer similarity index 100% rename from Casting_2/package_info/Casting_2/maintainer rename to Set_movable_separability_2/package_info/Casting_2/maintainer diff --git a/Casting_2/test/Casting_2/CMakeLists.txt b/Set_movable_separability_2/test/Casting_2/CMakeLists.txt similarity index 100% rename from Casting_2/test/Casting_2/CMakeLists.txt rename to Set_movable_separability_2/test/Casting_2/CMakeLists.txt diff --git a/Casting_2/test/Casting_2/cgal_test_with_cmake b/Set_movable_separability_2/test/Casting_2/cgal_test_with_cmake similarity index 100% rename from Casting_2/test/Casting_2/cgal_test_with_cmake rename to Set_movable_separability_2/test/Casting_2/cgal_test_with_cmake diff --git a/Casting_2/test/Casting_2/data/test01.txt b/Set_movable_separability_2/test/Casting_2/data/test01.txt similarity index 100% rename from Casting_2/test/Casting_2/data/test01.txt rename to Set_movable_separability_2/test/Casting_2/data/test01.txt diff --git a/Casting_2/test/Casting_2/test_single_mold_translational_casting.cmd b/Set_movable_separability_2/test/Casting_2/test_single_mold_translational_casting.cmd similarity index 100% rename from Casting_2/test/Casting_2/test_single_mold_translational_casting.cmd rename to Set_movable_separability_2/test/Casting_2/test_single_mold_translational_casting.cmd diff --git a/Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp b/Set_movable_separability_2/test/Casting_2/test_single_mold_translational_casting.cpp similarity index 100% rename from Casting_2/test/Casting_2/test_single_mold_translational_casting.cpp rename to Set_movable_separability_2/test/Casting_2/test_single_mold_translational_casting.cpp From 8d817422ee12f9e54f2fd4a561cf1edeeb14ee09 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 28 Sep 2016 16:56:48 +0300 Subject: [PATCH 26/90] Renamed Casting_2 => Set_movable_separability_2 --- .../CGAL/single_mold_translational_casting_2.h | 0 .../Doxyfile.in | 0 .../PackageDescription.txt | 0 .../Set_movable_separability_2.txt} | 0 .../dependencies | 0 .../examples.txt | 0 .../fig/Casting_2.png | Bin .../fig/mold.png | Bin .../CMakeLists.txt | 0 .../polygon.dat | 0 .../single_mold_translational_casting.cpp | 0 .../Circle_arrangment.h | 0 .../copyright | 0 .../description.txt | 0 .../license.txt | 0 .../long_description.txt | 0 .../maintainer | 0 .../CMakeLists.txt | 0 .../cgal_test_with_cmake | 0 .../data/test01.txt | 0 .../test_single_mold_translational_casting.cmd | 0 .../test_single_mold_translational_casting.cpp | 0 22 files changed, 0 insertions(+), 0 deletions(-) rename Set_movable_separability_2/doc/{Casting_2 => Set_movable_separability_2}/CGAL/single_mold_translational_casting_2.h (100%) rename Set_movable_separability_2/doc/{Casting_2 => Set_movable_separability_2}/Doxyfile.in (100%) rename Set_movable_separability_2/doc/{Casting_2 => Set_movable_separability_2}/PackageDescription.txt (100%) rename Set_movable_separability_2/doc/{Casting_2/Casting_2.txt => Set_movable_separability_2/Set_movable_separability_2.txt} (100%) rename Set_movable_separability_2/doc/{Casting_2 => Set_movable_separability_2}/dependencies (100%) rename Set_movable_separability_2/doc/{Casting_2 => Set_movable_separability_2}/examples.txt (100%) rename Set_movable_separability_2/doc/{Casting_2 => Set_movable_separability_2}/fig/Casting_2.png (100%) rename Set_movable_separability_2/doc/{Casting_2 => Set_movable_separability_2}/fig/mold.png (100%) rename Set_movable_separability_2/examples/{Casting_2 => Set_movable_separability_2}/CMakeLists.txt (100%) rename Set_movable_separability_2/examples/{Casting_2 => Set_movable_separability_2}/polygon.dat (100%) rename Set_movable_separability_2/examples/{Casting_2 => Set_movable_separability_2}/single_mold_translational_casting.cpp (100%) rename Set_movable_separability_2/include/CGAL/{Casting_2 => Set_movable_separability_2}/Circle_arrangment.h (100%) rename Set_movable_separability_2/package_info/{Casting_2 => Set_movable_separability_2}/copyright (100%) rename Set_movable_separability_2/package_info/{Casting_2 => Set_movable_separability_2}/description.txt (100%) rename Set_movable_separability_2/package_info/{Casting_2 => Set_movable_separability_2}/license.txt (100%) rename Set_movable_separability_2/package_info/{Casting_2 => Set_movable_separability_2}/long_description.txt (100%) rename Set_movable_separability_2/package_info/{Casting_2 => Set_movable_separability_2}/maintainer (100%) rename Set_movable_separability_2/test/{Casting_2 => Set_movable_separability_2}/CMakeLists.txt (100%) rename Set_movable_separability_2/test/{Casting_2 => Set_movable_separability_2}/cgal_test_with_cmake (100%) rename Set_movable_separability_2/test/{Casting_2 => Set_movable_separability_2}/data/test01.txt (100%) rename Set_movable_separability_2/test/{Casting_2 => Set_movable_separability_2}/test_single_mold_translational_casting.cmd (100%) rename Set_movable_separability_2/test/{Casting_2 => Set_movable_separability_2}/test_single_mold_translational_casting.cpp (100%) diff --git a/Set_movable_separability_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h similarity index 100% rename from Set_movable_separability_2/doc/Casting_2/CGAL/single_mold_translational_casting_2.h rename to Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h diff --git a/Set_movable_separability_2/doc/Casting_2/Doxyfile.in b/Set_movable_separability_2/doc/Set_movable_separability_2/Doxyfile.in similarity index 100% rename from Set_movable_separability_2/doc/Casting_2/Doxyfile.in rename to Set_movable_separability_2/doc/Set_movable_separability_2/Doxyfile.in diff --git a/Set_movable_separability_2/doc/Casting_2/PackageDescription.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt similarity index 100% rename from Set_movable_separability_2/doc/Casting_2/PackageDescription.txt rename to Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt diff --git a/Set_movable_separability_2/doc/Casting_2/Casting_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt similarity index 100% rename from Set_movable_separability_2/doc/Casting_2/Casting_2.txt rename to Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt diff --git a/Set_movable_separability_2/doc/Casting_2/dependencies b/Set_movable_separability_2/doc/Set_movable_separability_2/dependencies similarity index 100% rename from Set_movable_separability_2/doc/Casting_2/dependencies rename to Set_movable_separability_2/doc/Set_movable_separability_2/dependencies diff --git a/Set_movable_separability_2/doc/Casting_2/examples.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/examples.txt similarity index 100% rename from Set_movable_separability_2/doc/Casting_2/examples.txt rename to Set_movable_separability_2/doc/Set_movable_separability_2/examples.txt diff --git a/Set_movable_separability_2/doc/Casting_2/fig/Casting_2.png b/Set_movable_separability_2/doc/Set_movable_separability_2/fig/Casting_2.png similarity index 100% rename from Set_movable_separability_2/doc/Casting_2/fig/Casting_2.png rename to Set_movable_separability_2/doc/Set_movable_separability_2/fig/Casting_2.png diff --git a/Set_movable_separability_2/doc/Casting_2/fig/mold.png b/Set_movable_separability_2/doc/Set_movable_separability_2/fig/mold.png similarity index 100% rename from Set_movable_separability_2/doc/Casting_2/fig/mold.png rename to Set_movable_separability_2/doc/Set_movable_separability_2/fig/mold.png diff --git a/Set_movable_separability_2/examples/Casting_2/CMakeLists.txt b/Set_movable_separability_2/examples/Set_movable_separability_2/CMakeLists.txt similarity index 100% rename from Set_movable_separability_2/examples/Casting_2/CMakeLists.txt rename to Set_movable_separability_2/examples/Set_movable_separability_2/CMakeLists.txt diff --git a/Set_movable_separability_2/examples/Casting_2/polygon.dat b/Set_movable_separability_2/examples/Set_movable_separability_2/polygon.dat similarity index 100% rename from Set_movable_separability_2/examples/Casting_2/polygon.dat rename to Set_movable_separability_2/examples/Set_movable_separability_2/polygon.dat diff --git a/Set_movable_separability_2/examples/Casting_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp similarity index 100% rename from Set_movable_separability_2/examples/Casting_2/single_mold_translational_casting.cpp rename to Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp diff --git a/Set_movable_separability_2/include/CGAL/Casting_2/Circle_arrangment.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h similarity index 100% rename from Set_movable_separability_2/include/CGAL/Casting_2/Circle_arrangment.h rename to Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h diff --git a/Set_movable_separability_2/package_info/Casting_2/copyright b/Set_movable_separability_2/package_info/Set_movable_separability_2/copyright similarity index 100% rename from Set_movable_separability_2/package_info/Casting_2/copyright rename to Set_movable_separability_2/package_info/Set_movable_separability_2/copyright diff --git a/Set_movable_separability_2/package_info/Casting_2/description.txt b/Set_movable_separability_2/package_info/Set_movable_separability_2/description.txt similarity index 100% rename from Set_movable_separability_2/package_info/Casting_2/description.txt rename to Set_movable_separability_2/package_info/Set_movable_separability_2/description.txt diff --git a/Set_movable_separability_2/package_info/Casting_2/license.txt b/Set_movable_separability_2/package_info/Set_movable_separability_2/license.txt similarity index 100% rename from Set_movable_separability_2/package_info/Casting_2/license.txt rename to Set_movable_separability_2/package_info/Set_movable_separability_2/license.txt diff --git a/Set_movable_separability_2/package_info/Casting_2/long_description.txt b/Set_movable_separability_2/package_info/Set_movable_separability_2/long_description.txt similarity index 100% rename from Set_movable_separability_2/package_info/Casting_2/long_description.txt rename to Set_movable_separability_2/package_info/Set_movable_separability_2/long_description.txt diff --git a/Set_movable_separability_2/package_info/Casting_2/maintainer b/Set_movable_separability_2/package_info/Set_movable_separability_2/maintainer similarity index 100% rename from Set_movable_separability_2/package_info/Casting_2/maintainer rename to Set_movable_separability_2/package_info/Set_movable_separability_2/maintainer diff --git a/Set_movable_separability_2/test/Casting_2/CMakeLists.txt b/Set_movable_separability_2/test/Set_movable_separability_2/CMakeLists.txt similarity index 100% rename from Set_movable_separability_2/test/Casting_2/CMakeLists.txt rename to Set_movable_separability_2/test/Set_movable_separability_2/CMakeLists.txt diff --git a/Set_movable_separability_2/test/Casting_2/cgal_test_with_cmake b/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake similarity index 100% rename from Set_movable_separability_2/test/Casting_2/cgal_test_with_cmake rename to Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake diff --git a/Set_movable_separability_2/test/Casting_2/data/test01.txt b/Set_movable_separability_2/test/Set_movable_separability_2/data/test01.txt similarity index 100% rename from Set_movable_separability_2/test/Casting_2/data/test01.txt rename to Set_movable_separability_2/test/Set_movable_separability_2/data/test01.txt diff --git a/Set_movable_separability_2/test/Casting_2/test_single_mold_translational_casting.cmd b/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cmd similarity index 100% rename from Set_movable_separability_2/test/Casting_2/test_single_mold_translational_casting.cmd rename to Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cmd diff --git a/Set_movable_separability_2/test/Casting_2/test_single_mold_translational_casting.cpp b/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp similarity index 100% rename from Set_movable_separability_2/test/Casting_2/test_single_mold_translational_casting.cpp rename to Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp From d3a439f74f5107343d3a642f904e0b26ef06a15e Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 28 Sep 2016 17:25:45 +0300 Subject: [PATCH 27/90] Renamed Casting_2 => Set_movable_separability_2 --- Documentation/doc/Documentation/packages.txt | 2 +- .../CGAL/single_mold_translational_casting_2.h | 6 +++--- .../doc/Set_movable_separability_2/Doxyfile.in | 2 +- .../PackageDescription.txt | 12 ++++++------ .../Set_movable_separability_2.txt | 12 +++++------- .../doc/Set_movable_separability_2/examples.txt | 2 +- .../single_mold_translational_casting.cpp | 4 ++-- .../Set_movable_separability_2/Circle_arrangment.h | 4 ++-- .../CGAL/single_mold_translational_casting_2.h | 7 +++---- .../test_single_mold_translational_casting.cpp | 4 ++-- 10 files changed, 26 insertions(+), 29 deletions(-) diff --git a/Documentation/doc/Documentation/packages.txt b/Documentation/doc/Documentation/packages.txt index 7a80652122b..c5e91e52d46 100644 --- a/Documentation/doc/Documentation/packages.txt +++ b/Documentation/doc/Documentation/packages.txt @@ -23,7 +23,7 @@ h1 { \package_listing{Matrix_search} \package_listing{QP_solver} -\package_listing{Casting_2} +\package_listing{Set_movable_separability_2} \section PartKernels Geometry Kernels diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h index de231f92703..f589cea9392 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h @@ -1,7 +1,7 @@ namespace CGAL { -namespace Casting_2 { +namespace Set_movable_separability_2 { -/*! \ingroup PkgCasting2Funcs +/*! \ingroup PkgSetMovableSeparability2funcs * * 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 @@ -31,5 +31,5 @@ OutputIterator single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi); -} /* end namesapce Casting_2 */ +} /* end namesapce Set_movable_separability_2 */ } /* end namesapce CGAL */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Doxyfile.in b/Set_movable_separability_2/doc/Set_movable_separability_2/Doxyfile.in index bd25d8dafda..dee3260e68e 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Doxyfile.in +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Doxyfile.in @@ -1,3 +1,3 @@ @INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} -PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Castings" +PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Movable Separability of Sets" diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt index 4bea2df2c5c..15103844c72 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt @@ -1,17 +1,17 @@ -/// \defgroup PkgCasting2 2D Castings Reference +/// \defgroup PkgSetMovableSeparability2 2D Castings Reference -/// \defgroup PkgCasting2Funcs Free Functions -/// \ingroup PkgCasting2 +/// \defgroup PkgSetMovableSeparability2Funcs Free Functions +/// \ingroup PkgSetMovableSeparability2 /*! -\addtogroup PkgCasting2 +\addtogroup PkgSetMovableSeparability2 \todo check generated documentation -\cgalPkgDescriptionBegin{2D Castings,PkgCasting2Summary} +\cgalPkgDescriptionBegin{2D Castings,PkgSetMovableSeparability2Summary} \cgalPkgPicture{Casting_2.png} \cgalPkgSummaryBegin \cgalPkgAuthors{Shahar Shamai, Efi Fogel} \cgalPkgDesc{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 be used to compute all possible orientations of the feasible molds and the corresponding motions needed to remove the casted object from the mold.} -\cgalPkgManuals{Chapter_Castings_of_polygons,PkgCasting2} +\cgalPkgManuals{Chapter_Castings_of_polygons,PkgSetMovableSeparability2} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin \cgalPkgSince{4.10} diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index 5040cb20826..a96a12abce1 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -2,14 +2,12 @@ namespace CGAL { /*! \mainpage User Manual -\anchor Chapter_Castings_of_polygons - -\anchor chapterEnvelope2 +\anchor Chapter_SetMovableSeparability2 \cgalAutoToc \authors Shahar Shamai and Efi Fogel -\section casting_sec_intro Introduction +\section sms_sec_intro Introduction Casting is a manufacturing process where liquid material is poured into a cavity inside a mold, which has the shape of a desired @@ -30,14 +28,14 @@ polygon \f$P\f$ it 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 surface); see -\cgalFigureRef{casting_2_fig_mold} for an illustration. If the polygon +\cgalFigureRef{sms_2_fig_mold} for an illustration. If the polygon is castable, the function computes the set of top edges of such cavities and the corresponding closed ranges of pull directions. Assuming the top edge normal is parallel to the \f$y\f$-axis, every direction in a range must have a positive component in the positive \f$y\f$-direction. -\cgalFigureBegin{casting_2_fig_mold,mold.png} +\cgalFigureBegin{sms_2_fig_mold,mold.png} Polygons (light grey) in their molds (darker grey) and valid pull-out directions. \cgalFigureEnd @@ -58,7 +56,7 @@ and \f$O(1)\f$, respectively. In order to ensure robustness and correctness you are adviced to use a kernel that guarantees exact constructions as well as exact predicates. -\cgalExample{Casting_2/single_mold_translational_casting.cpp} +\cgalExample{Set_movable_separability_2/single_mold_translational_casting.cpp} */ } /* namespace CGAL */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/examples.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/examples.txt index dda045ca521..79413ffb596 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/examples.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/examples.txt @@ -1,3 +1,3 @@ /*! -\example Casting_2/single_mold_translational_casting.cpp +\example Set_movable_separability_2/single_mold_translational_casting.cpp */ diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp index 8bd0377a18c..c3b6d773c8f 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp @@ -13,7 +13,7 @@ typedef Kernel::Point_2 Point_2; typedef std::pair Direction_range; typedef std::pair Top_edge; -namespace CC = CGAL::Casting_2; +namespace SMS = CGAL::Set_movable_separability_2; // The main program: int main(int argc, char* argv[]) @@ -33,7 +33,7 @@ int main(int argc, char* argv[]) auto poly_orientation = pgn.orientation(); ++edge_index; std::list top_edges; - CC::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); + SMS::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); if (top_edges.empty()) std::cout << "The polygon is not castable!" << std::endl; diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h index 2ce36bbf42b..56cf249b77f 100644 --- a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h @@ -44,7 +44,7 @@ */ namespace CGAL { -namespace Casting_2 { +namespace Set_movable_separability_2 { namespace internal { template @@ -409,7 +409,7 @@ public: }; } // end of namespace internal -} // end of namespace Casting_2 +} // end of namespace Set_movable_separability_2 } // end of namespace CGAL #endif diff --git a/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h index 8ef04eb363e..1bafecd3c02 100644 --- a/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h @@ -24,11 +24,11 @@ #include #include -#include "Casting_2/Circle_arrangment.h" +#include "Set_movable_separability_2/Circle_arrangment.h" namespace CGAL { -namespace Casting_2 { +namespace Set_movable_separability_2 { /* Legend: * point = Represented as Direction_2. It is the intersection between the @@ -129,8 +129,7 @@ single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, return oi; } -} // end of namespace Casting_2 - +} // end of namespace Set_movable_separability_2 } // end of namespace CGAL #endif diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp b/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp index ccebbe74488..0c743db5c9f 100644 --- a/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp @@ -18,7 +18,7 @@ typedef Kernel::Point_2 Point_2; typedef std::pair Direction_range; typedef std::pair Top_edge; -namespace CC = CGAL::Casting_2; +namespace SMS = CGAL::Set_movable_separability_2; struct Top_edge_comparer { bool operator()(const Top_edge& a, const Top_edge& b) @@ -45,7 +45,7 @@ bool test_one_file(std::ifstream& inp) // std::cout << pgn << std::endl; std::vector top_edges; - CC::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); + SMS::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); size_t exp_num_top_edges; inp >> exp_num_top_edges; From fc81745e232223af6ffbbbc5e53b06d2ac65f506 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 28 Sep 2016 18:45:12 +0300 Subject: [PATCH 28/90] Updated --- Documentation/doc/biblio/geom.bib | 201 +++++++++--------- .../Set_movable_separability_2.txt | 37 +++- .../fig/sofa_problem.png | Bin 0 -> 3063 bytes 3 files changed, 135 insertions(+), 103 deletions(-) create mode 100644 Set_movable_separability_2/doc/Set_movable_separability_2/fig/sofa_problem.png diff --git a/Documentation/doc/biblio/geom.bib b/Documentation/doc/biblio/geom.bib index 68a236d9225..801a459f83e 100644 --- a/Documentation/doc/biblio/geom.bib +++ b/Documentation/doc/biblio/geom.bib @@ -4167,7 +4167,7 @@ cell neighborhood in $O(m)$ time." , succeeds = "aarx-clgta-96" , update = "98.07 rote, 98.03 mitchell, 97.03 rote" , abstract = "Exploiting the concept of so-called light edges, we introduce - a new way of defining the greedy triangulation GT(S) of a point + a new way of defining the greedy triangulation GT(S) of a point set S. It provides a decomposition of GT(S) into levels, and the number of levels allows us to bound the total edge length of GT(S). In particular, we show @@ -12292,9 +12292,9 @@ method that uses very different techniques." , pages = "201--290" , url = "http://wwwpi6.fernuni-hagen.de/Publikationen/tr198.pdf" , succeeds = "ak-vd-96" -, cites = "ahknu-vdcfc-95, abms-claho-94, aesw-emstb-91, agss-ltacv-89, ahl-sqrpc-90, aiks-fkpmd-91, a-dppuv-82, aaag-ntsp-95, aa-skfgpf-95, aacktrx-tin-96, a-nemts-83, as-vdco-95, ay-aampt1-90, ay-aampt2-90, ar-cvddp-96, a-gvdps-89, a-lbvdc-98, abky-cabmm-88, abcw-cpdts-88, ab-rdt-85, a-sdcgp-85, a-pdpaa-87, a-rpccc-87, a-iadbu-88, a-lcpd-88, a-ndrcv-90, a-vdsfg-91, ae-oacwv-84, aha-mttls-92, ai-grvd-88, as-solri-92, abi-cvus-88, br-rasas-90, bo-arcgi-79, bs-dcms-76, bwy-oetac-80, be-mgot-92i, beg-pgmg-94, b-bnvd, bt-gatuf-85, bmt-dppbp-96, bcdt-osc3d-91i, bdsty-arsol-92, bg-tdrcs-93, bsty-vdhdc-95, bt-rcdt-93, bh-cpcoe-88, b-rgsdd-89, b-vdch-79, b-gtfga-80, bms-hcvdl-94, b-gog-55, c-vmpmp-85, cd-svd-88, crw-gc-91, csy-oscpf-95, cdns-nsrgs-95, c-ochaa-93, ce-iacko-87, cgt-ecabs-95, cx-alesw-96, c-bvdcp-86, c-cdt-89, c-tapga-89, c-gqmgc-93, - cd-vdbcd-85, ckstw-vdl3s-95, csw-fmasp-95, c-wcanh-76, cms-mfdca-94, c-narsc-87, c-agmst-89, cms-frric-93, cs-arscg-89, cmrs-tspvd-93, cw-pspp-86, dj-wtacg-89, ds-oiti-89, bms-plpco-93, dfnp-stdt-91, d-eaclm-77, dk-savd-87, dk-bspwa-97, dn-cgacp-85, d-slsv-34, d-pp-44, d-rysoa-92, dv-cprac-77, dds-saeid-92, de-apphd-96, d-nhndt-87, d-tdt-90, d-fhcdt-92, d-udrdp-50, dl-cvdrp-91, ddg-fsp-83, dfs-dgaag-90, dl-pmtds-89, dl-msp-76, d-ec-83, d-fdcac-87, d-hdvdl-91, e-acg-87, e-atccd-90, e-ubids-95, egs-ueplf-89, egs-oplms-86, eks-sspp-83, em-tdas-94, eos-calha-86, es-vda-86, ess-ztha-93, es-itfwr-96, es-otatd-91, et-qtaml-93, et-ubcdt-93, etw-otama-92, ei-drmwc-79, f-sodt-90, f-iwatd-86, f-nsa2d-92, f-vddt-92, f-savd-87, gs-nsagv-69, gj-cigtn-79, g-3dmud-95, g-agt-85, grr-vdlsm-95, grss-sracp-95, - goy-cvdsl-93, gs-cdtp-78, gks-ricdv-92, gmr-vdmpp-92, gs-pmgsc-85, h-ca-75, h-rvdlp-92, h-gbitp-91, hkp-itnc-91, hn-sc-89, hns-psscp-88, h-pcprn-91, hks-uevsi-93, h-oarms-79, iklm-cdf3s-93, iki-awvdr-94, iss-nriac-92, j-3dtlt-89, j-ctddt-91, j-gspgm-91, jrz-ccdt-91, km-accvd-91, km-icdmc-92, kk-cdtmb-88, kg-cgwac-92, k-csmwt-94, ks-tpscv-93, k-eccs-79, k-ndot-80, k-osps-83, kr-fcm-85, k-cddvd-80, k-cavd-89, kl-ltrab-93, kl-fsc-95, kl-mpsp-95, kmm-ricav-93a, kw-vdbgm-88, k-sssgt-56, kl-fsacl-95, l-dtmmi-94, l-esta-94, l-scsi-77, l-vdlmh-94, l-ricsa-95, l-tdvdl-80, l-matps-82, l-knnvd-82, ld-gvdp-81, ll-gdtpg-86, lw-vdllm-80, lk-qgtam-96, l-ltcrn-94, msw-sblp-92, ms-pggrg-80, m-dtchn-84, mr-vdcdg-90, mks-cplvd-96, m-tdird-76, m-mnfcp-70, m-lpltw-84, mmo-cavd-91, m-zkav-93, +, cites = "ahknu-vdcfc-95, abms-claho-94, aesw-emstb-91, agss-ltacv-89, ahl-sqrpc-90, aiks-fkpmd-91, a-dppuv-82, aaag-ntsp-95, aa-skfgpf-95, aacktrx-tin-96, a-nemts-83, as-vdco-95, ay-aampt1-90, ay-aampt2-90, ar-cvddp-96, a-gvdps-89, a-lbvdc-98, abky-cabmm-88, abcw-cpdts-88, ab-rdt-85, a-sdcgp-85, a-pdpaa-87, a-rpccc-87, a-iadbu-88, a-lcpd-88, a-ndrcv-90, a-vdsfg-91, ae-oacwv-84, aha-mttls-92, ai-grvd-88, as-solri-92, abi-cvus-88, br-rasas-90, bo-arcgi-79, bs-dcms-76, bwy-oetac-80, be-mgot-92i, beg-pgmg-94, b-bnvd, bt-gatuf-85, bmt-dppbp-96, bcdt-osc3d-91i, bdsty-arsol-92, bg-tdrcs-93, bsty-vdhdc-95, bt-rcdt-93, bh-cpcoe-88, b-rgsdd-89, b-vdch-79, b-gtfga-80, bms-hcvdl-94, b-gog-55, c-vmpmp-85, cd-svd-88, crw-gc-91, csy-oscpf-95, cdns-nsrgs-95, c-ochaa-93, ce-iacko-87, cgt-ecabs-95, cx-alesw-96, c-bvdcp-86, c-cdt-89, c-tapga-89, c-gqmgc-93, + cd-vdbcd-85, ckstw-vdl3s-95, csw-fmasp-95, c-wcanh-76, cms-mfdca-94, c-narsc-87, c-agmst-89, cms-frric-93, cs-arscg-89, cmrs-tspvd-93, cw-pspp-86, dj-wtacg-89, ds-oiti-89, bms-plpco-93, dfnp-stdt-91, d-eaclm-77, dk-savd-87, dk-bspwa-97, dn-cgacp-85, d-slsv-34, d-pp-44, d-rysoa-92, dv-cprac-77, dds-saeid-92, de-apphd-96, d-nhndt-87, d-tdt-90, d-fhcdt-92, d-udrdp-50, dl-cvdrp-91, ddg-fsp-83, dfs-dgaag-90, dl-pmtds-89, dl-msp-76, d-ec-83, d-fdcac-87, d-hdvdl-91, e-acg-87, e-atccd-90, e-ubids-95, egs-ueplf-89, egs-oplms-86, eks-sspp-83, em-tdas-94, eos-calha-86, es-vda-86, ess-ztha-93, es-itfwr-96, es-otatd-91, et-qtaml-93, et-ubcdt-93, etw-otama-92, ei-drmwc-79, f-sodt-90, f-iwatd-86, f-nsa2d-92, f-vddt-92, f-savd-87, gs-nsagv-69, gj-cigtn-79, g-3dmud-95, g-agt-85, grr-vdlsm-95, grss-sracp-95, + goy-cvdsl-93, gs-cdtp-78, gks-ricdv-92, gmr-vdmpp-92, gs-pmgsc-85, h-ca-75, h-rvdlp-92, h-gbitp-91, hkp-itnc-91, hn-sc-89, hns-psscp-88, h-pcprn-91, hks-uevsi-93, h-oarms-79, iklm-cdf3s-93, iki-awvdr-94, iss-nriac-92, j-3dtlt-89, j-ctddt-91, j-gspgm-91, jrz-ccdt-91, km-accvd-91, km-icdmc-92, kk-cdtmb-88, kg-cgwac-92, k-csmwt-94, ks-tpscv-93, k-eccs-79, k-ndot-80, k-osps-83, kr-fcm-85, k-cddvd-80, k-cavd-89, kl-ltrab-93, kl-fsc-95, kl-mpsp-95, kmm-ricav-93a, kw-vdbgm-88, k-sssgt-56, kl-fsacl-95, l-dtmmi-94, l-esta-94, l-scsi-77, l-vdlmh-94, l-ricsa-95, l-tdvdl-80, l-matps-82, l-knnvd-82, ld-gvdp-81, ll-gdtpg-86, lw-vdllm-80, lk-qgtam-96, l-ltcrn-94, msw-sblp-92, ms-pggrg-80, m-dtchn-84, mr-vdcdg-90, mks-cplvd-96, m-tdird-76, m-mnfcp-70, m-lpltw-84, mmo-cavd-91, m-zkav-93, m-uuam-28, m-rcvdp-93, m-spop-93, mmp-dgp-87, ms-getcc-88, mp-fitcp-78, m-osclv-90, m-lavd-91, osy-gvdl-86, osy-gvdl-87, oy-rmpmd-85, oim-iimvd-84, obs-stcav-92, p-etspi-77, pl-ecgvd-95, p-kpudz-82, p-mrpdt-92, ps-cgi-85, p-scnsg-57, r-odtr-91, rr-oprav-94, r-aiv-94, r-mrpdt-90, r-tbvdm-93, rsl-ashts-77, st-pwvt-88, s-cvdhd-82, s-mplbc-85, s-chdch-86, s-nfhdv-87, s-cdtvd-88, s-sdlpc-91, s-barga-93, s-cg-78, sh-cpp-75, s-icpps-85, s-atubl-94, s-let-78, s-vidt-80, s-sagdt-91, s-facdt-87, s-mmdpsl-91a, sd-csdta-95, s-smane-92, si-cvdom-92, soi-toari-90, s-rngam-83, si-atpvd-86, t-otdt-93, too-natdv-83, t-gcvdm-86, t-rngfp-80, v-mstkd-88, v-sgagc-91, v-dmrsl-09, v-nadpc-08, w-eucdt-93, ws-oacdt-87, w-cnddt-81, w-sedbe-91a, www-sdpfo-87, y-cmstk-82, y-amp-87, y-oavds-87, zm-sdnah-91, ZZZ" , update = "00.11 smid, 00.03 bibrelex, 99.03 bibrelex, 98.11 bibrelex, 98.07 mitchell, 98.03 bibrelex, 97.03 icking" , annote = "Chapter 5 of su-hcg-00" @@ -12847,9 +12847,9 @@ method that uses very different techniques." , url = "http://www.ifor.math.ethz.ch/staff/fukuda/fukuda.html" , update = "98.03 houle, 97.03 pocchiola, 96.05 fukuda" , annote = "Reverse search is a general exhaustive search technique -which came out of the new convex hull algorithm by the authors. +which came out of the new convex hull algorithm by the authors. This technique can be applied to many enumeration problems in computer -science, operations research and geometry. +science, operations research and geometry. It is highly suitable for parallelization." } @@ -16291,7 +16291,7 @@ rendering. Contains pseudocode." , number = 4 , year = 1997 , note = "Special issue on parallel I/O. An earlier version - appears in Proc. of the 8th Annual + appears in Proc. of the 8th Annual ACM Symposium on Parallel Algorithms and Architectures (SPAA~'96), Padua, Italy, June 1996, 109--118" , update = "97.03 murali" @@ -18449,12 +18449,12 @@ the interior. Contains pseudocode." , succeeds = "d-rld-89" , update = "98.07 bibrelex, 98.03 mitchell, 93.09 held" , annote = "He considers rectilinear paths in a rectilinear simple polygon. In $O(n\log n)$ - preprocessing time and space, he builds a data structure that supports - $O(\log n)$ time queries for distance between two points ($O(1)$ time between - two polygon vertices). He is actually searching for paths that are``smallest'' in - that they are shortest simultaneously in rectilinear link distance and - $L_1$ length (which is always possible). See improvements to $O(n)$ time and - space by Lingas, Maheshwari, and Sack~\cite{lms-parld-95} and + preprocessing time and space, he builds a data structure that supports + $O(\log n)$ time queries for distance between two points ($O(1)$ time between + two polygon vertices). He is actually searching for paths that are``smallest'' in + that they are shortest simultaneously in rectilinear link distance and + $L_1$ length (which is always possible). See improvements to $O(n)$ time and + space by Lingas, Maheshwari, and Sack~\cite{lms-parld-95} and Schuierer~\cite{s-odssr-96}." } @@ -21011,10 +21011,10 @@ cubes with side-lengths not exceeding 1 in the $3$-dimensional euclidean space. Let $S$ and $T$ be two points lying outside the open cubes. Assume one needs to find a short path emanating from $S$ and terminating at $T$ avoiding the cubes of $\cal P$ -under the restriction that the cubes are not known prior to the search. +under the restriction that the cubes are not known prior to the search. In fact the positions and the side-lengths of the cubes become known to the searcher as the cubes are contacted. We give an algorithm to -construct a path of length less than +construct a path of length less than $\frac 32 d + 3 \sqrt 3 \log d + 5$, where $d > 3 \sqrt 3$ denotes the distance between S and T." } @@ -24325,7 +24325,7 @@ experimental results are given." , abstract = "This paper presents the main algorithmic and design choices that have been made -to implement triangulations in +to implement triangulations in the computational geometry algorithms library CGAL." } @@ -25614,9 +25614,9 @@ present a polynomial-time exact algorithm to solve this problem." rectangles floating in 3-space, with edges represented by vertical lines of sight. We apply an extension of the {Erd\H os}-Szekeres Theorem in a geometric setting to obtain an - upper bound of 56 for size of the largest complete graph which - is representable. On the other hand, we construct a - representation of the complete graph with 22 vertices. + upper bound of 56 for size of the largest complete graph which + is representable. On the other hand, we construct a + representation of the complete graph with 22 vertices. These are the best existing bounds." } @@ -28630,7 +28630,7 @@ determinants." , year = 1993 , update = "98.03 mitchell" , abstract = "We calculate the partition - of the configuration space $I\!\!R^2 x S^1$ + of the configuration space $I\!\!R^2 x S^1$ of a car-like robot, only moving forwards, with respect to the type of the length optimal paths. This kind of robot is subject to kinematic constraints on its path curvature and its orientation. @@ -33590,35 +33590,35 @@ determinants." Given a set of polygonal obstacles of $n$ vertices in the plane, the problem of processing the all-pairs Euclidean {\em short} path queries is that of reporting an obstacle-avoiding path $P$ (or -its length) between two arbitrary query points $p$ and $q$ in the -plane, such that the length of $P$ is within a small factor of the +its length) between two arbitrary query points $p$ and $q$ in the +plane, such that the length of $P$ is within a small factor of the length of a Euclidean {\em shortest} obstacle-avoiding path between $p$ and $q$. The goal is to answer each short path query quickly -by constructing data structures that capture path information in -the obstacle-scattered plane. For the related all-pairs Euclidean -{\em shortest} path problem, the best known algorithms for even -very simple cases (e.g., {\em rectilinear} shortest paths among +by constructing data structures that capture path information in +the obstacle-scattered plane. For the related all-pairs Euclidean +{\em shortest} path problem, the best known algorithms for even +very simple cases (e.g., {\em rectilinear} shortest paths among disjoint {\em rectangular} obstacles in the plane) require at least quadratic space and time to construct a data structure, -so that a length query can be answered in polylogarithmic time. -The previously best known solution to the all-pairs Euclidean -{\em short} path problem also uses a data structure of quadratic -space and superquadratic construction time, in order to answer a -length query in polylogarithmic time. In this paper, we present a -data structure that requires nearly linear space and takes subquadratic -time to construct. Precisely, for any given $\epsilon$ satisfying +so that a length query can be answered in polylogarithmic time. +The previously best known solution to the all-pairs Euclidean +{\em short} path problem also uses a data structure of quadratic +space and superquadratic construction time, in order to answer a +length query in polylogarithmic time. In this paper, we present a +data structure that requires nearly linear space and takes subquadratic +time to construct. Precisely, for any given $\epsilon$ satisfying $0$ $<$ $\epsilon$ $\leq$ $1$, our data structure can be built -in $o(q^{3/2})$ $+$ $O((n\log n)/\epsilon)$ time and -$O(n\log n+n/\epsilon)$ space, where $q$, $1$ $\leq$ $q$ $\leq$ $n$, -is the minimum number of faces needed to cover all the vertices of -a certain planar graph we use. This data structure enables us to +in $o(q^{3/2})$ $+$ $O((n\log n)/\epsilon)$ time and +$O(n\log n+n/\epsilon)$ space, where $q$, $1$ $\leq$ $q$ $\leq$ $n$, +is the minimum number of faces needed to cover all the vertices of +a certain planar graph we use. This data structure enables us to report the length of a short path between two arbitrary query points in $O((\log n)/\epsilon+1/\epsilon^2)$ time and the actual path -in $O((\log n)/\epsilon+1/\epsilon^2+L)$ time, where $L$ is the -number of edges of the output path. The constant approximation -factor, $6+\epsilon$, for the short paths that we compute is quite -small. Our techniques are parallelizable and can also be used -to improve the previously best known results on several related +in $O((\log n)/\epsilon+1/\epsilon^2+L)$ time, where $L$ is the +number of edges of the output path. The constant approximation +factor, $6+\epsilon$, for the short paths that we compute is quite +small. Our techniques are parallelizable and can also be used +to improve the previously best known results on several related graphic and geometric problems." } @@ -36888,7 +36888,7 @@ avoids overlap. This is useful in cartography." This paper shows that the $i$-level of an arrangement of hyperplanes in $E^d$ has at most ${{i+d-1}\choose {d-1}}$ local minima. This bound follows from ideas previously used to prove bounds on $(\leq k)$-sets. -Using linear programming duality, +Using linear programming duality, the Upper Bound Theorem is obtained as a corollary, giving yet another proof of this celebrated bound on the number of vertices of a simple polytope @@ -42606,10 +42606,10 @@ Contains C code." , succeeds = "dp-olacd-91" , update = "98.11 bibrelex, 98.07 bibrelex, 95.09 mitchell" , annote = "In this paper you will find the definition of a Constrained - Delaunay Triangulation, some theorems and the pseudocode of - the algorithms to program it. On-Line means that you can - insert points and required edges in any order. With this - algorithm you can update an old CDT without retriangulating + Delaunay Triangulation, some theorems and the pseudocode of + the algorithms to program it. On-Line means that you can + insert points and required edges in any order. With this + algorithm you can update an old CDT without retriangulating the old data." } @@ -44330,7 +44330,7 @@ Contains C code." @techreport{d-vrtdd-09 , author = "Olivier Devillers" -, title = "Vertex Removal in Two Dimensional {Delaunay} Triangulation: +, title = "Vertex Removal in Two Dimensional {Delaunay} Triangulation: Asymptotic Complexity is Pointless" , thanks = "triangles" , institution = "INRIA" @@ -53249,17 +53249,17 @@ library." , update = "98.11 bibrelex, 98.03 mitchell, 97.11 bibrelex, 97.03 rote" , abstract = "We call a line $l$ a separator for a set $S$ of objects in the plane if $l$ avoids all the objects and - partitions $S$ into two nonempty subsets, one consisting + partitions $S$ into two nonempty subsets, one consisting of objects lying above $l$ and the - other of objects lying below $l$. We present an + other of objects lying below $l$. We present an $O(n log n)$-time algorithm for - finding a separator line for a set of $n$ segments, provided - the ratio between the diameter of the set of segments and + finding a separator line for a set of $n$ segments, provided + the ratio between the diameter of the set of segments and the length of the smallest segment is bounded. - No subquadratic algorithms are known for the general case. + No subquadratic algorithms are known for the general case. Our algorithm is based on the recent results of - Matousek, Pach, Sharir, Sifrony, and Welzl (1994) concerning - the union of fat triangles, but we also include an analysis + Matousek, Pach, Sharir, Sifrony, and Welzl (1994) concerning + the union of fat triangles, but we also include an analysis which improves the bounds obtained by Matousek et al." } @@ -57348,18 +57348,18 @@ a simple polygon with vertex set P. We prove that it is NP-complete to find a minimum weight polygon or a maximum weight polygon for a given vertex set, resulting in a proof of NP-completeness for the corresponding area optimization problems. This answers a generalization -of a question stated by Suri in 1989. +of a question stated by Suri in 1989. We give evidence that it is unlikely that the minimization -problem can be approximated. +problem can be approximated. For the maximiation problem, we show that we can find in optimal time O(n log n) a polygon of more than half the area AR(conv(P)) of the convex hull conv(P) of P, yielding a fast 1/2 approximation method for the problem. We demonstrate that it is NP-complete to decide whether there -is a simple polygon of at least (2/3+eps)(AR(conv(P)). +is a simple polygon of at least (2/3+eps)(AR(conv(P)). We also sketch an NP-hardness proof for the problem of finding a minimum-link searating polygon for two finite point sets in the plane. -Finally, we turn to higher dimensions, where we prove that for +Finally, we turn to higher dimensions, where we prove that for 0Movable Separability of Sets +\cgalCite{t-mss-85}, considers the separability of sets of objects +under different kinds of motions and various definitions of +separation. The moving sofa problem or sofa problem +(see Moving sofa +problem 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. These problems become progressively more challenging as the +allowable 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 + +\section sms_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. After the material solidifies, the product is pulled out of the mold. Typically a mold is used to manufacture numerous copies of a -product, in which case we need to make sure that the solidified -product can be separated from its mold without breaking it. The -challenge of designing a proper mold belongs to a larger topic termed -Movable Separability of Sets; see \cgalCite{t-mss-85} -These problems become progressively more challenging as the allowable -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. +product. The challenge is design a proper mold, such that the solidified +product can be separated from its mold without breaking it. This package provides a function called `single_mold_translational_casting_2()` that given a simple closed diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/fig/sofa_problem.png b/Set_movable_separability_2/doc/Set_movable_separability_2/fig/sofa_problem.png new file mode 100644 index 0000000000000000000000000000000000000000..6511fc722326bef80c36cff066dfd1f514656859 GIT binary patch literal 3063 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 Date: Wed, 28 Sep 2016 18:58:25 +0300 Subject: [PATCH 29/90] Updated --- .../CGAL/single_mold_translational_casting_2.h | 2 +- .../doc/Set_movable_separability_2/PackageDescription.txt | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h index f589cea9392..69cd03db44d 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h @@ -1,7 +1,7 @@ namespace CGAL { namespace Set_movable_separability_2 { -/*! \ingroup PkgSetMovableSeparability2funcs +/*! \ingroup PkgSetMovableSeparability2Funcs * * 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 diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt index 15103844c72..d3ed314e7d9 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt @@ -1,17 +1,16 @@ -/// \defgroup PkgSetMovableSeparability2 2D Castings Reference +/// \defgroup PkgSetMovableSeparability2 2D Movable Separability of Sets Reference /// \defgroup PkgSetMovableSeparability2Funcs Free Functions /// \ingroup PkgSetMovableSeparability2 /*! \addtogroup PkgSetMovableSeparability2 -\todo check generated documentation -\cgalPkgDescriptionBegin{2D Castings,PkgSetMovableSeparability2Summary} +\cgalPkgDescriptionBegin{2D Movable Separability of Sets,PkgSetMovableSeparability2Summary} \cgalPkgPicture{Casting_2.png} \cgalPkgSummaryBegin \cgalPkgAuthors{Shahar Shamai, Efi Fogel} \cgalPkgDesc{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 be used to compute all possible orientations of the feasible molds and the corresponding motions needed to remove the casted object from the mold.} -\cgalPkgManuals{Chapter_Castings_of_polygons,PkgSetMovableSeparability2} +\cgalPkgManuals{Chapter_SetMovableSeparability2,PkgSetMovableSeparability2} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin \cgalPkgSince{4.10} From 81b32deff094c210d7563c9d6f77cad3170edb81 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 29 Sep 2016 18:38:31 +0300 Subject: [PATCH 30/90] Enhanced --- .../Set_movable_separability_2.txt | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index c6623bd79fa..abec5cabf37 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -9,15 +9,12 @@ namespace CGAL { \section sms_sec_intro Introduction -Problems of moving sets of objects, such as polygons in the plane and -polyhedra in three dimensions, without allowing collisions between the -objects are ubiquitous in many fields including motion planning, -computer graphics, VLSI layout, and manufacturing. One class of such -problems, referred to as Movable Separability of Sets -\cgalCite{t-mss-85}, considers the separability of sets of objects -under different kinds of motions and various definitions of -separation. The moving sofa problem or sofa problem -(see Movable Separability of Sets \cgalCite{t-mss-85} 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. The moving sofa problem or sofa +problem (see Moving sofa problem is a classic member of this class. It is a two-dimensional idealisation of real-life furniture-moving problems; it asks for the @@ -25,23 +22,29 @@ 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. These problems become progressively more challenging as the -allowable separation motions becomes more complex (have more degrees -of freedom), the number of objects involved grows, or the shape of the +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_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. 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 design a proper mold, such that the solidified -product can be separated from its mold without breaking it. +product. The challenge is design a proper mold, such that the +solidified product can be separated from its mold without breaking it. This package provides a function called `single_mold_translational_casting_2()` that given a simple closed @@ -79,5 +82,14 @@ constructions as well as exact predicates. \cgalExample{Set_movable_separability_2/single_mold_translational_casting.cpp} +This package also provides the following two functions: (i) +`is_top_edge_single_mold_translational_casting_2()` and (ii) +'top_edge_directions_single_mold_translational_casting_2(). The +former accepts a simple closed polygon \f$P\f$ and and edge \f$e\f$ of +the polygon. It determines whether \f$e\f$ is a top edge of +\f$P\f$. The latter accepts a simple closed polygon \f$P\f$ and a top +edge \f$e\f$ of \f$P\f$ and computes the range of pull +directions of \f$e\f$. */ + } /* namespace CGAL */ From 066b959f33576b793213b883c2f5676fdedea49c Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 29 Sep 2016 18:47:54 +0300 Subject: [PATCH 31/90] Fixed package name --- .../package_info/Set_movable_separability_2/description.txt | 2 +- .../Set_movable_separability_2/long_description.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Set_movable_separability_2/package_info/Set_movable_separability_2/description.txt b/Set_movable_separability_2/package_info/Set_movable_separability_2/description.txt index 04c8be96802..cb5cacb7868 100644 --- a/Set_movable_separability_2/package_info/Set_movable_separability_2/description.txt +++ b/Set_movable_separability_2/package_info/Set_movable_separability_2/description.txt @@ -1 +1 @@ -Various 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. +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. diff --git a/Set_movable_separability_2/package_info/Set_movable_separability_2/long_description.txt b/Set_movable_separability_2/package_info/Set_movable_separability_2/long_description.txt index c8b96a75c22..8d47d801254 100644 --- a/Set_movable_separability_2/package_info/Set_movable_separability_2/long_description.txt +++ b/Set_movable_separability_2/package_info/Set_movable_separability_2/long_description.txt @@ -1,3 +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. From 400c9a10318e0aa6124b5bec3942819bf9d69cb4 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 16 Nov 2016 18:29:50 +0200 Subject: [PATCH 32/90] Updated --- Documentation/doc/Documentation/dependencies | 4 +- Documentation/doc/Documentation/packages.txt | 2 +- .../single_mold_translational_casting_2.h | 7 +++- .../Concepts/CastingTraits_2.h | 38 +++++++++++++++++++ .../PackageDescription.txt | 7 ++++ .../Set_movable_separability_2.txt | 31 ++++++++------- 6 files changed, 70 insertions(+), 19 deletions(-) create mode 100644 Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h diff --git a/Documentation/doc/Documentation/dependencies b/Documentation/doc/Documentation/dependencies index 80888fecaa6..798293a809a 100644 --- a/Documentation/doc/Documentation/dependencies +++ b/Documentation/doc/Documentation/dependencies @@ -97,6 +97,4 @@ Barycentric_coordinates_2 Surface_mesh Surface_mesh_shortest_path Polygon_mesh_processing - - - +Set_movable_separability_2 diff --git a/Documentation/doc/Documentation/packages.txt b/Documentation/doc/Documentation/packages.txt index c5e91e52d46..91683c5186a 100644 --- a/Documentation/doc/Documentation/packages.txt +++ b/Documentation/doc/Documentation/packages.txt @@ -23,7 +23,6 @@ h1 { \package_listing{Matrix_search} \package_listing{QP_solver} -\package_listing{Set_movable_separability_2} \section PartKernels Geometry Kernels @@ -49,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 diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h index 69cd03db44d..519468e0efb 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h @@ -14,6 +14,9 @@ namespace Set_movable_separability_2 { * \f$y\f$-direction. 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[in] pgn the input polygon. * \param[out] oi the output iterator. Its value type is a pair, where * (i) the first element in the pair identifies a valid top edge @@ -26,9 +29,9 @@ namespace Set_movable_separability_2 { * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and * does not have three consecutive collinear vertices. */ -template +template OutputIterator -single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, +single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi); } /* end namesapce Set_movable_separability_2 */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h new file mode 100644 index 00000000000..73f4083825d --- /dev/null +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h @@ -0,0 +1,38 @@ +/*! + + \ingroup PkgSetMovableSeparability2Concepts + \cgalConcept + + This concept generalizes the concept of a 2D Kernel. + + \cgalRefines `DefaultConstructible` + \cgalRefines `PolygonTraits_2` + + \cgalGeneralizes `Kernel` + + \cgalHasModel Any CGAL kernel, e.g., CGAL::Exact_predicates_exact_constructions_kernel. + + \sa `GeneralPolygon_2` + +*/ + +class CastingTraits_2 { +public: + + /// \name Functor Types + /// @{ + + /*! models the concept `Kernel::Counterclockwise_in_between_2`. + */ + typedef unspecified_type Counterclockwise_in_between_2; + + /// @} + + /// \name Accessing Functor Objects + /// @{ + + Counterclockwise_in_between_2 counterclockwise_in_between_2_object() const; + + /// @} + +}; /* end GpsTraitsGeneralPolygon_2 */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt index d3ed314e7d9..23ae5b3ec48 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt @@ -3,6 +3,9 @@ /// \defgroup PkgSetMovableSeparability2Funcs Free Functions /// \ingroup PkgSetMovableSeparability2 +/// \defgroup PkgSetMovableSeparability2Concepts Concepts +/// \ingroup PkgSetMovableSeparability2 + /*! \addtogroup PkgSetMovableSeparability2 \cgalPkgDescriptionBegin{2D Movable Separability of Sets,PkgSetMovableSeparability2Summary} @@ -26,5 +29,9 @@ This package consists of the implementations of various predicates and operation ## Functions ## - `CGAL::single_mold_translational_casting_2()` +- `CGAL::top_edge_single_mold_translational_casting_2()` + +## Concepts ## +- `CastingTraits_2` */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index abec5cabf37..ff6040e00f6 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -9,6 +9,9 @@ namespace CGAL { \section sms_sec_intro Introduction +Chapter \ref Chapter_2D_Regularized_Boolean_Set-Operations +"2D Regularized Boolean Set-Operations" + Movable Separability of Sets \cgalCite{t-mss-85} 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 @@ -67,11 +70,12 @@ directions. 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, not consecuitive three vertices can be linear. If -you suspect that the input polygon may not satisfy the latter -condition, pre-process the polygon to elliminate this ill-condition. +Chapter_2D_Regularized_Boolean_Set-Operations +"2D Regularized Boolean Set-Operations" for the precise definition of +simple polygons. Secondly, any consecuitive three vertices cannot be +linear. 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 @@ -82,14 +86,15 @@ constructions as well as exact predicates. \cgalExample{Set_movable_separability_2/single_mold_translational_casting.cpp} -This package also provides the following two functions: (i) -`is_top_edge_single_mold_translational_casting_2()` and (ii) -'top_edge_directions_single_mold_translational_casting_2(). The -former accepts a simple closed polygon \f$P\f$ and and edge \f$e\f$ of -the polygon. It determines whether \f$e\f$ is a top edge of -\f$P\f$. The latter accepts a simple closed polygon \f$P\f$ and a top -edge \f$e\f$ of \f$P\f$ and computes the range of pull -directions of \f$e\f$. +This package also provides the function +`top_edge_single_mold_translational_casting_2()` that 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 pull directions of \f$e\f$. + +An overload of each of the two fimctions above that accepts an +additional traits argument is also provided by the package. + */ } /* namespace CGAL */ From 5c5844e0aba7d27a0670f2433c44ab0bb56d6fcb Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 16 Nov 2016 18:30:19 +0200 Subject: [PATCH 33/90] Updated --- ...edge_single_mold_translational_casting_2.h | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h new file mode 100644 index 00000000000..8ccdfc8137f --- /dev/null +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h @@ -0,0 +1,34 @@ +namespace CGAL { +namespace Set_movable_separability_2 { + +/*! \ingroup PkgSetMovableSeparability2Funcs + * + * 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 castable this way, the function computes the closed range of pull + * directions asuming that the the top edge normal is parallel to the + * \f$y\f$-axis. In other words, every direction in the range (if exists) must + * have a positive component in the positive \f$y\f$-direction. + * + * \param[in] pgn the input polygon. + * \param[in] i the index 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. + * + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. + */ +template +pair +top_edge_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, + size_t i); + +} /* end namesapce Set_movable_separability_2 */ +} /* end namesapce CGAL */ From b207d35fd9492ef2cc9d2405e30739d8b5aae90e Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 16 Nov 2016 23:26:53 +0200 Subject: [PATCH 34/90] updated --- .../Set_movable_separability_2/Set_movable_separability_2.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index ff6040e00f6..9135679be23 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -9,9 +9,6 @@ namespace CGAL { \section sms_sec_intro Introduction -Chapter \ref Chapter_2D_Regularized_Boolean_Set-Operations -"2D Regularized Boolean Set-Operations" - Movable Separability of Sets \cgalCite{t-mss-85} 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 From f05038ef9c97ce3330a267fbb3d50b2c43e6c9a1 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 17 Nov 2016 00:39:51 +0200 Subject: [PATCH 35/90] updated --- .../single_mold_translational_casting_2.h | 10 ++++++++++ ...edge_single_mold_translational_casting_2.h | 19 +++++++++++++++---- .../Concepts/CastingTraits_2.h | 2 -- .../single_mold_translational_casting_2.h | 2 +- 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h index 519468e0efb..69abe0b04e1 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h @@ -34,5 +34,15 @@ OutputIterator single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi); +/*! \ingroup PkgSetMovableSeparability2Funcs + * + * Same as above with the additional traits argument. + * \param[in] traits the traits to use. + */ +template +OutputIterator +single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, + OutputIterator oi, CastingTraits_2& traits); + } /* end namesapce Set_movable_separability_2 */ } /* end namesapce CGAL */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h index 8ccdfc8137f..e14b1301286 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h @@ -25,10 +25,21 @@ namespace Set_movable_separability_2 { * does not have three consecutive collinear vertices. */ template -pair -top_edge_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, - size_t i); +std::pair > +top_edge_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, size_t i); + +/*! \ingroup PkgSetMovableSeparability2Funcs + * + * Same as above with the additional traits argument. + * \param[in] traits the traits to use. + */ +template +std::pair > +top_edge_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, size_t i, CastingTraits_2& traits); } /* end namesapce Set_movable_separability_2 */ } /* end namesapce CGAL */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h index 73f4083825d..85790d250ad 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h @@ -12,8 +12,6 @@ \cgalHasModel Any CGAL kernel, e.g., CGAL::Exact_predicates_exact_constructions_kernel. - \sa `GeneralPolygon_2` - */ class CastingTraits_2 { diff --git a/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h index 1bafecd3c02..afe56a7af61 100644 --- a/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h @@ -1,4 +1,4 @@ -// Copyright (c) 2005,2006,2007,2008,2009,2010,2011 Tel-Aviv University (Israel). +// Copyright (c) 2016 Tel-Aviv University (Israel). // All rights reserved. // // This file is part of CGAL (www.cgal.org). From eba7bb0e5d75cfe4482bf58f14554a235fd1943d Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 17 Nov 2016 09:06:04 +0200 Subject: [PATCH 36/90] Added Set_movable_separability_2 --- copyright | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/copyright b/copyright index d5a3f795c33..0058490d087 100644 --- a/copyright +++ b/copyright @@ -88,7 +88,7 @@ R = RU Groningen Periodic_3_triangulation_3 I Point_set_2 Halle transfered copyright to Inria Point_set_processing_3 I - Poisson_surface_reconstruction_3 I + Poisson_surface_reconstruction_3 I Polygon ETIMU Polyhedron E Polyhedron_IO E @@ -105,6 +105,7 @@ R = RU Groningen Scripts ETIMU SearchStructures E Segment_Delaunay_graph_2 I Menelaos removed Notre Dame U + Set_movable_separability_2 T Skin_surface_3 R Gert Vegter agreed to upgrade Snap_rounding_2 T Spatial_searching U From 79e3df04af082defb4ff6daae8ffb0204b619215 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 17 Nov 2016 09:06:23 +0200 Subject: [PATCH 37/90] 1st revision --- ...edge_single_mold_translational_casting_2.h | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h diff --git a/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h new file mode 100644 index 00000000000..1a3470a443d --- /dev/null +++ b/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h @@ -0,0 +1,41 @@ +// 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 +// Efi Fogel + +#ifndef CGAL_TOP_EDGE_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#define CGAL_TOP_EDGE_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H + +#include + +namespace CGAL { + +namespace Set_movable_separability_2 { + +template +std::pair > +top_edge_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, size_t i) +{ + typedef CastingTraits_2 Casting_traits_2; + typename Casting_traits_2::Direction_2 d1, d2; + return std::make_pair(false, std::make_pair(d1, d2)); +} + +} // end of namespace Set_movable_separability_2 +} // end of namespace CGAL + +#endif From 7cdc9b3a1d804e38a92ed53c9fe440420cf0f08a Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 17 Nov 2016 09:09:19 +0200 Subject: [PATCH 38/90] Added missing parameter description --- .../CGAL/single_mold_translational_casting_2.h | 8 ++++++++ .../CGAL/top_edge_single_mold_translational_casting_2.h | 2 ++ 2 files changed, 10 insertions(+) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h index 69abe0b04e1..a1681c71233 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h @@ -37,6 +37,14 @@ single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, /*! \ingroup PkgSetMovableSeparability2Funcs * * Same as above with the additional traits argument. + * \param[in] pgn the input polygon. + * \param[out] oi the output iterator. Its value type is a pair, where + * (i) the first element in the pair identifies a valid top edge + * represented by its index the type of which is convertible to + `size_t`, and + * (ii) the second element is a closed range of pull-out directions + * represented as a pair of the extreme directions in the + * range of type `Kernel::Direction_2`. * \param[in] traits the traits to use. */ template diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h index e14b1301286..18f787e4253 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h @@ -33,6 +33,8 @@ top_edge_single_mold_translational_casting_2 /*! \ingroup PkgSetMovableSeparability2Funcs * * Same as above with the additional traits argument. + * \param[in] pgn the input polygon. + * \param[in] i the index of an edge in pgn. * \param[in] traits the traits to use. */ template From 864d456ed1e1f61443014addf3ca92653128bea5 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 17 Nov 2016 09:43:46 +0200 Subject: [PATCH 39/90] Updated --- .../Set_movable_separability_2.txt | 15 ++++++++++----- .../single_mold_translational_casting.cpp | 12 ++++-------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index 9135679be23..e23e0c0366f 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -43,7 +43,7 @@ Casting is a manufacturing process where liquid material is poured into a cavity inside a mold, which has the shape of a desired product. 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 design a proper mold, such that the +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 @@ -54,7 +54,7 @@ plane) that has the shape of \f$P\f$ can be used so that the polygon mold (but possibly sliding along the mold surface); see \cgalFigureRef{sms_2_fig_mold} for an illustration. If the polygon is castable, the function computes the set of top edges of -such cavities and the corresponding closed ranges of pull +such cavities and the corresponding closed ranges of pull-out directions. Assuming the top edge normal is parallel to the \f$y\f$-axis, every direction in a range must have a positive component in the positive \f$y\f$-direction. @@ -79,7 +79,12 @@ 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 are adviced to use a kernel that guarantees exact -constructions as well as exact predicates. +constructions as well as exact predicates, e,g,. +`Exact_predicates_exact_constructions_kernel`. + +The following example computes the top edges and their pull-out +directions of an input polygon read from a file and reports the results. + \cgalExample{Set_movable_separability_2/single_mold_translational_casting.cpp} @@ -87,9 +92,9 @@ This package also provides the function `top_edge_single_mold_translational_casting_2()` that 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 pull directions of \f$e\f$. +computes the range of pull-out directions of \f$e\f$. -An overload of each of the two fimctions above that accepts an +An overload of each of the two functions above that accepts an additional traits argument is also provided by the package. */ diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp index c3b6d773c8f..9c97516e61e 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp @@ -8,8 +8,6 @@ typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; typedef Kernel::Direction_2 Direction_2; -typedef Kernel::Point_2 Point_2; - typedef std::pair Direction_range; typedef std::pair Top_edge; @@ -27,11 +25,9 @@ int main(int argc, char* argv[]) return -1; } input_file >> pgn; + input_file.close(); - auto e_it = pgn.edges_begin(); - size_t edge_index(0); auto poly_orientation = pgn.orientation(); - ++edge_index; std::list top_edges; SMS::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); @@ -40,9 +36,9 @@ int main(int argc, char* argv[]) else { std::cout << "There are " << top_edges.size() << " top edges:" << std::endl; for (const auto& top_edge : top_edges) { - std::cout << "Edge number: "< Date: Thu, 17 Nov 2016 09:53:30 +0200 Subject: [PATCH 40/90] Updated --- .../single_mold_translational_casting_2.h | 23 +++++++++++++++---- ...edge_single_mold_translational_casting_2.h | 12 +++++++++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h index afe56a7af61..5f3f03c47c8 100644 --- a/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h @@ -92,13 +92,14 @@ bool is_any_edge_colinear(const CGAL::Polygon_2& pgn) /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) * \param[in] pgn the input polygon that we want to check if is castable or not. * \param[in,out] oi the output iterator to put the top edges in + * \param[in] kernel the kernel to use. * \return all the possible top edges of the polygon and there pullout direction * (with no rotation) */ template OutputIterator single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, - OutputIterator oi) + OutputIterator oi, Kernel& kernel) { /* Legend * point = Represented as Direction_2. It is the intersection between the @@ -115,11 +116,10 @@ single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, CGAL::Orientation poly_orientation = pgn.orientation(); auto segment_outer_circle = get_segment_outer_circle(*e_it++, poly_orientation); - internal::Circle_arrangment - circle_arrangment(segment_outer_circle); + internal::Circle_arrangment circle_arrangment(segment_outer_circle); ++edge_index; - for (; e_it!= pgn.edges_end(); ++e_it,++edge_index) { + for (; e_it!= pgn.edges_end(); ++e_it, ++edge_index) { segment_outer_circle = get_segment_outer_circle(*e_it, poly_orientation); circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); @@ -129,6 +129,21 @@ single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, return oi; } +/*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) + * \param[in] pgn the input polygon that we want to check if is castable or not. + * \param[in,out] oi the output iterator to put the top edges in + * \return all the possible top edges of the polygon and there pullout direction + * (with no rotation) + */ +template +OutputIterator +single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, + OutputIterator oi) +{ + Kernel kernel; + return single_mold_translational_casting_2(pgn, oi, kernel); +} + } // end of namespace Set_movable_separability_2 } // end of namespace CGAL diff --git a/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h index 1a3470a443d..87052197333 100644 --- a/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h @@ -28,13 +28,23 @@ template std::pair > top_edge_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i) +(const CGAL::Polygon_2& pgn, size_t i, Kernel& kernel) { typedef CastingTraits_2 Casting_traits_2; typename Casting_traits_2::Direction_2 d1, d2; return std::make_pair(false, std::make_pair(d1, d2)); } +template +std::pair > +top_edge_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, size_t i) +{ + Kernel kernel; + return top_edge_single_mold_translational_casting_2(pgn, i, kernel); +} + } // end of namespace Set_movable_separability_2 } // end of namespace CGAL From 47b1a93240dff5d251e662557173dbd0026a081a Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 17 Nov 2016 09:59:36 +0200 Subject: [PATCH 41/90] Updated --- ...edge_single_mold_translational_casting_2.h | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h index 87052197333..006361b394f 100644 --- a/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h @@ -24,6 +24,27 @@ namespace CGAL { namespace Set_movable_separability_2 { +/*! 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 castable this way, the function computes the closed range of pull + * directions asuming that the the top edge normal is parallel to the + * \f$y\f$-axis. In other words, every direction in the range (if exists) must + * have a positive component in the positive \f$y\f$-direction. + * + * \param[in] pgn the input polygon. + * \param[in] i the index 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. + * + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. + */ template std::pair > @@ -38,6 +59,11 @@ top_edge_single_mold_translational_casting_2 template std::pair > +/*! Same as above with the additional traits argument. + * \param[in] pgn the input polygon. + * \param[in] i the index of an edge in pgn. + * \param[in] traits the traits to use. + */ top_edge_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i) { From de912a0919634fd8b647d38b53119611b8655c8d Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 23 Nov 2016 15:28:32 +0200 Subject: [PATCH 42/90] Updated --- ...tion_single_mold_translational_casting_2.h | 49 +++++++++++++++++ ...ons_single_mold_translational_casting_2.h} | 13 ++--- ...ges_single_mold_translational_casting_2.h} | 15 +++--- .../PackageDescription.txt | 5 +- .../Set_movable_separability_2.txt | 42 ++++++++------- .../single_mold_translational_casting.cpp | 3 +- ...tion_single_mold_translational_casting_2.h | 53 +++++++++++++++++++ ...ons_single_mold_translational_casting_2.h} | 8 +-- ...ges_single_mold_translational_casting_2.h} | 12 ++--- 9 files changed, 155 insertions(+), 45 deletions(-) create mode 100644 Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h rename Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/{top_edge_single_mold_translational_casting_2.h => pullout_directions_single_mold_translational_casting_2.h} (84%) rename Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/{single_mold_translational_casting_2.h => top_edges_single_mold_translational_casting_2.h} (86%) create mode 100644 Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h rename Set_movable_separability_2/include/CGAL/{top_edge_single_mold_translational_casting_2.h => pullout_directions_single_mold_translational_casting_2.h} (92%) rename Set_movable_separability_2/include/CGAL/{single_mold_translational_casting_2.h => top_edges_single_mold_translational_casting_2.h} (93%) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h new file mode 100644 index 00000000000..226dd236b2c --- /dev/null +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -0,0 +1,49 @@ +namespace CGAL { +namespace Set_movable_separability_2 { + +/*! \ingroup PkgSetMovableSeparability2Funcs + * + * 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 rotated, such that the normal to the given edge is + * parallel to the \f$y\f$-axis, can be used so that 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). It is + * required that the polygon is castable this way. + * + * \param[in] pgn the input polygon. + * \param[in] i the index of an edge in pgn. + * \param[in] d the tested direction. + * \return true if `pgn` can be pulled out in the `d` direction, when rotated + * such that the normal to the edge identified by `i` is parallel to + * the \f$y\f$-axis. + * \pre pgn is castable and the edge identified by `i` is a top edge. + */ +template +std::pair > +is_pullout_direction_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, size_t i, + typename CastingTraits_2::Direction_2& d); + +/*! \ingroup PkgSetMovableSeparability2Funcs + * + * Same as above with the additional traits argument. + * \param[in] pgn the input polygon. + * \param[in] i the index of an edge in pgn. + * \param[in] d the tested direction. + * \param[in] traits the traits to use. + * \return true if `pgn` can be pulled out in the `d` direction, when rotated + * such that the normal to the edge identified by `i` is parallel to + * the \f$y\f$-axis. + * \pre pgn is castable and the edge identified by `i` is a top edge. + */ +template +std::pair > +is_pullout_direction_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, size_t i, + typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits); + +} /* end namesapce Set_movable_separability_2 */ +} /* end namesapce CGAL */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h similarity index 84% rename from Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h rename to Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h index 18f787e4253..0e4829e71b3 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edge_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -8,8 +8,8 @@ namespace Set_movable_separability_2 { * 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 castable this way, the function computes the closed range of pull - * directions asuming that the the top edge normal is parallel to the + * is castable this way, the function computes the closed range of + * pullout directions asuming that the the top edge normal is parallel to the * \f$y\f$-axis. In other words, every direction in the range (if exists) must * have a positive component in the positive \f$y\f$-direction. * @@ -17,7 +17,7 @@ namespace Set_movable_separability_2 { * \param[in] i the index 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 + * 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. * @@ -27,7 +27,7 @@ namespace Set_movable_separability_2 { template std::pair > -top_edge_single_mold_translational_casting_2 +pullout_directions_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i); /*! \ingroup PkgSetMovableSeparability2Funcs @@ -40,8 +40,9 @@ top_edge_single_mold_translational_casting_2 template std::pair > -top_edge_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, CastingTraits_2& traits); +pullout_directions_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, size_t i, + CastingTraits_2& traits); } /* end namesapce Set_movable_separability_2 */ } /* end namesapce CGAL */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h similarity index 86% rename from Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h rename to Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h index a1681c71233..df46d51a009 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h @@ -8,7 +8,7 @@ namespace Set_movable_separability_2 { * 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 castable, the function computes the set of top edges of - * such cavities and the corresponding closed ranges of pull directions. + * such cavities and the corresponding closed ranges of pullout directions. * Assuming the top edge normal is parallel to the \f$y\f$-axis, every direction * in a range must have a positive component in the positive * \f$y\f$-direction. Each top edge and corresponding range is added to a @@ -22,7 +22,7 @@ namespace Set_movable_separability_2 { * (i) the first element in the pair identifies a valid top edge * represented by its index the type of which is convertible to `size_t`, and - * (ii) the second element is a closed range of pull-out directions + * (ii) the second element is a closed range of pullout directions * represented as a pair of the extreme directions in the * range of type `Kernel::Direction_2`. * \return the past-the-end iterator of the output container. @@ -31,8 +31,8 @@ namespace Set_movable_separability_2 { */ template OutputIterator -single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, - OutputIterator oi); +top_edges_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, OutputIterator oi); /*! \ingroup PkgSetMovableSeparability2Funcs * @@ -42,15 +42,16 @@ single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, * (i) the first element in the pair identifies a valid top edge * represented by its index the type of which is convertible to `size_t`, and - * (ii) the second element is a closed range of pull-out directions + * (ii) the second element is a closed range of pullout directions * represented as a pair of the extreme directions in the * range of type `Kernel::Direction_2`. * \param[in] traits the traits to use. */ template OutputIterator -single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, - OutputIterator oi, CastingTraits_2& traits); +top_edges_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, OutputIterator oi, + CastingTraits_2& traits); } /* end namesapce Set_movable_separability_2 */ } /* end namesapce CGAL */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt index 23ae5b3ec48..9234aad135a 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt @@ -28,8 +28,9 @@ This package consists of the implementations of various predicates and operation \cgalClassifedRefPages ## Functions ## -- `CGAL::single_mold_translational_casting_2()` -- `CGAL::top_edge_single_mold_translational_casting_2()` +- `CGAL::top_edges_single_mold_translational_casting_2()` +- `CGAL::pullout_directions_single_mold_translational_casting_2()` +- `CGAL::is_pullout_direction_single_mold_translational_casting_2()` ## Concepts ## - `CastingTraits_2` diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index e23e0c0366f..33fab573855 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -47,20 +47,20 @@ 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 -`single_mold_translational_casting_2()` that given a simple closed -polygon \f$P\f$ it 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 surface); see -\cgalFigureRef{sms_2_fig_mold} for an illustration. If the polygon -is castable, the function computes the set of top edges of -such cavities and the corresponding closed ranges of pull-out -directions. Assuming the top edge normal is parallel to the -\f$y\f$-axis, every direction in a range must have a positive -component in the positive \f$y\f$-direction. +`top_edges_single_mold_translational_casting_2()` that given a simple +closed polygon \f$P\f$ it 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 surface); see +\cgalFigureRef{sms_2_fig_mold} for an illustration. If the polygon is +castable, the function computes the set of top edges of such +cavities and the corresponding closed ranges of pullout directions. +Assuming the top edge normal is parallel to the \f$y\f$-axis, every +direction in a range must have a positive component in the positive +\f$y\f$-direction. \cgalFigureBegin{sms_2_fig_mold,mold.png} -Polygons (light grey) in their molds (darker grey) and valid pull-out +Polygons (light grey) in their molds (darker grey) and valid pullout directions. \cgalFigureEnd @@ -82,19 +82,23 @@ correctness you are adviced to 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 pull-out +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/single_mold_translational_casting.cpp} -This package also provides the function -`top_edge_single_mold_translational_casting_2()` that 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 pull-out directions of \f$e\f$. +This package provides two additional functions, namely, +`pullout_directions_single_mold_translational_casting_2()` and +`is_pullout_direction_single_mold_translational_casting_2()`. 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 accepts a simple closed polygon \f$P\f$, a top edge +\f$e\f$ of the polygon \f$P\f$, and a direction \f$d\f$; it determines +whether \f$d\f$ is a pullout direction of \f$e\f$. -An overload of each of the two functions above that accepts an +An overload of each of the three functions above that accepts an additional traits argument is also provided by the package. */ diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp index 9c97516e61e..f22c8794b8a 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp @@ -29,7 +29,8 @@ int main(int argc, char* argv[]) auto poly_orientation = pgn.orientation(); std::list top_edges; - SMS::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); + SMS::top_edges_single_mold_translational_casting_2 + (pgn, std::back_inserter(top_edges)); if (top_edges.empty()) std::cout << "The polygon is not castable!" << std::endl; diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h new file mode 100644 index 00000000000..5bf8c20c667 --- /dev/null +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -0,0 +1,53 @@ +// 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 +// Efi Fogel + +#ifndef CGAL_IS_PULLOUT_DIRECTION_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#define CGAL_IS_PULLOUT_DIRECTION_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H + +namespace CGAL { + +namespace Set_movable_separability_2 { + +/*! + */ +template +std::pair > +is_pullout_direction_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, size_t i, + typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) +{ + return false; +} + +/*! + */ +template +std::pair > +is_pullout_direction_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, size_t i, + typename CastingTraits_2::Direction_2& d) +{ + CastingTraits_2 traits; + return is_pullout_direction_single_mold_translational_casting_2(pgn, i, d, traits); +} + +} /* end namesapce Set_movable_separability_2 */ +} /* end namesapce CGAL */ + +#endif diff --git a/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h similarity index 92% rename from Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h rename to Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h index 006361b394f..6f4fa38754e 100644 --- a/Set_movable_separability_2/include/CGAL/top_edge_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -15,8 +15,8 @@ // Author(s): Shahar // Efi Fogel -#ifndef CGAL_TOP_EDGE_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H -#define CGAL_TOP_EDGE_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#ifndef CGAL_PULLOUT_DIRECTIONS_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#define CGAL_PULLOUT_DIRECTIONS_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H #include @@ -48,7 +48,7 @@ namespace Set_movable_separability_2 { template std::pair > -top_edge_single_mold_translational_casting_2 +pullout_directions_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, Kernel& kernel) { typedef CastingTraits_2 Casting_traits_2; @@ -64,7 +64,7 @@ std::pair& pgn, size_t i) { Kernel kernel; diff --git a/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h similarity index 93% rename from Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h rename to Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h index 5f3f03c47c8..4d9d56c572b 100644 --- a/Set_movable_separability_2/include/CGAL/single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h @@ -15,8 +15,8 @@ // Author(s): Shahar // Efi Fogel -#ifndef CGAL_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H -#define CGAL_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#ifndef CGAL_TOP_EDGES_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#define CGAL_TOP_EDGES_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H #include #include @@ -98,8 +98,8 @@ bool is_any_edge_colinear(const CGAL::Polygon_2& pgn) */ template OutputIterator -single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, - OutputIterator oi, Kernel& kernel) +top_edges_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, OutputIterator oi, Kernel& kernel) { /* Legend * point = Represented as Direction_2. It is the intersection between the @@ -137,8 +137,8 @@ single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, */ template OutputIterator -single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, - OutputIterator oi) +top_edges_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, OutputIterator oi) { Kernel kernel; return single_mold_translational_casting_2(pgn, oi, kernel); From 9f06c04453380b4f9829982cc1eceebbef31195c Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 23 Nov 2016 15:53:15 +0200 Subject: [PATCH 43/90] updated --- .../single_mold_translational_casting.cpp | 2 +- .../Circle_arrangment.h | 39 ++++++++++++------- ...tion_single_mold_translational_casting_2.h | 3 +- ...ions_single_mold_translational_casting_2.h | 4 +- ...dges_single_mold_translational_casting_2.h | 7 ++-- 5 files changed, 33 insertions(+), 22 deletions(-) diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp index f22c8794b8a..3fb52cebfcf 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp @@ -3,7 +3,7 @@ #include #include -#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h index 56cf249b77f..d1e208e21b1 100644 --- a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h @@ -68,14 +68,15 @@ class Circle_arrangment { * epsilon area of p. false: same with clockwise * \param[in] A an Arc that should contain the epsilon area */ - static bool is_open_direction_contained_in_arc(const Point p, - const bool is_counterclockwise, - const Arc A) + 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; - return !p.counterclockwise_in_between(A.first,A.second); + 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) @@ -85,18 +86,19 @@ class Circle_arrangment { * \param[in] A - an arc * \param[in] B - an *open* arc */ - static bool is_a_contained_in_b(const bool is_a_start_closed, - const bool is_a_end_closed, - const Arc A,const Arc B) + 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; - return (!A.first.counterclockwise_in_between(B.first, B.second) && - !A.second.counterclockwise_in_between(B.first, B.second) && - !A.first.counterclockwise_in_between(B.first, A.second)); + 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 @@ -161,9 +163,14 @@ class Circle_arrangment { typedef typename std::list 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 struct Circle_arrangment_edge &edge) + /*! \fn void insert_if_legal(const Circle_edge_iterator cur_it, + * const Circle_edge_iterator next_it, + * const struct 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 @@ -221,7 +228,8 @@ public: * 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 Arc first_segment_outer_circle) + Circle_arrangment(const Kernel& kernel, const Arc first_segment_outer_circle) : + m_kernel(kernel) { m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, 0, false)); @@ -281,9 +289,10 @@ public: // ?------------? = "old" arc (the edge from the array) if (is_start_contained) { if (is_end_contained) { - bool isordered = - !segment_outer_circle.second. - counterclockwise_in_between(segment_outer_circle.first, edge.second); + 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 // ?-----------------------? diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index 5bf8c20c667..81799b16bff 100644 --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -44,7 +44,8 @@ is_pullout_direction_single_mold_translational_casting_2 typename CastingTraits_2::Direction_2& d) { CastingTraits_2 traits; - return is_pullout_direction_single_mold_translational_casting_2(pgn, i, d, traits); + return is_pullout_direction_single_mold_translational_casting_2(pgn, i, d, + traits); } } /* end namesapce Set_movable_separability_2 */ diff --git a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h index 6f4fa38754e..cd2380490c9 100644 --- a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -67,8 +67,8 @@ std::pair& pgn, size_t i) { - Kernel kernel; - return top_edge_single_mold_translational_casting_2(pgn, i, kernel); + CastingTraits_2 traits; + return pullout_directions_single_mold_translational_casting_2(pgn, i, traits); } } // end of namespace Set_movable_separability_2 diff --git a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h index 4d9d56c572b..a2c3bdb9d52 100644 --- a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h @@ -116,10 +116,11 @@ top_edges_single_mold_translational_casting_2 CGAL::Orientation poly_orientation = pgn.orientation(); auto segment_outer_circle = get_segment_outer_circle(*e_it++, poly_orientation); - internal::Circle_arrangment circle_arrangment(segment_outer_circle); + internal::Circle_arrangment circle_arrangment(kernel, + segment_outer_circle); ++edge_index; - for (; e_it!= pgn.edges_end(); ++e_it, ++edge_index) { + for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { segment_outer_circle = get_segment_outer_circle(*e_it, poly_orientation); circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); @@ -141,7 +142,7 @@ top_edges_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, OutputIterator oi) { Kernel kernel; - return single_mold_translational_casting_2(pgn, oi, kernel); + return top_edges_single_mold_translational_casting_2(pgn, oi, kernel); } } // end of namespace Set_movable_separability_2 From a28c3f37b2002cbfaef9b892a59f8216802cf3cf Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 23 Nov 2016 15:58:35 +0200 Subject: [PATCH 44/90] updated --- .../test_single_mold_translational_casting.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp b/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp index 0c743db5c9f..ff332b4223a 100644 --- a/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; @@ -45,7 +45,7 @@ bool test_one_file(std::ifstream& inp) // std::cout << pgn << std::endl; std::vector top_edges; - SMS::single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); + SMS::top_edges_single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); size_t exp_num_top_edges; inp >> exp_num_top_edges; From 09bee48c4bd0220e93d02bb190bb3a9afc30cbcf Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 23 Nov 2016 16:01:19 +0200 Subject: [PATCH 45/90] updated --- .../is_pullout_direction_single_mold_translational_casting_2.h | 3 +++ .../pullout_directions_single_mold_translational_casting_2.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index 226dd236b2c..a8959abec93 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -11,6 +11,9 @@ namespace Set_movable_separability_2 { * colliding into the mold (but possibly sliding along the mold surface). It is * required that the polygon is castable this way. * + * 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 index of an edge in pgn. * \param[in] d the tested direction. diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h index 0e4829e71b3..def1d501726 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -13,6 +13,9 @@ namespace Set_movable_separability_2 { * \f$y\f$-axis. In other words, every direction in the range (if exists) must * have a positive component in the positive \f$y\f$-direction. * + * 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 index of an edge in pgn. * \return a pair of elements, where the first is a Boolean that indicates From be023a3a77e54a0dd6f8460608ae0f856ef3e9a1 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 24 Nov 2016 15:52:27 +0200 Subject: [PATCH 46/90] updated --- ...tion_single_mold_translational_casting_2.h | 55 ++++++++++++++++--- ...ions_single_mold_translational_casting_2.h | 4 +- ...dges_single_mold_translational_casting_2.h | 10 ++-- .../Set_movable_separability_2.txt | 29 ++++++---- ...tion_single_mold_translational_casting_2.h | 25 +++++++++ ...ions_single_mold_translational_casting_2.h | 7 ++- 6 files changed, 100 insertions(+), 30 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index a8959abec93..7f48473988f 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -1,15 +1,58 @@ namespace CGAL { namespace Set_movable_separability_2 { +/*! \ingroup PkgSetMovableSeparability2Funcs + * + * 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). Naturally, 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[in] pgn the input polygon. + * \param[in] d the tested direction. + * \return true if `pgn` can be pulled out in the `d` direction, when rotated + * such that the normal to the edge identified by `i` is parallel to + * the \f$y\f$-axis. + */ +template +std::pair > +is_pullout_direction_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, + typename CastingTraits_2::Direction_2& d); + +/*! \ingroup PkgSetMovableSeparability2Funcs + * + * Same as above with the additional traits argument. + * \param[in] pgn the input polygon. + * \param[in] d the tested direction. + * \param[in] traits the traits to use. + * \return true if `pgn` can be pulled out in the `d` direction, when rotated + * such that the normal to the edge identified by `i` is parallel to + * the \f$y\f$-axis. + * \pre pgn is castable and the edge identified by `i` is a top edge. + */ +template +std::pair > +is_pullout_direction_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, + typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits); + /*! \ingroup PkgSetMovableSeparability2Funcs * * 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 rotated, such that the normal to the given edge is - * parallel to the \f$y\f$-axis, can be used so that 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). It is - * required that the polygon is castable this way. + * 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 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`. @@ -20,7 +63,6 @@ namespace Set_movable_separability_2 { * \return true if `pgn` can be pulled out in the `d` direction, when rotated * such that the normal to the edge identified by `i` is parallel to * the \f$y\f$-axis. - * \pre pgn is castable and the edge identified by `i` is a top edge. */ template std::pair std::paircastable this way, the function computes the closed range of - * pullout directions asuming that the the top edge normal is parallel to the - * \f$y\f$-axis. In other words, every direction in the range (if exists) must - * have a positive component in the positive \f$y\f$-direction. + * pullout directions. * * The type that substitutes the template parameter `%CastingTraits_2` must be * a model of the concept `CastingTraits_2`. diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h index df46d51a009..3f77208c923 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h @@ -8,11 +8,11 @@ namespace Set_movable_separability_2 { * 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 castable, the function computes the set of top edges of - * such cavities and the corresponding closed ranges of pullout directions. - * Assuming the top edge normal is parallel to the \f$y\f$-axis, every direction - * in a range must have a positive component in the positive - * \f$y\f$-direction. Each top edge and corresponding range is added to a - * container referred to by a given output iterator. + * such cavities and the corresponding closed ranges of pullout directions. Let + * \f$n\f$ denote the normal to a top \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$ is + * larger than zero (\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`. diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index 33fab573855..e1c0fdcb161 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -47,17 +47,19 @@ 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 -`top_edges_single_mold_translational_casting_2()` that given a simple -closed polygon \f$P\f$ it determines whether a cavity (of a mold in +`top_edges_single_mold_translational_casting_2()` that, given a simple +closed polygon \f$P\f$, it 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 surface); see -\cgalFigureRef{sms_2_fig_mold} for an illustration. If the polygon is -castable, the function computes the set of top edges of such -cavities and the corresponding closed ranges of pullout directions. -Assuming the top edge normal is parallel to the \f$y\f$-axis, every -direction in a range must have a positive component in the positive -\f$y\f$-direction. +\cgalFigureRef{sms_2_fig_mold} for an illustration. The mold of a +castable polygon must be rotated before the polygon is +casted, such that one edge becomes parallel to the \f$y\f$-axis and is +located above all other edges; such an edge is referred to as a +top edge. A polygon may have up to 4 top edges. If the +polygon is castable, 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_mold,mold.png} Polygons (light grey) in their molds (darker grey) and valid pullout @@ -94,11 +96,14 @@ This package provides two additional functions, namely, 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 accepts a simple closed polygon \f$P\f$, a top edge -\f$e\f$ of the polygon \f$P\f$, and a direction \f$d\f$; it determines -whether \f$d\f$ is a pullout direction of \f$e\f$. +\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 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$. -An overload of each of the three functions above that accepts an +An overload of each of the functions above that accepts an additional traits argument is also provided by the package. */ diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index 81799b16bff..603d951167e 100644 --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -48,6 +48,31 @@ is_pullout_direction_single_mold_translational_casting_2 traits); } +/*! + */ +template +std::pair > +is_pullout_direction_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, + typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) +{ + return false; +} + +/*! + */ +template +std::pair > +is_pullout_direction_single_mold_translational_casting_2 +(const CGAL::Polygon_2& pgn, size_t i, + typename CastingTraits_2::Direction_2& d) +{ + CastingTraits_2 traits; + return is_pullout_direction_single_mold_translational_casting_2(pgn, d, traits); +} + } /* end namesapce Set_movable_separability_2 */ } /* end namesapce CGAL */ diff --git a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h index cd2380490c9..87edaa52716 100644 --- a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -30,9 +30,10 @@ namespace Set_movable_separability_2 { * 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 castable this way, the function computes the closed range of pull - * directions asuming that the the top edge normal is parallel to the - * \f$y\f$-axis. In other words, every direction in the range (if exists) must - * have a positive component in the positive \f$y\f$-direction. + * 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 index of an edge in pgn. From 166591c96e54fa2396145825193fae80866df5c1 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Wed, 30 Nov 2016 14:07:04 +0200 Subject: [PATCH 47/90] Updated --- ...tion_single_mold_translational_casting_2.h | 58 ++++++++---------- ...ions_single_mold_translational_casting_2.h | 4 +- ...dges_single_mold_translational_casting_2.h | 7 ++- .../Set_movable_separability_2.txt | 51 +++++++-------- .../fig/castable1.png | Bin 0 -> 4124 bytes .../fig/castable2.png | Bin 0 -> 4381 bytes .../Set_movable_separability_2/fig/mold.png | Bin 16164 -> 0 bytes .../fig/noncastable1.png | Bin 0 -> 4012 bytes .../fig/noncastable2.png | Bin 0 -> 2937 bytes .../fig/polygons.png | Bin 0 -> 19758 bytes ...tion_single_mold_translational_casting_2.h | 16 ++--- 11 files changed, 61 insertions(+), 75 deletions(-) create mode 100644 Set_movable_separability_2/doc/Set_movable_separability_2/fig/castable1.png create mode 100644 Set_movable_separability_2/doc/Set_movable_separability_2/fig/castable2.png delete mode 100644 Set_movable_separability_2/doc/Set_movable_separability_2/fig/mold.png create mode 100644 Set_movable_separability_2/doc/Set_movable_separability_2/fig/noncastable1.png create mode 100644 Set_movable_separability_2/doc/Set_movable_separability_2/fig/noncastable2.png create mode 100644 Set_movable_separability_2/doc/Set_movable_separability_2/fig/polygons.png diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index 7f48473988f..c50fb8a74be 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -7,22 +7,21 @@ namespace Set_movable_separability_2 { * 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). Naturally, if the polygon is not castable at all, the function - * returns `false` whatsoever. + * 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[in] pgn the input polygon. - * \param[in] d the tested direction. - * \return true if `pgn` can be pulled out in the `d` direction, when rotated - * such that the normal to the edge identified by `i` is parallel to - * the \f$y\f$-axis. + * \param[in] d the inspected direction. + * \return `true` if `pgn` can be pulled out in the `d` direction, and `false` + * otherwise. + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. */ template -std::pair > -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, typename CastingTraits_2::Direction_2& d); @@ -30,17 +29,13 @@ is_pullout_direction_single_mold_translational_casting_2 * * Same as above with the additional traits argument. * \param[in] pgn the input polygon. - * \param[in] d the tested direction. + * \param[in] d the inspected direction. * \param[in] traits the traits to use. - * \return true if `pgn` can be pulled out in the `d` direction, when rotated - * such that the normal to the edge identified by `i` is parallel to - * the \f$y\f$-axis. - * \pre pgn is castable and the edge identified by `i` is a top edge. + * \return `true` if `pgn` can be pulled out in the `d` direction, and `false` + * otherwise. */ template -std::pair > -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits); @@ -49,10 +44,11 @@ is_pullout_direction_single_mold_translational_casting_2 * 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 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`. + * 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`. @@ -60,14 +56,13 @@ is_pullout_direction_single_mold_translational_casting_2 * \param[in] pgn the input polygon. * \param[in] i the index of an edge in pgn. * \param[in] d the tested direction. - * \return true if `pgn` can be pulled out in the `d` direction, when rotated - * such that the normal to the edge identified by `i` is parallel to - * the \f$y\f$-axis. + * \return true if `pgn` can be pulled out in the `d` direction with the + * edge identified by `i` being the top edge, and `false` otherwise. + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. */ template -std::pair > -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d); @@ -78,14 +73,11 @@ is_pullout_direction_single_mold_translational_casting_2 * \param[in] i the index of an edge in pgn. * \param[in] d the tested direction. * \param[in] traits the traits to use. - * \return true if `pgn` can be pulled out in the `d` direction, when rotated - * such that the normal to the edge identified by `i` is parallel to - * the \f$y\f$-axis. + * \return true if `pgn` can be pulled out in the `d` direction, with the + * edge identified by `i` being the top edge, and `false` otherwise. */ template -std::pair > -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits); diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h index cb2a9158e4b..8b7a5b20348 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -5,8 +5,8 @@ namespace Set_movable_separability_2 { * * 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 + * 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 castable this way, the function computes the closed range of * pullout directions. diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h index 3f77208c923..76061ce0ee5 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h @@ -10,9 +10,10 @@ namespace Set_movable_separability_2 { * polygon is castable, 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 \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$ is - * larger than zero (\f$n \cdot d > 0\f$). Each top edge and corresponding range - * is added to a container referred to by a given output iterator. + * 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`. diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index e1c0fdcb161..aac33597aad 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -13,20 +13,20 @@ namespace CGAL { 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. The moving sofa problem or sofa -problem (see Moving sofa -problem 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. +problem or sofa problem 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. @@ -52,18 +52,19 @@ closed polygon \f$P\f$, it 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 surface); see -\cgalFigureRef{sms_2_fig_mold} for an illustration. The mold of a -castable polygon must be rotated before the polygon is -casted, such that one edge becomes parallel to the \f$y\f$-axis and is -located above all other edges; such an edge is referred to as a -top edge. A polygon may have up to 4 top edges. If the -polygon is castable, the function computes the set of top -edges of such cavities and the corresponding closed ranges of pullout -directions in the plane. +\cgalFigureRef{sms_2_fig_polygons} for an illustration. In reality, +the mold of a castable polygon must be rotated before the +polygon is casted, such that one edge becomes parallel to the +\f$y\f$-axis and is located above all other edges; such an edge is +referred to as a top edge. A polygon may have up to 4 top +edges. If the polygon is castable, 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_mold,mold.png} -Polygons (light grey) in their molds (darker grey) and valid pullout -directions. +\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 @@ -99,7 +100,7 @@ the polygon \f$P\f$; it determines whether \f$e\f$ is a top edge 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 of some top edge -of \f$P\f$. The other version accepts in addition an edge \f$e\f$ of +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$. diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/fig/castable1.png b/Set_movable_separability_2/doc/Set_movable_separability_2/fig/castable1.png new file mode 100644 index 0000000000000000000000000000000000000000..c5385a0d4b8ea224757e1dd308a15d6af3e62ad3 GIT binary patch literal 4124 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 diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/fig/noncastable1.png b/Set_movable_separability_2/doc/Set_movable_separability_2/fig/noncastable1.png new file mode 100644 index 0000000000000000000000000000000000000000..eecc0c1bd1116ce5647c08085f3edf36018238a7 GIT binary patch literal 4012 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 literal 0 HcmV?d00001 diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index 603d951167e..4b8acc64e49 100644 --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -25,9 +25,7 @@ namespace Set_movable_separability_2 { /*! */ template -std::pair > -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) { @@ -37,9 +35,7 @@ is_pullout_direction_single_mold_translational_casting_2 /*! */ template -std::pair > -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d) { @@ -51,9 +47,7 @@ is_pullout_direction_single_mold_translational_casting_2 /*! */ template -std::pair > -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) { @@ -63,9 +57,7 @@ is_pullout_direction_single_mold_translational_casting_2 /*! */ template -std::pair > -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d) { From 5206aa9973eefb2397a8dc782d3523404db22943 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Tue, 13 Dec 2016 11:19:20 +0200 Subject: [PATCH 48/90] casting_2: completed is_pullout_direction_single_mold_translational_casting_2. --- ...tion_single_mold_translational_casting_2.h | 108 ++++++++++++++++-- 1 file changed, 100 insertions(+), 8 deletions(-) diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index 4b8acc64e49..aa43ee09ecb 100644 --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -17,25 +17,70 @@ #ifndef CGAL_IS_PULLOUT_DIRECTION_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H #define CGAL_IS_PULLOUT_DIRECTION_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H - +#include +#include +#include namespace CGAL { namespace Set_movable_separability_2 { -/*! +/*! 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] i the index of an edge in 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 -bool is_pullout_direction_single_mold_translational_casting_2 +bool +is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) { - return false; + //NOT CHECKED AT ALL + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!is_any_edge_colinear(pgn)); + + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + get_segment_outer_circle(*e_it++, poly_orientation); + + ++edge_index; + auto cc_in_between = traits.counterclockwise_in_between_2_object(); + + for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { + segment_outer_circle = + get_segment_outer_circle(*e_it, poly_orientation); + bool isordered = !cc_in_between(segment_outer_circle.second, + d, + segment_outer_circle.first); + if (isordered == (edge_index==i)) + { + return false; + } + } + + return true; } /*! */ template -bool is_pullout_direction_single_mold_translational_casting_2 +bool +is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d) { @@ -44,14 +89,61 @@ bool is_pullout_direction_single_mold_translational_casting_2 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 pair + * + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. */ +#define MAX_SIZE_T (std::numeric_limits::max()) template -bool is_pullout_direction_single_mold_translational_casting_2 +std::pair +is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) { - return false; + + //NOT CHECKED AT ALL + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!is_any_edge_colinear(pgn)); + + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + get_segment_outer_circle(*e_it++, poly_orientation); + ++edge_index; + auto cc_in_between = traits.counterclockwise_in_between_2_object(); + size_t top_edge= MAX_SIZE_T; + for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { + segment_outer_circle = + get_segment_outer_circle(*e_it, poly_orientation); + bool isordered = !cc_in_between(segment_outer_circle.second, + d, + segment_outer_circle.first); + if (!isordered) //unlikely - this if must be true atleast once for any polygon - add ref to paper + { + if(top_edge==MAX_SIZE_T) + { + top_edge= edge_index; + } + else + return std::make_pair(false, MAX_SIZE_T); + } + } + CGAL_postcondition(top_edge!=MAX_SIZE_T); + return std::make_pair(true, top_edge); } /*! From 9f4d8ef91190c7d3dbdb7c5ddf4d2703bf123412 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Tue, 13 Dec 2016 12:30:39 +0200 Subject: [PATCH 49/90] wrote is_pullout_direction_single_mold_translational_casting_2 - need to be tested --- .../is_pullout_direction_single_mold_translational_casting_2.h | 2 +- .../pullout_directions_single_mold_translational_casting_2.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index aa43ee09ecb..28297d0c617 100644 --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -103,7 +103,7 @@ is_pullout_direction_single_mold_translational_casting_2 * \param[in] d the pullout direction * \return pair * - * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * \pre `png` must be non-degenerate (has at least 3 vertices),simple, and * does not have three consecutive collinear vertices. */ #define MAX_SIZE_T (std::numeric_limits::max()) diff --git a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h index 87edaa52716..2effe20f58d 100644 --- a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -50,10 +50,11 @@ template std::pair > pullout_directions_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, Kernel& kernel) +(const CGAL::Polygon_2& pgn, size_t i, CastingTraits_2& traits) { typedef CastingTraits_2 Casting_traits_2; typename Casting_traits_2::Direction_2 d1, d2; + return std::make_pair(false, std::make_pair(d1, d2)); } From 9f240310d8ecf8cc0a40249f3dd9c3190d20340c Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 13 Dec 2016 17:48:42 +0200 Subject: [PATCH 50/90] Fixed concept---added direction. Added orientation parameter. --- ...tion_single_mold_translational_casting_2.h | 52 ++++++++++++++----- ...ions_single_mold_translational_casting_2.h | 22 ++++++-- ...dges_single_mold_translational_casting_2.h | 20 +++++-- .../Concepts/CastingTraits_2.h | 6 ++- 4 files changed, 79 insertions(+), 21 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index c50fb8a74be..bf8e02eb26d 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -15,29 +15,44 @@ namespace Set_movable_separability_2 { * * \param[in] pgn the input polygon. * \param[in] d the inspected direction. - * \return `true` if `pgn` can be pulled out in the `d` direction, and `false` - * otherwise. + * \param[in] traits the traits to use. + * \return a pair of elements, where the first is a Boolean that indicates + * whether `pgn` can be pulled out in the `d` direction, and the + * second is the index of the corresponding top edge in `pgn`. * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and * does not have three consecutive collinear vertices. */ template -bool is_pullout_direction_single_mold_translational_casting_2 +std::pair +is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, - typename CastingTraits_2::Direction_2& d); + typename CastingTraits_2::Direction_2& d, + const CastingTraits_2& traits = CastingTraits_2()); /*! \ingroup PkgSetMovableSeparability2Funcs * - * Same as above with the additional traits argument. + * 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[in] pgn the input polygon. * \param[in] d the inspected direction. + * \param[in] orientation the orientation of `pgn`. * \param[in] traits the traits to use. - * \return `true` if `pgn` can be pulled out in the `d` direction, and `false` - * otherwise. + * \return a pair of elements, where the first is a Boolean that indicates + * whether `pgn` can be pulled out in the `d` direction, and the + * second is the index of the corresponding top edge in `pgn`. + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. */ template -bool is_pullout_direction_single_mold_translational_casting_2 +std::pair +is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, - typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits); + typename CastingTraits_2::Direction_2& d, + CGAL::Orientation orientation, + const CastingTraits_2& traits = CastingTraits_2()); /*! \ingroup PkgSetMovableSeparability2Funcs * @@ -56,6 +71,7 @@ bool is_pullout_direction_single_mold_translational_casting_2 * \param[in] pgn the input polygon. * \param[in] i the index of an edge in pgn. * \param[in] d the tested direction. + * \param[in] traits the traits to use. * \return true if `pgn` can be pulled out in the `d` direction with the * edge identified by `i` being the top edge, and `false` otherwise. * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and @@ -64,22 +80,32 @@ bool is_pullout_direction_single_mold_translational_casting_2 template bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, - typename CastingTraits_2::Direction_2& d); + typename CastingTraits_2::Direction_2& d, + const CastingTraits_2& traits = CastingTraits_2()); /*! \ingroup PkgSetMovableSeparability2Funcs * - * Same as above with the additional traits argument. + * 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[in] pgn the input polygon. * \param[in] i the index of an edge in pgn. * \param[in] d the tested direction. + * \param[in] orientation the orientation of `pgn`. * \param[in] traits the traits to use. - * \return true if `pgn` can be pulled out in the `d` direction, with the + * \return true if `pgn` can be pulled out in the `d` direction with the * edge identified by `i` being the top edge, and `false` otherwise. + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. */ template bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, - typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits); + typename CastingTraits_2::Direction_2& d, + CGAL::Orientation orientation, + const CastingTraits_2& traits = CastingTraits_2()); } /* end namesapce Set_movable_separability_2 */ } /* end namesapce CGAL */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h index 8b7a5b20348..2a565a92825 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -16,6 +16,7 @@ namespace Set_movable_separability_2 { * * \param[in] pgn the input polygon. * \param[in] i the index of an edge in pgn. + * \param[in] 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 @@ -29,21 +30,36 @@ template std::pair > pullout_directions_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i); +(const CGAL::Polygon_2& pgn, size_t i, + CastingTraits_2& traits = CastingTraits_2()); /*! \ingroup PkgSetMovableSeparability2Funcs * - * Same as above with the additional traits argument. + * 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[in] pgn the input polygon. * \param[in] i the index of an edge in pgn. + * \param[in] orientation the orientation of `pgn`. * \param[in] 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 `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. */ template std::pair > pullout_directions_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, - CastingTraits_2& traits); + CGAL::Orientation orientation, + CastingTraits_2& traits = CastingTraits_2()); } /* end namesapce Set_movable_separability_2 */ } /* end namesapce CGAL */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h index 76061ce0ee5..dbd86f03224 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h @@ -26,6 +26,7 @@ namespace Set_movable_separability_2 { * (ii) the second element is a closed range of pullout directions * represented as a pair of the extreme directions in the * range of type `Kernel::Direction_2`. + * \param[in] traits the traits to use. * \return the past-the-end iterator of the output container. * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and * does not have three consecutive collinear vertices. @@ -33,11 +34,19 @@ namespace Set_movable_separability_2 { template OutputIterator top_edges_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, OutputIterator oi); +(const CGAL::Polygon_2& pgn, OutputIterator oi, + CastingTraits_2& traits = CastingTraits_2()); + +} /* end namesapce Set_movable_separability_2 */ +} /* end namesapce CGAL */ /*! \ingroup PkgSetMovableSeparability2Funcs * - * Same as above with the additional traits argument. + * 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[in] pgn the input polygon. * \param[out] oi the output iterator. Its value type is a pair, where * (i) the first element in the pair identifies a valid top edge @@ -46,13 +55,18 @@ top_edges_single_mold_translational_casting_2 * (ii) the second element is a closed range of pullout directions * represented as a pair of the extreme directions in the * range of type `Kernel::Direction_2`. + * \param[in] orientation the orientation of `pgn`. * \param[in] traits the traits to use. + * \return the past-the-end iterator of the output container. + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. */ template OutputIterator top_edges_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, OutputIterator oi, - CastingTraits_2& traits); + CGAL::Orientation orientation, + CastingTraits_2& traits = CastingTraits_2()); } /* end namesapce Set_movable_separability_2 */ } /* end namesapce CGAL */ diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h index 85790d250ad..a50ecaed2ca 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h @@ -20,8 +20,10 @@ public: /// \name Functor Types /// @{ - /*! models the concept `Kernel::Counterclockwise_in_between_2`. - */ + //! The direction type. + typedef unspecified_type Direction_2; + + //! models the concept `Kernel::Counterclockwise_in_between_2`. typedef unspecified_type Counterclockwise_in_between_2; /// @} From f04c83fb1568ac3cd2cb78f559daf9761dda9774 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Wed, 18 Jan 2017 12:33:33 +0200 Subject: [PATCH 51/90] casting_2: added pullout_direction_single_mold_translation --- .../single_mold_translational_casting.cpp | 77 +- .../Set_movable_separability_2/star.dat | 2 + .../Set_movable_separability_2/trapezoid.dat | 2 + .../Set_movable_separability_2/triangle.dat | 2 + .../Circle_arrangment.h | 702 +++++++++--------- .../CGAL/Set_movable_separability_2/Utils.h | 70 ++ ...tion_single_mold_translational_casting_2.h | 115 +-- ...ions_single_mold_translational_casting_2.h | 212 ++++-- ...dges_single_mold_translational_casting_2.h | 180 ++--- ...t_directions_single_mold_translational.cpp | 128 ++++ 10 files changed, 911 insertions(+), 579 deletions(-) create mode 100644 Set_movable_separability_2/examples/Set_movable_separability_2/star.dat create mode 100644 Set_movable_separability_2/examples/Set_movable_separability_2/trapezoid.dat create mode 100644 Set_movable_separability_2/examples/Set_movable_separability_2/triangle.dat create mode 100644 Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h mode change 100644 => 100755 Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h mode change 100644 => 100755 Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h mode change 100644 => 100755 Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h create mode 100644 Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp index 3fb52cebfcf..4eda2901905 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp @@ -4,10 +4,14 @@ #include #include #include +#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; typedef Kernel::Direction_2 Direction_2; +typedef Kernel::Vector_2 Vector_2; +typedef Kernel::Point_2 Point_2; typedef std::pair Direction_range; typedef std::pair Top_edge; @@ -21,27 +25,78 @@ int main(int argc, char* argv[]) 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; + std::cerr << "Failed to open the " << filename << std::endl; + return -1; } input_file >> pgn; input_file.close(); auto poly_orientation = pgn.orientation(); std::list top_edges; - SMS::top_edges_single_mold_translational_casting_2 - (pgn, std::back_inserter(top_edges)); + + //example for top_edges_single_mold_translational_casting_2 + SMS::top_edges_single_mold_translational_casting_2 + (pgn, 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 << "Edge number: " << top_edge.first << std::endl - << "\tEdge: "<< pgn.edge(top_edge.first) << std::endl - << "\tPullout directions from: "<< top_edge.second.first - << " to " << top_edge.second.second - << std::endl<< std::endl; + std::cout << "There are " << top_edges.size() << " top edges:" << std::endl; + for (const auto& top_edge : top_edges) { + std::cout << "Edge number: " << top_edge.first << std::endl + << "\tEdge: "<< pgn.edge(top_edge.first) << std::endl + << "\tPullout directions from: "<< top_edge.second.first + << " to " << top_edge.second.second + << std::endl<< std::endl; + } + } + std::cout << "-----------------------------------"<< std::endl; + + //example for pullout_directions_single_mold_translational_casting_2 + int index =0; + for (auto e_it = pgn.edges_begin(); e_it != pgn.edges_end(); ++e_it, ++index) + + { + + std::pair > res = SMS::pullout_directions_single_mold_translational_casting_2(pgn,e_it); + if (res.first) + { + std::cout << "The polygon is castable using edge "<(*e_it, poly_orientation); + Direction_2 d = segment_outer_circle.first; + d= d.perpendicular(CGAL::CLOCKWISE); + bool res = SMS::is_pullout_direction_single_mold_translational_casting_2(pgn,e_it,d); + std::cout << "The polygon is "<<(res?"":"not ") <<"castable using edge "< + res = SMS::is_pullout_direction_single_mold_translational_casting_2(pgn,d); + if (res.first) + { + std::cout << "The polygon is castable in direction d ("< -class Circle_arrangment { - typedef typename Kernel::Direction_2 Point; - typedef std::pair Arc; + template + class Circle_arrangment { + typedef typename Kernel::Direction_2 Point; + typedef std::pair Arc; - /* 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) - */ + /* 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_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)); - } + /*! \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; + /*! \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 + 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+) + uint8_t m_count; // no. of outer circles that cover the edge (0/1/2+) - size_t m_edge_index; // the index of the polygon edge the open - // half-circle of which covers this cell. - // only relevant if m_count ==1 + size_t m_edge_index; // the index 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, size_t edge_index, 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_index the index 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 size_t edge_index, - 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_index = edge_index; - } + /*! \ctor Circle_arrangment_edge(point edge_start_angle, size_t edge_index, 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_index the index 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 size_t edge_index, + 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_index = edge_index; + } - /*! \fn void plusplus(size_t edge_index) - * Adds new polygon edge who's open half-circle covers this cell - * \param[in] edge_index - the index 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 size_t edge_index) - { - if (this->m_count ==0) { - this->m_edge_index = edge_index; - this->m_count = 1; - } - else if(this->m_count ==1) this->m_count = 2; - } - bool is_covered() { return m_count == 2; } - }; + /*! \fn void plusplus(size_t edge_index) + * Adds new polygon edge who's open half-circle covers this cell + * \param[in] edge_index - the index 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 size_t edge_index) + { + if (this->m_count ==0) { + this->m_edge_index = edge_index; + 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_edges; + typedef typename std::list Circle_edges; - //! The kernel to use. - const Kernel& m_kernel; + //! The kernel to use. + const Kernel& m_kernel; - Circle_edges m_edges; + Circle_edges m_edges; - /*! \fn void insert_if_legal(const Circle_edge_iterator cur_it, - * const Circle_edge_iterator next_it, - * const struct 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 - void insert_if_legal(const InputIterator cur_it, - InputIterator next_it, - const struct 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 insert_if_legal(const Circle_edge_iterator cur_it, + * const Circle_edge_iterator next_it, + * const struct 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 + void insert_if_legal(const InputIterator cur_it, + InputIterator next_it, + const struct 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; - } - } + /*! \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) : - m_kernel(kernel) - { - m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, - 0, false)); - m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, - 0, true, false)); - } - - /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) - * 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_index this segment id - * 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 size_t edge_index) - { - 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)) + 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) : + m_kernel(kernel) { - it->plusplus(edge_index); - continue; + m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.first, + 0, false)); + m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, + 0, true, false)); } - 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-----? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = false; - edge2.m_edge_start_angle = segment_outer_circle.first; - edge2.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - struct 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-~-? - struct 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); - struct Circle_arrangment_edge edge3 = *it; - edge3.m_start_is_closed = false; - edge3.m_edge_start_angle = segment_outer_circle.first; - edge3.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge3); - it->plusplus(edge_index); - } - } - else { - // o~~~~~~~~~~~~o - // ?-----------? - //_____________________ - // ?----c - // o-~-~-~? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = false; - edge2.m_edge_start_angle = segment_outer_circle.first; - edge2.plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - } - } - else { - if (is_end_contained) { - // o~~~~~~~~~~~~o - // ?------------? - //_____________________ - // ?-~-~-~-o - // c----? - struct Circle_arrangment_edge edge2 = *it; - edge2.m_start_is_closed = true; - edge2.m_edge_start_angle = segment_outer_circle.second; - it->plusplus(edge_index); - this->insert_if_legal(it, next_it, edge2); - } - //else - no intersection, do noting - } - } - merge_adjacent_2_edges_and_remove_empty(); - } + + /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) + * 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_index this segment id + * 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 size_t edge_index) + { + 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_index); + 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-----? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = false; + edge2.m_edge_start_angle = segment_outer_circle.first; + edge2.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + struct 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-~-? + struct 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); + struct Circle_arrangment_edge edge3 = *it; + edge3.m_start_is_closed = false; + edge3.m_edge_start_angle = segment_outer_circle.first; + edge3.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge3); + it->plusplus(edge_index); + } + } + else { + // o~~~~~~~~~~~~o + // ?-----------? + //_____________________ + // ?----c + // o-~-~-~? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = false; + edge2.m_edge_start_angle = segment_outer_circle.first; + edge2.plusplus(edge_index); + this->insert_if_legal(it, next_it, edge2); + } + } + else { + if (is_end_contained) { + // o~~~~~~~~~~~~o + // ?------------? + //_____________________ + // ?-~-~-~-o + // c----? + struct Circle_arrangment_edge edge2 = *it; + edge2.m_start_is_closed = true; + edge2.m_edge_start_angle = segment_outer_circle.second; + it->plusplus(edge_index); + 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"; - } + // 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 > foreach valid top edge. - * Should only be called after all of the polygon edges where inserted. - */ - template - 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; - edge.first = (*it).m_edge_index; - 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 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 > foreach valid top edge. + * Should only be called after all of the polygon edges where inserted. + */ + template + 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; + edge.first = (*it).m_edge_index; + 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; } -}; + /*! \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; } + }; -} // end of namespace internal -} // end of namespace Set_movable_separability_2 + } // end of namespace internal + } // end of namespace Set_movable_separability_2 } // end of namespace CGAL #endif diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h new file mode 100644 index 00000000000..f1323435ec6 --- /dev/null +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h @@ -0,0 +1,70 @@ +/* + * utils.h + * + * Created on: Jan 17, 2017 + * Author: root + */ + +#ifndef SET_MOVABLE_SEPARABILITY_2_INCLUDE_CGAL_SET_MOVABLE_SEPARABILITY_2_UTILS_H_ +#define SET_MOVABLE_SEPARABILITY_2_INCLUDE_CGAL_SET_MOVABLE_SEPARABILITY_2_UTILS_H_ +#include +#include + + +namespace CGAL { +namespace Set_movable_separability_2 { +namespace internal { + +/*! \fn std::pair 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 +inline std::pair +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::Orientation::CLOCKWISE) ? + std::make_pair(backward, forward) : std::make_pair(forward, backward); +} + +template +bool is_any_edge_colinear(const CGAL::Polygon_2& pgn) +{ + typedef typename CGAL::Point_2 Point_2; + typedef typename CGAL::Polygon_2 Polygon_2; + typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; + 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 (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + } + vci = pgn.vertices_begin(); + firstVar = secondVar; + secondVar = thirdVar; + thirdVar = *(vci++); + if(CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + + firstVar = secondVar; + secondVar = thirdVar; + thirdVar = *(vci++); + if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + + return false; +} +} // end of namespace internal +} // end of namespace Set_movable_separability_2 +} // end of namespace CGAL + + + +#endif /* SET_MOVABLE_SEPARABILITY_2_INCLUDE_CGAL_SET_MOVABLE_SEPARABILITY_2_UTILS_H_ */ diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h old mode 100644 new mode 100755 index 28297d0c617..49f86e14871 --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -20,6 +20,7 @@ #include #include #include + namespace CGAL { namespace Set_movable_separability_2 { @@ -43,35 +44,34 @@ namespace Set_movable_separability_2 { * does not have three consecutive collinear vertices. */ template -bool -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) { - //NOT CHECKED AT ALL - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!is_any_edge_colinear(pgn)); + //NOT CHECKED AT ALL + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!is_any_edge_colinear(pgn)); - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + get_segment_outer_circle(*e_it++, poly_orientation); - ++edge_index; - auto cc_in_between = traits.counterclockwise_in_between_2_object(); + ++edge_index; + auto cc_in_between = traits.counterclockwise_in_between_2_object(); - for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - bool isordered = !cc_in_between(segment_outer_circle.second, - d, - segment_outer_circle.first); - if (isordered == (edge_index==i)) - { - return false; - } - } + for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { + segment_outer_circle = + get_segment_outer_circle(*e_it, poly_orientation); + bool isordered = !cc_in_between(segment_outer_circle.second, + d, + segment_outer_circle.first); + if (isordered == (edge_index==i)) + { + return false; + } + } return true; } @@ -79,8 +79,7 @@ is_pullout_direction_single_mold_translational_casting_2 /*! */ template -bool -is_pullout_direction_single_mold_translational_casting_2 +bool is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d) { @@ -101,55 +100,57 @@ is_pullout_direction_single_mold_translational_casting_2 * * \param[in] pgn the input polygon. * \param[in] d the pullout direction - * \return pair + * \return pair * * \pre `png` must be non-degenerate (has at least 3 vertices),simple, and * does not have three consecutive collinear vertices. */ #define MAX_SIZE_T (std::numeric_limits::max()) + template -std::pair +std::pair is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) { + //NOT CHECKED AT ALL + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!is_any_edge_colinear(pgn)); - //NOT CHECKED AT ALL - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!is_any_edge_colinear(pgn)); - - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); - ++edge_index; - auto cc_in_between = traits.counterclockwise_in_between_2_object(); - size_t top_edge= MAX_SIZE_T; - for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - bool isordered = !cc_in_between(segment_outer_circle.second, - d, - segment_outer_circle.first); - if (!isordered) //unlikely - this if must be true atleast once for any polygon - add ref to paper - { - if(top_edge==MAX_SIZE_T) - { - top_edge= edge_index; - } - else - return std::make_pair(false, MAX_SIZE_T); - } - } - CGAL_postcondition(top_edge!=MAX_SIZE_T); + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + get_segment_outer_circle(*e_it++, poly_orientation); + ++edge_index; + auto cc_in_between = traits.counterclockwise_in_between_2_object(); + size_t top_edge= MAX_SIZE_T; + for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { + segment_outer_circle = + get_segment_outer_circle(*e_it, poly_orientation); + bool isordered = !cc_in_between(segment_outer_circle.second, + d, + segment_outer_circle.first); + if (!isordered) //unlikely - this if must be true atleast once for any polygon - add ref to paper + { + if(top_edge==MAX_SIZE_T) + { + top_edge= edge_index; + } + else + return std::make_pair(false, MAX_SIZE_T); + } + } + CGAL_postcondition(top_edge!=MAX_SIZE_T); return std::make_pair(true, top_edge); } /*! */ template -bool is_pullout_direction_single_mold_translational_casting_2 +std::pair +is_pullout_direction_single_mold_translational_casting_2 (const CGAL::Polygon_2& pgn, size_t i, typename CastingTraits_2::Direction_2& d) { diff --git a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h old mode 100644 new mode 100755 index 2effe20f58d..d70c1636e10 --- a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -22,58 +22,174 @@ namespace CGAL { -namespace Set_movable_separability_2 { + namespace Set_movable_separability_2 { -/*! 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 castable 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 index 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. - * - * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and - * does not have three consecutive collinear vertices. - */ -template -std::pair > -pullout_directions_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, CastingTraits_2& traits) -{ - typedef CastingTraits_2 Casting_traits_2; - typename Casting_traits_2::Direction_2 d1, d2; - return std::make_pair(false, std::make_pair(d1, d2)); -} + /*! 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 + std::pair > + pullout_directions_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, const typename CGAL::Polygon_2::Edge_const_iterator& i, CastingTraits_2& traits) + { + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!internal::is_any_edge_colinear(pgn)); + CGAL_precondition(pgn.size()>i); + CGAL::Orientation poly_orientation = pgn.orientation(); -template -std::pair > -/*! Same as above with the additional traits argument. - * \param[in] pgn the input polygon. - * \param[in] i the index of an edge in pgn. - * \param[in] traits the traits to use. - */ -pullout_directions_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i) -{ - CastingTraits_2 traits; - return pullout_directions_single_mold_translational_casting_2(pgn, i, traits); -} + typedef CastingTraits_2 Casting_traits_2; + typename Casting_traits_2::Direction_2 clockFirst, clockSecond; //the returned range is [clockFirst,clockSecond] -} // end of namespace Set_movable_separability_2 + + auto segment_outer_circle = + internal::get_segment_outer_circle(*i, poly_orientation); + clockFirst=segment_outer_circle.first; + clockSecond=segment_outer_circle.second; + //well theoretically, this is a bug since the current intersection is currently (clockFirst,clockSecond) + //and not [clockFirst,clockSecond].. but this edges will surly change since we are in a polygon + + bool isRangeSmallerThanSemicircle=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 "<(*e_it, poly_orientation); + // std::cout<<"a "<castable 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 index 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 + std::pair > + pullout_directions_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, + + const typename CGAL::Polygon_2::Edge_const_iterator& i) + { + + CastingTraits_2 traits; + return pullout_directions_single_mold_translational_casting_2(pgn, i, traits); + } + + + + } // end of namespace Set_movable_separability_2 } // end of namespace CGAL #endif diff --git a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h old mode 100644 new mode 100755 index a2c3bdb9d52..7e95756cf15 --- a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h @@ -25,127 +25,83 @@ #include #include "Set_movable_separability_2/Circle_arrangment.h" +#include "Set_movable_separability_2/Utils.h" namespace CGAL { -namespace Set_movable_separability_2 { + namespace Set_movable_separability_2 { -/* 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. - */ + /* 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. + */ -/*! \fn std::pair 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 -inline std::pair -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::Orientation::CLOCKWISE) ? - std::make_pair(backward, forward) : std::make_pair(forward, backward); -} + /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) + * \param[in] pgn the input polygon that we want to check if is castable or not. + * \param[in,out] oi the output iterator to put the top edges in + * \param[in] kernel the kernel 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 + OutputIterator + top_edges_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, OutputIterator oi, Kernel& kernel) + { + /* 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) + */ + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!internal::is_any_edge_colinear(pgn)); -template -bool is_any_edge_colinear(const CGAL::Polygon_2& pgn) -{ - typedef typename CGAL::Point_2 Point_2; - typedef typename CGAL::Polygon_2 Polygon_2; - typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; - 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 (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; - } - vci = pgn.vertices_begin(); - firstVar = secondVar; - secondVar = thirdVar; - thirdVar = *(vci++); - if(CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + auto e_it = pgn.edges_begin(); + size_t edge_index = 0; + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + internal::get_segment_outer_circle(*e_it++, poly_orientation); + internal::Circle_arrangment circle_arrangment(kernel, + segment_outer_circle); - firstVar = secondVar; - secondVar = thirdVar; - thirdVar = *(vci++); - if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + ++edge_index; + for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { + segment_outer_circle = + internal::get_segment_outer_circle(*e_it, poly_orientation); + circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); + if (circle_arrangment.all_is_covered_twice()) return oi; + } + circle_arrangment.get_all_1_edges(oi); + return oi; + } - return false; -} + /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) + * \param[in] pgn the input polygon that we want to check if is castable or not. + * \param[in,out] 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 + OutputIterator + top_edges_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, OutputIterator oi) + { + Kernel kernel; + return top_edges_single_mold_translational_casting_2(pgn, oi, kernel); + } -/*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) - * \param[in] pgn the input polygon that we want to check if is castable or not. - * \param[in,out] oi the output iterator to put the top edges in - * \param[in] kernel the kernel to use. - * \return all the possible top edges of the polygon and there pullout direction - * (with no rotation) - */ -template -OutputIterator -top_edges_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, OutputIterator oi, Kernel& kernel) -{ - /* 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) - */ - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!is_any_edge_colinear(pgn)); - - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); - internal::Circle_arrangment circle_arrangment(kernel, - segment_outer_circle); - - ++edge_index; - for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); - if (circle_arrangment.all_is_covered_twice()) return oi; - } - circle_arrangment.get_all_1_edges(oi); - return oi; -} - -/*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) - * \param[in] pgn the input polygon that we want to check if is castable or not. - * \param[in,out] oi the output iterator to put the top edges in - * \return all the possible top edges of the polygon and there pullout direction - * (with no rotation) - */ -template -OutputIterator -top_edges_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, OutputIterator oi) -{ - Kernel kernel; - return top_edges_single_mold_translational_casting_2(pgn, oi, kernel); -} - -} // end of namespace Set_movable_separability_2 + } // end of namespace Set_movable_separability_2 } // end of namespace CGAL #endif diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp new file mode 100644 index 00000000000..ff332b4223a --- /dev/null +++ b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp @@ -0,0 +1,128 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef CGAL::Polygon_2 Polygon_2; +typedef Kernel::Direction_2 Direction_2; +typedef Kernel::Point_2 Point_2; + +typedef std::pair Direction_range; +typedef std::pair Top_edge; + +namespace SMS = CGAL::Set_movable_separability_2; + +struct Top_edge_comparer { + bool operator()(const Top_edge& a, const Top_edge& b) + { + auto facet_a = a.first; + const auto& d1_a = a.second.first; + const auto& d2_a = a.second.second; + auto facet_b = b.first; + const auto& d1_b = b.second.first; + const auto& d2_b = b.second.second; + + 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_edges; + SMS::top_edges_single_mold_translational_casting_2(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 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; + top_edge = std::make_pair(facet, 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; + const auto& d1 = it->second.first; + const auto& d2 = it->second.second; + auto exp_facet = exp_it->first; + const auto& exp_d1 = exp_it->second.first; + const auto& exp_d2 = exp_it->second.second; + if ((facet != exp_facet) || (d1 != exp_d1) || (d2 != exp_d2)) { + std::cerr << "Top edge[" << i++ << "]: " + << "obtained: " << facet << " " << d1 << " " << d2 + << ", expected: " << exp_facet << " " << 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 < 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; +} From fd28a5b2e1fce44b719427e57531e71b85d113d4 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Wed, 18 Jan 2017 12:34:59 +0200 Subject: [PATCH 52/90] Casting_2: fix Intend in Utils.h --- .../CGAL/Set_movable_separability_2/Utils.h | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) mode change 100644 => 100755 Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h old mode 100644 new mode 100755 index f1323435ec6..4e6db070964 --- a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h @@ -12,57 +12,57 @@ namespace CGAL { -namespace Set_movable_separability_2 { -namespace internal { + namespace Set_movable_separability_2 { + namespace internal { -/*! \fn std::pair 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 -inline std::pair -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::Orientation::CLOCKWISE) ? - std::make_pair(backward, forward) : std::make_pair(forward, backward); -} + /*! \fn std::pair 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 + inline std::pair + 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::Orientation::CLOCKWISE) ? + std::make_pair(backward, forward) : std::make_pair(forward, backward); + } -template -bool is_any_edge_colinear(const CGAL::Polygon_2& pgn) -{ - typedef typename CGAL::Point_2 Point_2; - typedef typename CGAL::Polygon_2 Polygon_2; - typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; - 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 (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; - } - vci = pgn.vertices_begin(); - firstVar = secondVar; - secondVar = thirdVar; - thirdVar = *(vci++); - if(CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + template + bool is_any_edge_colinear(const CGAL::Polygon_2& pgn) + { + typedef typename CGAL::Point_2 Point_2; + typedef typename CGAL::Polygon_2 Polygon_2; + typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; + 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 (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + } + vci = pgn.vertices_begin(); + firstVar = secondVar; + secondVar = thirdVar; + thirdVar = *(vci++); + if(CGAL::collinear(firstVar, secondVar, thirdVar)) return true; - firstVar = secondVar; - secondVar = thirdVar; - thirdVar = *(vci++); - if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; + firstVar = secondVar; + secondVar = thirdVar; + thirdVar = *(vci++); + if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; - return false; -} -} // end of namespace internal -} // end of namespace Set_movable_separability_2 + return false; + } + } // end of namespace internal + } // end of namespace Set_movable_separability_2 } // end of namespace CGAL From 5582a8e1ec558cafa9f30ee470b258b50438d216 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Wed, 18 Jan 2017 22:57:16 +0200 Subject: [PATCH 53/90] Casting_2: fixed print bug in example --- .../single_mold_translational_casting.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp index 4eda2901905..3efb164197e 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp @@ -72,6 +72,7 @@ int main(int argc, char* argv[]) } std::cout << "-----------------------------------"<< std::endl; //example for is_pullout_directions_single_mold_translational_casting_2 that accepts the edge + index =0; for (auto e_it = pgn.edges_begin(); e_it != pgn.edges_end(); ++e_it, ++index) { auto segment_outer_circle = From 6b30f30562bd2957216dafed46f8c4ea7a155cb2 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Wed, 15 Mar 2017 00:49:07 +0200 Subject: [PATCH 54/90] Casting_2: changes code such that it will work with edges iterator instead of indices --- .../single_mold_translational_casting.cpp | 13 +- .../Circle_arrangment.h | 47 ++-- ...tion_single_mold_translational_casting_2.h | 247 +++++++++--------- ...ions_single_mold_translational_casting_2.h | 4 +- ...dges_single_mold_translational_casting_2.h | 8 +- 5 files changed, 155 insertions(+), 164 deletions(-) diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp index 3efb164197e..46285235d7b 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp @@ -13,7 +13,8 @@ typedef Kernel::Direction_2 Direction_2; typedef Kernel::Vector_2 Vector_2; typedef Kernel::Point_2 Point_2; typedef std::pair Direction_range; -typedef std::pair Top_edge; +typedef Polygon_2::Edge_const_iterator Edge_iter; +typedef std::pair< Edge_iter, Direction_range> Top_edge; namespace SMS = CGAL::Set_movable_separability_2; @@ -43,8 +44,8 @@ int main(int argc, char* argv[]) else { std::cout << "There are " << top_edges.size() << " top edges:" << std::endl; for (const auto& top_edge : top_edges) { - std::cout << "Edge number: " << top_edge.first << std::endl - << "\tEdge: "<< pgn.edge(top_edge.first) << std::endl + std::cout + << "\tEdge: "<< *top_edge.first<< std::endl << "\tPullout directions from: "<< top_edge.second.first << " to " << top_edge.second.second << std::endl<< std::endl; @@ -89,11 +90,11 @@ int main(int argc, char* argv[]) { Vector_2 v (Point_2(0,0),Point_2(1,0)); Direction_2 d(v); - std::pair + CGAL::Polygon_2::Edge_const_iterator res = SMS::is_pullout_direction_single_mold_translational_casting_2(pgn,d); - if (res.first) + if (res!= pgn.edges_end()) { - std::cout << "The polygon is castable in direction d ("< Arc; + typedef typename CGAL::Polygon_2::Edge_const_iterator Edge_iter; /* Legend: * Point = Represented as Direction_2. It is the intersection between the @@ -118,14 +119,14 @@ namespace CGAL { uint8_t m_count; // no. of outer circles that cover the edge (0/1/2+) - size_t m_edge_index; // the index of the polygon edge the open + 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, size_t edge_index, bool start_is_closed,bool set_count_to_one=true) + /*! \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_index the index of the polygon edge who's open + * \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 @@ -133,27 +134,27 @@ namespace CGAL { * var is false) */ Circle_arrangment_edge(const Point edge_start_angle, - const size_t edge_index, + 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_index = edge_index; + this->m_edge_iter = edge_iter; } - /*! \fn void plusplus(size_t edge_index) + /*! \fn void plusplus(const Edge_iter edge_ite) * Adds new polygon edge who's open half-circle covers this cell - * \param[in] edge_index - the index of this edge + * \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 size_t edge_index) + void plusplus(const Edge_iter edge_iter) { if (this->m_count ==0) { - this->m_edge_index = edge_index; + this->m_edge_iter = edge_iter; this->m_count = 1; } else if(this->m_count ==1) this->m_count = 2; @@ -228,27 +229,27 @@ namespace CGAL { * 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) : + 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, - 0, false)); + edge_iter, false)); m_edges.push_back(Circle_arrangment_edge(first_segment_outer_circle.second, - 0, true, false)); + edge_iter, true, false)); } - /*! \fn add_segment_outer_circle(arc segment_outer_circle, size_t edge_index) + /*! \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_index this segment id + * \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 size_t edge_index) + const Edge_iter edge_iter) { Arc edge; bool is_start_closed_segment = m_edges.begin()->m_start_is_closed; @@ -276,7 +277,7 @@ namespace CGAL { if (is_a_contained_in_b(is_start_closed_segment, is_end_closed_segment, edge, segment_outer_circle)) { - it->plusplus(edge_index); + it->plusplus(edge_iter); continue; } bool is_start_contained = @@ -303,7 +304,7 @@ namespace CGAL { struct Circle_arrangment_edge edge2 = *it; edge2.m_start_is_closed = false; edge2.m_edge_start_angle = segment_outer_circle.first; - edge2.plusplus(edge_index); + edge2.plusplus(edge_iter); this->insert_if_legal(it, next_it, edge2); struct Circle_arrangment_edge edge3 = *it; edge3.m_start_is_closed = true; @@ -324,9 +325,9 @@ namespace CGAL { struct Circle_arrangment_edge edge3 = *it; edge3.m_start_is_closed = false; edge3.m_edge_start_angle = segment_outer_circle.first; - edge3.plusplus(edge_index); + edge3.plusplus(edge_iter); this->insert_if_legal(it, next_it, edge3); - it->plusplus(edge_index); + it->plusplus(edge_iter); } } else { @@ -338,7 +339,7 @@ namespace CGAL { struct Circle_arrangment_edge edge2 = *it; edge2.m_start_is_closed = false; edge2.m_edge_start_angle = segment_outer_circle.first; - edge2.plusplus(edge_index); + edge2.plusplus(edge_iter); this->insert_if_legal(it, next_it, edge2); } } @@ -352,7 +353,7 @@ namespace CGAL { struct Circle_arrangment_edge edge2 = *it; edge2.m_start_is_closed = true; edge2.m_edge_start_angle = segment_outer_circle.second; - it->plusplus(edge_index); + it->plusplus(edge_iter); this->insert_if_legal(it, next_it, edge2); } //else - no intersection, do noting @@ -388,8 +389,8 @@ namespace CGAL { { for (auto it = m_edges.begin(); it != m_edges.end();) { if ((*it).m_count == 1) { - std::pair edge; - edge.first = (*it).m_edge_index; + std::pair edge; + edge.first = (*it).m_edge_iter; edge.second.first = (*it).m_edge_start_angle; ++it; edge.second.second = diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index 49f86e14871..8fd8a432634 100755 --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -23,142 +23,133 @@ namespace CGAL { -namespace Set_movable_separability_2 { + namespace Set_movable_separability_2 { -/*! 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] i the index of an edge in 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 -bool is_pullout_direction_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, - typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) -{ - //NOT CHECKED AT ALL - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!is_any_edge_colinear(pgn)); - - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); - - ++edge_index; - auto cc_in_between = traits.counterclockwise_in_between_2_object(); - - for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - bool isordered = !cc_in_between(segment_outer_circle.second, - d, - segment_outer_circle.first); - if (isordered == (edge_index==i)) + /*! 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] i the index of an edge in 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 + bool is_pullout_direction_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn,const typename CGAL::Polygon_2::Edge_const_iterator& i, + typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) { - return false; - } - } + //NOT CHECKED AT ALL + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!internal::is_any_edge_colinear(pgn)); - return true; -} + auto e_it = pgn.edges_begin(); + CGAL::Orientation poly_orientation = pgn.orientation(); + auto cc_in_between = traits.counterclockwise_in_between_2_object(); -/*! - */ -template -bool is_pullout_direction_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, - typename CastingTraits_2::Direction_2& d) -{ - CastingTraits_2 traits; - return is_pullout_direction_single_mold_translational_casting_2(pgn, i, d, - 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 pair - * - * \pre `png` must be non-degenerate (has at least 3 vertices),simple, and - * does not have three consecutive collinear vertices. - */ -#define MAX_SIZE_T (std::numeric_limits::max()) - -template -std::pair -is_pullout_direction_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, - typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) -{ - //NOT CHECKED AT ALL - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!is_any_edge_colinear(pgn)); - - auto e_it = pgn.edges_begin(); - size_t edge_index = 0; - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - get_segment_outer_circle(*e_it++, poly_orientation); - ++edge_index; - auto cc_in_between = traits.counterclockwise_in_between_2_object(); - size_t top_edge= MAX_SIZE_T; - for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { - segment_outer_circle = - get_segment_outer_circle(*e_it, poly_orientation); - bool isordered = !cc_in_between(segment_outer_circle.second, - d, - segment_outer_circle.first); - if (!isordered) //unlikely - this if must be true atleast once for any polygon - add ref to paper - { - if(top_edge==MAX_SIZE_T) - { - top_edge= edge_index; + for (; e_it != pgn.edges_end(); ++e_it) { + auto segment_outer_circle = + internal::get_segment_outer_circle(*e_it, poly_orientation); + bool isordered = !cc_in_between(d,segment_outer_circle.second, + segment_outer_circle.first); + if (isordered == (e_it==i)) + { + return false; + } } - else - return std::make_pair(false, MAX_SIZE_T); + + return true; } - } - CGAL_postcondition(top_edge!=MAX_SIZE_T); - return std::make_pair(true, top_edge); -} -/*! - */ -template -std::pair -is_pullout_direction_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, - typename CastingTraits_2::Direction_2& d) -{ - CastingTraits_2 traits; - return is_pullout_direction_single_mold_translational_casting_2(pgn, d, traits); -} + /*! + */ + template + bool is_pullout_direction_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, const typename CGAL::Polygon_2::Edge_const_iterator& i, + typename CastingTraits_2::Direction_2& d) + { + CastingTraits_2 traits; + return is_pullout_direction_single_mold_translational_casting_2(pgn, i, d, + traits); + } -} /* end namesapce Set_movable_separability_2 */ + /*! 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 - top the edge, else 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 CGAL::Polygon_2::Edge_const_iterator + is_pullout_direction_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, + typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) + { + //NOT CHECKED AT ALL +typedef typename CGAL::Polygon_2::Edge_const_iterator Edge_iter; + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!internal::is_any_edge_colinear(pgn)); + + Edge_iter e_it = pgn.edges_begin(); + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + internal::get_segment_outer_circle(*e_it++, poly_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(*e_it, poly_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; + } + + /*! + */ + template + typename CGAL::Polygon_2::Edge_const_iterator + is_pullout_direction_single_mold_translational_casting_2 + (const CGAL::Polygon_2& pgn, + typename CastingTraits_2::Direction_2& d) + { + CastingTraits_2 traits; + return is_pullout_direction_single_mold_translational_casting_2(pgn, d, traits); + } + + } /* end namesapce Set_movable_separability_2 */ } /* end namesapce CGAL */ #endif diff --git a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h index d70c1636e10..32392d6ad64 100755 --- a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -72,7 +72,7 @@ namespace CGAL { { CGAL_precondition(pgn.is_simple()); CGAL_precondition(!internal::is_any_edge_colinear(pgn)); - CGAL_precondition(pgn.size()>i); + CGAL_precondition(pgn.edges_end()!=i); CGAL::Orientation poly_orientation = pgn.orientation(); typedef CastingTraits_2 Casting_traits_2; @@ -163,7 +163,7 @@ namespace CGAL { * a model of the concept `CastingTraits_2`. * * \param[in] pgn the input polygon. - * \param[in] i the index of an edge in pgn. + * \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 diff --git a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h index 7e95756cf15..f1c7fc7b5fe 100755 --- a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h @@ -67,18 +67,16 @@ namespace CGAL { CGAL_precondition(!internal::is_any_edge_colinear(pgn)); auto e_it = pgn.edges_begin(); - size_t edge_index = 0; CGAL::Orientation poly_orientation = pgn.orientation(); auto segment_outer_circle = internal::get_segment_outer_circle(*e_it++, poly_orientation); internal::Circle_arrangment circle_arrangment(kernel, - segment_outer_circle); + segment_outer_circle,pgn.edges_begin()); - ++edge_index; - for (; e_it != pgn.edges_end(); ++e_it, ++edge_index) { + for (; e_it != pgn.edges_end(); ++e_it) { segment_outer_circle = internal::get_segment_outer_circle(*e_it, poly_orientation); - circle_arrangment.add_segment_outer_circle(segment_outer_circle, edge_index); + 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); From 29e2d7a7d5a84b04a9da6020fc7e7f4637bfb637 Mon Sep 17 00:00:00 2001 From: shahar shamai Date: Sat, 18 Mar 2017 01:20:00 +0200 Subject: [PATCH 55/90] casting_2: Added some needed includes --- .../is_pullout_direction_single_mold_translational_casting_2.h | 2 ++ .../pullout_directions_single_mold_translational_casting_2.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index 8fd8a432634..7955c9b6882 100755 --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -20,6 +20,8 @@ #include #include #include +#include "Set_movable_separability_2/Utils.h" +#include "Set_movable_separability_2/Circle_arrangment.h" namespace CGAL { diff --git a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h index 32392d6ad64..ded667a0536 100755 --- a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -19,6 +19,8 @@ #define CGAL_PULLOUT_DIRECTIONS_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H #include +#include "Set_movable_separability_2/Utils.h" +#include "Set_movable_separability_2/Circle_arrangment.h" namespace CGAL { From e0cbbd868973d728dfec6a3dd0a595f7eb2eac29 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Mon, 3 Jul 2017 14:22:20 +0300 Subject: [PATCH 56/90] Added namespace Single_mold_translational_casting --- ...tion_single_mold_translational_casting_2.h | 54 +-- ...ions_single_mold_translational_casting_2.h | 20 +- ...dges_single_mold_translational_casting_2.h | 25 +- .../Set_movable_separability_2.txt | 2 +- .../Set_movable_separability_2/examples.txt | 4 +- .../Set_movable_separability_2/CMakeLists.txt | 17 +- ...tion_single_mold_translational_casting.cpp | 67 ++++ ...ions_single_mold_translational_casting.cpp | 44 +++ .../single_mold_translational_casting.cpp | 106 ------ ...dges_single_mold_translational_casting.cpp | 60 ++++ .../CGAL/Set_movable_separability_2/Utils.h | 0 ...tion_single_mold_translational_casting_2.h | 254 +++++++------- ...ions_single_mold_translational_casting_2.h | 323 +++++++++--------- ...dges_single_mold_translational_casting_2.h | 146 ++++---- .../Set_movable_separability_2/CMakeLists.txt | 1 + .../cgal_test_with_cmake | 1 + ...t_directions_single_mold_translational.cmd | 15 + ...t_directions_single_mold_translational.cpp | 69 +--- ...test_single_mold_translational_casting.cpp | 16 +- 19 files changed, 644 insertions(+), 580 deletions(-) create mode 100644 Set_movable_separability_2/examples/Set_movable_separability_2/is_pullout_direction_single_mold_translational_casting.cpp create mode 100644 Set_movable_separability_2/examples/Set_movable_separability_2/pullout_directions_single_mold_translational_casting.cpp delete mode 100644 Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp create mode 100644 Set_movable_separability_2/examples/Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp mode change 100755 => 100644 Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h create mode 100644 Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cmd diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index bf8e02eb26d..cf8b833c94f 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -1,5 +1,6 @@ namespace CGAL { namespace Set_movable_separability_2 { +namespace Single_mold_translational_casting { /*! \ingroup PkgSetMovableSeparability2Funcs * @@ -16,18 +17,16 @@ namespace Set_movable_separability_2 { * \param[in] pgn the input polygon. * \param[in] d the inspected direction. * \param[in] traits the traits to use. - * \return a pair of elements, where the first is a Boolean that indicates - * whether `pgn` can be pulled out in the `d` direction, and the - * second is the index of the corresponding top edge in `pgn`. + * \return if `pgn` can be pullout in the `d` direction the iterator of the + * corresponding 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 -std::pair -is_pullout_direction_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, - typename CastingTraits_2::Direction_2& d, - const CastingTraits_2& traits = CastingTraits_2()); +typename CGAL::Polygon_2::Edge_const_iterator +is_pullout_direction(const CGAL::Polygon_2& pgn, + const typename CastingTraits_2::Direction_2& d, + const CastingTraits_2& traits = CastingTraits_2()); /*! \ingroup PkgSetMovableSeparability2Funcs * @@ -40,19 +39,17 @@ is_pullout_direction_single_mold_translational_casting_2 * \param[in] d the inspected direction. * \param[in] orientation the orientation of `pgn`. * \param[in] traits the traits to use. - * \return a pair of elements, where the first is a Boolean that indicates - * whether `pgn` can be pulled out in the `d` direction, and the - * second is the index of the corresponding top edge in `pgn`. + * \return if `pgn` can be pullout in the `d` direction the iterator of the + * corresponding 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 -std::pair -is_pullout_direction_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, - typename CastingTraits_2::Direction_2& d, - CGAL::Orientation orientation, - const CastingTraits_2& traits = CastingTraits_2()); +typename CGAL::Polygon_2::Edge_const_iterator +is_pullout_direction(const CGAL::Polygon_2& pgn, + const typename CastingTraits_2::Direction_2& d, + CGAL::Orientation orientation, + const CastingTraits_2& traits = CastingTraits_2()); /*! \ingroup PkgSetMovableSeparability2Funcs * @@ -69,7 +66,7 @@ is_pullout_direction_single_mold_translational_casting_2 * a model of the concept `CastingTraits_2`. * * \param[in] pgn the input polygon. - * \param[in] i the index of an edge in pgn. + * \param[in] it an iterator to an edge in pgn. * \param[in] d the tested direction. * \param[in] traits the traits to use. * \return true if `pgn` can be pulled out in the `d` direction with the @@ -78,9 +75,10 @@ is_pullout_direction_single_mold_translational_casting_2 * does not have three consecutive collinear vertices. */ template -bool is_pullout_direction_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, - typename CastingTraits_2::Direction_2& d, +bool is_pullout_direction +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_2::Edge_const_iterator& it, + const typename CastingTraits_2::Direction_2& d, const CastingTraits_2& traits = CastingTraits_2()); /*! \ingroup PkgSetMovableSeparability2Funcs @@ -91,7 +89,7 @@ bool is_pullout_direction_single_mold_translational_casting_2 * polygon requires time linear in the number of edges. * * \param[in] pgn the input polygon. - * \param[in] i the index of an edge in pgn. + * \param[in] it an iterator to an edge in pgn. * \param[in] d the tested direction. * \param[in] orientation the orientation of `pgn`. * \param[in] traits the traits to use. @@ -101,11 +99,13 @@ bool is_pullout_direction_single_mold_translational_casting_2 * does not have three consecutive collinear vertices. */ template -bool is_pullout_direction_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, - typename CastingTraits_2::Direction_2& d, +bool is_pullout_direction +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_2::Edge_const_iterator& it, + const typename CastingTraits_2::Direction_2& d, CGAL::Orientation orientation, const CastingTraits_2& traits = CastingTraits_2()); -} /* end namesapce Set_movable_separability_2 */ -} /* end namesapce CGAL */ +} // namespace Single_mold_translational_casting +} // namesapce Set_movable_separability_2 +} // namesapce CGAL diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h index 2a565a92825..888aa5ff75f 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -1,5 +1,6 @@ namespace CGAL { namespace Set_movable_separability_2 { +namespace Single_mold_translational_casting { /*! \ingroup PkgSetMovableSeparability2Funcs * @@ -15,7 +16,7 @@ namespace Set_movable_separability_2 { * a model of the concept `CastingTraits_2`. * * \param[in] pgn the input polygon. - * \param[in] i the index of an edge in pgn. + * \param[in] it an iterator to an edge in pgn. * \param[in] 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 @@ -29,8 +30,9 @@ namespace Set_movable_separability_2 { template std::pair > -pullout_directions_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, +pullout_directions +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_2::Edge_const_iterator& it, CastingTraits_2& traits = CastingTraits_2()); /*! \ingroup PkgSetMovableSeparability2Funcs @@ -41,7 +43,7 @@ pullout_directions_single_mold_translational_casting_2 * polygon requires time linear in the number of edges. * * \param[in] pgn the input polygon. - * \param[in] i the index of an edge in pgn. + * \param[in] it an iterator to an edge in pgn. * \param[in] orientation the orientation of `pgn`. * \param[in] traits the traits to use. * \return a pair of elements, where the first is a Boolean that indicates @@ -56,10 +58,12 @@ pullout_directions_single_mold_translational_casting_2 template std::pair > -pullout_directions_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, size_t i, +pullout_directions +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_2::Edge_const_iterator& it, CGAL::Orientation orientation, CastingTraits_2& traits = CastingTraits_2()); -} /* end namesapce Set_movable_separability_2 */ -} /* end namesapce CGAL */ +} // namespace Single_mold_translational_casting +} // namesapce Set_movable_separability_2 +} // namesapce CGAL diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h index dbd86f03224..dc3de291db6 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h @@ -1,5 +1,6 @@ namespace CGAL { namespace Set_movable_separability_2 { +namespace Single_mold_translational_casting { /*! \ingroup PkgSetMovableSeparability2Funcs * @@ -32,13 +33,9 @@ namespace Set_movable_separability_2 { * does not have three consecutive collinear vertices. */ template -OutputIterator -top_edges_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, OutputIterator oi, - CastingTraits_2& traits = CastingTraits_2()); - -} /* end namesapce Set_movable_separability_2 */ -} /* end namesapce CGAL */ +OutputIterator top_edges(const CGAL::Polygon_2& pgn, + OutputIterator oi, + CastingTraits_2& traits = CastingTraits_2()); /*! \ingroup PkgSetMovableSeparability2Funcs * @@ -62,11 +59,11 @@ top_edges_single_mold_translational_casting_2 * does not have three consecutive collinear vertices. */ template -OutputIterator -top_edges_single_mold_translational_casting_2 -(const CGAL::Polygon_2& pgn, OutputIterator oi, - CGAL::Orientation orientation, - CastingTraits_2& traits = CastingTraits_2()); +OutputIterator top_edges(const CGAL::Polygon_2& pgn, + OutputIterator oi, + CGAL::Orientation orientation, + CastingTraits_2& traits = CastingTraits_2()); -} /* end namesapce Set_movable_separability_2 */ -} /* end namesapce CGAL */ +} // namespace Single_mold_translational_casting +} // namesapce Set_movable_separability_2 +} // namesapce CGAL diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index aac33597aad..bb5426f1ba4 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -89,7 +89,7 @@ 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/single_mold_translational_casting.cpp} +\cgalExample{Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp} This package provides two additional functions, namely, `pullout_directions_single_mold_translational_casting_2()` and diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/examples.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/examples.txt index 79413ffb596..9ec7a566451 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/examples.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/examples.txt @@ -1,3 +1,5 @@ /*! -\example Set_movable_separability_2/single_mold_translational_casting.cpp +\example Set_movable_separability_2/is_pullout_direction_single_mold_translational_casting.cpp +\example Set_movable_separability_2/pullout_directions_single_mold_translational_casting.cpp +\example Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp */ diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/CMakeLists.txt b/Set_movable_separability_2/examples/Set_movable_separability_2/CMakeLists.txt index de1af6b046d..5846bd699a3 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/CMakeLists.txt +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/CMakeLists.txt @@ -6,6 +6,16 @@ project( Casting_2_example ) cmake_minimum_required(VERSION 2.8.10) +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 Core ) if ( CGAL_FOUND ) @@ -16,10 +26,9 @@ if ( CGAL_FOUND ) include_directories (BEFORE "../../include") - create_single_source_cgal_program( "single_mold_translational_casting.cpp" ) - if (CMAKE_COMPILER_IS_GNUCXX) - add_definitions(-std=c++11) - endif() + create_single_source_cgal_program( "top_edges_single_mold_translational_casting.cpp" ) + create_single_source_cgal_program( "is_pullout_direction_single_mold_translational_casting.cpp" ) + create_single_source_cgal_program( "pullout_directions_single_mold_translational_casting.cpp" ) else() diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/is_pullout_direction_single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/is_pullout_direction_single_mold_translational_casting.cpp new file mode 100644 index 00000000000..5f240a6b1ed --- /dev/null +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/is_pullout_direction_single_mold_translational_casting.cpp @@ -0,0 +1,67 @@ +#include + +#include +#include + +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 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(*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; +} diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/pullout_directions_single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/pullout_directions_single_mold_translational_casting.cpp new file mode 100644 index 00000000000..fe1ccf4767b --- /dev/null +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/pullout_directions_single_mold_translational_casting.cpp @@ -0,0 +1,44 @@ +#include + +#include +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef CGAL::Polygon_2 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; +} diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp deleted file mode 100644 index 46285235d7b..00000000000 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/single_mold_translational_casting.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include - -typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; -typedef CGAL::Polygon_2 Polygon_2; -typedef Kernel::Direction_2 Direction_2; -typedef Kernel::Vector_2 Vector_2; -typedef Kernel::Point_2 Point_2; -typedef std::pair 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; - -// The main program: -int main(int argc, char* argv[]) -{ - Polygon_2 pgn; - - 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 >> pgn; - input_file.close(); - - auto poly_orientation = pgn.orientation(); - std::list top_edges; - - - //example for top_edges_single_mold_translational_casting_2 - SMS::top_edges_single_mold_translational_casting_2 - (pgn, 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; - } - } - std::cout << "-----------------------------------"<< std::endl; - - //example for pullout_directions_single_mold_translational_casting_2 - int index =0; - for (auto e_it = pgn.edges_begin(); e_it != pgn.edges_end(); ++e_it, ++index) - - { - - std::pair > res = SMS::pullout_directions_single_mold_translational_casting_2(pgn,e_it); - if (res.first) - { - std::cout << "The polygon is castable using edge "<(*e_it, poly_orientation); - Direction_2 d = segment_outer_circle.first; - d= d.perpendicular(CGAL::CLOCKWISE); - bool res = SMS::is_pullout_direction_single_mold_translational_casting_2(pgn,e_it,d); - std::cout << "The polygon is "<<(res?"":"not ") <<"castable using edge "<::Edge_const_iterator - res = SMS::is_pullout_direction_single_mold_translational_casting_2(pgn,d); - if (res!= pgn.edges_end()) - { - std::cout << "The polygon is castable in direction d ("< +#include + +#include +#include +#include +#include +#include + +typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; +typedef CGAL::Polygon_2 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_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 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_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; + } + } + std::cout << "-----------------------------------"<< std::endl; + + return 0; +} diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h old mode 100755 new mode 100644 diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h index 7955c9b6882..04b17d926cf 100755 --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h @@ -15,143 +15,145 @@ // Author(s): Shahar // Efi Fogel -#ifndef CGAL_IS_PULLOUT_DIRECTION_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H -#define CGAL_IS_PULLOUT_DIRECTION_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#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 + #include #include -#include -#include "Set_movable_separability_2/Utils.h" -#include "Set_movable_separability_2/Circle_arrangment.h" +#include +#include namespace CGAL { +namespace Set_movable_separability_2 { +namespace Single_mold_translational_casting { - namespace Set_movable_separability_2 { +/*! 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] i the index of an edge in 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 +bool is_pullout_direction +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_2::Edge_const_iterator& i, + const typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) +{ + //NOT CHECKED AT ALL + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!internal::is_any_edge_colinear(pgn)); - /*! 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] i the index of an edge in 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 - bool is_pullout_direction_single_mold_translational_casting_2 - (const CGAL::Polygon_2& pgn,const typename CGAL::Polygon_2::Edge_const_iterator& i, - typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) - { - //NOT CHECKED AT ALL - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!internal::is_any_edge_colinear(pgn)); + auto e_it = pgn.edges_begin(); + CGAL::Orientation poly_orientation = pgn.orientation(); + auto cc_in_between = traits.counterclockwise_in_between_2_object(); - auto e_it = pgn.edges_begin(); - CGAL::Orientation poly_orientation = pgn.orientation(); - 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(*e_it, + poly_orientation); + bool isordered = !cc_in_between(d, segment_outer_circle.second, + segment_outer_circle.first); + if (isordered == (e_it == i)) return false; + } - for (; e_it != pgn.edges_end(); ++e_it) { - auto segment_outer_circle = - internal::get_segment_outer_circle(*e_it, poly_orientation); - bool isordered = !cc_in_between(d,segment_outer_circle.second, - segment_outer_circle.first); - if (isordered == (e_it==i)) - { - return false; - } - } + return true; +} - return true; +/*! + */ +template +bool is_pullout_direction +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_2::Edge_const_iterator& i, + const typename CastingTraits_2::Direction_2& d) +{ + CastingTraits_2 traits; + return is_pullout_direction(pgn, i, d, 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 CGAL::Polygon_2::Edge_const_iterator +is_pullout_direction(const CGAL::Polygon_2& pgn, + typename CastingTraits_2::Direction_2& d, + CastingTraits_2& traits) +{ + //NOT CHECKED AT ALL + typedef CGAL::Polygon_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)); + + Edge_iter e_it = pgn.edges_begin(); + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + internal::get_segment_outer_circle(*e_it++, + poly_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(*e_it, + poly_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; +} - /*! - */ - template - bool is_pullout_direction_single_mold_translational_casting_2 - (const CGAL::Polygon_2& pgn, const typename CGAL::Polygon_2::Edge_const_iterator& i, - typename CastingTraits_2::Direction_2& d) - { - CastingTraits_2 traits; - return is_pullout_direction_single_mold_translational_casting_2(pgn, i, d, - traits); - } +/*! + */ +template +typename CGAL::Polygon_2::Edge_const_iterator +is_pullout_direction(const CGAL::Polygon_2& pgn, + typename CastingTraits_2::Direction_2& d) +{ + CastingTraits_2 traits; + return is_pullout_direction(pgn, d, 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 - top the edge, else 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 CGAL::Polygon_2::Edge_const_iterator - is_pullout_direction_single_mold_translational_casting_2 - (const CGAL::Polygon_2& pgn, - typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) - { - //NOT CHECKED AT ALL -typedef typename CGAL::Polygon_2::Edge_const_iterator Edge_iter; - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!internal::is_any_edge_colinear(pgn)); - - Edge_iter e_it = pgn.edges_begin(); - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - internal::get_segment_outer_circle(*e_it++, poly_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(*e_it, poly_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; - } - - /*! - */ - template - typename CGAL::Polygon_2::Edge_const_iterator - is_pullout_direction_single_mold_translational_casting_2 - (const CGAL::Polygon_2& pgn, - typename CastingTraits_2::Direction_2& d) - { - CastingTraits_2 traits; - return is_pullout_direction_single_mold_translational_casting_2(pgn, d, traits); - } - - } /* end namesapce Set_movable_separability_2 */ -} /* end namesapce CGAL */ +} // namespace Single_mold_translational_casting +} // namesapce Set_movable_separability_2 +} // namesapce CGAL #endif diff --git a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h index ded667a0536..0f9739757f7 100755 --- a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h @@ -15,183 +15,182 @@ // Author(s): Shahar // Efi Fogel -#ifndef CGAL_PULLOUT_DIRECTIONS_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H -#define CGAL_PULLOUT_DIRECTIONS_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#ifndef CGAL_SMS_2_PULLOUT_DIRECTIONS_SINGLE_MOLD_TRANSLATIONAL_CASTING_H +#define CGAL_SMS_2_PULLOUT_DIRECTIONS_SINGLE_MOLD_TRANSLATIONAL_CASTING_H #include -#include "Set_movable_separability_2/Utils.h" -#include "Set_movable_separability_2/Circle_arrangment.h" +#include +#include namespace CGAL { +namespace Set_movable_separability_2 { +namespace Single_mold_translational_casting { - namespace Set_movable_separability_2 { +/*! 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 +std::pair > +pullout_directions +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_2::Edge_const_iterator& i, + CastingTraits_2& traits) +{ + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!internal::is_any_edge_colinear(pgn)); + CGAL_precondition(pgn.edges_end()!=i); + CGAL::Orientation poly_orientation = pgn.orientation(); + + typedef CastingTraits_2 Casting_traits_2; + //the returned range is [clock_first, clock_second] + typename Casting_traits_2::Direction_2 clock_first, clock_second; - /*! 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 - std::pair > - pullout_directions_single_mold_translational_casting_2 - (const CGAL::Polygon_2& pgn, const typename CGAL::Polygon_2::Edge_const_iterator& i, CastingTraits_2& traits) - { - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!internal::is_any_edge_colinear(pgn)); - CGAL_precondition(pgn.edges_end()!=i); - CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + internal::get_segment_outer_circle(*i, poly_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 - typedef CastingTraits_2 Casting_traits_2; - typename Casting_traits_2::Direction_2 clockFirst, clockSecond; //the returned range is [clockFirst,clockSecond] + 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(*e_it, + poly_orientation); + // std::cout << "a "<< segment_outer_circle.second << " b " + // << segment_outer_circle.first<(*i, poly_orientation); - clockFirst=segment_outer_circle.first; - clockSecond=segment_outer_circle.second; - //well theoretically, this is a bug since the current intersection is currently (clockFirst,clockSecond) - //and not [clockFirst,clockSecond].. but this edges will surly change since we are in a polygon - - bool isRangeSmallerThanSemicircle=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 "<(*e_it, poly_orientation); - // std::cout<<"a "<castable 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 - std::pair > - pullout_directions_single_mold_translational_casting_2 - (const CGAL::Polygon_2& pgn, + 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"<::Edge_const_iterator& i) - { + return std::make_pair(true, std::make_pair(clock_first, clock_second)); +} - CastingTraits_2 traits; - return pullout_directions_single_mold_translational_casting_2(pgn, i, traits); - } +/*! 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 castable 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 +std::pair > +pullout_directions +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_2::Edge_const_iterator& i) +{ + CastingTraits_2 traits; + return pullout_directions(pgn, i, traits); +} - - - } // end of namespace Set_movable_separability_2 -} // end of namespace CGAL +} // namespace Single_mold_translational_casting +} // namespace Set_movable_separability_2 +} // namespace CGAL #endif diff --git a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h index f1c7fc7b5fe..c83f6c74987 100755 --- a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h @@ -15,91 +15,95 @@ // Author(s): Shahar // Efi Fogel -#ifndef CGAL_TOP_EDGES_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H -#define CGAL_TOP_EDGES_SINGLE_MOLD_TRANSLATIONAL_CASTING_2_H +#ifndef CGAL_SMS_2_TOP_EDGES_SINGLE_MOLD_TRANSLATIONAL_CASTING_H +#define CGAL_SMS_2_TOP_EDGES_SINGLE_MOLD_TRANSLATIONAL_CASTING_H #include #include #include #include - -#include "Set_movable_separability_2/Circle_arrangment.h" -#include "Set_movable_separability_2/Utils.h" +#include +#include namespace CGAL { +namespace Set_movable_separability_2 { +namespace Single_mold_translational_casting { - namespace Set_movable_separability_2 { +/* 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. + */ - /* 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. - */ +/*! \fn OutputIterator top_edges(const CGAL::Polygon_2& pgn, + * OutputIterator oi, + * CastingTraits_2& traits) + * \param[in] pgn the input polygon that we want to check if is castable or not. + * \param[in,out] oi the output iterator to put the top edges in + * \param[in] 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 +OutputIterator top_edges(const CGAL::Polygon_2& pgn, + OutputIterator oi, 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; - /*! \fn OutputIterator find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) - * \param[in] pgn the input polygon that we want to check if is castable or not. - * \param[in,out] oi the output iterator to put the top edges in - * \param[in] kernel the kernel 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 - OutputIterator - top_edges_single_mold_translational_casting_2 - (const CGAL::Polygon_2& pgn, OutputIterator oi, Kernel& kernel) - { - /* 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) - */ - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!internal::is_any_edge_colinear(pgn)); + CGAL_precondition(pgn.is_simple()); + CGAL_precondition(!internal::is_any_edge_colinear(pgn)); - auto e_it = pgn.edges_begin(); - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - internal::get_segment_outer_circle(*e_it++, poly_orientation); - internal::Circle_arrangment circle_arrangment(kernel, - segment_outer_circle,pgn.edges_begin()); + auto e_it = pgn.edges_begin(); + CGAL::Orientation poly_orientation = pgn.orientation(); + auto segment_outer_circle = + internal::get_segment_outer_circle(*e_it++, poly_orientation); + typedef internal::Circle_arrangment Circle_arrangment; + Circle_arrangment circle_arrangment(traits, + segment_outer_circle,pgn.edges_begin()); - for (; e_it != pgn.edges_end(); ++e_it) { - segment_outer_circle = - internal::get_segment_outer_circle(*e_it, poly_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; - } + for (; e_it != pgn.edges_end(); ++e_it) { + segment_outer_circle = + internal::get_segment_outer_circle(*e_it, poly_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 find_single_mold_translational_casting_2(const CGAL::Polygon_2& pgn, OutputIterator oi) - * \param[in] pgn the input polygon that we want to check if is castable or not. - * \param[in,out] 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 - OutputIterator - top_edges_single_mold_translational_casting_2 - (const CGAL::Polygon_2& pgn, OutputIterator oi) - { - Kernel kernel; - return top_edges_single_mold_translational_casting_2(pgn, oi, kernel); - } +/*! \fn OutputIterator top_edges(const CGAL::Polygon_2& pgn, + * OutputIterator oi) + * \param[in] pgn the input polygon that we want to check if is castable or not. + * \param[in,out] 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 +OutputIterator top_edges(const CGAL::Polygon_2& pgn, + OutputIterator oi) +{ + CastingTraits_2 traits; + return top_edges(pgn, oi, traits); +} - } // end of namespace Set_movable_separability_2 -} // end of namespace CGAL +} // namespace Single_mold_translational_casting +} // namespace Set_movable_separability_2 +} // namespace CGAL #endif diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/CMakeLists.txt b/Set_movable_separability_2/test/Set_movable_separability_2/CMakeLists.txt index 0e39af47ec3..517603b4032 100644 --- a/Set_movable_separability_2/test/Set_movable_separability_2/CMakeLists.txt +++ b/Set_movable_separability_2/test/Set_movable_separability_2/CMakeLists.txt @@ -21,6 +21,7 @@ if ( CGAL_FOUND ) endif() create_single_source_cgal_program( "test_single_mold_translational_casting.cpp" ) +create_single_source_cgal_program( "test_is_pullout_directions_single_mold_translational.cpp" ) else() diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake b/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake index f89576f0cdb..e87666205f6 100755 --- a/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake +++ b/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake @@ -98,6 +98,7 @@ else echo "Run all tests." if ${MAKE_CMD} -f Makefile help | grep -E "test_single_mold_translational_casting$" > /dev/null; then compile_and_run test_single_mold_translational_casting + compile_and_run test_is_pullout_directions_single_mold_translational NEED_CLEAN=y fi fi diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cmd b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cmd new file mode 100644 index 00000000000..e8f30c0cf64 --- /dev/null +++ b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cmd @@ -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 diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp index ff332b4223a..1a58bfaba27 100644 --- a/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp +++ b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp @@ -9,6 +9,7 @@ #include #include #include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; @@ -16,27 +17,11 @@ typedef Kernel::Direction_2 Direction_2; typedef Kernel::Point_2 Point_2; typedef std::pair Direction_range; -typedef std::pair Top_edge; +typedef Polygon_2::Edge_const_iterator Edge_iter; +typedef std::pair Top_edge; namespace SMS = CGAL::Set_movable_separability_2; - -struct Top_edge_comparer { - bool operator()(const Top_edge& a, const Top_edge& b) - { - auto facet_a = a.first; - const auto& d1_a = a.second.first; - const auto& d2_a = a.second.second; - auto facet_b = b.first; - const auto& d1_b = b.second.first; - const auto& d2_b = b.second.second; - - 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; - } -}; +namespace casting = SMS::Single_mold_translational_casting; bool test_one_file(std::ifstream& inp) { @@ -45,46 +30,20 @@ bool test_one_file(std::ifstream& inp) // std::cout << pgn << std::endl; std::vector top_edges; - SMS::top_edges_single_mold_translational_casting_2(pgn, std::back_inserter(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 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; - top_edge = std::make_pair(facet, 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) { + 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; - auto exp_facet = exp_it->first; - const auto& exp_d1 = exp_it->second.first; - const auto& exp_d2 = exp_it->second.second; - if ((facet != exp_facet) || (d1 != exp_d1) || (d2 != exp_d2)) { - std::cerr << "Top edge[" << i++ << "]: " - << "obtained: " << facet << " " << d1 << " " << d2 - << ", expected: " << exp_facet << " " << exp_d1 << " " << exp_d2 - << std::endl; - return false; - } + + 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; } diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp b/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp index ff332b4223a..78b16758bc3 100644 --- a/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -16,7 +17,8 @@ typedef Kernel::Direction_2 Direction_2; typedef Kernel::Point_2 Point_2; typedef std::pair Direction_range; -typedef std::pair Top_edge; +typedef Polygon_2::Edge_const_iterator Edge_iter; +typedef std::pair Top_edge; namespace SMS = CGAL::Set_movable_separability_2; @@ -56,7 +58,9 @@ bool test_one_file(std::ifstream& inp) Direction_2 d1, d2; inp >> facet >> d1 >> d2; // std::cout << facet << " " << d1 << " " << d2 << std::endl; - top_edge = std::make_pair(facet, std::make_pair(d1, d2)); + 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()); @@ -73,15 +77,17 @@ bool test_one_file(std::ifstream& inp) 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 ((facet != exp_facet) || (d1 != exp_d1) || (d2 != exp_d2)) { + if ((fid != exp_fid) || (d1 != exp_d1) || (d2 != exp_d2)) { std::cerr << "Top edge[" << i++ << "]: " - << "obtained: " << facet << " " << d1 << " " << d2 - << ", expected: " << exp_facet << " " << exp_d1 << " " << exp_d2 + << "obtained: " << fid << " " << d1 << " " << d2 + << ", expected: " << exp_fid << " " << exp_d1 << " " << exp_d2 << std::endl; return false; } From e00777bc998ba82d1a40d425218ba16f5dd0a3f4 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Mon, 3 Jul 2017 21:32:16 +0300 Subject: [PATCH 57/90] Moved headers to appropriate places. Added overloads that accept the orientation of the input polygon. --- .../is_pullout_direction.h} | 60 +-- .../pullout_directions.h} | 22 +- .../top_edges.h} | 22 +- .../Concepts/CastingTraits_2.h | 10 +- .../PackageDescription.txt | 28 +- ...tion_single_mold_translational_casting.cpp | 2 +- ...ions_single_mold_translational_casting.cpp | 2 +- ...dges_single_mold_translational_casting.cpp | 4 +- .../Circle_arrangment.h | 425 ------------------ .../is_pullout_direction.h} | 85 +++- .../pullout_directions.h} | 46 +- .../top_edges.h} | 108 +++-- .../CGAL/Set_movable_separability_2/Utils.h | 70 --- .../internal/Circle_arrangment.h | 425 ++++++++++++++++++ .../internal/Utils.h | 80 ++++ .../Set_movable_separability_2/CMakeLists.txt | 4 +- .../cgal_test_with_cmake | 13 +- ...ons_single_mold_translational_casting.cmd} | 0 ...ons_single_mold_translational_casting.cpp} | 4 +- ...ges_single_mold_translational_casting.cmd} | 0 ...ges_single_mold_translational_casting.cpp} | 5 +- 21 files changed, 786 insertions(+), 629 deletions(-) rename Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/{is_pullout_direction_single_mold_translational_casting_2.h => Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h} (71%) rename Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/{pullout_directions_single_mold_translational_casting_2.h => Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h} (85%) rename Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/{top_edges_single_mold_translational_casting_2.h => Set_movable_separability_2/Single_mold_translational_casting/top_edges.h} (87%) delete mode 100644 Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h rename Set_movable_separability_2/include/CGAL/{is_pullout_direction_single_mold_translational_casting_2.h => Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h} (68%) mode change 100755 => 100644 rename Set_movable_separability_2/include/CGAL/{pullout_directions_single_mold_translational_casting_2.h => Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h} (85%) mode change 100755 => 100644 rename Set_movable_separability_2/include/CGAL/{top_edges_single_mold_translational_casting_2.h => Set_movable_separability_2/Single_mold_translational_casting/top_edges.h} (59%) mode change 100755 => 100644 delete mode 100644 Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h create mode 100644 Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Circle_arrangment.h create mode 100644 Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Utils.h rename Set_movable_separability_2/test/Set_movable_separability_2/{test_is_pullout_directions_single_mold_translational.cmd => test_is_pullout_directions_single_mold_translational_casting.cmd} (100%) rename Set_movable_separability_2/test/Set_movable_separability_2/{test_is_pullout_directions_single_mold_translational.cpp => test_is_pullout_directions_single_mold_translational_casting.cpp} (92%) rename Set_movable_separability_2/test/Set_movable_separability_2/{test_single_mold_translational_casting.cmd => test_top_edges_single_mold_translational_casting.cmd} (100%) rename Set_movable_separability_2/test/Set_movable_separability_2/{test_single_mold_translational_casting.cpp => test_top_edges_single_mold_translational_casting.cpp} (95%) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h similarity index 71% rename from Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h rename to Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h index cf8b833c94f..839bf7b7f98 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h @@ -2,7 +2,7 @@ namespace CGAL { namespace Set_movable_separability_2 { namespace Single_mold_translational_casting { -/*! \ingroup PkgSetMovableSeparability2Funcs +/*! \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 @@ -14,44 +14,44 @@ namespace Single_mold_translational_casting { * 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 inspected direction. - * \param[in] traits the traits to use. - * \return if `pgn` can be pullout in the `d` direction the iterator of the - * corresponding top edge, otherwise, `pgn.edges_end()`. + * \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 `png` must be non-degenerate (has at least 3 vertices), simple, and * does not have three consecutive collinear vertices. */ template typename CGAL::Polygon_2::Edge_const_iterator -is_pullout_direction(const CGAL::Polygon_2& pgn, +is_pullout_direction(const CGAL::Polygon_2& polygon, const typename CastingTraits_2::Direction_2& d, const CastingTraits_2& traits = CastingTraits_2()); -/*! \ingroup PkgSetMovableSeparability2Funcs +/*! \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[in] pgn the input polygon. - * \param[in] d the inspected direction. - * \param[in] orientation the orientation of `pgn`. - * \param[in] traits the traits to use. - * \return if `pgn` can be pullout in the `d` direction the iterator of the - * corresponding top edge, otherwise, `pgn.edges_end()`. + * \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 `png` must be non-degenerate (has at least 3 vertices), simple, and * does not have three consecutive collinear vertices. */ template typename CGAL::Polygon_2::Edge_const_iterator -is_pullout_direction(const CGAL::Polygon_2& pgn, +is_pullout_direction(const CGAL::Polygon_2& polygon, const typename CastingTraits_2::Direction_2& d, CGAL::Orientation orientation, const CastingTraits_2& traits = CastingTraits_2()); -/*! \ingroup PkgSetMovableSeparability2Funcs +/*! \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 @@ -65,42 +65,42 @@ is_pullout_direction(const CGAL::Polygon_2& pgn, * 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] d the tested direction. - * \param[in] traits the traits to use. - * \return true if `pgn` can be pulled out in the `d` direction with the + * \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 `png` must be non-degenerate (has at least 3 vertices), simple, and * does not have three consecutive collinear vertices. */ template bool is_pullout_direction -(const CGAL::Polygon_2& pgn, +(const CGAL::Polygon_2& polygon, const typename CGAL::Polygon_2::Edge_const_iterator& it, const typename CastingTraits_2::Direction_2& d, const CastingTraits_2& traits = CastingTraits_2()); -/*! \ingroup PkgSetMovableSeparability2Funcs +/*! \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[in] pgn the input polygon. - * \param[in] it an iterator to an edge in pgn. - * \param[in] d the tested direction. - * \param[in] orientation the orientation of `pgn`. - * \param[in] traits the traits to use. - * \return true if `pgn` can be pulled out in the `d` direction with the + * \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 `png` must be non-degenerate (has at least 3 vertices), simple, and * does not have three consecutive collinear vertices. */ template bool is_pullout_direction -(const CGAL::Polygon_2& pgn, +(const CGAL::Polygon_2& polygon, const typename CGAL::Polygon_2::Edge_const_iterator& it, const typename CastingTraits_2::Direction_2& d, CGAL::Orientation orientation, diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h similarity index 85% rename from Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h rename to Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h index 888aa5ff75f..7a1993b447f 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h @@ -2,7 +2,7 @@ namespace CGAL { namespace Set_movable_separability_2 { namespace Single_mold_translational_casting { -/*! \ingroup PkgSetMovableSeparability2Funcs +/*! \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 @@ -15,9 +15,9 @@ namespace Single_mold_translational_casting { * 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] traits the traits to use. + * \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 @@ -31,21 +31,21 @@ template std::pair > pullout_directions -(const CGAL::Polygon_2& pgn, +(const CGAL::Polygon_2& polygon, const typename CGAL::Polygon_2::Edge_const_iterator& it, CastingTraits_2& traits = CastingTraits_2()); -/*! \ingroup PkgSetMovableSeparability2Funcs +/*! \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[in] pgn the input polygon. - * \param[in] it an iterator to an edge in pgn. - * \param[in] orientation the orientation of `pgn`. - * \param[in] traits the traits to use. + * \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 @@ -59,7 +59,7 @@ template std::pair > pullout_directions -(const CGAL::Polygon_2& pgn, +(const CGAL::Polygon_2& polygon, const typename CGAL::Polygon_2::Edge_const_iterator& it, CGAL::Orientation orientation, CastingTraits_2& traits = CastingTraits_2()); diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h similarity index 87% rename from Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h rename to Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h index dc3de291db6..1f26e3634f2 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h @@ -2,7 +2,7 @@ namespace CGAL { namespace Set_movable_separability_2 { namespace Single_mold_translational_casting { -/*! \ingroup PkgSetMovableSeparability2Funcs +/*! \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 @@ -19,47 +19,47 @@ namespace Single_mold_translational_casting { * 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[out] oi the output iterator. Its value type is a pair, where + * \param polygon the input polygon. + * \param oi the output iterator. Its dereference type is a pair, where * (i) the first element in the pair identifies a valid top edge * represented by its index the type of which is convertible to `size_t`, 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 `Kernel::Direction_2`. - * \param[in] traits the traits to use. + * \param traits the traits to use. * \return the past-the-end iterator of the output container. * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and * does not have three consecutive collinear vertices. */ template -OutputIterator top_edges(const CGAL::Polygon_2& pgn, +OutputIterator top_edges(const CGAL::Polygon_2& polygon, OutputIterator oi, CastingTraits_2& traits = CastingTraits_2()); -/*! \ingroup PkgSetMovableSeparability2Funcs +/*! \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[in] pgn the input polygon. - * \param[out] oi the output iterator. Its value type is a pair, where + * \param polygon the input polygon. + * \param oi the output iterator. Its dereference type is a pair, where * (i) the first element in the pair identifies a valid top edge * represented by its index the type of which is convertible to `size_t`, 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 `Kernel::Direction_2`. - * \param[in] orientation the orientation of `pgn`. - * \param[in] traits the traits to use. + * \param orientation the orientation of `polygon`. + * \param traits the traits to use. * \return the past-the-end iterator of the output container. * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and * does not have three consecutive collinear vertices. */ template -OutputIterator top_edges(const CGAL::Polygon_2& pgn, +OutputIterator top_edges(const CGAL::Polygon_2& polygon, OutputIterator oi, CGAL::Orientation orientation, CastingTraits_2& traits = CastingTraits_2()); diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h index a50ecaed2ca..c9fdb077c76 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h @@ -8,8 +8,6 @@ \cgalRefines `DefaultConstructible` \cgalRefines `PolygonTraits_2` - \cgalGeneralizes `Kernel` - \cgalHasModel Any CGAL kernel, e.g., CGAL::Exact_predicates_exact_constructions_kernel. */ @@ -20,18 +18,22 @@ public: /// \name Functor Types /// @{ - //! The direction type. + //! The direction type. Models the concept `Kernel::Direction_2`. typedef unspecified_type Direction_2; - //! models the concept `Kernel::Counterclockwise_in_between_2`. + //! 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; + Counterclockwise_in_between_2 Collinear_2_object() const; /// @} diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt index 9234aad135a..fba230721c4 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt @@ -1,6 +1,26 @@ /// \defgroup PkgSetMovableSeparability2 2D Movable Separability of Sets Reference -/// \defgroup PkgSetMovableSeparability2Funcs Free Functions +/// \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 surface). +/// \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 surface). +/// \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 +/// surface). If the polygon is castable this way, the function +/// computes the closed range of pullout directions. /// \ingroup PkgSetMovableSeparability2 /// \defgroup PkgSetMovableSeparability2Concepts Concepts @@ -28,9 +48,9 @@ This package consists of the implementations of various predicates and operation \cgalClassifedRefPages ## Functions ## -- `CGAL::top_edges_single_mold_translational_casting_2()` -- `CGAL::pullout_directions_single_mold_translational_casting_2()` -- `CGAL::is_pullout_direction_single_mold_translational_casting_2()` +- `CGAL::top_edges()` +- `CGAL::pullout_directions()` +- `CGAL::is_pullout_direction()` ## Concepts ## - `CastingTraits_2` diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/is_pullout_direction_single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/is_pullout_direction_single_mold_translational_casting.cpp index 5f240a6b1ed..4e17dcff030 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/is_pullout_direction_single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/is_pullout_direction_single_mold_translational_casting.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef Kernel::Vector_2 Vector_2; diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/pullout_directions_single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/pullout_directions_single_mold_translational_casting.cpp index fe1ccf4767b..5e7e72adb35 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/pullout_directions_single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/pullout_directions_single_mold_translational_casting.cpp @@ -1,7 +1,7 @@ #include #include -#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp index 1a71977a00a..7d63bfb7f87 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp @@ -3,9 +3,7 @@ #include #include -#include -#include -#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h deleted file mode 100644 index e1630062d22..00000000000 --- a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Circle_arrangment.h +++ /dev/null @@ -1,425 +0,0 @@ -// 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 -// Efi Fogel - -#ifndef CGAL_CIRCLE_ARRANGMENT_CASTING_2_H -#define CGAL_CIRCLE_ARRANGMENT_CASTING_2_H - -#include - -#include -#include - -/* 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 - class Circle_arrangment { - typedef typename Kernel::Direction_2 Point; - typedef std::pair Arc; - typedef typename CGAL::Polygon_2::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_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 struct 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 - void insert_if_legal(const InputIterator cur_it, - InputIterator next_it, - const struct 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-----? - struct 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); - struct 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-~-? - struct 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); - struct 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-~-~-~? - struct 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----? - struct 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 > foreach valid top edge. - * Should only be called after all of the polygon edges where inserted. - */ - template - 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; - 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; } - }; - - } // end of namespace internal - } // end of namespace Set_movable_separability_2 -} // end of namespace CGAL - -#endif diff --git a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h old mode 100755 new mode 100644 similarity index 68% rename from Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h rename to Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h index 04b17d926cf..ca26da9235f --- a/Set_movable_separability_2/include/CGAL/is_pullout_direction_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h @@ -22,8 +22,8 @@ #include #include -#include -#include +#include +#include namespace CGAL { namespace Set_movable_separability_2 { @@ -40,7 +40,8 @@ namespace Single_mold_translational_casting { * a model of the concept `CastingTraits_2`. * * \param[in] pgn the input polygon. - * \param[in] i the index of an edge in pgn. + * \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 * @@ -51,20 +52,19 @@ template bool is_pullout_direction (const CGAL::Polygon_2& pgn, const typename CGAL::Polygon_2::Edge_const_iterator& i, - const typename CastingTraits_2::Direction_2& d, CastingTraits_2& traits) + 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)); + CGAL_precondition(!internal::is_any_edge_colinear(pgn, traits)); auto e_it = pgn.edges_begin(); - CGAL::Orientation poly_orientation = pgn.orientation(); 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(*e_it, - poly_orientation); + internal::get_segment_outer_circle(*e_it, orientation); bool isordered = !cc_in_between(d, segment_outer_circle.second, segment_outer_circle.first); if (isordered == (e_it == i)) return false; @@ -73,7 +73,19 @@ bool is_pullout_direction return true; } -/*! +/*! Same as above without the traits argument. + */ +template +bool is_pullout_direction +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_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 bool is_pullout_direction @@ -81,8 +93,21 @@ bool is_pullout_direction const typename CGAL::Polygon_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, traits); + return is_pullout_direction(pgn, i, d, orientation, traits); +} + +/*! Same as above without the orientation argument. + */ +template +bool is_pullout_direction +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_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) @@ -107,26 +132,23 @@ template typename CGAL::Polygon_2::Edge_const_iterator is_pullout_direction(const CGAL::Polygon_2& pgn, typename CastingTraits_2::Direction_2& d, - CastingTraits_2& traits) + CGAL::Orientation orientation, CastingTraits_2& traits) { //NOT CHECKED AT ALL typedef CGAL::Polygon_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)); + CGAL_precondition(!internal::is_any_edge_colinear(pgn, traits)); Edge_iter e_it = pgn.edges_begin(); - CGAL::Orientation poly_orientation = pgn.orientation(); auto segment_outer_circle = - internal::get_segment_outer_circle(*e_it++, - poly_orientation); + internal::get_segment_outer_circle(*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(*e_it, - poly_orientation); + internal::get_segment_outer_circle(*e_it, orientation); bool isordered = !cc_in_between(d, segment_outer_circle.second, segment_outer_circle.first); @@ -141,15 +163,40 @@ is_pullout_direction(const CGAL::Polygon_2& pgn, return top_edge; } -/*! +/*! Same as above without the traits argument. + */ +template +typename CGAL::Polygon_2::Edge_const_iterator +is_pullout_direction(const CGAL::Polygon_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 CGAL::Polygon_2::Edge_const_iterator +is_pullout_direction(const CGAL::Polygon_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 CGAL::Polygon_2::Edge_const_iterator is_pullout_direction(const CGAL::Polygon_2& pgn, typename CastingTraits_2::Direction_2& d) { + CGAL::Orientation orientation = pgn.orientation(); CastingTraits_2 traits; - return is_pullout_direction(pgn, d, traits); + return is_pullout_direction(pgn, d, orientation, traits); } } // namespace Single_mold_translational_casting diff --git a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h old mode 100755 new mode 100644 similarity index 85% rename from Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h rename to Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h index 0f9739757f7..1ab7f599913 --- a/Set_movable_separability_2/include/CGAL/pullout_directions_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h @@ -19,8 +19,8 @@ #define CGAL_SMS_2_PULLOUT_DIRECTIONS_SINGLE_MOLD_TRANSLATIONAL_CASTING_H #include -#include -#include +#include +#include namespace CGAL { namespace Set_movable_separability_2 { @@ -71,12 +71,12 @@ std::pair& pgn, const typename CGAL::Polygon_2::Edge_const_iterator& i, + CGAL::Orientation orientation, CastingTraits_2& traits) { CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!internal::is_any_edge_colinear(pgn)); + CGAL_precondition(!internal::is_any_edge_colinear(pgn, traits)); CGAL_precondition(pgn.edges_end()!=i); - CGAL::Orientation poly_orientation = pgn.orientation(); typedef CastingTraits_2 Casting_traits_2; //the returned range is [clock_first, clock_second] @@ -84,7 +84,7 @@ pullout_directions auto segment_outer_circle = - internal::get_segment_outer_circle(*i, poly_orientation); + internal::get_segment_outer_circle(*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 @@ -98,8 +98,7 @@ pullout_directions if (e_it==i) continue; // std::cout << "f " << clock_first << " s " << clock_second << std::endl; auto segment_outer_circle = - internal::get_segment_outer_circle(*e_it, - poly_orientation); + internal::get_segment_outer_circle(*e_it, orientation); // std::cout << "a "<< segment_outer_circle.second << " b " // << segment_outer_circle.first< > pullout_directions (const CGAL::Polygon_2& pgn, - const typename CGAL::Polygon_2::Edge_const_iterator& i) + const typename CGAL::Polygon_2::Edge_const_iterator& it, + CGAL::Orientation orientation) { CastingTraits_2 traits; - return pullout_directions(pgn, i, traits); + return pullout_directions(pgn, it, orientation, traits); +} + +/*! Same as above with the orientation argument. + */ +template +std::pair > +pullout_directions +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_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 +std::pair > +pullout_directions +(const CGAL::Polygon_2& pgn, + const typename CGAL::Polygon_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 diff --git a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h old mode 100755 new mode 100644 similarity index 59% rename from Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h rename to Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h index c83f6c74987..64786c499c9 --- a/Set_movable_separability_2/include/CGAL/top_edges_single_mold_translational_casting_2.h +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h @@ -23,8 +23,8 @@ #include #include -#include -#include +#include +#include namespace CGAL { namespace Set_movable_separability_2 { @@ -42,6 +42,62 @@ namespace Single_mold_translational_casting { * 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[in] pgn the input polygon. + * \param[out] oi the output iterator. Its value type is a pair, where + * (i) the first element in the pair identifies a valid top edge + * represented by its index the type of which is convertible to + `size_t`, 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 `Kernel::Direction_2`. + * \param[in] orientation the orientation of `pgn`. + * \param[in] traits the traits to use. + * \return the past-the-end iterator of the output container. + * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and + * does not have three consecutive collinear vertices. + */ +template +OutputIterator top_edges(const CGAL::Polygon_2& pgn, + 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(pgn.is_simple()); + CGAL_precondition(!internal::is_any_edge_colinear(pgn, traits)); + + auto e_it = pgn.edges_begin(); + auto segment_outer_circle = + internal::get_segment_outer_circle(*e_it++, orientation); + typedef internal::Circle_arrangment Circle_arrangment; + Circle_arrangment circle_arrangment(traits, + segment_outer_circle,pgn.edges_begin()); + + for (; e_it != pgn.edges_end(); ++e_it) { + segment_outer_circle = + internal::get_segment_outer_circle(*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& pgn, * OutputIterator oi, * CastingTraits_2& traits) @@ -56,34 +112,25 @@ template OutputIterator top_edges(const CGAL::Polygon_2& pgn, OutputIterator oi, 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::Orientation orientation = pgn.orientation(); + return top_edges(pgn, oi, orientation, traits); +} - CGAL_precondition(pgn.is_simple()); - CGAL_precondition(!internal::is_any_edge_colinear(pgn)); - - auto e_it = pgn.edges_begin(); - CGAL::Orientation poly_orientation = pgn.orientation(); - auto segment_outer_circle = - internal::get_segment_outer_circle(*e_it++, poly_orientation); - typedef internal::Circle_arrangment Circle_arrangment; - Circle_arrangment circle_arrangment(traits, - segment_outer_circle,pgn.edges_begin()); - - for (; e_it != pgn.edges_end(); ++e_it) { - segment_outer_circle = - internal::get_segment_outer_circle(*e_it, poly_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& pgn, + * OutputIterator oi) + * \param[in] pgn the input polygon that we want to check if is castable or not. + * \param[in,out] oi the output iterator to put the top edges in + * \param[in] orientation the orientation of `pgn`. + * \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 +OutputIterator top_edges(const CGAL::Polygon_2& pgn, + OutputIterator oi, CGAL::Orientation orientation) +{ + CastingTraits_2 traits; + return top_edges(pgn, oi, orientation, traits); } /*! \fn OutputIterator top_edges(const CGAL::Polygon_2& pgn, @@ -98,8 +145,9 @@ template OutputIterator top_edges(const CGAL::Polygon_2& pgn, OutputIterator oi) { + CGAL::Orientation orientation = pgn.orientation(); CastingTraits_2 traits; - return top_edges(pgn, oi, traits); + return top_edges(pgn, oi, orientation, traits); } } // namespace Single_mold_translational_casting diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h deleted file mode 100644 index 4e6db070964..00000000000 --- a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/Utils.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * utils.h - * - * Created on: Jan 17, 2017 - * Author: root - */ - -#ifndef SET_MOVABLE_SEPARABILITY_2_INCLUDE_CGAL_SET_MOVABLE_SEPARABILITY_2_UTILS_H_ -#define SET_MOVABLE_SEPARABILITY_2_INCLUDE_CGAL_SET_MOVABLE_SEPARABILITY_2_UTILS_H_ -#include -#include - - -namespace CGAL { - namespace Set_movable_separability_2 { - namespace internal { - - /*! \fn std::pair 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 - inline std::pair - 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::Orientation::CLOCKWISE) ? - std::make_pair(backward, forward) : std::make_pair(forward, backward); - } - - template - bool is_any_edge_colinear(const CGAL::Polygon_2& pgn) - { - typedef typename CGAL::Point_2 Point_2; - typedef typename CGAL::Polygon_2 Polygon_2; - typedef typename Polygon_2::Vertex_const_iterator Vertex_const_iterator; - 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 (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; - } - vci = pgn.vertices_begin(); - firstVar = secondVar; - secondVar = thirdVar; - thirdVar = *(vci++); - if(CGAL::collinear(firstVar, secondVar, thirdVar)) return true; - - firstVar = secondVar; - secondVar = thirdVar; - thirdVar = *(vci++); - if (CGAL::collinear(firstVar, secondVar, thirdVar)) return true; - - return false; - } - } // end of namespace internal - } // end of namespace Set_movable_separability_2 -} // end of namespace CGAL - - - -#endif /* SET_MOVABLE_SEPARABILITY_2_INCLUDE_CGAL_SET_MOVABLE_SEPARABILITY_2_UTILS_H_ */ diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Circle_arrangment.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Circle_arrangment.h new file mode 100644 index 00000000000..3858c36ee63 --- /dev/null +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Circle_arrangment.h @@ -0,0 +1,425 @@ +// 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 +// Efi Fogel + +#ifndef CGAL_SET_MOVABLE_SEPARABILITY_2_INTERNAL_CIRCLE_ARRANGMENT_H +#define CGAL_SET_MOVABLE_SEPARABILITY_2_INTERNAL_CIRCLE_ARRANGMENT_H + +#include + +#include +#include + +/* 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 +class Circle_arrangment { + typedef typename Kernel::Direction_2 Point; + typedef std::pair Arc; + typedef typename CGAL::Polygon_2::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_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 struct 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 + void insert_if_legal(const InputIterator cur_it, + InputIterator next_it, + const struct 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-----? + struct 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); + struct 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-~-? + struct 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); + struct 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-~-~-~? + struct 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----? + struct 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 > foreach valid top edge. + * Should only be called after all of the polygon edges where inserted. + */ + template + 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; + 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 diff --git a/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Utils.h b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Utils.h new file mode 100644 index 00000000000..72981ef9342 --- /dev/null +++ b/Set_movable_separability_2/include/CGAL/Set_movable_separability_2/internal/Utils.h @@ -0,0 +1,80 @@ +// 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 +// Efi Fogel + +#ifndef CGAL_SET_MOVABLE_SEPARABILITY_2_INTERNAL_UTILS_H +#define CGAL_SET_MOVABLE_SEPARABILITY_2_INTERNAL_UTILS_H + +#include +#include + +namespace CGAL { +namespace Set_movable_separability_2 { +namespace internal { + +/*! \fn std::pair 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 +inline std::pair +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::Orientation::CLOCKWISE) ? + std::make_pair(backward, forward) : std::make_pair(forward, backward); +} + +template +bool is_any_edge_colinear(const CGAL::Polygon_2& pgn, Kernel& kernel) +{ + typedef typename Kernel::Point_2 Point_2; + typedef typename CGAL::Polygon_2 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 diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/CMakeLists.txt b/Set_movable_separability_2/test/Set_movable_separability_2/CMakeLists.txt index 517603b4032..4e2b1434c1a 100644 --- a/Set_movable_separability_2/test/Set_movable_separability_2/CMakeLists.txt +++ b/Set_movable_separability_2/test/Set_movable_separability_2/CMakeLists.txt @@ -20,8 +20,8 @@ if ( CGAL_FOUND ) add_definitions(-std=c++11) endif() -create_single_source_cgal_program( "test_single_mold_translational_casting.cpp" ) -create_single_source_cgal_program( "test_is_pullout_directions_single_mold_translational.cpp" ) +create_single_source_cgal_program( "test_top_edges_single_mold_translational_casting.cpp" ) +create_single_source_cgal_program( "test_is_pullout_directions_single_mold_translational_casting.cpp" ) else() diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake b/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake index e87666205f6..b0975287638 100755 --- a/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake +++ b/Set_movable_separability_2/test/Set_movable_separability_2/cgal_test_with_cmake @@ -96,11 +96,14 @@ if [ $# -ne 0 ] ; then done else echo "Run all tests." -if ${MAKE_CMD} -f Makefile help | grep -E "test_single_mold_translational_casting$" > /dev/null; then - compile_and_run test_single_mold_translational_casting - compile_and_run test_is_pullout_directions_single_mold_translational - NEED_CLEAN=y -fi + if ${MAKE_CMD} -f Makefile help | grep -E "test_top_edges_single_mold_translational_casting$" > /dev/null; then + compile_and_run test_top_edges_single_mold_translational_casting + NEED_CLEAN=y + fi + if ${MAKE_CMD} -f Makefile help | grep -E "test_is_pullout_directions_single_mold_translational_casting$" > /dev/null; then + compile_and_run test_is_pullout_directions_single_mold_translational_casting + NEED_CLEAN=y + fi fi # diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cmd b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational_casting.cmd similarity index 100% rename from Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cmd rename to Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational_casting.cmd diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational_casting.cpp similarity index 92% rename from Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp rename to Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational_casting.cpp index 1a58bfaba27..eda7e9fe773 100644 --- a/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational.cpp +++ b/Set_movable_separability_2/test/Set_movable_separability_2/test_is_pullout_directions_single_mold_translational_casting.cpp @@ -8,8 +8,8 @@ #include #include -#include -#include +#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cmd b/Set_movable_separability_2/test/Set_movable_separability_2/test_top_edges_single_mold_translational_casting.cmd similarity index 100% rename from Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cmd rename to Set_movable_separability_2/test/Set_movable_separability_2/test_top_edges_single_mold_translational_casting.cmd diff --git a/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp b/Set_movable_separability_2/test/Set_movable_separability_2/test_top_edges_single_mold_translational_casting.cpp similarity index 95% rename from Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp rename to Set_movable_separability_2/test/Set_movable_separability_2/test_top_edges_single_mold_translational_casting.cpp index 78b16758bc3..dc57cafa13a 100644 --- a/Set_movable_separability_2/test/Set_movable_separability_2/test_single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/test/Set_movable_separability_2/test_top_edges_single_mold_translational_casting.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; typedef CGAL::Polygon_2 Polygon_2; @@ -21,6 +21,7 @@ typedef Polygon_2::Edge_const_iterator Edge_iter; typedef std::pair 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) @@ -47,7 +48,7 @@ bool test_one_file(std::ifstream& inp) // std::cout << pgn << std::endl; std::vector top_edges; - SMS::top_edges_single_mold_translational_casting_2(pgn, std::back_inserter(top_edges)); + casting::top_edges(pgn, std::back_inserter(top_edges)); size_t exp_num_top_edges; inp >> exp_num_top_edges; From 206256910ecb1dabd02b221bcfb319cea43775ea Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Mon, 3 Jul 2017 21:35:53 +0300 Subject: [PATCH 58/90] Fixed typo --- .../doc/Set_movable_separability_2/Concepts/CastingTraits_2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h index c9fdb077c76..c76f0103073 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h @@ -33,7 +33,7 @@ public: /// @{ Counterclockwise_in_between_2 counterclockwise_in_between_2_object() const; - Counterclockwise_in_between_2 Collinear_2_object() const; + Collinear_2 collinear_2_object() const; /// @} From 83995705646e7841c69fc7a5fe41f28ee2c75ea0 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Mon, 3 Jul 2017 21:36:51 +0300 Subject: [PATCH 59/90] Fixed typo --- .../doc/Set_movable_separability_2/Concepts/CastingTraits_2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h index c76f0103073..9cdbd050278 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h @@ -37,4 +37,4 @@ public: /// @} -}; /* end GpsTraitsGeneralPolygon_2 */ +}; From eee965dcd673e6ab0db2f94fefc222815c7447ae Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 4 Jul 2017 12:07:56 +0300 Subject: [PATCH 60/90] Added namespace to functions --- .../doc/Set_movable_separability_2/PackageDescription.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt index fba230721c4..b42da56f23e 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt @@ -48,9 +48,9 @@ This package consists of the implementations of various predicates and operation \cgalClassifedRefPages ## Functions ## -- `CGAL::top_edges()` -- `CGAL::pullout_directions()` -- `CGAL::is_pullout_direction()` +- `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()` ## Concepts ## - `CastingTraits_2` From fb533f473355c5b83ece4b5c4f2b683bd1222350 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 4 Jul 2017 12:14:25 +0300 Subject: [PATCH 61/90] Fixed bib and version --- .../doc/Set_movable_separability_2/PackageDescription.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt index b42da56f23e..ccf63304ac7 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt @@ -36,9 +36,9 @@ \cgalPkgManuals{Chapter_SetMovableSeparability2,PkgSetMovableSeparability2} \cgalPkgSummaryEnd \cgalPkgShortInfoBegin -\cgalPkgSince{4.10} +\cgalPkgSince{4.11} \cgalPkgDependsOn{\ref PkgPolygon2Summary} -\cgalPkgBib{cgal:sf-casting2} +\cgalPkgBib{cgal:sf-sms2} \cgalPkgLicense{\ref licensesGPL "GPL"} \cgalPkgShortInfoEnd \cgalPkgDescriptionEnd @@ -47,7 +47,7 @@ This package consists of the implementations of various predicates and operation \cgalClassifedRefPages -## Functions ## +## 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()` From 733d3fa34c22c22767d306aa7ae29685194c4238 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Tue, 4 Jul 2017 12:16:45 +0300 Subject: [PATCH 62/90] Fixed Title --- .../doc/Set_movable_separability_2/PackageDescription.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt index ccf63304ac7..2f376221674 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt @@ -52,7 +52,7 @@ This package consists of the implementations of various predicates and operation - `CGAL::Set_movable_separability_2::Single_mold_translational_casting::pullout_directions()` - `CGAL::Set_movable_separability_2::Single_mold_translational_casting::is_pullout_direction()` -## Concepts ## +## Casting Concepts ## - `CastingTraits_2` */ From fd8809f31d685f18b01701ab50f48897f7578938 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Sun, 9 Jul 2017 21:51:09 +0300 Subject: [PATCH 63/90] Fixed spelling mistakes --- .../Set_movable_separability_2.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index bb5426f1ba4..e34c587f357 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -70,10 +70,10 @@ right. 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 consecuitive three vertices cannot be -linear. If you suspect that the input polygon may not satisfy the +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. From ecba36658ab19c57c6e02f64471fe64d6977e67c Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Sun, 9 Jul 2017 21:51:47 +0300 Subject: [PATCH 64/90] Aplit Functor Types to Types and Functor types --- .../Set_movable_separability_2/Concepts/CastingTraits_2.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h index 9cdbd050278..f67bf8ba17b 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Concepts/CastingTraits_2.h @@ -15,12 +15,17 @@ class CastingTraits_2 { public: - /// \name Functor Types + /// \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; From f1804075a30542e5ff2d37acf4384abd83ebdcc5 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Sun, 9 Jul 2017 21:53:20 +0300 Subject: [PATCH 65/90] Replaced png with polygon and rephrased the precondition --- .../is_pullout_direction.h | 16 ++++++++-------- .../pullout_directions.h | 8 ++++---- .../top_edges.h | 8 ++++---- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h index 839bf7b7f98..0a2926ff5c1 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/is_pullout_direction.h @@ -19,8 +19,8 @@ namespace Single_mold_translational_casting { * \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 `png` must be non-degenerate (has at least 3 vertices), simple, and - * does not have three consecutive collinear vertices. + * \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple, + * and it does not have three consecutive collinear vertices. */ template typename CGAL::Polygon_2::Edge_const_iterator @@ -41,8 +41,8 @@ is_pullout_direction(const CGAL::Polygon_2& 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 `png` must be non-degenerate (has at least 3 vertices), simple, and - * does not have three consecutive collinear vertices. + * \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple, + * and it does not have three consecutive collinear vertices. */ template typename CGAL::Polygon_2::Edge_const_iterator @@ -71,8 +71,8 @@ is_pullout_direction(const CGAL::Polygon_2& 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 `png` must be non-degenerate (has at least 3 vertices), simple, and - * does not have three consecutive collinear vertices. + * \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple, + * and it does not have three consecutive collinear vertices. */ template bool is_pullout_direction @@ -95,8 +95,8 @@ bool is_pullout_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 `png` must be non-degenerate (has at least 3 vertices), simple, and - * does not have three consecutive collinear vertices. + * \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple, + * and it does not have three consecutive collinear vertices. */ template bool is_pullout_direction diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h index 7a1993b447f..756c3585de1 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/pullout_directions.h @@ -24,8 +24,8 @@ namespace Single_mold_translational_casting { * of the extreme directions in the range. If the input edge is not * a valid top edge, the range is nondeterministic. * - * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and - * does not have three consecutive collinear vertices. + * \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple, + * and it does not have three consecutive collinear vertices. */ template std::pair std::pair OutputIterator top_edges(const CGAL::Polygon_2& polygon, @@ -55,8 +55,8 @@ OutputIterator top_edges(const CGAL::Polygon_2& polygon, * \param orientation the orientation of `polygon`. * \param traits the traits to use. * \return the past-the-end iterator of the output container. - * \pre `png` must be non-degenerate (has at least 3 vertices), simple, and - * does not have three consecutive collinear vertices. + * \pre `polygon` must be non-degenerate (has at least 3 vertices) and simple, + * and it does not have three consecutive collinear vertices. */ template OutputIterator top_edges(const CGAL::Polygon_2& polygon, From 3aaabfbf07cc92e32d636ceb774e8e4563aedcdc Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Mon, 10 Jul 2017 01:54:14 +0300 Subject: [PATCH 66/90] Enhanced based on Eric's comments --- .../top_edges.h | 14 +++---- .../PackageDescription.txt | 8 +++- .../Set_movable_separability_2.txt | 41 ++++++++++--------- ...dges_single_mold_translational_casting.cpp | 9 ++-- 4 files changed, 39 insertions(+), 33 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h index 085a8019ae8..116e6dfd302 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/CGAL/Set_movable_separability_2/Single_mold_translational_casting/top_edges.h @@ -10,11 +10,11 @@ namespace Single_mold_translational_casting { * colliding into the mold (but possibly sliding along the mold surface). If the * polygon is castable, 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 \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. + * \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`. @@ -26,7 +26,7 @@ namespace Single_mold_translational_casting { `size_t`, 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 `Kernel::Direction_2`. + * 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, @@ -51,7 +51,7 @@ OutputIterator top_edges(const CGAL::Polygon_2& polygon, `size_t`, 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 `Kernel::Direction_2`. + * 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. diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt index 2f376221674..bc453aa8338 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/PackageDescription.txt @@ -32,7 +32,11 @@ \cgalPkgPicture{Casting_2.png} \cgalPkgSummaryBegin \cgalPkgAuthors{Shahar Shamai, Efi Fogel} -\cgalPkgDesc{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 be used to compute all possible orientations of the feasible molds and the corresponding motions needed to remove the casted object from the mold.} +\cgalPkgDesc{Movable Separability of Sets \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 @@ -43,7 +47,7 @@ \cgalPkgShortInfoEnd \cgalPkgDescriptionEnd -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. +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 diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index e34c587f357..88e56605642 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -41,25 +41,28 @@ polygon, and considers a single translation of the moving polygon. Casting is a manufacturing process where liquid material is poured into a cavity inside a mold, which has the shape of a desired -product. 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. +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 -`top_edges_single_mold_translational_casting_2()` that, given a simple -closed polygon \f$P\f$, it 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 surface); see -\cgalFigureRef{sms_2_fig_polygons} for an illustration. In reality, -the mold of a castable polygon must be rotated before the -polygon is casted, such that one edge becomes parallel to the -\f$y\f$-axis and is located above all other edges; such an edge is -referred to as a top edge. A polygon may have up to 4 top -edges. If the polygon is castable, the function computes the -set of top edges of such cavities and the corresponding closed ranges -of pullout directions in the plane. +`CGAL::Set_movable_separability_2::Single_mold_translational_casting::top_edges()` +that, given a simple closed polygon \f$P\f$, it 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 +surface); see \cgalFigureRef{sms_2_fig_polygons} for an +illustration. In reality, the mold of a castable 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 top edge. A polygon may have +up to four edges that can serve as top edges. If the polygon is +castable, 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 @@ -81,7 +84,7 @@ 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 are adviced to use a kernel that guarantees exact +correctness you must use a kernel that guarantees exact constructions as well as exact predicates, e,g,. `Exact_predicates_exact_constructions_kernel`. @@ -99,7 +102,7 @@ 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 of some top edge +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$. diff --git a/Set_movable_separability_2/examples/Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp b/Set_movable_separability_2/examples/Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp index 7d63bfb7f87..39df6bdc720 100644 --- a/Set_movable_separability_2/examples/Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp +++ b/Set_movable_separability_2/examples/Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp @@ -38,7 +38,7 @@ int main(int argc, char* argv[]) std::list top_edges; - //example for top_edges_single_mold_translational_casting_2 + // 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; @@ -46,13 +46,12 @@ int main(int argc, char* argv[]) 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 + << "\tEdge: " << *top_edge.first<< std::endl + << "\tPullout directions from: " << top_edge.second.first << " to " << top_edge.second.second - << std::endl<< std::endl; + << std::endl << std::endl; } } - std::cout << "-----------------------------------"<< std::endl; return 0; } From 82ae67eaae57c262e437731c1ea533b9c88c7e85 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Mon, 10 Jul 2017 02:15:17 +0300 Subject: [PATCH 67/90] Enhanced the overload description --- .../Set_movable_separability_2.txt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index 88e56605642..4c51ce6167b 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -95,20 +95,22 @@ directions of an input polygon read from a file and reports the results. \cgalExample{Set_movable_separability_2/top_edges_single_mold_translational_casting.cpp} This package provides two additional functions, namely, -`pullout_directions_single_mold_translational_casting_2()` and -`is_pullout_direction_single_mold_translational_casting_2()`. 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 +`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 +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$. -An overload of each of the functions above that accepts an -additional traits argument is also provided by the package. +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. */ From 3662e61ce2f95f9f8cfff69148bccea63c6c3bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 10 Jul 2017 08:32:04 +0200 Subject: [PATCH 68/90] tiny fixes in the user manual --- .../Set_movable_separability_2.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt index 4c51ce6167b..d996c8b33a0 100644 --- a/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt +++ b/Set_movable_separability_2/doc/Set_movable_separability_2/Set_movable_separability_2.txt @@ -41,8 +41,8 @@ polygon, and considers a single translation of the moving polygon. 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 (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 @@ -50,7 +50,7 @@ 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$, it determines whether a +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 From 4eeea35800003087b8568508df16fecba2943659 Mon Sep 17 00:00:00 2001 From: Efi Fogel Date: Thu, 13 Jul 2017 15:53:19 +0300 Subject: [PATCH 69/90] Added a new item to release 4.11: 2D Movable Separability of Sets --- Installation/changes.html | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Installation/changes.html b/Installation/changes.html index bd49e80a74a..0007996ed1f 100644 --- a/Installation/changes.html +++ b/Installation/changes.html @@ -134,6 +134,13 @@ and src/ directories).

Release date: April 2018

+

2D Movable Separability of Sets

+
    +
  • 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> + +

    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.

    +
  • +
@@ -555,7 +562,7 @@ and src/ directories). All models of the Kernel concept now provide the functor Compare_slope_3, and the free function compare_slope() is available. -
  • Add an operator in CGAL Kernel concept Angle_3 to qualify the angle +
  • Add an operator in CGAL Kernel concept Angle_3 to qualify the angle between the normal of the triangle given by three points, and a vector.
  • @@ -699,7 +706,7 @@ and src/ directories). all of its descriptors. - +

    Cone Based Spanners