Documentation of MARTY
A Modern ARtificial Theoretical phYsicist
planargraph.h
1 // This file is part of MARTY.
2 //
3 // MARTY is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, either version 3 of the License, or
6 // (at your option) any later version.
7 //
8 // MARTY is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with MARTY. If not, see <https://www.gnu.org/licenses/>.
15 
23 #pragma once
24 
25 #include <cmath>
26 #include <map>
27 #include <csignal>
28 #include <functional>
29 #include "adjacencyMatrix.h"
30 #include <gsl/gsl_vector.h>
31 
32 namespace drawer {
33 
34 struct Point {
35 
36  double x;
37  double y;
38  double z;
39 
40  Point()
41  :x(0),
42  y(0),
43  z(0)
44  {}
45 
46  Point(double value)
47  :x(value),
48  y(value),
49  z(0)
50  {}
51 
52  Point(double t_x,
53  double t_y,
54  double t_z = 0)
55  :x(t_x),
56  y(t_y),
57  z(t_z)
58  {}
59 
60  Point(Point const&) = default;
61  Point(Point&&) = default;
62  Point& operator=(Point const&) = default;
63  Point& operator=(Point&&) = default;
64 
65  Point& rotate(double theta,
66  int axis = 2)
67  {
68  if (axis < 0 or axis > 2) {
69  std::cerr << "Axis " << axis << " unavailable for rotation, "
70  << " space in 3D has axis 0, 1 or 2.\n";
71  std::raise(SIGTERM);
72  }
73  double& xref = *(&x + (axis + 1)%3);
74  double& yref = *(&x + (axis + 2)%3);
75  double new_x = std::cos(theta)*xref - std::sin(theta)*yref;
76  yref = std::sin(theta)*xref + std::cos(theta)*yref;
77  xref = new_x;
78 
79  return *this;
80  }
81 
82  double angle(int axis = 2) const
83  {
84  if (axis < 0 or axis > 2) {
85  std::cerr << "Axis " << axis << " unavailable for rotation, "
86  << " space in 3D has axis 0, 1 or 2.\n";
87  std::raise(SIGTERM);
88  }
89  if (axis == 0)
90  return std::atan2(z, y);
91  if (axis == 1)
92  return std::atan2(x, z);
93  return std::atan2(y, x);
94  }
95 
96  double norm() const
97  {
98  return std::sqrt(x*x + y*y + z*z);
99  }
100 
101  template<typename Value_Type>
102  Point& operator+=(Value_Type value) {
103  x += value;
104  y += value;
105  z += value;
106  return *this;
107  }
108  Point& operator+=(Point const& p) {
109  x += p.x;
110  y += p.y;
111  z += p.z;
112  return *this;
113  }
114 
115  template<typename Value_Type>
116  Point& operator*=(Value_Type value) {
117  x *= value;
118  y *= value;
119  z *= value;
120  return *this;
121  }
122  Point& operator*=(Point const& p) {
123  x *= p.x;
124  y *= p.y;
125  z *= p.z;
126  return *this;
127  }
128 
129  template<typename Value_Type>
130  Point& operator-=(Value_Type value) {
131  x -= value;
132  y -= value;
133  z -= value;
134  return *this;
135  }
136  Point& operator-=(Point const& p) {
137  x -= p.x;
138  y -= p.y;
139  z -= p.z;
140  return *this;
141  }
142 
143  template<typename Value_Type>
144  Point& operator/=(Value_Type value) {
145  x /= value;
146  y /= value;
147  z /= value;
148  return *this;
149  }
150  Point& operator/=(Point const& p) {
151  x /= p.x;
152  y /= p.y;
153  z /= p.z;
154  return *this;
155  }
156 
157  friend
158  std::ostream& operator<<(std::ostream& out,
159  Point const& point)
160  {
161  out << point.x << " " << point.y << " " << point.z;
162  return out;
163  }
164 };
165 
166 class LatexLinker;
167 class Energy;
168 
169 class Graph {
170 
171  friend class LatexLinker;
172 
173  public:
174 
175  inline static bool writeResToFile = false;
176  inline static std::string fileNameBegin = "graph/begin";
177  inline static std::string fileName3DRes = "graph/3D";
178  inline static std::string fileNameProject = "graph/project";
179  inline static std::string fileName2DRes = "graph/2D";
180 
181  inline static constexpr double externalLegSizeRation = 0.70;
182  inline static constexpr double absAngleMultiple = 4;
183  inline static constexpr double decouplingDistance = -1;
184 
185  inline static constexpr double defaultNodeSizeFactor = 16.50;
186  inline static constexpr double defaultAngleFactor = 6.50;
187  inline static constexpr double defaultExternalLayout = 0.95;
188  inline static constexpr double defaultExternalRepulsion = 2.00;
189  inline static constexpr double defaultLegsRepulsion = 4.00;
190  inline static constexpr double defaultNodeLegsRepulsion = 3.00;
191  inline static constexpr double defaultExtensionFactor = 1.00;
192  inline static constexpr double defaultAbsAngleFactor = 0.00;
193  inline static constexpr double default_3DFactor = 0.10;
194  inline static constexpr double defaultCrossEnergyValue = 1.00;
195  inline static constexpr double defaultSpecialAnglesValue = 6.50;
196 
197  inline static bool enable3D = true;
198  inline static double nodeSizeFactor = defaultNodeSizeFactor;
199  inline static double angleFactor = defaultAngleFactor;
200  inline static double externalRepulsion = defaultExternalRepulsion;
201  inline static double externalLayout = defaultExternalLayout;
202  inline static double legsRepulsion = defaultLegsRepulsion;
203  inline static double nodeLegsRepulsion = defaultNodeLegsRepulsion;
204  inline static double extensionFactor = defaultExtensionFactor;
205  inline static double absAngleFactor = 0;
206  inline static double _3DFactor = default_3DFactor;
207  inline static double specialAnglesValue = 0;
208 
209  Graph();
210 
211  explicit
212  Graph(size_t N);
213 
214  Graph(size_t N,
215  std::vector<std::pair<int, int>> const& init);
216 
217  Graph(Graph const& other) = default;
218  Graph(Graph&& other) = default;
219  Graph& operator=(Graph const& other) = default;
220  Graph& operator=(Graph&& other) = default;
221 
222  ~Graph() {}
223 
224  void reinit();
225 
226  void clear();
227 
228  size_t size() const {
229  return nodes.size();
230  }
231 
232  double& getPosition(size_t pos) {
233  if (pos / 2 > nodes.size()) {
234  std::cerr << nodes.size() << ", " << pos << std::endl;
235  std::cerr << "IndexError.\n";
236  std::raise(SIGSEGV);
237  }
238  return (pos % 2 == 0) ? nodes[pos / 2].x : nodes[pos / 2].y;
239  }
240 
241  double getPosition(size_t pos) const {
242  if (pos / 2 > nodes.size()) {
243  std::cerr << nodes.size() << ", " << pos << std::endl;
244  std::cerr << "IndexError.\n";
245  std::raise(SIGSEGV);
246  }
247  return (pos % 2 == 0) ? nodes[pos / 2].x : nodes[pos / 2].y;
248  }
249 
250  std::vector<Point>& getNodes();
251 
252  std::vector<Point> const& getNodes() const;
253 
254  Matrix<int>& getAdjacency();
255 
256  Matrix<int> const& getAdjacency() const;
257 
258  bool isSame(drawer::Graph const& other) const;
259 
260  bool isSame(drawer::Graph const& other,
261  std::map<size_t, size_t>& mapping) const;
262 
263  void addEdge(int left, int right);
264 
265  void setSide(int pos, int t_side);
266 
267  double xMin() const;
268 
269  double xMax() const;
270 
271  double yMin() const;
272 
273  double yMax() const;
274 
275  double zMin() const;
276 
277  double zMax() const;
278 
279  double computeEnergy(bool verbose = false);
280 
281  int minimize(int mode = 0);
282 
283  int minimize2D();
284 
285  void project(bool only2DRotation = false,
286  bool keepExternal = false);
287 
288  void center();
289 
290  void centerMargin();
291 
292  void flip(int axis = -1);
293 
294  void tryFlip();
295 
296  void scale(double s);
297 
298  void rotate(double theta);
299 
300  void move(double x, double y);
301 
302  Point getCenter() const;
303 
304  void placeTopLeft();
305 
306  void write(std::string const& fileName) const;
307 
308  void addNode(double x, double y);
309 
310  void deleteNode(size_t i);
311 
312  friend
313  std::ostream& operator<<(std::ostream& out,
314  Graph const& graph);
315 
316  protected:
317 
318  gsl_vector* allocGslVector();
319 
320  size_t getNVar();
321 
322  void fillGslVector(gsl_vector* x);
323 
324  void readGslVector(gsl_vector const* x);
325 
326  void initExternalDistance();
327 
328  static void initPoint(Point& p, size_t N);
329 
330  void gatherExternalNodes();
331 
332  bool tryPermutation(int order = 1, double energy = -1);
333 
334  void initEnergies();
335 
336  private:
337 
338  size_t nInsertions;
339 
340  std::vector<Point> nodes;
341 
342  std::vector<int> loop;
343 
344  std::vector<int> external;
345 
346  std::vector<int> side;
347 
348  Matrix<int> adjacency;
349 
350  std::vector<Energy> energies;
351 };
352 
353 class Energy {
354 
355  private:
356 
357  const double* factor;
358 
359  std::function<double(Graph const& g)> func;
360 
361  std::string name;
362 
363  public:
364 
365  Energy(double const& t_factor,
366  std::function<double(Graph const& g)> const& t_func,
367  std::string const& t_name = "Energy")
368  :factor(&t_factor),
369  func(t_func),
370  name(t_name)
371  {}
372 
373  double compute(Graph const& g,
374  bool verbose = false) const
375  {
376  if (verbose and *factor != 0) {
377  auto energy = func(g);
378  std::cout << name << ": ";
379  std::cout << energy << std::endl;
380  return *factor * energy;
381  }
382  return (*factor == 0) ? 0 : *factor * func(g);
383  }
384 };
385 
386 inline
387 Point operator+(Point const& B,
388  Point const& A)
389 {
390  Point C(A);
391  C += B;
392  return C;
393 }
394 
395 template<class T>
396 Point operator+(T const& B,
397  Point const& A)
398 {
399  Point C(A);
400  C += B;
401  return C;
402 }
403 
404 template<class T>
405 Point operator+(Point const& A,
406  T const& B)
407 {
408  Point C(A);
409  C += B;
410  return C;
411 }
412 
413 template<class T>
414 Point operator*(T const& B,
415  Point const& A)
416 {
417  Point C(A);
418  C *= B;
419  return C;
420 }
421 
422 template<class T>
423 Point operator*(Point const& A,
424  T const& B)
425 {
426  Point C(A);
427  C *= B;
428  return C;
429 }
430 
431 inline
432 Point operator-(Point const& A) {
433  return Point(-A.x, -A.y);
434 }
435 
436 inline
437 Point operator-(Point const& A,
438  Point const& B)
439 {
440  return Point(A.x - B.x, A.y - B.y);
441 }
442 
443 template<class T>
444 Point operator-(T const& B,
445  Point const& A)
446 {
447  Point C(-A);
448  C += B;
449  return C;
450 }
451 
452 template<class T>
453 Point operator-(Point const& A,
454  T const& B)
455 {
456  Point C(A);
457  C -= B;
458  return C;
459 }
460 
461 template<class T>
462 Point operator/(T const& B,
463  Point const& A)
464 {
465  Point C(B);
466  C /= A;
467  return C;
468 }
469 
470 template<class T>
471 Point operator/(Point const& A,
472  T const& B)
473 {
474  Point C(A);
475  C /= B;
476  return C;
477 }
478 
479 inline double distance2(Point const& A,
480  Point const& B)
481 {
482  if (Graph::enable3D)
483  return std::max(1e-10,
484  std::pow(A.x - B.x, 2)
485  + std::pow(A.y - B.y, 2)
486  + std::pow(A.z - B.z, 2));
487  return std::max(1e-10,
488  std::pow(A.x - B.x, 2)
489  + std::pow(A.y - B.y, 2));
490 }
491 
492 inline double distance(Point const& A,
493  Point const& B)
494 {
495  return std::sqrt(distance2(A, B));
496 }
497 
498 inline double remainder(double angle)
499 {
500  if (std::abs(std::abs(angle) - M_PI/2) < 1e-10)
501  return ((angle < 0) ? -1 : 1) * M_PI/2;
502  return std::atan2(std::sin(angle), std::cos(angle));
503 }
504 
505 inline double angle(Point const& ref,
506  Point const& A,
507  Point const& B)
508 {
509  Point newA = (A - ref).rotate(-(B - ref).angle());
510  return newA.angle();
511 }
512 
513 struct line {
514 
515  double a;
516  double b;
517 };
518 
519 inline line getEquation(Point const& A,
520  Point const& B)
521 {
522  line res;
523  res.a = (A.x == B.x) ? 0 : (A.y - B.y) / (A.x - B.x);
524  res.b = A.y - res.a * A.x;
525 
526  return res;
527 }
528 
529 }
Definition: drawer.h:29
std::ostream & operator<<(std::ostream &fout, csl::Type type)
Expr operator+(const Expr &a, const Expr &b)
Expr operator-(const Expr &a, const Expr &b)
Definition: planargraph.h:169
Expr operator/(const Expr &a, const Expr &b)
Expr operator*(const Expr &a, const Expr &b)