1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
|
// 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
Kernel::Circular_arc_point_2 L,R;
typedef std::pair<Kernel::Circular_arc_point_2, unsigned > The_pair;
std::vector<The_pair> result;
CGAL::intersection(circ, poincare, CGAL::dispatch_or_drop_output<The_pair>(std::back_inserter(result)));
assert (result.size()==2);
L = result[0].first;
R = result[1].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)
|