From c4ef2c709eb93807e77f288289e256e8ee1bbadf Mon Sep 17 00:00:00 2001 From: Fernando Cacciola Date: Tue, 27 Jul 2010 15:51:36 +0000 Subject: [PATCH] Added drawing helpers for unbounded bisectors --- .../Create_partial_straight_skeleton_2.cpp | 2 +- .../Create_straight_skeleton_2.cpp | 3 +- .../Create_weighted_straight_skeleton_2.cpp | 4 +- .../Show_offset_polygon.cpp | 2 +- .../Show_straight_skeleton.cpp | 7 +- .../Straight_skeleton_2/dump_to_eps.h | 180 ++++++++++++------ .../Straight_skeleton_aux.h | 50 +++++ 7 files changed, 183 insertions(+), 65 deletions(-) diff --git a/Straight_skeleton_2/examples/Straight_skeleton_2/Create_partial_straight_skeleton_2.cpp b/Straight_skeleton_2/examples/Straight_skeleton_2/Create_partial_straight_skeleton_2.cpp index a04630bb196..1a600197556 100644 --- a/Straight_skeleton_2/examples/Straight_skeleton_2/Create_partial_straight_skeleton_2.cpp +++ b/Straight_skeleton_2/examples/Straight_skeleton_2/Create_partial_straight_skeleton_2.cpp @@ -27,7 +27,7 @@ int main() SsPtr ss = CGAL::create_interior_straight_skeleton_2(input,lMaxTime); - dump_to_eps(input,*ss,"partial_skeleton.eps"); + dump_ss_to_eps(input,ss,"partial_skeleton.eps"); return 0; diff --git a/Straight_skeleton_2/examples/Straight_skeleton_2/Create_straight_skeleton_2.cpp b/Straight_skeleton_2/examples/Straight_skeleton_2/Create_straight_skeleton_2.cpp index 05b0e0efd12..86fa81fd811 100644 --- a/Straight_skeleton_2/examples/Straight_skeleton_2/Create_straight_skeleton_2.cpp +++ b/Straight_skeleton_2/examples/Straight_skeleton_2/Create_straight_skeleton_2.cpp @@ -33,8 +33,7 @@ int main() // Or you can pass the polygon directly, as below. SsPtr oss = CGAL::create_exterior_straight_skeleton_2(poly); - dump_to_eps(poly,*iss,"interior_skeleton.eps"); - dump_to_eps(poly,*oss,"exterior_skeleton.eps"); + dump_ss_to_eps(poly,iss,oss,"straight_skeleton.eps"); return 0; } diff --git a/Straight_skeleton_2/examples/Straight_skeleton_2/Create_weighted_straight_skeleton_2.cpp b/Straight_skeleton_2/examples/Straight_skeleton_2/Create_weighted_straight_skeleton_2.cpp index dc0326158b8..0393e0a1877 100644 --- a/Straight_skeleton_2/examples/Straight_skeleton_2/Create_weighted_straight_skeleton_2.cpp +++ b/Straight_skeleton_2/examples/Straight_skeleton_2/Create_weighted_straight_skeleton_2.cpp @@ -29,13 +29,13 @@ int main() SsPtr ss0 = CGAL::create_straight_skeleton_2(poly, -1.5); - dump_to_eps(poly,*ss0,"uniform_weights_skeleton.eps"); + dump_ss_to_eps(poly,ss0,"uniform_weights_skeleton.eps"); double weights[] = { -1.0, -1.0, -1.5, -1.0, -0.5, 1.0, 1.5, -1.0 } ; SsPtr ss1 = CGAL::create_straight_skeleton_2(poly.vertices_begin(), poly.vertices_end(), weights, weights+8); - dump_to_eps(poly,*ss1,"mixed_weights_skeleton.eps"); + dump_ss_to_eps(poly,ss1,"mixed_weights_skeleton.eps"); return 0; } diff --git a/Straight_skeleton_2/examples/Straight_skeleton_2/Show_offset_polygon.cpp b/Straight_skeleton_2/examples/Straight_skeleton_2/Show_offset_polygon.cpp index 03615924ffd..0dee835d94b 100644 --- a/Straight_skeleton_2/examples/Straight_skeleton_2/Show_offset_polygon.cpp +++ b/Straight_skeleton_2/examples/Straight_skeleton_2/Show_offset_polygon.cpp @@ -57,7 +57,7 @@ int main( int argc, char* argv[] ) if ( eps ) { std::cerr << "Result: " << eps_name << std::endl ; - dump_to_eps(input,offset_polygons,eps); + dump_offset_to_eps(input,offset_polygons,eps); } else { diff --git a/Straight_skeleton_2/examples/Straight_skeleton_2/Show_straight_skeleton.cpp b/Straight_skeleton_2/examples/Straight_skeleton_2/Show_straight_skeleton.cpp index 7f9ec928ae6..5a20a68f603 100644 --- a/Straight_skeleton_2/examples/Straight_skeleton_2/Show_straight_skeleton.cpp +++ b/Straight_skeleton_2/examples/Straight_skeleton_2/Show_straight_skeleton.cpp @@ -39,8 +39,9 @@ int main( int argc, char* argv[] ) { read_polygon_with_holes(is, input) ; - Straight_skeleton_ptr ss = CGAL::create_interior_straight_skeleton_2(input); - if ( ss ) + Straight_skeleton_ptr inss = CGAL::create_interior_straight_skeleton_2(input); + Straight_skeleton_ptr outss = CGAL::create_exterior_straight_skeleton_2(input); + if ( inss && outss ) { std::string eps_name ; if ( argc > 2 ) @@ -51,7 +52,7 @@ int main( int argc, char* argv[] ) if ( eps ) { std::cerr << "Result: " << eps_name << std::endl ; - dump_to_eps(input,*ss,eps); + dump_ss_to_eps(input,inss,outss,eps); } else { diff --git a/Straight_skeleton_2/examples/Straight_skeleton_2/dump_to_eps.h b/Straight_skeleton_2/examples/Straight_skeleton_2/dump_to_eps.h index e0b35edaeca..c7015ba088c 100644 --- a/Straight_skeleton_2/examples/Straight_skeleton_2/dump_to_eps.h +++ b/Straight_skeleton_2/examples/Straight_skeleton_2/dump_to_eps.h @@ -25,8 +25,9 @@ Bbox_2 bbox_2 ( Polygon_with_holes_2 const& aPolyWH ) } + template -void dump_to_eps( InputIterator aBegin, InputIterator aEnd, char const* aType, double aScale, std::ostream& rOut ) +void dump_poly_to_eps( InputIterator aBegin, InputIterator aEnd, char const* aType, double aScale, std::ostream& rOut ) { InputIterator lLast = aEnd - 1 ; @@ -46,60 +47,84 @@ void dump_to_eps( InputIterator aBegin, InputIterator aEnd, char const* aType, d } } -template -void dump_to_eps( Poly const& aPoly, char const* aType, double aScale, std::ostream& rOut ) +template +void dump_poly_to_eps( CGAL::Polygon_2 const& aPoly, char const* aType, double aScale, std::ostream& rOut ) { - dump_to_eps(aPoly.begin(), aPoly.end(), aType, aScale, rOut); + dump_poly_to_eps(aPoly.vertices_begin(), aPoly.vertices_end(), aType, aScale, rOut); } template -void dump_to_eps( CGAL::Polygon_2 const& aPoly, char const* aType, double aScale, std::ostream& rOut ) +void dump_poly_to_eps( CGAL::Polygon_with_holes_2 const& aPWH, char const* aType, double aScale, std::ostream& rOut ) { - dump_to_eps(aPoly.vertices_begin(), aPoly.vertices_end(), aType, aScale, rOut); -} - -template -void dump_to_eps( CGAL::Polygon_with_holes_2 const& aPWH, char const* aType, double aScale, std::ostream& rOut ) -{ - dump_to_eps(aPWH.outer_boundary(), aType, aScale, rOut ) ; + dump_poly_to_eps(aPWH.outer_boundary(), aType, aScale, rOut ) ; for ( typename CGAL::Polygon_with_holes_2::Hole_const_iterator hit = aPWH.holes_begin() ; hit != aPWH.holes_end() ; ++ hit ) - dump_to_eps(*hit, aType, aScale, rOut ) ; + dump_poly_to_eps(*hit, aType, aScale, rOut ) ; } template -void dump_to_eps( CGAL::Straight_skeleton_2 const& aSkeleton, char const* aType, double aScale, std::ostream& rOut ) +void dump_ss_to_eps( CGAL::Straight_skeleton_2 const& aSkeleton, char const* aType, double aScale, std::ostream& rOut ) { typedef typename CGAL::Straight_skeleton_2::Halfedge_const_iterator Halfedge_const_iterator ; typedef typename CGAL::Straight_skeleton_2::Halfedge_const_handle Halfedge_const_handle ; + typedef typename CGAL::Straight_skeleton_2::Traits Traits ; + + typedef typename Traits::Point_2 Point_2 ; + typedef typename Traits::Vector_2 Vector_2 ; + typedef typename Traits::Segment_2 Segment_2 ; for(Halfedge_const_iterator hit = aSkeleton.halfedges_begin(); hit != aSkeleton.halfedges_end(); ++hit) { Halfedge_const_handle h = hit ; - if( h->is_bisector() && ((h->id()%2)==0) && !h->has_infinite_time() && !h->opposite()->has_infinite_time() ) + if( h->is_bisector() && ((h->id()%2)==0) ) { - rOut << aType << std::endl - << aScale * h->vertex()->point().x() + Point_2 s,t; + + if ( !h->has_infinite_time() && !h->opposite()->has_infinite_time() ) + { + s = h->vertex()->point() ; + t = h->opposite()->vertex()->point(); + } + else + { + Halfedge_const_handle outh = h->has_infinite_time() ? h : h->opposite(); + + Halfedge_const_handle contour_edge_0 = outh ->defining_contour_edge(); + Halfedge_const_handle contour_edge_1 = outh->opposite()->defining_contour_edge(); + + Point_2 const& p0 = contour_edge_0->opposite()->vertex()->point(); + Point_2 const& p1 = contour_edge_0 ->vertex()->point(); + Point_2 const& p2 = contour_edge_1 ->vertex()->point(); + + Vector_2 bisect = CGAL::CGAL_SS_i::ccw_angular_bisector_2(p0, p1, p2); + + s = p1 ; + t = p1 - ( h->weight() > 0 ? bisect : - bisect ) ; + } + + rOut << aType + << std::endl + << aScale * CGAL::to_double(s.x()) << " " - << aScale * h->vertex()->point().y() - << " " - << aScale * h->opposite()->vertex()->point().x() - << " " - << aScale * h->opposite()->vertex()->point().y() + << aScale * CGAL::to_double(s.y()) + << " " + << aScale * CGAL::to_double(t.x()) + << " " + << aScale * CGAL::to_double(t.y()) << " E\n"; } } } template -void dump_to_eps ( Poly const& aInput - , std::vector< boost::shared_ptr > const& aOutput - , std::ostream& rOut - ) +void dump_offset_to_eps( Poly const& aInput + , std::vector< boost::shared_ptr > const& aOutput + , std::ostream& rOut + ) { typedef std::vector< boost::shared_ptr > Poly_vector ; @@ -108,19 +133,32 @@ void dump_to_eps ( Poly const& aInput for( typename Poly_vector::const_iterator it = aOutput.begin() ; it != aOutput.end(); ++ it ) lBbox = lBbox + CGAL::bbox_2(**it); - double lScale = 1000 / (lBbox.xmax() - lBbox.xmin()) ; + double lWidth = (lBbox.xmax() - lBbox.xmin()) ; + double lHeight = (lBbox.ymax() - lBbox.ymin()) ; + + double lSize = (std::max)(lWidth, lHeight); + + double lScale = 1000 / lSize ; + + double lMargin = lSize * 0.05 ; if ( lScale < 1 ) lScale = 1 ; + CGAL::Bbox_2 lViewport(std::floor(lScale * (lBbox.xmin() - lMargin) ) + ,std::floor(lScale * (lBbox.ymin() - lMargin) ) + ,std::ceil (lScale * (lBbox.xmax() + lMargin) ) + ,std::ceil (lScale * (lBbox.ymax() + lMargin) ) + ); + rOut << "%!PS-Adobe-2.0 EPSF-2.0\n%%BoundingBox:" - << static_cast(std::floor(lScale* lBbox.xmin()-1)) + << static_cast(lViewport.xmin()) << " " - << static_cast(std::floor(lScale* lBbox.ymin()-1)) + << static_cast(lViewport.ymin()) << " " - << static_cast(std::ceil(lScale*lBbox.xmax()+1)) + << static_cast(lViewport.xmax()) << " " - << static_cast(std::ceil(lScale*lBbox.ymax()+1)) + << static_cast(lViewport.ymax()) << std::endl; rOut << "%%EndComments\n" @@ -133,36 +171,50 @@ void dump_to_eps ( Poly const& aInput "% stroke - x1 y1 x2 y2 E\n" "/E {newpath moveto lineto stroke} bind def\n\n" ; - dump_to_eps(aInput,"input",lScale,rOut); + dump_poly_to_eps(aInput,"input",lScale,rOut); for( typename Poly_vector::const_iterator it = aOutput.begin() ; it != aOutput.end(); ++ it ) - dump_to_eps(**it,"output",lScale,rOut); + dump_poly_to_eps(**it,"output",lScale,rOut); rOut << "grestore\nshowpage" << std::endl; } template -void dump_to_eps ( Input const& aInput - , CGAL::Straight_skeleton_2 const& aSkeleton - , std::ostream& rOut - ) +void dump_ss_to_eps ( Input const& aInput + , boost::shared_ptr< CGAL::Straight_skeleton_2 > const& aInSkeleton + , boost::shared_ptr< CGAL::Straight_skeleton_2 > const& aOutSkeleton + , std::ostream& rOut + ) { CGAL::Bbox_2 lBbox = CGAL::bbox_2(aInput); - double lScale = 1000 / (lBbox.xmax() - lBbox.xmin()) ; + double lWidth = (lBbox.xmax() - lBbox.xmin()) ; + double lHeight = (lBbox.ymax() - lBbox.ymin()) ; + + double lSize = (std::max)(lWidth, lHeight); + + double lScale = 1000 / lSize ; + + double lMargin = lSize * 0.25 ; if ( lScale < 1 ) lScale = 1 ; + CGAL::Bbox_2 lViewport(std::floor(lScale * (lBbox.xmin() - lMargin) ) + ,std::floor(lScale * (lBbox.ymin() - lMargin) ) + ,std::ceil (lScale * (lBbox.xmax() + lMargin) ) + ,std::ceil (lScale * (lBbox.ymax() + lMargin) ) + ); + rOut << "%!PS-Adobe-2.0 EPSF-2.0\n%%BoundingBox:" - << static_cast(std::floor(lScale* lBbox.xmin()-1)) + << static_cast(lViewport.xmin()) << " " - << static_cast(std::floor(lScale* lBbox.ymin()-1)) + << static_cast(lViewport.ymin()) << " " - << static_cast(std::ceil(lScale*lBbox.xmax()+1)) + << static_cast(lViewport.xmax()) << " " - << static_cast(std::ceil(lScale*lBbox.ymax()+1)) + << static_cast(lViewport.ymax()) << std::endl; rOut << "%%EndComments\n" @@ -170,30 +222,37 @@ void dump_to_eps ( Input const& aInput "1.0 setlinewidth\n" "/input { 1 0 0 setrgbcolor } bind def\n" "/input_w { 0.1 setlinewidth } bind def\n" - "/skeleton { 0 1 0 setrgbcolor } bind def\n" - "/skeleton_w { 0.1 setlinewidth } bind def\n" + "/in_skeleton { 0 1 0 setrgbcolor } bind def\n" + "/in_skeleton_w { 0.1 setlinewidth } bind def\n" + "/out_skeleton { 0 1 0 setrgbcolor } bind def\n" + "/out_skeleton_w { 0.1 setlinewidth } bind def\n" "% stroke - x1 y1 x2 y2 E\n" "/E {newpath moveto lineto stroke} bind def\n\n" ; - dump_to_eps(aInput,"input",lScale,rOut); + dump_poly_to_eps(aInput,"input",lScale,rOut); - dump_to_eps(aSkeleton,"skeleton",lScale,rOut); + if ( aInSkeleton ) + dump_ss_to_eps(*aInSkeleton,"in_skeleton",lScale,rOut); + + if ( aOutSkeleton ) + dump_ss_to_eps(*aOutSkeleton,"out_skeleton",lScale,rOut); rOut << "grestore\nshowpage" << std::endl; } template -void dump_to_eps ( Input const& aInput - , CGAL::Straight_skeleton_2 const& aSkeleton - , std::string aFilename - ) +void dump_ss_to_eps ( Input const& aInput + , boost::shared_ptr< CGAL::Straight_skeleton_2 > const& aInSkeleton + , boost::shared_ptr< CGAL::Straight_skeleton_2 > const& aOutSkeleton + , std::string aFilename + ) { std::ofstream eps(aFilename.c_str()) ; if ( eps ) { std::cerr << "Result: " << aFilename << std::endl ; - dump_to_eps(aInput,aSkeleton,eps); + dump_ss_to_eps(aInput,aInSkeleton,aOutSkeleton,eps); } else { @@ -201,17 +260,26 @@ void dump_to_eps ( Input const& aInput } } +template +void dump_ss_to_eps ( Input const& aInput + , boost::shared_ptr< CGAL::Straight_skeleton_2 > const& aSkeleton + , std::string aFilename + ) +{ + dump_ss_to_eps(aInput, aSkeleton, boost::shared_ptr< CGAL::Straight_skeleton_2 >() , aFilename); +} + template -void dump_to_eps ( Input const& aInput - , Output const& aOutput - , std::string aFilename - ) +void dump_offset_to_eps ( Input const& aInput + , Output const& aOutput + , std::string aFilename + ) { std::ofstream eps(aFilename.c_str()) ; if ( eps ) { std::cerr << "Result: " << aFilename << std::endl ; - dump_to_eps(aInput,aOutput,eps); + dump_offset_to_eps(aInput,aOutput,eps); } else { diff --git a/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_aux.h b/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_aux.h index 5050e7192ab..f0904134af4 100644 --- a/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_aux.h +++ b/Straight_skeleton_2/include/CGAL/Straight_skeleton_2/Straight_skeleton_aux.h @@ -147,6 +147,56 @@ private: Handle mE[3]; } ; +// +// The following functions are only for drawing of unbounded bisectors +// + +template +inline double vector_angle_wrt_X_axis_2( Vector_2 const& v ) { return std::atan2( CGAL::to_double(v.y()), CGAL::to_double(v.x())); } + +template +inline double ccw_angle_between_vectors_2( Vector_2 const& u, Vector_2 const& v ) +{ + double au = vector_angle_wrt_X_axis_2(u); + double av = vector_angle_wrt_X_axis_2(v); + + double phi = av - au ; + + if ( phi < 0) + phi = 2.0 * CGAL_PI + phi; + + return phi ; +} + +template +inline Vector_2 create_vector_rotated_2( Vector_2 const& u, double phi ) +{ + double cos = std::cos(phi); + double sin = std::sin(phi); + + return Vector_2( u.x() * cos - u.y() * sin + , u.x() * sin + u.y() * cos + ) ; +} + +template +typename CGAL::Kernel_traits::Kernel::Vector_2 +ccw_angular_bisector_2( Point_2 const& p0, Point_2 const& p1, Point_2 const& p2 ) +{ + typedef typename CGAL::Kernel_traits::Kernel K ; + + typedef typename K::Segment_2 Segment_2 ; + typedef typename K::Vector_2 Vector_2 ; + + Vector_2 u = p2 - p1 ; + Vector_2 v = p0 - p1 ; + + double sweep = ccw_angle_between_vectors_2(u ,v); + double phi = sweep * 0.5; + + return create_vector_rotated_2(u, phi); +} + } // namespace CGAL_SS_i enum Trisegment_collinearity