File: hyperbolic.cpp

package info (click to toggle)
cgal 6.1.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 144,952 kB
  • sloc: cpp: 811,597; ansic: 208,576; sh: 493; python: 411; makefile: 286; javascript: 174
file content (231 lines) | stat: -rw-r--r-- 7,030 bytes parent folder | download | duplicates (2)
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)