Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
eepicgeom_test.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
53#include <gtest/gtest.h>
54#include <sstream>
55#include <cmath>
56#include <eepicgeom.H>
57
58// Global variable required by eepicgeom.H (declared extern there)
59bool tiny_keys = false;
60
61using namespace Aleph;
62
63// Tolerance for floating-point comparisons
64constexpr double EPSILON = 1e-6;
65
66// Helper to compare doubles with tolerance
67bool approx_equal(double a, double b, double tol = EPSILON)
68{
69 return std::abs(a - b) < tol;
70}
71
72//============================================================================
73// Eepic_Plane Construction Tests
74//============================================================================
75
76class EepicPlaneTest : public ::testing::Test
77{
78protected:
79 void SetUp() override
80 {
81 plane_default = std::make_unique<Eepic_Plane>(500, 300);
82 plane_with_offset = std::make_unique<Eepic_Plane>(500, 300, 10, 20);
83 }
84
85 std::unique_ptr<Eepic_Plane> plane_default;
86 std::unique_ptr<Eepic_Plane> plane_with_offset;
87};
88
90{
91 EXPECT_EQ(plane_default->get_wide(), 500);
92 EXPECT_EQ(plane_default->get_height(), 300);
93 EXPECT_EQ(plane_default->get_xoffset(), 0);
94 EXPECT_EQ(plane_default->get_yoffset(), 0);
95}
96
98{
99 EXPECT_EQ(plane_with_offset->get_wide(), 500);
100 EXPECT_EQ(plane_with_offset->get_height(), 300);
101 EXPECT_EQ(plane_with_offset->get_xoffset(), 10);
102 EXPECT_EQ(plane_with_offset->get_yoffset(), 20);
103}
104
106{
107 plane_default->set_resolution(0.1);
108 EXPECT_EQ(plane_default->get_resolution(), 0.1);
109
110 plane_default->set_resolution(0.05);
111 EXPECT_EQ(plane_default->get_resolution(), 0.05);
112}
113
115{
116 double original = plane_default->get_shade_thickness();
117 plane_default->set_shade_thickness(2.0);
118 EXPECT_EQ(plane_default->get_shade_thickness(), 2.0);
119
120 plane_default->set_shade_thickness(original);
121 EXPECT_EQ(plane_default->get_shade_thickness(), original);
122}
123
125{
126 Eepic_Plane plane(500, 300);
127 plane.zoom(2.0);
128 EXPECT_EQ(plane.get_wide(), 1000);
129 EXPECT_EQ(plane.get_height(), 600);
130}
131
133{
134 Eepic_Plane plane(500, 300);
135 plane.zoom(0.5);
136 EXPECT_EQ(plane.get_wide(), 250);
137 EXPECT_EQ(plane.get_height(), 150);
138}
139
141{
142 Eepic_Plane plane(500, 300);
143 EXPECT_THROW(plane.zoom(0), std::domain_error);
144 EXPECT_THROW(plane.zoom(-1.0), std::domain_error);
145}
146
147//============================================================================
148// Eepic_Plane with Objects Tests
149//============================================================================
150
151class EepicPlaneWithObjectsTest : public ::testing::Test
152{
153protected:
154 void SetUp() override
155 {
156 plane = std::make_unique<Eepic_Plane>(500, 500);
157 }
158
159 std::unique_ptr<Eepic_Plane> plane;
160};
161
162// NOTE: Single point causes assertion failure due to zero geom_wide/geom_height
163// This is a known bug in eepicgeom.H. The DISABLED_ prefix documents this issue.
165{
166 // BUG: Single point causes assertion failure at line 447 of eepicgeom.H
167 // because geom_wide = rightmost.x - leftmost.x = 0 for a single point
168 Point p(10, 20);
169 put_in_plane(*plane, p);
170
171 std::ostringstream output;
172 plane->draw(output);
173
174 std::string result = output.str();
175 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
176 EXPECT_TRUE(result.find("\\end{picture}") != std::string::npos);
177}
178
180{
181 // Use two points to avoid zero-range bug
182 Point p1(10, 20);
183 Point p2(100, 80);
184 put_in_plane(*plane, p1);
185 put_in_plane(*plane, p2);
186
187 std::ostringstream output;
188 plane->draw(output);
189
190 std::string result = output.str();
191 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
192 EXPECT_TRUE(result.find("\\end{picture}") != std::string::npos);
193}
194
196{
197 Point p1(0, 0);
198 Point p2(100, 100);
199 Segment seg(p1, p2);
200 put_in_plane(*plane, seg);
201
202 std::ostringstream output;
203 plane->draw(output);
204
205 std::string result = output.str();
206 EXPECT_TRUE(result.find("\\path") != std::string::npos);
207}
208
210{
211 Point p1(0, 0);
212 Point p2(100, 50);
213 Arrow arrow(p1, p2);
214 put_in_plane(*plane, arrow);
215
216 std::ostringstream output;
217 plane->draw(output);
218
219 std::string result = output.str();
220 // Arrow should produce a path plus arrow edges
221 EXPECT_TRUE(result.find("\\path") != std::string::npos);
222}
223
225{
226 Point center(50, 50);
227 Ellipse ellipse(center, 20, 10);
228 put_in_plane(*plane, ellipse);
229
230 std::ostringstream output;
231 plane->draw(output);
232
233 std::string result = output.str();
234 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
235}
236
238{
239 Polygon poly;
240 poly.add_vertex(Point(0, 0));
241 poly.add_vertex(Point(100, 0));
242 poly.add_vertex(Point(100, 100));
243 poly.add_vertex(Point(0, 100));
244 poly.close();
245
246 put_in_plane(*plane, poly);
247
248 std::ostringstream output;
249 plane->draw(output);
250
251 std::string result = output.str();
252 EXPECT_TRUE(result.find("\\path") != std::string::npos);
253}
254
256{
257 Point p1(0, 0);
258 Point p2(100, 0);
259 Point p3(50, 100);
260 Triangle tri(p1, p2, p3);
261
262 put_in_plane(*plane, tri);
263
264 std::ostringstream output;
265 plane->draw(output);
266
267 std::string result = output.str();
268 EXPECT_TRUE(result.find("\\path") != std::string::npos);
269}
270
272{
273 // Add a segment first to provide coordinate range (avoid single-point bug)
274 put_in_plane(*plane, Segment(Point(0, 0), Point(100, 100)));
275
276 Point p(50, 50);
277 Text text(p, "Hello");
278 put_in_plane(*plane, text);
279
280 std::ostringstream output;
281 plane->draw(output);
282
283 std::string result = output.str();
284 EXPECT_TRUE(result.find("Hello") != std::string::npos);
285}
286
288{
289 Point p(50, 50);
290 put_in_plane(*plane, p);
291
292 Segment seg(Point(0, 0), Point(100, 100));
293 put_in_plane(*plane, seg);
294
295 Ellipse ellipse(Point(50, 50), 10, 10);
296 put_in_plane(*plane, ellipse);
297
298 std::ostringstream output;
299 plane->draw(output);
300
301 std::string result = output.str();
302 // Check that 3 objects were put in the plane
303 EXPECT_TRUE(result.find("3 geometric objects were put in the plane") !=
304 std::string::npos);
305}
306
307//============================================================================
308// Extreme Points Calculation Tests
309//============================================================================
310
311class ExtremePointsTest : public ::testing::Test
312{
313protected:
314 void SetUp() override
315 {
316 plane = std::make_unique<Eepic_Plane>(500, 500);
317 }
318
319 std::unique_ptr<Eepic_Plane> plane;
320};
321
322// NOTE: Single point causes assertion failure due to zero geom_wide/geom_height
324{
325 // BUG: Crashes due to assertion failure at line 447 in eepicgeom.H
326 Point p(50, 75);
327 put_in_plane(*plane, p);
328
329 std::ostringstream output;
330 plane->draw(output);
331
332 // After draw, extreme points should be computed
333 EXPECT_EQ(plane->leftmost(), p);
334 EXPECT_EQ(plane->rightmost(), p);
335 EXPECT_EQ(plane->highest(), p);
336 EXPECT_EQ(plane->lowest(), p);
337}
338
340{
341 Point p1(10, 20);
342 Point p2(100, 150);
343 Segment seg(p1, p2);
344 put_in_plane(*plane, seg);
345
346 std::ostringstream output;
347 plane->draw(output);
348
349 EXPECT_EQ(plane->leftmost().get_x(), p1.get_x());
350 EXPECT_EQ(plane->rightmost().get_x(), p2.get_x());
351 EXPECT_EQ(plane->lowest().get_y(), p1.get_y());
352 EXPECT_EQ(plane->highest().get_y(), p2.get_y());
353}
354
356{
357 Point p1(-50, -25);
358 Point p2(150, 200);
359
360 put_in_plane(*plane, p1);
361 put_in_plane(*plane, p2);
362
363 std::ostringstream output;
364 plane->draw(output);
365
366 EXPECT_EQ(plane->leftmost().get_x(), Geom_Number(-50));
367 EXPECT_EQ(plane->rightmost().get_x(), Geom_Number(150));
368 EXPECT_EQ(plane->lowest().get_y(), Geom_Number(-25));
369 EXPECT_EQ(plane->highest().get_y(), Geom_Number(200));
370}
371
372//============================================================================
373// Segment Drawing Variants Tests
374//============================================================================
375
376class SegmentVariantsTest : public ::testing::Test
377{
378protected:
379 void SetUp() override
380 {
381 plane = std::make_unique<Eepic_Plane>(500, 500);
382 p1 = Point(0, 0);
383 p2 = Point(100, 100);
384 }
385
386 std::unique_ptr<Eepic_Plane> plane;
387 Point p1, p2;
388};
389
391{
392 Thick_Segment thick_seg(p1, p2);
393 put_in_plane(*plane, thick_seg);
394
395 std::ostringstream output;
396 plane->draw(output);
397
398 std::string result = output.str();
399 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
400}
401
403{
405 put_in_plane(*plane, dotted_seg);
406
407 std::ostringstream output;
408 plane->draw(output);
409
410 std::string result = output.str();
411 EXPECT_TRUE(result.find("\\dottedline") != std::string::npos);
412}
413
415{
416 Dash_Segment dash_seg(p1, p2);
417 put_in_plane(*plane, dash_seg);
418
419 std::ostringstream output;
420 plane->draw(output);
421
422 std::string result = output.str();
423 EXPECT_TRUE(result.find("\\dashline") != std::string::npos);
424}
425
427{
429 put_in_plane(*plane, dotted_arrow);
430
431 std::ostringstream output;
432 plane->draw(output);
433
434 std::string result = output.str();
435 EXPECT_TRUE(result.find("\\dottedline") != std::string::npos);
436 // Should also have arrow edges
437 EXPECT_TRUE(result.find("arrow's edges") != std::string::npos);
438}
439
441{
442 Dash_Arrow dash_arrow(p1, p2);
443 put_in_plane(*plane, dash_arrow);
444
445 std::ostringstream output;
446 plane->draw(output);
447
448 std::string result = output.str();
449 EXPECT_TRUE(result.find("\\dashline") != std::string::npos);
450}
451
452//============================================================================
453// Arrow Edge Case Tests - Testing the vertical segment bug
454//============================================================================
455
456class ArrowEdgeCaseTest : public ::testing::Test
457{
458protected:
459 void SetUp() override
460 {
461 plane = std::make_unique<Eepic_Plane>(500, 500);
462 }
463
464 std::unique_ptr<Eepic_Plane> plane;
465};
466
468{
469 // Standard diagonal arrow - should work fine
470 Point p1(0, 0);
471 Point p2(100, 50);
472 Arrow arrow(p1, p2);
473 put_in_plane(*plane, arrow);
474
475 std::ostringstream output;
476 EXPECT_NO_THROW(plane->draw(output));
477
478 std::string result = output.str();
479 EXPECT_FALSE(result.find("nan") != std::string::npos);
480 EXPECT_FALSE(result.find("inf") != std::string::npos);
481}
482
483// Disabled due to zero-range bug when y1 == y2 (geom_height = 0)
485{
486 // Horizontal arrow (tgt_y == src_y) - BUG: triggers zero-range in y
487 Point p1(0, 50);
488 Point p2(100, 50);
489 Arrow arrow(p1, p2);
490 put_in_plane(*plane, arrow);
491
492 std::ostringstream output;
493 EXPECT_NO_THROW(plane->draw(output));
494
495 std::string result = output.str();
496 EXPECT_FALSE(result.find("nan") != std::string::npos);
497 EXPECT_FALSE(result.find("inf") != std::string::npos);
498}
499
501{
502 // Nearly horizontal arrow with slight y difference to avoid zero-range bug
503 Point p1(0, 50);
504 Point p2(100, 50.001); // Slight y offset
505 Arrow arrow(p1, p2);
506 put_in_plane(*plane, arrow);
507
508 std::ostringstream output;
509 EXPECT_NO_THROW(plane->draw(output));
510
511 std::string result = output.str();
512 EXPECT_FALSE(result.find("nan") != std::string::npos);
513 EXPECT_FALSE(result.find("inf") != std::string::npos);
514}
515
516// NOTE: This test documents the known bug - vertical segments cause
517// division by zero in PUT_ARROW macro (line 692 in eepicgeom.H)
518// The test is marked as disabled until the bug is fixed
520{
521 // Vertical arrow (tgt_x == src_x) - BUG: causes division by zero
522 // in: const double phi = atan( fabs( (tgt_y - src_y)/(tgt_x - src_x) ) );
523 Point p1(50, 0);
524 Point p2(50, 100);
525 Arrow arrow(p1, p2);
526 put_in_plane(*plane, arrow);
527
528 std::ostringstream output;
529 // This would produce nan/inf values due to division by zero
530 plane->draw(output);
531
532 std::string result = output.str();
533 // When fixed, these should pass
534 EXPECT_FALSE(result.find("nan") != std::string::npos);
535 EXPECT_FALSE(result.find("inf") != std::string::npos);
536}
537
539{
540 // Nearly vertical arrow - should work but may have precision issues
541 Point p1(50, 0);
542 Point p2(50.001, 100); // Very slight horizontal offset
543 Arrow arrow(p1, p2);
544 put_in_plane(*plane, arrow);
545
546 std::ostringstream output;
547 EXPECT_NO_THROW(plane->draw(output));
548}
549
550//============================================================================
551// Polygon Variants Tests
552//============================================================================
553
554class PolygonVariantsTest : public ::testing::Test
555{
556protected:
557 void SetUp() override
558 {
559 plane = std::make_unique<Eepic_Plane>(500, 500);
560
561 // Create a simple square polygon
562 base_poly.add_vertex(Point(0, 0));
563 base_poly.add_vertex(Point(100, 0));
564 base_poly.add_vertex(Point(100, 100));
565 base_poly.add_vertex(Point(0, 100));
567 }
568
569 std::unique_ptr<Eepic_Plane> plane;
571};
572
574{
575 Shade_Polygon shade_poly(base_poly);
576 put_in_plane(*plane, shade_poly);
577
578 std::ostringstream output;
579 plane->draw(output);
580
581 std::string result = output.str();
582 EXPECT_TRUE(result.find("\\shade") != std::string::npos);
583}
584
586{
587 Dotted_Polygon dotted_poly(base_poly);
588 put_in_plane(*plane, dotted_poly);
589
590 std::ostringstream output;
591 plane->draw(output);
592
593 std::string result = output.str();
594 EXPECT_TRUE(result.find("\\dottedline") != std::string::npos);
595}
596
598{
599 Dash_Polygon dash_poly(base_poly);
600 put_in_plane(*plane, dash_poly);
601
602 std::ostringstream output;
603 plane->draw(output);
604
605 std::string result = output.str();
606 EXPECT_TRUE(result.find("\\dashline") != std::string::npos);
607}
608
610{
611 Polygon_With_Points poly_pts(base_poly);
612 put_in_plane(*plane, poly_pts);
613
614 std::ostringstream output;
615 plane->draw(output);
616
617 std::string result = output.str();
618 // Should contain ellipses for the vertex points
619 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
620}
621
623{
624 Spline spline(base_poly);
625 put_in_plane(*plane, spline);
626
627 std::ostringstream output;
628 plane->draw(output);
629
630 std::string result = output.str();
631 EXPECT_TRUE(result.find("\\spline") != std::string::npos);
632}
633
635{
636 Spline_Arrow spline_arrow(base_poly);
637 put_in_plane(*plane, spline_arrow);
638
639 std::ostringstream output;
640 plane->draw(output);
641
642 std::string result = output.str();
643 EXPECT_TRUE(result.find("\\spline") != std::string::npos);
644}
645
646//============================================================================
647// Ellipse Variants Tests
648//============================================================================
649
650class EllipseVariantsTest : public ::testing::Test
651{
652protected:
653 void SetUp() override
654 {
655 plane = std::make_unique<Eepic_Plane>(500, 500);
656 center = Point(50, 50);
657 }
658
659 std::unique_ptr<Eepic_Plane> plane;
660 Point center;
661};
662
664{
665 Ellipse ellipse(center, 20, 10);
666 put_in_plane(*plane, ellipse);
667
668 std::ostringstream output;
669 plane->draw(output);
670
671 std::string result = output.str();
672 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
673}
674
676{
677 Thick_Ellipse thick_ellipse(center, 20, 10);
679
680 std::ostringstream output;
681 plane->draw(output);
682
683 std::string result = output.str();
684 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
685 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
686}
687
689{
690 Shade_Ellipse shade_ellipse(center, 20, 10);
692
693 std::ostringstream output;
694 plane->draw(output);
695
696 std::string result = output.str();
697 EXPECT_TRUE(result.find("\\shade") != std::string::npos);
698}
699
701{
702 // When hradius == vradius, it's a circle
703 Ellipse circle(center, 15, 15);
704 put_in_plane(*plane, circle);
705
706 std::ostringstream output;
707 plane->draw(output);
708
709 std::string result = output.str();
710 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
711}
712
713//============================================================================
714// Text Variants Tests
715//============================================================================
716
717class TextVariantsTest : public ::testing::Test
718{
719protected:
720 void SetUp() override
721 {
722 plane = std::make_unique<Eepic_Plane>(500, 500);
723 pos = Point(50, 50);
724 // Add a segment to provide coordinate range (avoid single-point bug)
725 put_in_plane(*plane, Segment(Point(0, 0), Point(100, 100)));
726 }
727
728 std::unique_ptr<Eepic_Plane> plane;
729 Point pos;
730};
731
733{
734 Left_Text left_text(pos, "LeftAligned");
735 put_in_plane(*plane, left_text);
736
737 std::ostringstream output;
738 plane->draw(output);
739
740 std::string result = output.str();
741 EXPECT_TRUE(result.find("LeftAligned") != std::string::npos);
742}
743
745{
746 Right_Text right_text(pos, "RightAligned");
747 put_in_plane(*plane, right_text);
748
749 std::ostringstream output;
750 plane->draw(output);
751
752 std::string result = output.str();
753 EXPECT_TRUE(result.find("RightAligned") != std::string::npos);
754}
755
757{
758 Center_Text center_text(pos, "Centered");
759 put_in_plane(*plane, center_text);
760
761 std::ostringstream output;
762 plane->draw(output);
763
764 std::string result = output.str();
765 EXPECT_TRUE(result.find("Centered") != std::string::npos);
766}
767
769{
770 // Test with LaTeX special characters (should be handled by user)
771 Center_Text text(pos, "Test$LaTeX$");
772 put_in_plane(*plane, text);
773
774 std::ostringstream output;
775 plane->draw(output);
776
777 std::string result = output.str();
778 EXPECT_TRUE(result.find("Test$LaTeX$") != std::string::npos);
779}
780
781//============================================================================
782// Regular Polygon Tests
783//============================================================================
784
785class RegularPolygonTest : public ::testing::Test
786{
787protected:
788 void SetUp() override
789 {
790 plane = std::make_unique<Eepic_Plane>(500, 500);
791 center = Point(100, 100);
792 }
793
794 std::unique_ptr<Eepic_Plane> plane;
795 Point center;
796};
797
799{
800 Regular_Polygon tri(center, 50, 3, 0);
801 Polygon poly(tri); // Convert to regular polygon
802 put_in_plane(*plane, poly);
803
804 std::ostringstream output;
805 plane->draw(output);
806
807 std::string result = output.str();
808 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
809}
810
812{
813 Regular_Polygon square(center, 50, 4, M_PI / 4); // 45 degree rotation
814 Polygon poly(square);
815 put_in_plane(*plane, poly);
816
817 std::ostringstream output;
818 plane->draw(output);
819
820 std::string result = output.str();
821 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
822}
823
825{
826 Regular_Polygon hexagon(center, 50, 6, 0);
827 Polygon poly(hexagon);
828 put_in_plane(*plane, poly);
829
830 std::ostringstream output;
831 plane->draw(output);
832
833 std::string result = output.str();
834 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
835}
836
837//============================================================================
838// EEPIC Output Format Tests
839//============================================================================
840
841class EepicOutputFormatTest : public ::testing::Test
842{
843protected:
844 void SetUp() override
845 {
846 plane = std::make_unique<Eepic_Plane>(500, 500);
847 }
848
849 std::unique_ptr<Eepic_Plane> plane;
850};
851
853{
854 // Use segment to avoid single-point zero-range bug
855 Segment seg(Point(0, 0), Point(100, 100));
856 put_in_plane(*plane, seg);
857
858 plane->set_resolution(0.1);
859
860 std::ostringstream output;
861 plane->draw(output);
862
863 std::string result = output.str();
864 EXPECT_TRUE(result.find("\\setlength{\\unitlength}{0.1") != std::string::npos);
865}
866
868{
869 // Use segment to avoid single-point zero-range bug
870 Segment seg(Point(0, 0), Point(100, 100));
871 put_in_plane(*plane, seg);
872
873 plane->set_fill_type("gray");
874
875 std::ostringstream output;
876 plane->draw(output);
877
878 std::string result = output.str();
879 EXPECT_TRUE(result.find("\\filltype{gray}") != std::string::npos);
880}
881
883{
884 // Use segment to avoid single-point zero-range bug
885 Segment seg(Point(0, 0), Point(100, 100));
886 put_in_plane(*plane, seg);
887
888 std::ostringstream output;
889 plane->draw(output);
890
891 std::string result = output.str();
892
893 // Check for proper LaTeX picture environment
894 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
895 EXPECT_TRUE(result.find("\\end{picture}") != std::string::npos);
896
897 // Picture environment should come before end
898 size_t begin_pos = result.find("\\begin{picture}");
899 size_t end_pos = result.find("\\end{picture}");
901}
902
904{
905 Point p1(0, 0);
906 Point p2(100, 100);
907 Thick_Segment thick_seg(p1, p2);
908 put_in_plane(*plane, thick_seg);
909
910 std::ostringstream output;
911 plane->draw(output);
912
913 std::string result = output.str();
914 // Each object should be drawn with thinlines reset
915 EXPECT_TRUE(result.find("\\thinlines") != std::string::npos);
916}
917
919{
920 Point p1(10, 20);
921 Point p2(90, 80);
922 Segment seg(p1, p2);
923 put_in_plane(*plane, seg);
924
925 std::ostringstream output;
926 plane->draw(output);
927
928 std::string result = output.str();
929
930 // Output should contain comments about extreme points
931 EXPECT_TRUE(result.find("leftmost point") != std::string::npos);
932 EXPECT_TRUE(result.find("rightmost point") != std::string::npos);
933 EXPECT_TRUE(result.find("highest point") != std::string::npos);
934 EXPECT_TRUE(result.find("lowest point") != std::string::npos);
935}
936
937//============================================================================
938// Squarize Mode Tests
939//============================================================================
940
941class SquarizeModeTest : public ::testing::Test
942{
943protected:
944 void SetUp() override
945 {
946 plane = std::make_unique<Eepic_Plane>(500, 300);
947 }
948
949 std::unique_ptr<Eepic_Plane> plane;
950};
951
953{
954 Point p1(0, 0);
955 Point p2(100, 50);
956 Segment seg(p1, p2);
957 put_in_plane(*plane, seg);
958
959 std::ostringstream output;
960 plane->draw(output, true); // squarize = true
961
962 std::string result = output.str();
963 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
964}
965
967{
968 Point p1(0, 0);
969 Point p2(100, 50);
970 Segment seg(p1, p2);
971 put_in_plane(*plane, seg);
972
973 std::ostringstream output;
974 plane->draw(output, false); // squarize = false
975
976 std::string result = output.str();
977 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
978}
979
980//============================================================================
981// Cartesian Axis Tests
982//============================================================================
983
984class CartesianAxisTest : public ::testing::Test
985{
986protected:
987 void SetUp() override
988 {
989 plane = std::make_unique<Eepic_Plane>(500, 500);
990 }
991
992 std::unique_ptr<Eepic_Plane> plane;
993};
994
996{
997 // Add a segment to provide coordinate range (avoid zero-range bug)
998 Segment seg(Point(0, 0), Point(100, 100));
999 put_in_plane(*plane, seg);
1000
1001 plane->put_cartesian_axis();
1002
1003 std::ostringstream output;
1004 plane->draw(output);
1005
1006 // The output should contain axis drawings
1007 std::string result = output.str();
1008 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
1009}
1010
1011//============================================================================
1012// Coordinate Transformation Tests
1013//============================================================================
1014
1015class CoordinateTransformTest : public ::testing::Test
1016{
1017protected:
1018 void SetUp() override
1019 {
1020 plane = std::make_unique<Eepic_Plane>(500, 500);
1021
1022 // Add some objects to set up coordinate system
1023 Point p1(0, 0);
1024 Point p2(100, 100);
1025 Segment seg(p1, p2);
1027
1028 // Force computation of extreme points
1029 std::ostringstream dummy;
1030 plane->draw(dummy);
1031 }
1032
1033 std::unique_ptr<Eepic_Plane> plane;
1034};
1035
1037{
1038 Point p(50, 50);
1039 std::string str = plane->point_string(p);
1040
1041 // Should be in format "(x,y)"
1042 EXPECT_TRUE(str.front() == '(');
1043 EXPECT_TRUE(str.back() == ')');
1044 EXPECT_TRUE(str.find(',') != std::string::npos);
1045}
1046
1048{
1049 Geom_Number x(50);
1050 double result = plane->h_geom_number_to_eepic(x);
1051
1052 // Result should be a valid coordinate
1053 EXPECT_TRUE(std::isfinite(result));
1054}
1055
1057{
1058 Geom_Number y(50);
1059 double result = plane->v_geom_number_to_eepic(y);
1060
1061 // Result should be a valid coordinate
1062 EXPECT_TRUE(std::isfinite(result));
1063}
1064
1065//============================================================================
1066// Clone and Polymorphism Tests
1067// Note: Eepic_* classes have private constructors. The public interface is
1068// put_in_plane(). These tests verify that cloning works correctly when
1069// objects are added to a plane.
1070//============================================================================
1071
1072// Disabled due to single-point zero-range bug
1074{
1075 Eepic_Plane plane(500, 500);
1076 Point p(10, 20);
1077 put_in_plane(plane, p);
1078
1079 std::ostringstream output;
1080 plane.draw(output);
1081
1082 // After draw, extreme points should match the point
1083 EXPECT_EQ(plane.highest(), p);
1084 EXPECT_EQ(plane.lowest(), p);
1085 EXPECT_EQ(plane.leftmost(), p);
1086 EXPECT_EQ(plane.rightmost(), p);
1087}
1088
1090{
1091 Eepic_Plane plane(500, 500);
1092 Point p1(0, 0);
1093 Point p2(100, 50);
1094 Segment seg(p1, p2);
1095 put_in_plane(plane, seg);
1096
1097 std::ostringstream output;
1098 plane.draw(output);
1099
1100 // Verify extreme points
1101 EXPECT_EQ(plane.leftmost().get_x(), p1.get_x());
1102 EXPECT_EQ(plane.rightmost().get_x(), p2.get_x());
1103}
1104
1106{
1107 Eepic_Plane plane(500, 500);
1108 Point center(50, 50);
1109 Ellipse ellipse(center, 20, 10);
1110 put_in_plane(plane, ellipse);
1111
1112 std::ostringstream output;
1113 plane.draw(output);
1114
1115 // Ellipse extreme points are center +/- radii
1116 EXPECT_EQ(plane.leftmost().get_x(), Geom_Number(30)); // 50 - 20
1117 EXPECT_EQ(plane.rightmost().get_x(), Geom_Number(70)); // 50 + 20
1118 EXPECT_EQ(plane.lowest().get_y(), Geom_Number(40)); // 50 - 10
1119 EXPECT_EQ(plane.highest().get_y(), Geom_Number(60)); // 50 + 10
1120}
1121
1122//============================================================================
1123// Thick Segment Variants Tests
1124//============================================================================
1125
1126class ThickVariantsTest : public ::testing::Test
1127{
1128protected:
1129 void SetUp() override
1130 {
1131 plane = std::make_unique<Eepic_Plane>(500, 500);
1132 p1 = Point(0, 0);
1133 p2 = Point(100, 100);
1134 }
1135
1136 std::unique_ptr<Eepic_Plane> plane;
1137 Point p1, p2;
1138};
1139
1141{
1143 put_in_plane(*plane, thick_dash);
1144
1145 std::ostringstream output;
1146 plane->draw(output);
1147
1148 std::string result = output.str();
1149 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
1150 EXPECT_TRUE(result.find("\\dashline") != std::string::npos);
1151}
1152
1154{
1155 Thick_Arrow thick_arrow(p1, p2);
1156 put_in_plane(*plane, thick_arrow);
1157
1158 std::ostringstream output;
1159 plane->draw(output);
1160
1161 std::string result = output.str();
1162 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
1163}
1164
1166{
1169
1170 std::ostringstream output;
1171 plane->draw(output);
1172
1173 std::string result = output.str();
1174 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
1175 EXPECT_TRUE(result.find("\\dashline") != std::string::npos);
1176}
1177
1178//============================================================================
1179// Thick Polygon Variants Tests
1180//============================================================================
1181
1182class ThickPolygonVariantsTest : public ::testing::Test
1183{
1184protected:
1185 void SetUp() override
1186 {
1187 plane = std::make_unique<Eepic_Plane>(500, 500);
1188
1189 base_poly.add_vertex(Point(0, 0));
1190 base_poly.add_vertex(Point(100, 0));
1191 base_poly.add_vertex(Point(100, 100));
1192 base_poly.add_vertex(Point(0, 100));
1193 base_poly.close();
1194 }
1195
1196 std::unique_ptr<Eepic_Plane> plane;
1198};
1199
1201{
1202 Thick_Spline thick_spline(base_poly);
1203 put_in_plane(*plane, thick_spline);
1204
1205 std::ostringstream output;
1206 plane->draw(output);
1207
1208 std::string result = output.str();
1209 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
1210 EXPECT_TRUE(result.find("\\spline") != std::string::npos);
1211}
1212
1214{
1217
1218 std::ostringstream output;
1219 plane->draw(output);
1220
1221 std::string result = output.str();
1222 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
1223}
1224
1226{
1228 put_in_plane(*plane, thick_shade);
1229
1230 std::ostringstream output;
1231 plane->draw(output);
1232
1233 std::string result = output.str();
1234 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
1235 EXPECT_TRUE(result.find("\\shade") != std::string::npos);
1236}
1237
1238//============================================================================
1239// Edge Cases and Boundary Conditions
1240//============================================================================
1241
1242class EdgeCaseTest : public ::testing::Test
1243{
1244protected:
1245 std::unique_ptr<Eepic_Plane> plane;
1246};
1247
1249{
1250 plane = std::make_unique<Eepic_Plane>(500, 500);
1251
1252 Point p1(0.001, 0.001);
1253 Point p2(0.002, 0.002);
1254 Segment seg(p1, p2);
1255 put_in_plane(*plane, seg);
1256
1257 std::ostringstream output;
1258 EXPECT_NO_THROW(plane->draw(output));
1259}
1260
1262{
1263 plane = std::make_unique<Eepic_Plane>(500, 500);
1264
1265 Point p1(1000000, 1000000);
1266 Point p2(1000100, 1000100);
1267 Segment seg(p1, p2);
1268 put_in_plane(*plane, seg);
1269
1270 std::ostringstream output;
1271 EXPECT_NO_THROW(plane->draw(output));
1272}
1273
1275{
1276 plane = std::make_unique<Eepic_Plane>(500, 500);
1277
1278 Point p1(-100, -100);
1279 Point p2(100, 100);
1280 Segment seg(p1, p2);
1281 put_in_plane(*plane, seg);
1282
1283 std::ostringstream output;
1284 EXPECT_NO_THROW(plane->draw(output));
1285}
1286
1287// Disabled due to zero-range bug (zero-length segment has same start/end point)
1289{
1290 plane = std::make_unique<Eepic_Plane>(500, 500);
1291
1292 Point p(50, 50);
1293 Segment seg(p, p); // Zero-length segment
1294 put_in_plane(*plane, seg);
1295
1296 std::ostringstream output;
1297 // BUG: Crashes due to zero geom_wide and geom_height
1298 EXPECT_NO_THROW(plane->draw(output));
1299}
1300
1301// Disabled due to zero-range bug (single vertex = single point)
1303{
1304 plane = std::make_unique<Eepic_Plane>(500, 500);
1305
1306 Polygon poly;
1307 poly.add_vertex(Point(50, 50));
1308 // Single vertex polygon - edge case
1309
1310 put_in_plane(*plane, poly);
1311
1312 std::ostringstream output;
1313 // BUG: Crashes due to zero geom_wide and geom_height
1314 EXPECT_NO_THROW(plane->draw(output));
1315}
1316
1318{
1319 plane = std::make_unique<Eepic_Plane>(500, 500);
1320
1321 Polygon poly;
1322 poly.add_vertex(Point(0, 0));
1323 poly.add_vertex(Point(100, 100));
1324 // Two vertex polygon is essentially a segment
1325
1326 put_in_plane(*plane, poly);
1327
1328 std::ostringstream output;
1329 EXPECT_NO_THROW(plane->draw(output));
1330}
1331
1332//============================================================================
1333// Memory Management Tests
1334//============================================================================
1335
1337{
1338 // Plane should properly clean up all objects on destruction
1339 {
1340 Eepic_Plane plane(500, 500);
1341
1342 for (int i = 0; i < 100; ++i)
1343 {
1344 Point p(i, i * 2);
1345 put_in_plane(plane, p);
1346 }
1347
1348 std::ostringstream output;
1349 plane.draw(output);
1350
1351 // Plane goes out of scope and should clean up
1352 }
1353
1354 // If we get here without crashes, memory management is working
1355 SUCCEED();
1356}
1357
1358// Disabled due to single-point zero-range bug
1360{
1361 Eepic_Plane plane(500, 500);
1362
1363 Point p(50, 50);
1364 put_in_plane(plane, p);
1365
1366 // Multiple draw calls should work correctly
1367 for (int i = 0; i < 10; ++i)
1368 {
1369 std::ostringstream output;
1370 plane.draw(output);
1371 }
1372
1373 SUCCEED();
1374}
1375
1377{
1378 Eepic_Plane plane(500, 500);
1379
1380 // Use segment to avoid zero-range bug
1381 Segment seg(Point(0, 0), Point(100, 100));
1382 put_in_plane(plane, seg);
1383
1384 // Multiple draw calls should work correctly
1385 for (int i = 0; i < 10; ++i)
1386 {
1387 std::ostringstream output;
1388 plane.draw(output);
1389 }
1390
1391 SUCCEED();
1392}
1393
1394//============================================================================
1395// Integration Tests
1396//============================================================================
1397
1399{
1400 Eepic_Plane plane(1000, 800);
1401
1402 // Add various object types to create a complex diagram
1403
1404 // Points
1405 put_in_plane(plane, Point(100, 100));
1406 put_in_plane(plane, Point(500, 100));
1407 put_in_plane(plane, Point(300, 400));
1408
1409 // Segments and arrows
1410 put_in_plane(plane, Segment(Point(100, 100), Point(500, 100)));
1411 put_in_plane(plane, Arrow(Point(500, 100), Point(300, 400)));
1412 put_in_plane(plane, Dash_Segment(Point(300, 400), Point(100, 100)));
1413
1414 // Ellipse
1415 put_in_plane(plane, Ellipse(Point(300, 250), 50, 30));
1416
1417 // Polygon
1418 Polygon poly;
1419 poly.add_vertex(Point(600, 200));
1420 poly.add_vertex(Point(700, 200));
1421 poly.add_vertex(Point(700, 300));
1422 poly.add_vertex(Point(600, 300));
1423 poly.close();
1424 put_in_plane(plane, poly);
1425
1426 // Text
1427 put_in_plane(plane, Center_Text(Point(300, 50), "Title"));
1428
1429 std::ostringstream output;
1430 plane.draw(output);
1431
1432 std::string result = output.str();
1433
1434 // Verify complete output
1435 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
1436 EXPECT_TRUE(result.find("\\end{picture}") != std::string::npos);
1437 EXPECT_TRUE(result.find("Title") != std::string::npos);
1438 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
1439
1440 // Should have recorded all objects
1441 EXPECT_TRUE(result.find("geometric objects were put in the plane") !=
1442 std::string::npos);
1443}
1444
1446{
1447 // Simulate a graph-like diagram with nodes and edges
1448 Eepic_Plane plane(800, 600);
1449
1450 // Node positions
1451 Point node1(100, 300);
1452 Point node2(400, 100);
1453 Point node3(400, 500);
1454 Point node4(700, 300);
1455
1456 // Draw nodes as ellipses
1457 double node_radius = 30;
1462
1463 // Draw edges as arrows
1464 put_in_plane(plane, Arrow(node1, node2));
1465 put_in_plane(plane, Arrow(node1, node3));
1466 put_in_plane(plane, Arrow(node2, node4));
1467 put_in_plane(plane, Arrow(node3, node4));
1468
1469 // Add node labels
1470 put_in_plane(plane, Center_Text(node1, "A"));
1471 put_in_plane(plane, Center_Text(node2, "B"));
1472 put_in_plane(plane, Center_Text(node3, "C"));
1473 put_in_plane(plane, Center_Text(node4, "D"));
1474
1475 std::ostringstream output;
1476 plane.draw(output);
1477
1478 std::string result = output.str();
1479 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
1480 EXPECT_TRUE(result.find("12 geometric objects were put in the plane") !=
1481 std::string::npos);
1482}
1483
1484//============================================================================
1485// Main
1486//============================================================================
1487
1488int main(int argc, char **argv)
1489{
1490 ::testing::InitGoogleTest(&argc, argv);
1491 return RUN_ALL_TESTS();
1492}
int main()
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
std::unique_ptr< Eepic_Plane > plane
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
std::unique_ptr< Eepic_Plane > plane_with_offset
std::unique_ptr< Eepic_Plane > plane_default
std::unique_ptr< Eepic_Plane > plane
2D canvas for generating EEPIC/LaTeX picture environments.
Definition eepicgeom.H:250
const double & get_height() const
Picture height (in EEPIC units).
Definition eepicgeom.H:526
void zoom(const double &factor)
Scale the EEPIC plane in real points (zoom in/out).
Definition eepicgeom.H:395
const double & get_wide() const
Plane accessors.
Definition eepicgeom.H:523
const Point & highest() const
Definition eepicgeom.H:453
const Point & lowest() const
Definition eepicgeom.H:455
const Point & rightmost() const
Definition eepicgeom.H:451
void draw(std::ostream &output, const bool &squarize=true)
Emits a complete LaTeX picture environment containing the geometric objects.
Definition eepicgeom.H:475
const Point & leftmost() const
Definition eepicgeom.H:449
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
Rectangular point in the plane.
Definition point.H:156
const Geom_Number & get_y() const
Returns y value.
Definition point.H:226
const Geom_Number & get_x() const
Returns x value.
Definition point.H:221
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
A general (irregular) 2D polygon defined by a sequence of vertices.
Definition polygon.H:233
void close()
Close the polygon.
Definition polygon.H:710
void add_vertex(const Point &point)
Add a vertex to the polygon.
Definition polygon.H:610
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
A regular polygon defined by center, side length, and vertex count.
Definition polygon.H:829
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
Fundamental segment defined by two points.
Definition point.H:417
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
Definition point.H:1524
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
#define TEST(name)
void put_in_plane(Eepic_Plane &plane, const Point &geom_obj)
Definition eepicgeom.C:50
EEPIC/LaTeX geometric drawing utilities.
bool approx_equal(double a, double b, double tol=EPSILON)
TEST_F(EepicPlaneTest, DefaultConstruction)
bool tiny_keys
Global flag to enable tiny font size for keys/labels.
constexpr double EPSILON
static mpfr_t y
Definition mpfr_mul_d.c:3
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
Segment-drawing variants (types).
Definition eepicgeom.H:1205
ofstream output
Definition writeHeap.C:213