1/** \file
2 * \brief Tests for ogdf::GraphAttributes.
3 *
4 * \author Mirko Wagner, Tilo Wiedera
5 *
6 * \par License:
7 * This file is part of the Open Graph Drawing Framework (OGDF).
8 *
9 * \par
10 * Copyright (C)<br>
11 * See README.md in the OGDF root directory for details.
12 *
13 * \par
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * Version 2 or 3 as published by the Free Software Foundation;
17 * see the file LICENSE.txt included in the packaging of this file
18 * for details.
19 *
20 * \par
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * \par
27 * You should have received a copy of the GNU General Public
28 * License along with this program; if not, see
29 * http://www.gnu.org/copyleft/gpl.html
30 */
31
32#include <ogdf/basic/DualGraph.h>
33#include <ogdf/basic/graph_generators.h>
34#include <ogdf/basic/extended_graph_alg.h>
35#include <resources.h>
36
37using GA = GraphAttributes;
38
39/**
40 * Tests getters and setter of an attribute.
41 *
42 * \param elemFunc Returns a list of elements which properties are to be tested.
43 * \param refFunc Returns a non-const reference to the attribute (getter & setter to be tested).
44 * \param constRefFunc Returns a copy of the attribute (second getter to be tested).
45 * \param defaultValue Value that the attribute is supposed to be initialized to.
46 * \param secondValue Differs from \p defaultValue, used for testing setters.
47 * \param neededAttributes Attribute flags that are required to enable the attribute.
48 * \param attributeName Human-readable name of the property. Used to create a title for the test.
49 * \tparam Attribute Type of property to be read/written.
50 * \tparam Element Type of the graph element that has the property.
51 */
52template<class Attribute, class Element>
53void testAttribute(
54 std::function<List<Element>(const Graph&)> elemFunc,
55 std::function<Attribute& (GraphAttributes&, Element)> refFunc,
56 std::function<Attribute (const GraphAttributes&, Element)> constRefFunc,
57 Attribute defaultValue,
58 Attribute secondValue,
59 long neededAttributes,
60 string attributeName)
61{
62 describe(attributeName, [&] {
63 Graph graph;
64 GraphAttributes attr(graph);
65 List<Element> elements;
66
67 before_each([&] {
68 completeGraph(graph, 7);
69 attr.init(neededAttributes);
70 elements = elemFunc(graph);
71 });
72
73#ifdef OGDF_USE_ASSERT_EXCEPTIONS
74 it("throws an exception on access if the attribute is disabled", [&] {
75 attr.destroyAttributes(neededAttributes);
76 AssertThrows(AssertionFailed, refFunc(attr, elements.front()));
77 });
78#endif
79
80 it("gets the value", [&] {
81 for(Element elem : elements) {
82 AssertThat(constRefFunc(attr, elem), Equals(defaultValue));
83 AssertThat(refFunc(attr, elem), Equals(defaultValue));
84 }
85 });
86
87 it("sets the value", [&] {
88 for(Element elem : elements) {
89 Attribute &value = refFunc(attr, elem);
90 value = secondValue;
91 AssertThat(refFunc(attr, elem), Equals(secondValue));
92 AssertThat(constRefFunc(attr, elem), Equals(secondValue));
93 }
94 });
95 });
96}
97
98//! @see testAttribute
99template<class Attribute, class... Args>
100void testNodeAttribute(Args... args) {
101 testAttribute<Attribute, node>([](const Graph &graph) {
102 List<node> result;
103 graph.allNodes(result);
104 return result;
105 }, std::forward<Args>(args)...);
106}
107
108//! @see testAttribute
109template<class Attribute, class... Args>
110void testEdgeAttribute(Args... args) {
111 testAttribute<Attribute, edge>([](const Graph &graph) {
112 List<edge> result;
113 graph.allEdges(result);
114 return result;
115 }, std::forward<Args>(args)...);
116}
117
118go_bandit([] {
119describe("graph attributes", [] {
120 it("initializes with no attributes by default", [] {
121 GraphAttributes attr;
122 AssertThat(attr.attributes(), Equals(0));
123 });
124
125 it("initializes with a graph and flags", [] {
126 Graph graph;
127 GraphAttributes attr(graph, GA::nodeId);
128 AssertThat(&attr.constGraph(), Equals(&graph));
129 AssertThat(attr.attributes(), Equals(GA::nodeId));
130 });
131
132 it("initializes with a graph", [] {
133 Graph graph;
134 GraphAttributes attr(graph);
135 AssertThat(&attr.constGraph(), Equals(&graph));
136 AssertThat(attr.attributes(), Equals(GA::nodeGraphics | GA::edgeGraphics));
137 });
138
139 it("initializes using explicit init", [] {
140 Graph graph;
141 GraphAttributes attr;
142 attr.init(graph, GA::nodeId);
143 AssertThat(&attr.constGraph(), Equals(&graph));
144 AssertThat(attr.attributes(), Equals(GA::nodeId));
145 });
146
147 it("destroys its attributes", [] {
148 Graph graph;
149 GraphAttributes attr(graph, GA::nodeGraphics | GA::nodeLabel);
150 AssertThat(&attr.constGraph(), Equals(&graph));
151 AssertThat(attr.attributes(), Equals(GA::nodeGraphics | GA::nodeLabel));
152 attr.destroyAttributes(GA::nodeGraphics | GA::nodeId);
153 AssertThat(attr.attributes(), Equals(GA::nodeLabel));
154 });
155
156 it("adds new attributes", [] {
157 Graph graph;
158 GraphAttributes attr(graph, GA::nodeGraphics | GA::nodeLabel);
159 AssertThat(&attr.constGraph(), Equals(&graph));
160 AssertThat(attr.attributes(), Equals(GA::nodeGraphics | GA::nodeLabel));
161 attr.addAttributes(GA::nodeId | GA::nodeLabel);
162 AssertThat(attr.attributes(), Equals(GA::nodeGraphics | GA::nodeLabel | GA::nodeId));
163 });
164
165 it("knows its currently enabled attributes", [] {
166 Graph graph;
167 GraphAttributes attr(graph, GA::nodeId | GA::nodeLabel);
168 AssertThat(attr.has(GA::nodeId | GA::nodeLabel), IsTrue());
169 AssertThat(attr.has(GA::nodeId), IsTrue());
170 AssertThat(attr.has(GA::nodeId | GA::nodeGraphics), IsFalse());
171 AssertThat(attr.has(GA::nodeGraphics), IsFalse());
172 });
173
174 describe("attributes", [] {
175 it("knows if it's directed", [] {
176 Graph graph;
177 GraphAttributes attr(graph);
178 AssertThat(attr.directed(), IsTrue());
179 attr.directed() = false;
180 AssertThat(attr.directed(), IsFalse());
181 });
182
183 testNodeAttribute<double>(
184 [](GraphAttributes &a, node v) -> double& { return a.x(v); },
185 [](const GraphAttributes &a, node v) { return a.x(v); },
186 0, 42,
187 GA::nodeGraphics, "x");
188
189 testNodeAttribute<double>(
190 [](GraphAttributes &a, node v) -> double& { return a.xLabel(v); },
191 [](const GraphAttributes &a, node v) { return a.xLabel(v); },
192 0, 42,
193 GA::nodeLabel | GA::nodeLabelPosition, "xLabel");
194
195 testNodeAttribute<double>(
196 [](GraphAttributes &a, node v) -> double& { return a.y(v); },
197 [](const GraphAttributes &a, node v) { return a.y(v); },
198 0, 42,
199 GA::nodeGraphics, "y");
200
201 testNodeAttribute<double>(
202 [](GraphAttributes &a, node v) -> double& { return a.yLabel(v); },
203 [](const GraphAttributes &a, node v) { return a.yLabel(v); },
204 0, 42,
205 GA::nodeLabel | GA::nodeLabelPosition, "yLabel");
206
207 testNodeAttribute<double>(
208 [](GraphAttributes &a, node v) -> double& { return a.z(v); },
209 [](const GraphAttributes &a, node v) { return a.z(v); },
210 0, 42,
211 GA::nodeGraphics | GA::threeD, "z");
212
213 testNodeAttribute<double>(
214 [](GraphAttributes &a, node v) -> double& { return a.zLabel(v); },
215 [](const GraphAttributes &a, node v) { return a.zLabel(v); },
216 0, 42,
217 GA::nodeLabel | GA::nodeLabelPosition | GA::threeD | GA::nodeGraphics, "zLabel");
218
219 testNodeAttribute<double>(
220 [](GraphAttributes &a, node v) -> double& { return a.width(v); },
221 [](const GraphAttributes &a, node v) { return a.width(v); },
222 20, 42,
223 GA::nodeGraphics, "width of a node");
224
225 testNodeAttribute<int>(
226 [](GraphAttributes &a, node v) -> int& { return a.weight(v); },
227 [](const GraphAttributes &a, node v) { return a.weight(v); },
228 0, 42,
229 GA::nodeWeight, "weight of a node");
230
231 testEdgeAttribute<Graph::EdgeType>(
232 [](GraphAttributes &a, edge e) -> Graph::EdgeType& { return a.type(e); },
233 [](const GraphAttributes &a, edge e) { return a.type(e); },
234 Graph::EdgeType::association, Graph::EdgeType::generalization,
235 GA::edgeType, "type of an edge");
236
237 testNodeAttribute<Graph::NodeType>(
238 [](GraphAttributes &a, node v) -> Graph::NodeType& { return a.type(v); },
239 [](const GraphAttributes &a, node v) { return a.type(v); },
240 Graph::NodeType::vertex, Graph::NodeType::dummy,
241 GA::nodeType, "type of a node");
242
243 testEdgeAttribute<uint32_t>(
244 [](GraphAttributes &a, edge e) -> uint32_t& { return a.subGraphBits(e); },
245 [](const GraphAttributes &a, edge e) { return a.subGraphBits(e); },
246 0, 42,
247 GA::edgeSubGraphs, "SubGraphBits");
248
249 testEdgeAttribute<float>(
250 [](GraphAttributes &a, edge e) -> float& { return a.strokeWidth(e); },
251 [](const GraphAttributes &a, edge e) { return a.strokeWidth(e); },
252 LayoutStandards::defaultEdgeStroke().m_width, 42,
253 GA::edgeStyle | GA::edgeGraphics, "strokeWidth edge");
254
255 testNodeAttribute<float>(
256 [](GraphAttributes &a, node v) -> float& { return a.strokeWidth(v); },
257 [](const GraphAttributes &a, node v) { return a.strokeWidth(v); },
258 LayoutStandards::defaultEdgeStroke().m_width, 42,
259 GA::nodeStyle | GA::nodeGraphics, "strokeWidth node");
260
261 testNodeAttribute<StrokeType>(
262 [](GraphAttributes &a, node v) -> StrokeType& { return a.strokeType(v); },
263 [](const GraphAttributes &a, node v) { return a.strokeType(v); },
264 LayoutStandards::defaultNodeStroke().m_type, StrokeType::Dot,
265 GA::nodeStyle | GA::nodeGraphics, "strokeType node");
266
267 testEdgeAttribute<StrokeType>(
268 [](GraphAttributes &a, edge e) -> StrokeType& { return a.strokeType(e); },
269 [](const GraphAttributes &a, edge e) { return a.strokeType(e); },
270 LayoutStandards::defaultEdgeStroke().m_type, StrokeType::Dot,
271 GA::edgeStyle | GA::edgeGraphics, "strokeType edge");
272
273 testEdgeAttribute<Color>(
274 [](GraphAttributes &a, edge e) -> Color& { return a.strokeColor(e); },
275 [](const GraphAttributes &a, edge e) { return a.strokeColor(e); },
276 LayoutStandards::defaultEdgeStroke().m_color, ogdf::Color::Name::Turquoise,
277 GA::edgeStyle | GA::edgeGraphics, "strokeColor edge");
278
279 testNodeAttribute<Color>(
280 [](GraphAttributes &a, node v) -> Color& { return a.strokeColor(v); },
281 [](const GraphAttributes &a, node v) { return a.strokeColor(v); },
282 LayoutStandards::defaultEdgeStroke().m_color, ogdf::Color::Name::Turquoise,
283 GA::nodeStyle | GA::nodeGraphics, "strokeColor node");
284
285 testNodeAttribute<Shape>(
286 [](GraphAttributes &a, node v) -> Shape& { return a.shape(v); },
287 [](const GraphAttributes &a, node v) { return a.shape(v); },
288 LayoutStandards::defaultNodeShape(), Shape::Rect,
289 GA::nodeGraphics, "shape node");
290
291 testEdgeAttribute<EdgeArrow>(
292 [](GraphAttributes &a, edge e) -> EdgeArrow& { return a.arrowType(e); },
293 [](const GraphAttributes &a, edge e) { return a.arrowType(e); },
294 LayoutStandards::defaultEdgeArrow(), EdgeArrow::Both,
295 GA::edgeArrow, "arrowType");
296
297 testEdgeAttribute<double>(
298 [](GraphAttributes &a, edge e) -> double& { return a.doubleWeight(e); },
299 [](const GraphAttributes &a, edge e) { return a.doubleWeight(e); },
300 1.0, 42.0,
301 GA::edgeDoubleWeight, "doubleWeight");
302
303 testNodeAttribute<Color>(
304 [](GraphAttributes &a, node v) -> Color& { return a.fillBgColor(v); },
305 [](const GraphAttributes &a, node v) { return a.fillBgColor(v); },
306 LayoutStandards::defaultNodeFill().m_bgColor, ogdf::Color::Name::Turquoise,
307 GA::nodeStyle | GA::nodeGraphics, "fillBgColor");
308
309 testNodeAttribute<Color>(
310 [](GraphAttributes &a, node v) -> Color& { return a.fillColor(v); },
311 [](const GraphAttributes &a, node v) { return a.fillColor(v); },
312 LayoutStandards::defaultNodeFill().m_color, Color(ogdf::Color::Name::Turquoise),
313 GA::nodeStyle | GA::nodeGraphics, "fillColor");
314
315 testNodeAttribute<FillPattern>(
316 [](GraphAttributes &a, node v) -> FillPattern& { return a.fillPattern(v); },
317 [](const GraphAttributes &a, node v) { return a.fillPattern(v); },
318 LayoutStandards::defaultNodeFill().m_pattern, FillPattern::Cross,
319 GA::nodeStyle | GA::nodeGraphics, "fillPattern");
320
321 testNodeAttribute<int>(
322 [](GraphAttributes &a, node v) -> int& { return a.idNode(v); },
323 [](const GraphAttributes &a, node v) { return a.idNode(v); },
324 -1, 42,
325 GA::nodeId, "idNode");
326
327 describe("advanced", [] {
328 Graph graph;
329 GraphAttributes attr(graph);
330 const GraphAttributes &constAttr = attr;
331
332 before_each([&] {
333 completeGraph(graph, 7);
334 });
335
336 it("(in|add|remove)SubGraph", [&] {
337 edge e = graph.chooseEdge();
338 #ifdef OGDF_USE_ASSERT_EXCEPTIONS
339 AssertThrows(AssertionFailed, attr.inSubGraph(e, 13));
340 #endif
341 attr.init(GA::edgeSubGraphs);
342 AssertThat(constAttr.inSubGraph(e, 13), IsFalse());
343 AssertThat(attr.inSubGraph(e, 13), IsFalse());
344 attr.addSubGraph(e, 13);
345 AssertThat(constAttr.inSubGraph(e, 13), IsTrue());
346 AssertThat(attr.inSubGraph(e, 13), IsTrue());
347 attr.removeSubGraph(e, 13);
348 AssertThat(constAttr.inSubGraph(e, 13), IsFalse());
349 AssertThat(attr.inSubGraph(e, 13), IsFalse());
350 });
351
352 it("assigns width using a NodeArray", [&] {
353 #ifdef OGDF_USE_ASSERT_EXCEPTIONS
354 attr.destroyAttributes(GA::nodeGraphics);
355 AssertThrows(AssertionFailed, attr.width());
356 #endif
357 attr.init(GA::nodeGraphics);
358 node v = graph.chooseNode();
359 NodeArray<double> widthNA(graph, 42);
360 AssertThat(constAttr.width().graphOf(), Equals(&graph));
361 AssertThat(attr.width().graphOf(), Equals(&graph));
362 AssertThat(constAttr.width()[v], Equals(LayoutStandards::defaultNodeWidth()));
363 AssertThat(attr.width()[v], Equals(LayoutStandards::defaultNodeWidth()));
364 attr.width() = widthNA;
365 AssertThat(constAttr.width()[v], Equals(42));
366 AssertThat(attr.width()[v], Equals(42));
367 attr.setAllWidth(1337);
368 AssertThat(constAttr.width(v), Equals(1337));
369 AssertThat(attr.width(v), Equals(1337));
370 });
371
372 testNodeAttribute<double>(
373 [](GraphAttributes &a, node v) -> double& { return a.height(v); },
374 [](const GraphAttributes &a, node v) { return a.height(v); },
375 20, 42,
376 GA::nodeGraphics, "height of a node");
377
378 it("assigns height using a NodeArray", [&] {
379 #ifdef OGDF_USE_ASSERT_EXCEPTIONS
380 attr.destroyAttributes(GA::nodeGraphics);
381 AssertThrows(AssertionFailed, attr.height());
382 #endif
383 attr.init(GA::nodeGraphics);
384 node v = graph.chooseNode();
385 NodeArray<double> heightNA(graph, 42);
386 AssertThat(constAttr.height().graphOf(), Equals(&graph));
387 AssertThat(attr.height().graphOf(), Equals(&graph));
388 attr.height() = heightNA;
389 AssertThat(constAttr.height()[v], Equals(42));
390 AssertThat(attr.height()[v], Equals(42));
391 attr.setAllHeight(1337);
392 AssertThat(constAttr.height(v), Equals(1337));
393 AssertThat(attr.height(v), Equals(1337));
394 });
395 });
396
397 testEdgeAttribute<int>(
398 [](GraphAttributes &a, edge e) -> int& { return a.intWeight(e); },
399 [](const GraphAttributes &a, edge e) { return a.intWeight(e); },
400 1, 42,
401 GA::edgeIntWeight, "intWeight");
402
403 testNodeAttribute<string>(
404 [](GraphAttributes &a, node v) -> string& { return a.label(v); },
405 [](const GraphAttributes &a, node v) { return a.label(v); },
406 "", "ogdf" ,
407 GA::nodeLabel, "label");
408
409 testEdgeAttribute<string>(
410 [](GraphAttributes &a, edge e) -> string& { return a.label(e); },
411 [](const GraphAttributes &a, edge e) { return a.label(e); },
412 "", "ogdf" ,
413 GA::edgeLabel, "label");
414
415
416 testNodeAttribute<string>(
417 [](GraphAttributes &a, node v) -> string& { return a.templateNode(v); },
418 [](const GraphAttributes &a, node v) { return a.templateNode(v); },
419 "", "ogdf" ,
420 GA::nodeTemplate, "templateNode");
421 });
422
423 describe("change position of elements", [] {
424 GraphAttributes attr;
425 Graph graph;
426
427 before_each([&] {
428 completeGraph(graph, 100);
429 attr = GraphAttributes(graph, GA::nodeGraphics | GA::edgeGraphics);
430 for(node v : graph.nodes) {
431 attr.x(v) = ogdf::randomNumber(-100, 100);
432 attr.y(v) = ogdf::randomNumber(-100, 100);
433 }
434 attr.addNodeCenter2Bends(1);
435 attr.translateToNonNeg();
436 });
437
438 it("translates to non-negative coordinates", [&] {
439 for(node v : graph.nodes) {
440 AssertThat(attr.x(v) - attr.width(v) / 2, IsGreaterThan(0) || Equals(0));
441 AssertThat(attr.y(v) - attr.width(v) / 2, IsGreaterThan(0) || Equals(0));
442 }
443 for(edge e : graph.edges) {
444 for(DPoint &p : attr.bends(e)) {
445 AssertThat(p.m_x, IsGreaterThan(0) || Equals(0));
446 AssertThat(p.m_y, IsGreaterThan(0) || Equals(0));
447 }
448 }
449 });
450
451 it("translates", [&] {
452 GraphAttributes ga = GraphAttributes(attr);
453 attr.translate(1.0, 42.0);
454 for(node v : graph.nodes) {
455 AssertThat(attr.x(v), Equals(ga.x(v)+1.0));
456 AssertThat(attr.y(v), Equals(ga.y(v)+42.0));
457 }
458 for(edge e : graph.edges) {
459 DPolyline &bendpoints = ga.bends(e);
460 for(DPoint &p_new : attr.bends(e)) {
461 DPoint p_old = bendpoints.popFrontRet();
462 AssertThat(p_new.m_x, Equals(p_old.m_x+1.0));
463 AssertThat(p_new.m_y, Equals(p_old.m_y+42.0));
464 }
465 }
466 });
467
468 it("scales", [&] {
469 GraphAttributes ga = GraphAttributes(attr);
470 attr.scale(-1.0, -2.0, true);
471 for(node v : graph.nodes) {
472 AssertThat(attr.x(v), Equals(-ga.x(v)));
473 AssertThat(attr.y(v), Equals(-2.0 * ga.y(v)));
474 }
475 for(edge e : graph.edges) {
476 DPolyline &bendpoints = ga.bends(e);
477 for(DPoint &p_new : attr.bends(e)) {
478 DPoint p_old = bendpoints.popFrontRet();
479 AssertThat(p_new.m_x, Equals(-p_old.m_x));
480 AssertThat(p_new.m_y, Equals(-2.0 * p_old.m_y));
481 }
482 }
483 });
484
485 it("scales and then translates", [&] {
486 GraphAttributes ga = GraphAttributes(attr);
487 attr.scaleAndTranslate(-1.0, -42.0, 13, 37, true);
488 for(node v : graph.nodes) {
489 AssertThat(attr.x(v), Equals(-ga.x(v) + 13));
490 AssertThat(attr.y(v), Equals(-42 * ga.y(v) + 37));
491 }
492 for(edge e : graph.edges) {
493 DPolyline &bendpoints = ga.bends(e);
494 for(DPoint &p_new : attr.bends(e)) {
495 DPoint p_old = bendpoints.popFrontRet();
496 AssertThat(p_new.m_x, Equals(-p_old.m_x + 13));
497 AssertThat(p_new.m_y, Equals(-42 * p_old.m_y + 37));
498 }
499 }
500 });
501
502 it("flips vertical within its bounding box", [&] {
503 DRect boundingBox = attr.boundingBox();
504 double height = boundingBox.height();
505 GraphAttributes ga = GraphAttributes(attr);
506 attr.flipVertical();
507 for(node v : graph.nodes) {
508 AssertThat(attr.x(v), Equals(ga.x(v)));
509 AssertThat(attr.y(v), Equals(height - ga.y(v)));
510 }
511 for(edge e : graph.edges) {
512 DPolyline &bendpoints = ga.bends(e);
513 for(DPoint &p_new : attr.bends(e)) {
514 DPoint p_old = bendpoints.popFrontRet();
515 AssertThat(p_new.m_x, Equals(p_old.m_x));
516 AssertThat(p_new.m_y, Equals(height - p_old.m_y));
517 }
518 }
519 });
520
521 it("flips vertical with a given box", [&] {
522 GraphAttributes ga = GraphAttributes(attr);
523 attr.flipVertical(DRect());
524 for(node v : graph.nodes) {
525 AssertThat(attr.x(v), Equals(ga.x(v)));
526 AssertThat(attr.y(v), Equals(-ga.y(v)));
527 }
528 for(edge e : graph.edges) {
529 DPolyline &bendpoints = ga.bends(e);
530 for(DPoint &p_new : attr.bends(e)) {
531 DPoint p_old = bendpoints.popFrontRet();
532 AssertThat(p_new.m_x, Equals(p_old.m_x));
533 AssertThat(p_new.m_y, Equals(-p_old.m_y));
534 }
535 }
536 });
537
538 it("flips horizontal within its bounding box", [&] {
539 DRect boundingBox = attr.boundingBox();
540 double width = boundingBox.width();
541 GraphAttributes ga = GraphAttributes(attr);
542 attr.flipHorizontal();
543 for(node v : graph.nodes) {
544 AssertThat(attr.x(v), Equals(width - ga.x(v)));
545 AssertThat(attr.y(v), Equals(ga.y(v)));
546 }
547 for(edge e : graph.edges) {
548 DPolyline &bendpoints = ga.bends(e);
549 for(DPoint &p_new : attr.bends(e)) {
550 DPoint p_old = bendpoints.popFrontRet();
551 AssertThat(p_new.m_x, Equals(width - p_old.m_x));
552 AssertThat(p_new.m_y, Equals(p_old.m_y));
553 }
554 }
555 });
556
557 it("flips horizontal with a given box", [&] {
558 GraphAttributes ga = GraphAttributes(attr);
559 attr.flipHorizontal(DRect());
560 for(node v : graph.nodes) {
561 AssertThat(attr.x(v), Equals(-ga.x(v)));
562 AssertThat(attr.y(v), Equals(ga.y(v)));
563 }
564 for(edge e : graph.edges) {
565 DPolyline &bendpoints = ga.bends(e);
566 for(DPoint &p_new : attr.bends(e)) {
567 DPoint p_old = bendpoints.popFrontRet();
568 AssertThat(p_new.m_x, Equals(-p_old.m_x));
569 AssertThat(p_new.m_y, Equals(p_old.m_y));
570 }
571 }
572 });
573
574 it("rotates left", [&] {
575 GraphAttributes ga = GraphAttributes(attr);
576 attr.rotateLeft90();
577 for(node v : graph.nodes) {
578 AssertThat(attr.x(v), Equals(ga.y(v)));
579 AssertThat(attr.y(v), Equals(-ga.x(v)));
580 }
581 for(edge e : graph.edges) {
582 DPolyline &bendpoints = ga.bends(e);
583 for(DPoint &p_new : attr.bends(e)) {
584 DPoint p_old = bendpoints.popFrontRet();
585 AssertThat(p_new.m_x, Equals(p_old.m_y));
586 AssertThat(p_new.m_y, Equals(-p_old.m_x));
587 }
588 }
589 });
590
591 it("rotates right", [&] {
592 GraphAttributes ga = GraphAttributes(attr);
593 attr.rotateRight90();
594 for(node v : graph.nodes) {
595 AssertThat(attr.x(v), Equals(-ga.y(v)));
596 AssertThat(attr.y(v), Equals(ga.x(v)));
597 }
598 for(edge e : graph.edges) {
599 DPolyline &bendpoints = ga.bends(e);
600 for(DPoint &p_new : attr.bends(e)) {
601 DPoint p_old = bendpoints.popFrontRet();
602 AssertThat(p_new.m_x, Equals(-p_old.m_y));
603 AssertThat(p_new.m_y, Equals(p_old.m_x));
604 }
605 }
606 });
607 });
608
609 it("knows its bounding box", [] {
610 Graph graph;
611 randomGraph(graph, 100, 1000);
612 GraphAttributes attr(graph, GA::nodeGraphics | GA::edgeGraphics);
613 for(node v : graph.nodes) {
614 attr.x(v) = ogdf::randomNumber(-1000, 1000);
615 attr.y(v) = ogdf::randomNumber(-1000, 1000);
616 }
617 attr.addNodeCenter2Bends(1);
618 attr.translateToNonNeg();
619 DRect boundBox = attr.boundingBox();
620 AssertThat(boundBox.p1().m_x, Equals(0) || IsGreaterThan(0));
621 AssertThat(boundBox.p1().m_y, Equals(0) || IsGreaterThan(0));
622 AssertThat(boundBox.p2().m_x, Equals(2020) || IsLessThan(2020));
623 AssertThat(boundBox.p2().m_y, Equals(2020) || IsLessThan(2020));
624 for(node v : graph.nodes) {
625 AssertThat(boundBox.contains(DPoint(attr.x(v), attr.y(v))), IsTrue());
626 }
627 for(edge e : graph.edges) {
628 for(DPoint &p : attr.bends(e)) {
629 AssertThat(boundBox.contains(p), IsTrue());
630 }
631 }
632 });
633
634 describe("bends", [] {
635 Graph graph;
636 GraphAttributes attr;
637
638 before_each([&] {
639 completeGraph(graph, 3);
640 attr = GraphAttributes(graph, GA::nodeGraphics | GA::edgeGraphics);
641 });
642
643 it("clears all bends", [&] {
644 attr.addNodeCenter2Bends(1);
645 AssertThat(attr.bends(graph.chooseEdge()).size(), IsGreaterThan(0));
646 attr.clearAllBends();
647 for(edge e : graph.edges) {
648 AssertThat(attr.bends(e).size(), Equals(0));
649 }
650 });
651
652 it("knows its bends", [&] {
653 for(edge e : graph.edges) {
654 AssertThat(attr.bends(e).size(), Equals(0));
655 }
656 attr.addNodeCenter2Bends(0);
657 for(edge e : graph.edges) {
658 AssertThat(attr.bends(e).size(), Equals(2));
659 }
660 edge e = graph.chooseEdge();
661 DPolyline dpl;
662 dpl.emplaceFront(42, 17);
663 attr.bends(e) = dpl;
664 AssertThat(attr.bends(e).size(), Equals(1));
665 AssertThat((*attr.bends(e).get(0)).m_x, Equals(42));
666 AssertThat((*attr.bends(e).get(0)).m_y, Equals(17));
667 });
668 });
669});
670});
671