// 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 #include #define CURRENTLAYER get_IpeletData()->iLayer #define CURRENTATTRIBUTES get_IpeletData()->iAttributes namespace CGAL{ template class Ipelet_base : public ipe::Ipelet { private: const std::string* SubLab; const std::string* HMsg; std::string Name; ipe::IpeletData* data_; ipe::IpeletHelper* helper_; public: typedef ipe::Vector IpeVector; //ipe6 compatibility typedef ipe::Curve IpeSegmentSubPath;//ipe6 compatibility typedef ipe::Matrix IpeMatrix;//ipe6 compatibility typedef ipe::Path IpePath;//ipe6 compatibility //indicates if the selection should be primary or secondary. Exactly one primary selection should exist ipe::TSelect get_selection_type() const { return get_IpePage()->primarySelection()==-1 ? ipe::EPrimarySelected : ipe::ESecondarySelected;} //ipe6 compatibility void transform_selected_objects_(const IpeMatrix& tfm) const { for (int i=0;icount();++i) if (get_IpePage()->select(i)!=ipe::ENotSelected) get_IpePage()->transform(i,tfm); } void delete_selected_objects_() const { for (unsigned i=get_IpePage()->count();i>0;--i) if (get_IpePage()->select(i-1)!=ipe::ENotSelected) get_IpePage()->remove(i-1); } void group_selected_objects_() const { ipe::Group* grp=new ipe::Group(); for (unsigned i=get_IpePage()->count();i>0;--i) if (get_IpePage()->select(i-1)!=ipe::ENotSelected){ grp->push_back( get_IpePage()->object(i-1)->clone() ); //~ grp->push_back( get_IpePage()->object(i-1) ); get_IpePage()->remove(i-1); } get_IpePage()->append(get_selection_type(),CURRENTLAYER,grp); } //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 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),data_(NULL),helper_(NULL){}; ipe::Page* get_IpePage() const {return data_->iPage;} ipe::IpeletData* get_IpeletData() const {return data_;} ipe::IpeletHelper* get_IpeletHelper() const {return helper_;} int ipelibVersion() const { return ipe::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];}; bool run (int i, ipe::IpeletData* data, ipe::IpeletHelper* helper) { data_=data; helper_=helper; try{ protected_run(i); return true; } catch(...){ helper->messageBox("Error : Save your page in a file and submit it to \n https://www.cgal.org/bug_report.html",NULL,ipe::IpeletHelper::EOkCancelButtons); return false; } }; virtual void protected_run(int)=0; 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]+"
  • "; get_IpeletHelper()->messageBox(&hmsg[0],NULL,ipe::IpeletHelper::EOkCancelButtons); 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 { get_IpeletHelper()->message(s); } template std::pair request_value_from_user(std::string msg) const { ipe::String str; std::pair ret_val=std::make_pair(-1,T()); if (get_IpeletHelper()-> getString(msg.c_str(),str)){ if (!str.empty()){ ipe::Lex 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 ipe::CurveSegment& segment,ipe::Path* obj_ipe,int i) const { CGAL_precondition(i<2); ipe::Vector pt_ipe = obj_ipe -> matrix() * segment.cp(i); return Point_2((double)(pt_ipe.x),(double)(pt_ipe.y));//conversion into CGAL point } Point_2 to_point_2(ipe::Object* object) const { ipe::Vector pt_ipe = object-> matrix() * object-> asReference() -> position(); return Point_2((double)(pt_ipe.x),(double)(pt_ipe.y));//conversion into CGAL point } Circle_2 to_circle_2(ipe::Path* obj_ipe,int subpath=0) const { const ipe::Ellipse* ell_ipe = obj_ipe -> shape().subPath(subpath) -> asEllipse(); ipe::Matrix mat_ipe = obj_ipe -> matrix() * ell_ipe -> matrix(); FT radius = (mat_ipe*ipe::Vector(1,0)-mat_ipe.translation()).len(); ipe::Vector pt_ipe = mat_ipe.translation(); return Circle_2(Point_2(pt_ipe.x,pt_ipe.y),radius*radius); } //Picking functions //------------------------------ bool is_only_rotated_or_scaled(const ipe::Matrix& m) const { return (m.a[0]==m.a[3] && m.a[1]==-m.a[2]); } bool is_IPE_circle(ipe::Object* object,int subpath=0) const { return ( object -> asPath() && object -> asPath() -> shape().subPath(subpath) -> asEllipse() && is_only_rotated_or_scaled(object ->asPath()->matrix())); } public: //declaration template< class multi_output_iterator > bool read_one_active_object( ipe::Object* 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 { ipe::Rect bbox_ipe; if (!get_IpePage()->hasSelection()) { return Iso_rectangle_2(); } for (int i=0;icount();++i){ if (get_IpePage()->select(i)==ipe::ENotSelected) continue; bbox_ipe.addRect(get_IpePage()->bbox(i)); //Test one function for segments, circles, circle arcs and polygons bool desel_it=read_one_active_object(get_IpePage()->object(i),it_out); if ( delete_selected_objects && desel_it ) get_IpePage()->setSelect(i,ipe::ENotSelected); } if (delete_selected_objects) delete_selected_objects_(); if (deselect_all) get_IpePage()->deselectAll(); Iso_rectangle_2 bbox_cgal( static_cast(bbox_ipe.bottomLeft().x),static_cast(bbox_ipe.bottomLeft().y), static_cast(bbox_ipe.topRight().x),static_cast(bbox_ipe.topRight().y) ); return bbox_cgal; } //drawing functions //------------------------------ void create_polygon_with_holes(bool delete_underlying_polygons=false) const { std::list SSPqu; for (int i=0;icount();++i){ if (get_IpePage()->select(i)!=ipe::ENotSelected && get_IpePage()->object(i)->asPath()->shape().subPath(0)->closed() ){ ipe::SubPath* ssp=new ipe::Curve(*get_IpePage()->object(i)->asPath()->shape().subPath(0)->asCurve()); SSPqu.push_back(ssp); } } if (!delete_underlying_polygons) get_IpePage() -> deselectAll(); ipe::Shape shape;// create new objects with current attributes for (std::list::iterator it=SSPqu.begin();it!=SSPqu.end();++it) shape.appendSubPath(*it); if (delete_underlying_polygons) delete_selected_objects_(); get_IpePage()->append(get_selection_type(),CURRENTLAYER,new ipe::Path(CURRENTATTRIBUTES,shape)); } void center_selection_in_page() const { ipe::Vector paper_size=get_paper_size(); ipe::Matrix tfm (1,0,0,1,paper_size.x/2.,paper_size.y/2.); for (int i=0;icount();++i) if (get_IpePage()->select(i)!=ipe::ENotSelected ) get_IpePage()->transform(i,tfm); } template ipe::Curve* create_polyline(const iterator first, const iterator last,bool setclose=false) const { if (boost::next(first)!=last){ ipe::Curve* SSP_ipe = new ipe::Curve(); ipe::Vector Prev_pt=ipe::Vector(CGAL::to_double(first->x()),CGAL::to_double(first->y())) ; for (iterator it = boost::next(first);it!=last;++it){ ipe::Vector Cur_pt=ipe::Vector(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 ipe::Path* 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 { ipe::Curve* SSP_ipe=create_polyline(first,last,setclose); if (SSP_ipe!=NULL){ ipe::Shape shape; shape.appendSubPath(SSP_ipe); ipe::Path* obj_ipe=new ipe::Path(CURRENTATTRIBUTES,shape); if (blackfill){ obj_ipe->setPathMode(ipe::EStrokedAndFilled); obj_ipe->setFill(ipe::Attribute::BLACK()); } get_IpePage()->append( (deselect_all?ipe::ENotSelected:get_selection_type()),CURRENTLAYER,obj_ipe); return obj_ipe; } return NULL; } void draw_in_ipe(const Circle_2& C,bool deselect_all=false) const { ipe::Ellipse *ellipse = new ipe::Ellipse(ipe::Matrix(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()) ) ); ipe::Shape shape; shape.appendSubPath(ellipse); get_IpePage()->append( (deselect_all?ipe::ENotSelected:get_selection_type()),CURRENTLAYER,new ipe::Path(CURRENTATTRIBUTES,shape)); } void draw_in_ipe(const Point_2& P,bool deselect_all=false) const { ipe::Reference *mark = new ipe::Reference(CURRENTATTRIBUTES,CURRENTATTRIBUTES.iMarkShape, ipe::Vector(CGAL::to_double(P.x()),CGAL::to_double(P.y()))); get_IpePage()->append( (deselect_all?ipe::ENotSelected:get_selection_type()),CURRENTLAYER,mark); } void draw_in_ipe(const Segment_2& S,bool deselect_all=false) const { ipe::Segment seg_ipe; seg_ipe.iP = ipe::Vector(CGAL::to_double(S.point(0).x()),CGAL::to_double(S.point(0).y())); seg_ipe.iQ = ipe::Vector(CGAL::to_double(S.point(1).x()),CGAL::to_double(S.point(1).y())); get_IpePage()->append( (deselect_all?ipe::ENotSelected:get_selection_type()),CURRENTLAYER,new ipe::Path(CURRENTATTRIBUTES,ipe::Shape(seg_ipe))); } 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 { ipe::Curve* SSP_ipe = new ipe::Curve; ipe::Vector ipeS=ipe::Vector( CGAL::to_double(CGAL::cpp11::get<1>(arc).x()), CGAL::to_double(CGAL::cpp11::get<1>(arc).y()));//convert ot ipe format ipe::Vector ipeT=ipe::Vector( 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(ipe::Matrix(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); ipe::Shape shape; shape.appendSubPath(SSP_ipe); get_IpePage()->append( (deselect_all?ipe::ENotSelected:get_selection_type()),CURRENTLAYER,new ipe::Path(CURRENTATTRIBUTES,shape)); } void draw_in_ipe(const Triangle_2& t,bool deselect_all=false) const { ipe::Curve* SSP_ipe = new ipe::Curve(); ipe::Vector P0=ipe::Vector(t[0].x(),t[0].y()); ipe::Vector P1=ipe::Vector(t[1].x(),t[1].y()); ipe::Vector P2=ipe::Vector(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); ipe::Shape shape; shape.appendSubPath(SSP_ipe); get_IpePage()->append( (deselect_all?ipe::ENotSelected:get_selection_type()),CURRENTLAYER,new ipe::Path(CURRENTATTRIBUTES,shape)); } void draw_in_ipe(const Iso_rectangle_2& r,bool deselect_all=false) { ipe::Curve* SSP_ipe = new ipe::Curve(); ipe::Vector P0=ipe::Vector(r[0].x(),r[0].y()); ipe::Vector P1=ipe::Vector(r[1].x(),r[1].y()); ipe::Vector P2=ipe::Vector(r[2].x(),r[2].y()); ipe::Vector P3=ipe::Vector(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); ipe::Shape shape; shape.appendSubPath(SSP_ipe); get_IpePage()->append( (deselect_all?ipe::ENotSelected:get_selection_type()),CURRENTLAYER,new ipe::Path(CURRENTATTRIBUTES,shape)); } //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) get_IpePage()->deselectAll(); } void draw_in_ipe(const Line_2& line,bool deselect_all=false) const { ipe::Vector paper_size=get_paper_size(); Iso_rectangle_2 bbox(0,0,paper_size.x,paper_size.y); draw_in_ipe(line,bbox,deselect_all); } void draw_in_ipe(const Ray_2& ray,bool deselect_all=false) { ipe::Vector paper_size=get_paper_size(); Iso_rectangle_2 bbox(0,0,paper_size.x,paper_size.y); 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) group_selected_objects_(); if (deselect_all) get_IpePage()->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) group_selected_objects_(); if (deselect_all) get_IpePage()->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) group_selected_objects_(); if (deselect_all) get_IpePage()->deselectAll(); } private: ipe::Vector get_paper_size() const { return data_->iDoc->cascade()->findLayout()->iPaperSize; } 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) get_IpePage()->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) get_IpePage()->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); CGAL_USE(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); CGAL_USE(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); CGAL_USE(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(ipe::Object* object, multi_output_iterator it_out) const { if (object->asGroup()){ bool deselect_grp=false; for (ipe::Group::const_iterator it=object->asGroup()->begin(); it!=object->asGroup()->end();++it) { ipe::Object *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->asReference() ){ 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()->shape().countSubPaths();++i){ if(object->asPath()-> shape().subPath(i)->asCurve()){ std::list seg_list; bool is_polygon=object-> asPath() -> shape().subPath(i)->closed(); const ipe::Curve* SSP_ipe = object -> asPath() -> shape().subPath(i) -> asCurve(); for(int j=0; j< SSP_ipe->countSegments();++j){ if (SSP_ipe -> segment(j).type()==ipe::CurveSegment::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()==ipe::CurveSegment::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; ipe::Path* obj_ipe=object->asPath(); ipe::Matrix mat=obj_ipe->matrix() * SSP_ipe->segment(j).matrix(); ipe::Vector ipe_center=ipe::Vector(mat.a[4],mat.a[5]); ipe::Vector ipe_first=obj_ipe->matrix() * SSP_ipe->segment(j).cp(0); ipe::Vector 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.x,ipe_center.y),(ipe_first-ipe_center).len()*(ipe_first-ipe_center).len()), Point_2(ipe_first.x,ipe_first.y), Point_2(ipe_last.x,ipe_last.y), mat.a[0]*mat.a[3]-mat.a[1]*mat.a[2]<0?CGAL::CLOCKWISE:CGAL::COUNTERCLOCKWISE ); it_out++=arc; } else to_deselect=true; } } if (object->asPath() -> shape().subPath(i)->closed() && (SSP_ipe -> segment(0).cp(0)-SSP_ipe -> segment(SSP_ipe->countSegments()-1).cp(1)).len()!=0 ){ //for close polygon, seg seg_list.push_back( Segment_2( segment_endpoint(SSP_ipe -> segment(SSP_ipe->countSegments()-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 ipe::Ipelet *newIpelet(){ return new T; } #endif //CGAL_IPELET_BASE_H