// Copyright (c) 2005-2009 INRIA Sophia-Antipolis (France). // All rights reserved. // // This file is part of CGAL (www.cgal.org); you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 3 of the License, // or (at your option) any later version. // // Licensees holding a valid commercial license may use this file in // accordance with the commercial license agreement provided with the software. // // This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE // WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. // // $URL$ // $Id$ // SPDX-License-Identifier: LGPL-3.0+ // // // Author(s) : Sebastien Loriot, Sylvain Pion #ifndef CGAL_IPELET_BASE_H #define CGAL_IPELET_BASE_H // Ipe headers use uint which is not standard. #ifdef __APPLE__ typedef unsigned int uint; #endif #include #include #include #include #include #include #include #include #include #include #include namespace CGAL{ template class Ipelet_base : public Ipelet { private: const std::string* SubLab; const std::string* HMsg; std::string Name; IpePage* _page; IpeletHelper* _helper; public: //typedefs typedef typename Kernel::FT FT; typedef typename CGAL::Point_2 Point_2; typedef typename CGAL::Weighted_point_2 Weighted_point_2; typedef typename Kernel::Segment_2 Segment_2; typedef typename Kernel::Ray_2 Ray_2; typedef typename Kernel::Line_2 Line_2; typedef typename Kernel::Iso_rectangle_2 Iso_rectangle_2; typedef typename Kernel::Triangle_2 Triangle_2; //~ typedef typename CGAL::Polygon_2 > Polygon_2; typedef typename CGAL::Polygon_2 Polygon_2; typedef typename Kernel::Circle_2 Circle_2; typedef CGAL::cpp11::tuple Circular_arc_2; Ipelet_base(const std::string NameS,const std::string SubLabS[],const std::string HMsgS[]) :SubLab(&SubLabS[0]),HMsg(&HMsgS[0]),Name(NameS),_page(NULL),_helper(NULL){}; IpePage* get_IpePage() const {return _page;} IpeletHelper* get_IpeletHelper() const {return _helper;} int IpelibVersion() const { return IPELIB_VERSION; } int NumFunctions() const { return nbf; } virtual const char *Label() const{ return &Name[0]; } const char *About() const {return "https://www.cgal.org";}; virtual const char *SubLabel(int function) const {return &SubLab[function][0];}; virtual const char *HelpMsg(int function) const{return &HMsg[function][0];}; void Run (int i, IpePage *page, IpeletHelper *helper) { _page=page; _helper=helper; try{ protected_run(i); } catch(...){ helper->MessageBox("Error : Save your page in a file and submit it to \n https://www.cgal.org/bug_report.html","OK",NULL,NULL); } }; virtual void protected_run(int)=0; void group_selected_objects_() const { get_IpePage()->Group(get_IpeletHelper()->CurrentLayer()); } void transform_selected_objects_(const IpeMatrix& tfm) const { for (IpePage::iterator it = get_IpePage() -> begin();it!=get_IpePage() -> end(); ++it) if (it->Select()) it->Transform(tfm); } void show_help(bool gen=true) const{ std::string hmsg; hmsg="

"+Name+"

    "; if (gen) for(int i=0;i"+SubLab[i]+": "+HMsg[i]+""; else hmsg=hmsg+"
  • "+HMsg[0]+"
  • "; _helper->MessageBox(&hmsg[0],"OK",NULL,NULL); return; } //grabbers template struct Point_grabber:public internal::Point_grabber{ Point_grabber(output_iterator it):internal::Point_grabber(it){} }; template boost::function_output_iterator > point_grabber(output_iterator it){ return boost::make_function_output_iterator(Point_grabber(it)); } template struct Segment_grabber:public internal::Segment_grabber{ Segment_grabber(output_iterator it):internal::Segment_grabber(it){} }; template boost::function_output_iterator > segment_grabber(output_iterator it){ return boost::make_function_output_iterator(Segment_grabber(it)); } template struct Wpoint_grabber:public internal::Wpoint_grabber{ Wpoint_grabber(output_iterator it):internal::Wpoint_grabber(it){} }; template boost::function_output_iterator > wpoint_grabber(output_iterator it){ return boost::make_function_output_iterator(Wpoint_grabber(it)); } //Interaction functions //------------------------------ void print_error_message(const char* s) const { _helper->Message(s); } template std::pair request_value_from_user(std::string msg) const { IpeString str; std::pair ret_val=std::make_pair(-1,T()); if (_helper-> GetString(msg.c_str(),str)){ if (!str.empty()){ IpeLex lex(str); lex >> ret_val.second; ret_val.first=1; } else ret_val.first=0; } return ret_val; } //Conversion functions //------------------------------ Point_2 segment_endpoint(const IpePathSegment& segment,IpePath* obj_ipe,int i) const { CGAL_precondition(i<2); IpeVector pt_ipe = obj_ipe -> Matrix() * segment.CP(i); return Point_2((double)(pt_ipe.iX),(double)(pt_ipe.iY));//conversion into CGAL point } Point_2 to_point_2(IpeObject* object) const { IpeVector pt_ipe = object-> Matrix() * object-> AsMark() -> Position(); return Point_2((double)(pt_ipe.iX),(double)(pt_ipe.iY));//conversion into CGAL point } Circle_2 to_circle_2(IpePath* obj_ipe,int subpath=0) const { const IpeEllipse* ell_ipe = obj_ipe -> SubPath(subpath) -> AsEllipse(); IpeMatrix mat_ipe = obj_ipe -> Matrix() * ell_ipe -> Matrix(); FT radius = (mat_ipe*IpeVector(1,0)-mat_ipe.Translation()).Len(); IpeVector pt_ipe = mat_ipe.Translation(); return Circle_2(Point_2(pt_ipe.iX,pt_ipe.iY),radius*radius); } //Picking functions //------------------------------ bool is_only_rotated_or_scaled(const IpeMatrix& m) const { return (m.iA[0]==m.iA[3] && m.iA[1]==-m.iA[2]); } bool is_IPE_circle(IpeObject* object,int subpath=0) const { return ( object -> AsPath() && object -> AsPath() -> SubPath(subpath) -> AsEllipse() && is_only_rotated_or_scaled(object ->AsPath()->Matrix())); } private: //declaration template< class multi_output_iterator > bool read_one_active_object( IpeObject* object, multi_output_iterator it_out) const; public: template< class V,class O> Iso_rectangle_2 read_active_objects ( CGAL::Dispatch_or_drop_output_iterator it_out, bool deselect_all=true, bool delete_selected_objects=false) const { IpeRect bbox_ipe; if (!_page->HasSelection()) { return Iso_rectangle_2(); } for(IpePage::iterator it = get_IpePage() -> begin(); it!=get_IpePage() -> end(); ++it){ if ( !it->Select() ) continue; bbox_ipe.AddRect(it->BBox()); //Test one function for segments, circles, circle arcs and polygons bool desel_it=read_one_active_object(it->Object(),it_out); if ( delete_selected_objects && desel_it ) it->SetSelect(IpePgObject::ENone); } if (delete_selected_objects) _page -> Delete(); if (deselect_all) _page->DeselectAll(); Iso_rectangle_2 bbox_cgal( static_cast(bbox_ipe.Min().iX),static_cast(bbox_ipe.Min().iY), static_cast(bbox_ipe.Max().iX),static_cast(bbox_ipe.Max().iY) ); return bbox_cgal; } //drawing functions //------------------------------ void copy_attributes(IpeAllAttributes& AAttr,IpeObject* obj_ipe) const { AAttr.iStroke = obj_ipe -> Stroke(); if (obj_ipe->AsFillable()){ AAttr.iFill = obj_ipe->AsFillable() -> Fill(); AAttr.iLineWidth = obj_ipe->AsFillable() -> LineWidth(); AAttr.iDashStyle = obj_ipe->AsFillable() -> DashStyle(); } if (obj_ipe->AsPath()){ AAttr.iForwardArrow = obj_ipe->AsPath() -> ForwardArrow(); AAttr.iBackwardArrow = obj_ipe->AsPath() -> BackwardArrow(); } } void create_polygon_with_holes(bool delete_underlying_polygons=false) const { std::list SSPqu; for(IpePage::iterator it=get_IpePage()->begin();it!=get_IpePage()->end();++it){ if(it->Select() && it->Object()->AsPath()->SubPath(0)->Closed()){ IpeSubPath* ssp=it->Object()->AsPath()->SubPath(0)->Transform(it->Object()->AsPath()->Matrix()); SSPqu.push_back(ssp); } } if (!delete_underlying_polygons) get_IpePage() -> DeselectAll(); IpePath* obj_ipe = new IpePath(get_IpeletHelper() -> Attributes());// create new objects with current attributes for (std::list::iterator it=SSPqu.begin();it!=SSPqu.end();++it) obj_ipe->AddSubPath(*it); if (delete_underlying_polygons) get_IpePage()->Delete(); get_IpePage()->push_back(IpePgObject(IpePgObject::ESecondary,get_IpeletHelper()->CurrentLayer(),obj_ipe)); } void center_selection_in_page() const { IpeVector paper_size=get_paper_size(); IpeMatrix tfm (1,0,0,1,paper_size.iX/2.,paper_size.iY/2.); for (IpePage::iterator it = get_IpePage()->begin(); it != get_IpePage()->end(); ++it) if (it->Select()) it->Transform(tfm); } template IpeSegmentSubPath* create_polyline(const iterator first, const iterator last,bool setclose=false) const { if (boost::next(first)!=last){ IpeSegmentSubPath* SSP_ipe = new IpeSegmentSubPath(); IpeVector Prev_pt=IpeVector(CGAL::to_double(first->x()),CGAL::to_double(first->y())) ; for (iterator it = boost::next(first);it!=last;++it){ IpeVector Cur_pt=IpeVector(CGAL::to_double(it->x()),CGAL::to_double(it->y())); SSP_ipe -> AppendSegment(Prev_pt,Cur_pt); Prev_pt=Cur_pt; } if (setclose) SSP_ipe->SetClosed(true); return SSP_ipe; } return NULL; } template IpePath* draw_polyline_in_ipe(const iterator first, const iterator last, bool setclose=false,bool deselect_all=false, bool blackfill=false, typename boost::enable_if< boost::is_same< typename std::iterator_traits::value_type, Point_2 > >::type* =NULL) const { IpeSegmentSubPath* SSP_ipe=create_polyline(first,last,setclose); if (SSP_ipe!=NULL){ IpePath* obj_ipe = new IpePath(_helper->Attributes()); obj_ipe->AddSubPath(SSP_ipe); if (blackfill) obj_ipe->SetFill(IpeAttribute::Black()); _page->push_back(IpePgObject(IpePgObject::ESecondary,_helper->CurrentLayer(),obj_ipe)); if (deselect_all) (--_page->end())->SetSelect(IpePgObject::ENone); return obj_ipe; } return NULL; } void draw_in_ipe(const Circle_2& C,bool deselect_all=false) const { IpeEllipse *ellipse = new IpeEllipse(IpeMatrix(sqrt(CGAL::to_double(C.squared_radius())),0, 0,sqrt(CGAL::to_double(C.squared_radius())), to_double(C.center().x()),to_double(C.center().y()) ) ); IpePath *path = new IpePath(_helper->Attributes()); path->AddSubPath(ellipse); _page->push_back(IpePgObject(IpePgObject::EPrimary,_helper->CurrentLayer(), path)); if (deselect_all) (--_page->end())->SetSelect(IpePgObject::ENone); } void draw_in_ipe(const Point_2& P,bool deselect_all=false) const { IpeMark *mark = new IpeMark(_helper->Attributes(), IpeVector(CGAL::to_double(P.x()),CGAL::to_double(P.y()))); _page->push_back(IpePgObject(IpePgObject::ESecondary,_helper->CurrentLayer(),mark)); if (deselect_all) (--_page->end())->SetSelect(IpePgObject::ENone); } void draw_in_ipe(const Segment_2& S,bool deselect_all=false) const { IpeSegment seg_ipe; seg_ipe.iP = IpeVector(CGAL::to_double(S.point(0).x()),CGAL::to_double(S.point(0).y())); seg_ipe.iQ = IpeVector(CGAL::to_double(S.point(1).x()),CGAL::to_double(S.point(1).y())); _page->push_back(IpePgObject(IpePgObject::ESecondary,_helper->CurrentLayer(),new IpePath(_helper->Attributes(),seg_ipe))); if (deselect_all) (--_page->end())->SetSelect(IpePgObject::ENone); } template void draw_in_ipe(const CGAL::Polygon_2& poly,bool deselect_all=false) const { std::list LP; for (typename CGAL::Polygon_2::iterator it=poly.vertices_begin();it!= poly.vertices_end();++it) LP.push_back(*it); draw_polyline_in_ipe(LP.begin(),LP.end(),true,deselect_all,false); } void draw_in_ipe(const Circular_arc_2& arc,bool deselect_all=false) const { IpeSegmentSubPath* SSP_ipe = new IpeSegmentSubPath; IpeVector ipeS=IpeVector( CGAL::to_double(CGAL::cpp11::get<1>(arc).x()), CGAL::to_double(CGAL::cpp11::get<1>(arc).y()));//convert ot ipe format IpeVector ipeT=IpeVector( CGAL::to_double(CGAL::cpp11::get<2>(arc).x()), CGAL::to_double(CGAL::cpp11::get<2>(arc).y()));//convert ot ipe format SSP_ipe->AppendArc(IpeMatrix(sqrt(CGAL::to_double(CGAL::cpp11::get<0>(arc).squared_radius())),0, 0,(CGAL::cpp11::get<3>(arc)==CGAL::COUNTERCLOCKWISE?1:-1)* sqrt(CGAL::to_double(CGAL::cpp11::get<0>(arc).squared_radius())), CGAL::to_double(CGAL::cpp11::get<0>(arc).center().x()), CGAL::to_double(CGAL::cpp11::get<0>(arc).center().y())), ipeS,ipeT); IpePath* obj_ipe = new IpePath(_helper->Attributes()); obj_ipe->AddSubPath(SSP_ipe); _page->push_back(IpePgObject(IpePgObject::ESecondary,_helper->CurrentLayer(),obj_ipe)); if (deselect_all) (--_page->end())->SetSelect(IpePgObject::ENone); } void draw_in_ipe(const Triangle_2& t,bool deselect_all=false) const { IpeSegmentSubPath* SSP_ipe = new IpeSegmentSubPath(); IpeVector P0=IpeVector(t[0].x(),t[0].y()); IpeVector P1=IpeVector(t[1].x(),t[1].y()); IpeVector P2=IpeVector(t[2].x(),t[2].y()); SSP_ipe->AppendSegment(P0,P1); SSP_ipe->AppendSegment(P1,P2); SSP_ipe->AppendSegment(P2,P0); SSP_ipe->SetClosed(true); IpePath* obj_ipe = new IpePath(_helper->Attributes()); obj_ipe->AddSubPath(SSP_ipe); _page->push_back(IpePgObject(IpePgObject::ESecondary,_helper->CurrentLayer(),obj_ipe)); if (deselect_all) (--_page->end())->SetSelect(IpePgObject::ENone); } void draw_in_ipe(const Iso_rectangle_2& r,bool deselect_all=false) { IpeSegmentSubPath* SSP_ipe = new IpeSegmentSubPath(); IpeVector P0=IpeVector(r[0].x(),r[0].y()); IpeVector P1=IpeVector(r[1].x(),r[1].y()); IpeVector P2=IpeVector(r[2].x(),r[2].y()); IpeVector P3=IpeVector(r[3].x(),r[3].y()); SSP_ipe->AppendSegment(P0,P1); SSP_ipe->AppendSegment(P1,P2); SSP_ipe->AppendSegment(P2,P3); SSP_ipe->AppendSegment(P3,P0); SSP_ipe->SetClosed(true); IpePath* obj_ipe = new IpePath(_helper->Attributes()); obj_ipe->AddSubPath(SSP_ipe); _page->push_back(IpePgObject(IpePgObject::ESecondary,_helper->CurrentLayer(),obj_ipe)); if (deselect_all) (--_page->end())->SetSelect(IpePgObject::ENone); } //Drawing function with bbox : global version template void draw_in_ipe(const T& object,const Iso_rectangle_2& bbox,bool deselect_all=false) const { Segment_2 s; bool success=cast_into_seg(object,bbox,&s); if (success) draw_in_ipe(s,deselect_all); } private: enum Type_circ_arc{SRC,TRG,OSRC,OTRG}; public: void draw_in_ipe(const Circular_arc_2& object,const Iso_rectangle_2& bbox,bool deselect_all=false) const { std::vector arc_list; const Circle_2& circle=CGAL::cpp11::get<0>(object); restrict_circle_to_bbox(circle,bbox,std::back_inserter(arc_list)); if (arc_list.empty() && bbox.has_on_bounded_side(circle.center()) ){ draw_in_ipe(object,deselect_all); return; } const Point_2* source=(CGAL::cpp11::get<3>(object)==CGAL::COUNTERCLOCKWISE)? &CGAL::cpp11::get<1>(object):&CGAL::cpp11::get<2>(object); const Point_2* target=(CGAL::cpp11::get<3>(object)==CGAL::COUNTERCLOCKWISE)? &CGAL::cpp11::get<2>(object):&CGAL::cpp11::get<1>(object); std::multimap > map_theta; typedef typename std::multimap >::iterator Map_theta_iterator; Map_theta_iterator s_it=map_theta.insert( std::make_pair(get_theta(*source,circle),std::make_pair(OSRC,source))); /*Map_theta_iterator t_it=*/map_theta.insert( std::make_pair(get_theta(*target,circle),std::make_pair(OTRG,target))); for (typename std::vector::iterator it_arc=arc_list.begin();it_arc!=arc_list.end();++it_arc){ const Point_2* arc_s=(CGAL::cpp11::get<3>(*it_arc)==CGAL::COUNTERCLOCKWISE)? &CGAL::cpp11::get<1>(*it_arc):&CGAL::cpp11::get<2>(*it_arc); const Point_2* arc_t=(CGAL::cpp11::get<3>(*it_arc)==CGAL::COUNTERCLOCKWISE)? &CGAL::cpp11::get<2>(*it_arc):&CGAL::cpp11::get<1>(*it_arc); map_theta.insert( std::make_pair(get_theta(*arc_s,circle),std::make_pair(SRC,arc_s) ) ); map_theta.insert( std::make_pair(get_theta(*arc_t,circle),std::make_pair(TRG,arc_t) ) ); } Map_theta_iterator next_s=s_it; ++next_s; if (next_s==map_theta.end()) next_s=map_theta.begin(); switch (next_s->second.first){ case TRG: draw_in_ipe(Circular_arc_2(circle,*source,*(next_s->second.second),CGAL::COUNTERCLOCKWISE)); break; case OSRC: CGAL_error(); case SRC:{ Map_theta_iterator current=next_s; ++next_s; if (next_s==map_theta.end()) next_s=map_theta.begin(); draw_in_ipe(Circular_arc_2(circle,*(current->second.second),*(next_s->second.second),CGAL::COUNTERCLOCKWISE)); if(next_s->second.first==OTRG) return; break; } case OTRG: ++next_s; if (next_s==map_theta.end()) next_s=map_theta.end(); if (next_s->second.first==TRG){ draw_in_ipe(object); return; } else return; } ++next_s; if (next_s==map_theta.end()) next_s=map_theta.begin(); Map_theta_iterator current=next_s; ++next_s; if (next_s==map_theta.end()) next_s=map_theta.begin(); do{ if (current->second.first==OTRG) return; CGAL_assertion(current->second.first==SRC); draw_in_ipe(Circular_arc_2(circle,*(current->second.second),*(next_s->second.second),CGAL::COUNTERCLOCKWISE)); if (next_s->second.first==OTRG) return; CGAL_assertion(next_s->second.first==TRG); ++next_s; if (next_s==map_theta.end()) next_s=map_theta.begin(); current=next_s; ++next_s; if (next_s==map_theta.end()) next_s=map_theta.begin(); }while(true); } void draw_in_ipe(const Circle_2& object,const Iso_rectangle_2& bbox,bool deselect_all=false) const { std::vector arc_list; restrict_circle_to_bbox(object,bbox,std::back_inserter(arc_list)); if (arc_list.empty() && bbox.has_on_bounded_side(object.center()) ) draw_in_ipe(object,deselect_all); else draw_in_ipe(arc_list.begin(),arc_list.end(),false,deselect_all); } void draw_in_ipe(const Triangle_2& object,const Iso_rectangle_2& bbox,bool deselect_all=false) const { for (unsigned int i=0;i!=3;++i) draw_in_ipe(Segment_2(object.vertex(i),object.vertex(i+1)),bbox,deselect_all); } void draw_in_ipe(const Iso_rectangle_2& object,const Iso_rectangle_2& bbox,bool deselect_all=false) const { for (unsigned int i=0;i!=4;++i) draw_in_ipe(Segment_2(object.vertex(i),object.vertex(i+1)),bbox,deselect_all); } void draw_in_ipe(const Polygon_2& object,const Iso_rectangle_2& bbox,bool deselect_all=false) const { for (typename Polygon_2::Edge_const_iterator it=object.edges_begin();it!=object.edges_end();++it) draw_in_ipe(*it,bbox,deselect_all); } template void draw_in_ipe(const CGAL::Triangulation_2& tri,const Iso_rectangle_2& bbox,bool deselect_all=false) const { typedef CGAL::Triangulation_2 Triangulation; typename Triangulation::Finite_edges_iterator first=tri.finite_edges_begin(); typename Triangulation::Finite_edges_iterator last=tri.finite_edges_end(); for(typename Triangulation::Finite_edges_iterator it=first;it!=last;++it) draw_in_ipe(tri.segment(*it),bbox); if (deselect_all) _page->DeselectAll(); } void draw_in_ipe(const Line_2& line,bool deselect_all=false) const { IpeVector paper_size=get_paper_size(); Iso_rectangle_2 bbox(0,0,paper_size.iX,paper_size.iY); draw_in_ipe(line,bbox,deselect_all); } void draw_in_ipe(const Ray_2& ray,bool deselect_all=false) { IpeVector paper_size=get_paper_size(); Iso_rectangle_2 bbox(0,0,paper_size.iX,paper_size.iY); draw_in_ipe(ray,bbox,deselect_all); } template void draw_in_ipe(const CGAL::Triangulation_2& tri,bool deselect_all=false,bool make_grp=true) const { typedef CGAL::Triangulation_2 Triangulation; typename Triangulation::Finite_edges_iterator first=tri.finite_edges_begin(); typename Triangulation::Finite_edges_iterator last=tri.finite_edges_end(); for(typename Triangulation::Finite_edges_iterator it=first;it!=last;++it) draw_in_ipe(tri.segment(*it)); if (make_grp) _page->Group(_helper->CurrentLayer()); if (deselect_all) _page->DeselectAll(); } template void draw_in_ipe(const iterator begin,const iterator end,bool make_grp=true,bool deselect_all=false) const { for (iterator it=begin;it!=end;++it) draw_in_ipe(*it); if (make_grp and ++iterator(begin)!=end) _page->Group(_helper->CurrentLayer()); if (deselect_all) _page->DeselectAll(); } template void draw_in_ipe(const iterator begin,const iterator end,const Iso_rectangle_2& bbox,bool make_grp=true,bool deselect_all=false, typename boost::enable_if< boost::mpl::or_< boost::is_same::value_type,Point_2> , boost::mpl::or_< boost::is_same::value_type,Segment_2> , boost::mpl::or_< boost::is_same::value_type,Circle_2> , boost::mpl::or_< boost::is_same::value_type,Circular_arc_2> , boost::is_same::value_type,Polygon_2> > > > > >::type* = NULL) const { for (iterator it=begin;it!=end;++it) draw_in_ipe(*it,bbox); if (make_grp and ++iterator(begin)!=end) _page->Group(_helper->CurrentLayer()); if (deselect_all) _page->DeselectAll(); } private: IpeVector get_paper_size() const { if (IPELIB_VERSION >= 60028) return get_IpeletHelper()->StyleSheet()->findLayout().iPaperSize; else return IpeVector(595,842); } struct Voronoi_from_tri{ //Class using stream to get the voronoi diagram std::list ray_list; std::list line_list; std::list seg_list; void operator<<(const Ray_2& p){ray_list.push_back(p);} void operator<<(const Line_2& p){line_list.push_back(p);} void operator<<(const Segment_2& p){seg_list.push_back(p);} }; template bool cast_into_seg(const T& obj,const Iso_rectangle_2& bbox,output_iterator out_it) const{ CGAL::Object obj_cgal = CGAL::intersection(obj,bbox); Segment_2 s; bool ret=CGAL::assign(s, obj_cgal); if (ret) *out_it++=s; return ret; } //Convert infinite objects into drawable segments template void cast_into_seg(const iterator first,const iterator end, const Iso_rectangle_2& bbox, output_iterator out_it) const { for (iterator it=first;it!=end;++it) cast_into_seg(*it,bbox,out_it); } void draw_dual_(Voronoi_from_tri& v_recup,const Iso_rectangle_2& bbox,bool makegrp) const { std::vector seg_cont; //filter degenerate segments for(typename std::list::iterator iteS = v_recup.seg_list.begin();iteS!=v_recup.seg_list.end();){ typename std::list::iterator itc=iteS++; if (itc->is_degenerate()) v_recup.seg_list.erase(itc); } cast_into_seg(v_recup.ray_list.begin(),v_recup.ray_list.end(),bbox,std::back_inserter(seg_cont));//cast rays into segments in bbox cast_into_seg(v_recup.line_list.begin(),v_recup.line_list.end(),bbox,std::back_inserter(seg_cont));//cast lines into segments in bbox cast_into_seg(v_recup.seg_list.begin(),v_recup.seg_list.end(),bbox,std::back_inserter(seg_cont));//cast lines into segments in bbox draw_in_ipe(seg_cont.begin(), seg_cont.end(),makegrp); } public: template void draw_dual_in_ipe(Triangulation& T,const Iso_rectangle_2& bbox,bool makegrp=true,bool deselect_all=false) const { //~ template //~ void draw_dual_in_ipe(const CGAL::Triangulation_2& T,const Iso_rectangle_2& bbox) const{ Voronoi_from_tri v_recup; T.draw_dual(v_recup); draw_dual_(v_recup,bbox,makegrp); if (deselect_all) _page->DeselectAll(); } template void draw_skeleton_in_ipe(Triangulation& T,const Iso_rectangle_2& bbox, bool makegrp=true,bool deselect_all=false) const { //~ template //~ void draw_skeleton_in_ipe(const CGAL::Triangulation_2& T,const Iso_rectangle_2& bbox) const{ Voronoi_from_tri v_recup; T.draw_skeleton(v_recup); draw_dual_(v_recup,bbox,makegrp); if (deselect_all) _page->DeselectAll(); } //Circle restriction private: inline double get_theta(const Point_2& point, const Circle_2& circle) const { return atan2(CGAL::to_double(point.y()-circle.center().y()),CGAL::to_double(point.x()-circle.center().x())); } //SK objects typedef CGAL::Exact_circular_kernel_2 SK; typedef SK::Circle_2 Exact_circle_2; typedef SK::Point_2 Exact_point_2; typedef SK::Circular_arc_point_2 Circular_arc_point_2; //s and t are given such that if center of exact_circle is inside bbox then turn COUNTERCLOCKWISE Circular_arc_2 build_arc(const Exact_circle_2& exact_circle,const SK::Circular_arc_point_2& s, const SK::Circular_arc_point_2& t,bool sign_known=false) const { Point_2 sd=Point_2(CGAL::to_double(s.x()),CGAL::to_double(s.y())); Point_2 td=Point_2(CGAL::to_double(t.x()),CGAL::to_double(t.y())); Point_2 center(CGAL::to_double(exact_circle.center().x()),CGAL::to_double(exact_circle.center().y())); CGAL::Cartesian_converter conv; Circle_2 approx_circle=conv(exact_circle); if (!sign_known){ CGAL::Sign sign = (CGAL::orientation(sd,td,center)==CGAL::LEFT_TURN)?CGAL::POSITIVE:CGAL::NEGATIVE; return CGAL::cpp11::make_tuple(approx_circle,sd,td,sign); } return CGAL::cpp11::make_tuple(approx_circle,sd,td,CGAL::POSITIVE); } void get_pair_indices(int* array,int* pair) const { for (int i=0;i<8;++i) if (array[i]!=-1) *pair++=i; } void set_done(int* array,int index) const { for (int i =0;i<8;++i) if (array[i]==index) array[i]=-1; } bool indices_are_on_opposite_side(int* array) const { if (array[0]!=-1 || array[5]!=-1) return array[2]!=-1 || array[7]!=-1; if (array[1]!=-1 || array[6]!=-1) return array[3]!=-1 || array[4]!=-1; return false; } int count_points(int* array) const { int ret=0; for (int i =0;i<8;++i) if (array[i]!=-1) ++ret; return ret; } public: // // .-----7---------2-------. // | | // 3 6 // | indices | // 4 1 // | | // .-----0---------5-------. template void restrict_circle_to_bbox(const Circle_2& approx_circle, const Iso_rectangle_2& bbox,Output_iterator out) const { CGAL::Cartesian_converter conv; Exact_circle_2 exact_circle=conv(approx_circle); SK::Intersect_2 inter=SK().intersect_2_object(); std::vector< std::pair > points; points.reserve(8); std::vector ints; ints.reserve(2); std::pair tmp_pt; int indices[8]={-1,-1,-1,-1,-1,-1,-1,-1}; for (unsigned i=0;i!=4;++i){ ints.clear(); SK::Segment_2 S(conv(bbox[i]),conv(bbox[(i+1)%4])); inter(exact_circle,SK::Line_arc_2(S),std::back_inserter(ints)); unsigned index=0; bool ok=true; switch (ints.size()){ case 1: ok=CGAL::assign(tmp_pt,ints[0]); CGAL_assertion(ok); points.push_back(tmp_pt); index=points.size()-1; indices[i]=index; indices[(i+1)%4+4]=index; break; case 2: int right_ind=i<2?0:1; ok=CGAL::assign(tmp_pt,ints[right_ind]); CGAL_assertion(ok); points.push_back(tmp_pt); index=points.size()-1; indices[i]=index; ok=CGAL::assign(tmp_pt,ints[(right_ind+1)%2]); CGAL_assertion(ok); points.push_back(tmp_pt); index=points.size()-1; indices[(i+1)%4+4]=index; break; } } //corner case for (unsigned i=0;i!=4;++i){ if (indices[i]!=-1 && indices[i+4]!=-1){ *out++=build_arc(exact_circle,points[ indices[i+4] ].first,points[ indices[i] ].first); if (points[ indices[i] ].second==1) set_done(indices,indices[i]); else indices[i]=-1; if (points[ indices[i+4] ].second==1) set_done(indices,indices[i+4]); else indices[i+4]=-1; } } int rem_pt=count_points(indices); if (rem_pt==4){ //double opposite if (indices[0]!=-1){ *out++=build_arc(exact_circle,points[ indices[7] ].first,points[ indices[0] ].first); if (indices[7]!=indices[2] && indices[0]!=indices[5]) *out++=build_arc(exact_circle,points[ indices[5] ].first,points[ indices[2] ].first); } else{ *out++=build_arc(exact_circle,points[ indices[6] ].first,points[ indices[3] ].first); if (indices[6]!=indices[1] && indices[3]!=indices[4]) *out++=build_arc(exact_circle,points[ indices[4] ].first,points[ indices[1] ].first); } return; } if (rem_pt==2){ int pair[2]; get_pair_indices(indices,pair); if (!indices_are_on_opposite_side(indices)) *out++=build_arc(exact_circle,points[ indices[pair[1]] ].first,points[ indices[pair[0]] ].first,true); else *out++=build_arc(exact_circle,points[ indices[pair[1]] ].first,points[ indices[pair[0]] ].first); return; } CGAL_assertion (rem_pt==0); } }; //definition template template< class multi_output_iterator > bool Ipelet_base::read_one_active_object(IpeObject* object, multi_output_iterator it_out) const { if (object->AsGroup()){ bool deselect_grp=false; for (IpeGroup::const_iterator it=object->AsGroup()->begin(); it!=object->AsGroup()->end();++it) { IpeObject *obj = (*it)->Clone(); obj->SetMatrix(obj->Matrix()*object->Matrix()); bool cur=read_one_active_object(obj,it_out); deselect_grp=deselect_grp || cur; } return deselect_grp; } //detect Points if( object->AsMark() ){ if ( !CGAL::Is_in_tuple::value ) return true; it_out++=to_point_2(object); return false; } bool to_deselect=true; //Test one function for segments, circles, circle arcs and polygons if (object->AsPath()){ //iterate on each subpath to_deselect=false; for (int i=0;iAsPath()->NumSubPaths();++i){ if(object->AsPath()-> SubPath(i)->AsSegs()){ std::list seg_list; bool is_polygon=object-> AsPath() -> SubPath(i)->Closed(); const IpeSegmentSubPath* SSP_ipe = object -> AsPath() -> SubPath(i) -> AsSegs(); for(int j=0; j< SSP_ipe->NumSegments();++j){ if (SSP_ipe -> Segment(j).Type()==IpePathSegment::ESegment){ //TODO depending on if current_it is a polygon or not do not do the same thing seg_list.push_back(Segment_2(segment_endpoint(SSP_ipe -> Segment(j),object -> AsPath(),0), segment_endpoint(SSP_ipe -> Segment(j),object -> AsPath(),1))); } else{ //retrieve circle arcs if(SSP_ipe -> Segment(j).Type()==IpePathSegment::EArc && is_only_rotated_or_scaled(object->AsPath()->Matrix())) {//retreve circle arcs if ( !CGAL::Is_in_tuple::value ){ to_deselect=true; continue; } is_polygon=false; IpePath* obj_ipe=object->AsPath(); IpeMatrix mat=obj_ipe->Matrix() * SSP_ipe->Segment(j).Matrix(); IpeVector ipe_center=IpeVector(mat.iA[4],mat.iA[5]); IpeVector ipe_first=obj_ipe->Matrix() * SSP_ipe->Segment(j).CP(0); IpeVector ipe_last=obj_ipe->Matrix() * SSP_ipe->Segment(j).Last(); //TODO Check how object is defined Circular_arc_2 arc( Circle_2(Point_2(ipe_center.iX,ipe_center.iY),(ipe_first-ipe_center).Len()*(ipe_first-ipe_center).Len()), Point_2(ipe_first.iX,ipe_first.iY), Point_2(ipe_last.iX,ipe_last.iY), mat.iA[0]*mat.iA[3]-mat.iA[1]*mat.iA[2]<0?CGAL::CLOCKWISE:CGAL::COUNTERCLOCKWISE ); it_out++=arc; } else to_deselect=true; } } if (object->AsPath() -> SubPath(i)->Closed() && (SSP_ipe -> Segment(0).CP(0)-SSP_ipe -> Segment(SSP_ipe->NumSegments()-1).CP(1)).Len()!=0 ){ //for close polygon, seg seg_list.push_back( Segment_2( segment_endpoint(SSP_ipe -> Segment(SSP_ipe->NumSegments()-1),object-> AsPath(),1), segment_endpoint(SSP_ipe -> Segment(0),object-> AsPath(),0) )); } //~ if (seg_list.empty()) //~ to_deselect=true; if (is_polygon){ if ( !CGAL::Is_in_tuple::value ) to_deselect=true; else{ Polygon_2 polygon; typename std::list::iterator its=seg_list.begin(); for (;its!=seg_list.end();++its) polygon.push_back(its->source()); it_out++=polygon; } } else{ if ( !CGAL::Is_in_tuple::value ) to_deselect=true; else{ for (typename std::list::iterator its=seg_list.begin();its!=seg_list.end();++its) it_out++=*its; } } } else if (is_IPE_circle(object,i)){ if ( !CGAL::Is_in_tuple::value ) to_deselect=true; else{ Circle_2 C=to_circle_2(object -> AsPath(),i); it_out++=C; } } else to_deselect=true; // avoid deleting no handled objects } } return to_deselect; } } //CGAL #define CGAL_IPELET(T) IPELET_DECLARE Ipelet *NewIpelet(){ return new T; } #endif //CGAL_IPELET_BASE_H