cgal/CGAL_ipelets/demo/CGAL_ipelets/hyperbolic.cpp

234 lines
6.9 KiB
C++

// Copyright (c) 2013 INRIA Sophia Antipolis - Mediterranee, (France).
// All rights reserved.
//
// This file is part of CGAL (www.cgal.org)
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial
//
//
// Author(s) : Olivier Devillers
#include <CGAL/Exact_circular_kernel_2.h>
#include <CGAL/CGAL_Ipelet_base.h>
#include <CGAL/Object.h>
#include "include/CGAL_ipelets/pencils.h"
#include <CGAL/Cartesian.h>
namespace CGAL_hyperbolic{
typedef CGAL::Exact_circular_kernel_2 Kernel;
// --------------------------------------------------------------------
const std::string sublabel[] = {
"Line through two points",
"Segment through two points",
"Bisector of two points",
"Circle by center and point",
"Circle center",
"Help"
};
const std::string helpmsg[] = {
"Draw the hyperbolic line through two points in Poincare disk",
"Draw the hyperbolic segment through two points in Poincare disk",
"Draw the hyperbolic bisector of two points in Poincare disk",
"Draw the hyperbolic circle given the center (primary selection) and a point in Poincare disk",
"Draw the hyperbolic center given a circle (primary selection) in Poincare disk",
};
class hyperbolicIpelet
: public CGAL::Ipelet_base<Kernel,6> {
public:
hyperbolicIpelet()
:CGAL::Ipelet_base<Kernel,6>("Hyperbolic",sublabel,helpmsg){}
void protected_run(int);
};
// --------------------------------------------------------------------
void hyperbolicIpelet::protected_run(int fn)
{
Circle_2 circ; //constructed circle:
Circle_2 p1,p2;
Circle_2 poincare,selected;
if (fn==5) {
show_help();
return;
}
std::list<Point_2> pt_list,pt_list1;
std::list<Circle_2> cir_list,cir_list1;
int i=get_IpePage()->primarySelection();
if (i<0) {
print_error_message(("No mark or circle selected"));
return;
}
read_one_active_object(get_IpePage()->object(i),CGAL::dispatch_or_drop_output<Point_2,Circle_2>(
std::back_inserter(pt_list1),
std::back_inserter(cir_list1)));
Iso_rectangle_2 bbox=
read_active_objects(
CGAL::dispatch_or_drop_output<Point_2,Circle_2>(
std::back_inserter(pt_list),
std::back_inserter(cir_list)
)
);
std::list<Point_2>::iterator it1=pt_list1.begin();
std::list<Circle_2>::iterator cit1=cir_list1.begin();
std::list<Point_2>::iterator it=pt_list.begin();
std::list<Circle_2>::iterator cit=cir_list.begin();
if (fn!=4){
if (pt_list.empty() || cir_list.empty()){
print_error_message(("Two marks and a circle have to be selected"));
return;
}
}else{
if (cir_list.empty()){
print_error_message(("Two circles have to be selected"));
return;
}
}
poincare=*cit;++cit;
if(fn==4){
if( (cit==cir_list.end()) || (cit1==cir_list1.end())){
print_error_message(("Two circles have to be selected"));
return;
}
if (*cit1==poincare) poincare=*cit;
selected=*cit1;
}else{
p1=Circle_2(*it,0);
++it;
if (it!=pt_list.end()) {
p2=Circle_2(*it,0);
++it;
}else{
print_error_message(("Two marks and a circle have to be selected"));
return;
}
if( (it!=pt_list.end())||(cit!=cir_list.end())){
print_error_message(("Only two marks and a circle have to be selected"));
return;
}
}
if (fn==3){//primary selection must be a point (p1)
if (pt_list1.empty()){
print_error_message(("Primary selection must be a mark (center)"));
return;
}
if (*it1 != p1.center()) {
//swap
circ = p1;
p1 = p2;
p2 = circ;
}
if (*it1 != p1.center()) {
print_error_message(("Primary selection must be a mark (center)"));
return;
}
}
switch(fn){
case 0:
// Circle orthogonal to p1, p2, and poincare
circ = compute_circle_orthogonal<Kernel>(p1,p2,poincare);
break; //goto clip
case 1:
// Circle orthogonal to p1, p2, and poincare
circ = compute_circle_orthogonal<Kernel>(p1,p2,poincare);
if (orientation(poincare.center(),p1.center(),p2.center())>0)
draw_in_ipe(Circular_arc_2(circ,p2.center(),p1.center(),circ.orientation()));
else if (orientation(poincare.center(),p1.center(),p2.center())==0){
print_error_message(
"degenerate case, hyperbolic line is on a diameter of Poincare disk");
draw_in_ipe(Segment_2(p1.center(),p2.center()));
}else
draw_in_ipe(Circular_arc_2(circ,p1.center(),p2.center(),circ.orientation()));
return;
case 2:
// Circle of pencil generated by p1 p2 orthogonal to poincare
circ = compute_circle_in_pencil<Kernel>(poincare,p1,p2);
break; //goto clip
case 3:
// Circle of pencil p1 poincare through p2
circ = compute_circle_in_pencil<Kernel>(p2,poincare,p1);
draw_in_ipe(circ);
return;
case 4:
// Zere radius circle of pencil selected poincare inside
// translate so that Poincare : x^2+y^2=A
// and selected : x^2+y^2 -2ax -2by +a^2+ b^2=C
// look for l so that l.Poincare + selected has zero radius
double a=CGAL::to_double(selected.center().x())-CGAL::to_double(poincare.center().x());
double b=CGAL::to_double(selected.center().y())-CGAL::to_double(poincare.center().y());
double C=CGAL::to_double(selected.squared_radius());
double A=CGAL::to_double(poincare.squared_radius());
double B=A+C-a*a-b*b;
double delta=B*B-4*A*C;
double l=(-B+sqrt(delta))/2/A;
l = 1/(1+l);
Point_2 center=poincare.center()+ (l*(selected.center()-poincare.center()));
draw_in_ipe(center);
return;
} //end of switch
// detect degenerate case
if (circ==Circle_2()){
Kernel::Vector_2 v;
if (fn==2) v= Kernel::Vector_2
(p2.center().y()-p1.center().y(),p2.center().x()-p1.center().x());
else v=p2.center()-p1.center();
Kernel::FT sqr_length=poincare.squared_radius() / v.squared_length();
double length = sqrt( CGAL::to_double(sqr_length) );
v = Kernel::FT(length)*v;
Point_2 q1=poincare.center()+ v;
Point_2 q2=poincare.center()- v;
print_error_message(
"degenerate case, hyperbolic line is a diameter of Poincare disk");
Kernel::Segment_2 s(q1,q2);
draw_in_ipe(s);
return;
}
// clip circ by poincare
std::vector< CGAL::Object > result;
Kernel::Circular_arc_point_2 L,R;
std::pair<Kernel::Circular_arc_point_2, unsigned > the_pair;
CGAL::intersection(circ, poincare, std::back_inserter(result));
assert (result.size()==2);
assign(the_pair, result[0]);
L = the_pair.first;
assign(the_pair, result[1]);
R = the_pair.first;
Point_2 LL(CGAL::to_double(L.x()),CGAL::to_double(L.y()));
Point_2 RR(CGAL::to_double(R.x()),CGAL::to_double(R.y()));
assert( LL.x() <= RR.x());
Circular_arc_2 arc;
if ( orientation(poincare.center(),circ.center(),LL) >0)
arc = Circular_arc_2(circ,LL,RR,circ.orientation());
else arc = Circular_arc_2(circ,RR,LL,circ.orientation());
draw_in_ipe( arc );
}
}
CGAL_IPELET(CGAL_hyperbolic::hyperbolicIpelet)