dust3d/thirdparty/cgal/CGAL-4.13/include/CGAL/CGAL_Ipelet_base_v6.h

1032 lines
39 KiB
C
Raw Normal View History

// 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 <ipelib.h>
#include <CGAL/Polygon_2.h>
#include <CGAL/iterator.h>
#include <CGAL/Triangulation_2.h>
#include <CGAL/grabbers.h>
#include <CGAL/iterator.h>
#include <CGAL/tuple.h>
#include<CGAL/Exact_circular_kernel_2.h>
#include <CGAL/Cartesian_converter.h>
#include <CGAL/assertions.h>
#include <boost/utility.hpp>
namespace CGAL{
template <class Kernel,int nbf>
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<Kernel> Point_2;
typedef typename CGAL::Weighted_point_2<Kernel> 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<Kernel,std::list<Point_2> > Polygon_2;
typedef typename CGAL::Polygon_2<Kernel> Polygon_2;
typedef typename Kernel::Circle_2 Circle_2;
typedef CGAL::cpp11::tuple<Circle_2,Point_2,Point_2,CGAL::Sign> 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="<qt><h1>"+Name+"</h1><ul>";
if (gen)
for(int i=0;i<nbf-1;++i)
hmsg=hmsg+"<li><i>"+SubLab[i]+"</i>: "+HMsg[i]+"</li>";
else
hmsg=hmsg+"<li>"+HMsg[0]+"</li>";
_helper->MessageBox(&hmsg[0],"OK",NULL,NULL);
return;
}
//grabbers
template <class output_iterator>
struct Point_grabber:public internal::Point_grabber<Kernel,output_iterator>{
Point_grabber(output_iterator it):internal::Point_grabber<Kernel,output_iterator>(it){}
};
template<class output_iterator>
boost::function_output_iterator<Point_grabber<output_iterator> >
point_grabber(output_iterator it){
return boost::make_function_output_iterator(Point_grabber<output_iterator>(it));
}
template <class output_iterator>
struct Segment_grabber:public internal::Segment_grabber<Kernel,output_iterator>{
Segment_grabber(output_iterator it):internal::Segment_grabber<Kernel,output_iterator>(it){}
};
template<class output_iterator>
boost::function_output_iterator<Segment_grabber<output_iterator> >
segment_grabber(output_iterator it){
return boost::make_function_output_iterator(Segment_grabber<output_iterator>(it));
}
template <class output_iterator>
struct Wpoint_grabber:public internal::Wpoint_grabber<Kernel,output_iterator>{
Wpoint_grabber(output_iterator it):internal::Wpoint_grabber<Kernel,output_iterator>(it){}
};
template<class output_iterator>
boost::function_output_iterator<Wpoint_grabber<output_iterator> >
wpoint_grabber(output_iterator it){
return boost::make_function_output_iterator(Wpoint_grabber<output_iterator>(it));
}
//Interaction functions
//------------------------------
void
print_error_message(const char* s) const
{
_helper->Message(s);
}
template <class T>
std::pair<int,T>
request_value_from_user(std::string msg) const
{
IpeString str;
std::pair<int,T> 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<V,O> 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<double>(bbox_ipe.Min().iX),static_cast<double>(bbox_ipe.Min().iY),
static_cast<double>(bbox_ipe.Max().iX),static_cast<double>(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<IpeSubPath*> 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<IpeSubPath*>::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<class iterator>
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<class iterator>
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<iterator>::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<class Container>
void
draw_in_ipe(const CGAL::Polygon_2<Kernel,Container>& poly,bool deselect_all=false) const
{
std::list<Point_2> LP;
for (typename CGAL::Polygon_2<Kernel,Container>::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 <class T>
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<Circular_arc_2> 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<double,std::pair<Type_circ_arc,const Point_2*> > map_theta;
typedef typename std::multimap<double,std::pair<Type_circ_arc,const Point_2*> >::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<Circular_arc_2>::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<Circular_arc_2> 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<class GT,class TDS>
void
draw_in_ipe(const CGAL::Triangulation_2<GT,TDS>& tri,const Iso_rectangle_2& bbox,bool deselect_all=false) const
{
typedef CGAL::Triangulation_2<GT,TDS> 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<class GT,class TDS>
void
draw_in_ipe(const CGAL::Triangulation_2<GT,TDS>& tri,bool deselect_all=false,bool make_grp=true) const
{
typedef CGAL::Triangulation_2<GT,TDS> 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<class iterator>
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<class iterator>
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<typename std::iterator_traits<iterator>::value_type,Point_2> ,
boost::mpl::or_< boost::is_same<typename std::iterator_traits<iterator>::value_type,Segment_2> ,
boost::mpl::or_< boost::is_same<typename std::iterator_traits<iterator>::value_type,Circle_2> ,
boost::mpl::or_< boost::is_same<typename std::iterator_traits<iterator>::value_type,Circular_arc_2> ,
boost::is_same<typename std::iterator_traits<iterator>::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_2> ray_list;
std::list<Line_2> line_list;
std::list<Segment_2> 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 <class T,class output_iterator>
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<class iterator,class output_iterator>
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<Segment_2> seg_cont;
//filter degenerate segments
for(typename std::list<Segment_2>::iterator iteS = v_recup.seg_list.begin();iteS!=v_recup.seg_list.end();){
typename std::list<Segment_2>::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<class Triangulation>
void
draw_dual_in_ipe(Triangulation& T,const Iso_rectangle_2& bbox,bool makegrp=true,bool deselect_all=false) const
{
//~ template<class GT,class TDS>
//~ void draw_dual_in_ipe(const CGAL::Triangulation_2<GT,TDS>& 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<class Triangulation>
void
draw_skeleton_in_ipe(Triangulation& T,const Iso_rectangle_2& bbox,
bool makegrp=true,bool deselect_all=false) const
{
//~ template<class GT,class TDS>
//~ void draw_skeleton_in_ipe(const CGAL::Triangulation_2<GT,TDS>& 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<SK,Kernel> 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 <class Output_iterator>
void
restrict_circle_to_bbox(const Circle_2& approx_circle,
const Iso_rectangle_2& bbox,Output_iterator out) const
{
CGAL::Cartesian_converter<Kernel,SK> conv;
Exact_circle_2 exact_circle=conv(approx_circle);
SK::Intersect_2 inter=SK().intersect_2_object();
std::vector< std::pair<Circular_arc_point_2,unsigned> > points;
points.reserve(8);
std::vector<CGAL::Object> ints;
ints.reserve(2);
std::pair<Circular_arc_point_2,unsigned> 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 <class Kernel,int nbf>
template< class multi_output_iterator >
bool
Ipelet_base<Kernel,nbf>::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<Point_2,typename multi_output_iterator::Value_type_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;i<object->AsPath()->NumSubPaths();++i){
if(object->AsPath()-> SubPath(i)->AsSegs()){
std::list<Segment_2> 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<Circular_arc_2,typename multi_output_iterator::Value_type_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<Polygon_2,typename multi_output_iterator::Value_type_tuple>::value )
to_deselect=true;
else{
Polygon_2 polygon;
typename std::list<Segment_2>::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<Segment_2,typename multi_output_iterator::Value_type_tuple>::value )
to_deselect=true;
else{
for (typename std::list<Segment_2>::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<Circle_2,typename multi_output_iterator::Value_type_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