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
48#include <gtest/gtest.h>
49#include <sstream>
50#include <cmath>
51#include <eepicgeom.H>
52
53// Global variable required by eepicgeom.H (declared extern there)
54bool tiny_keys = false;
55
56using namespace Aleph;
57
58// Tolerance for floating-point comparisons
59constexpr double EPSILON = 1e-6;
60
61// Helper to compare doubles with tolerance
62bool approx_equal(double a, double b, double tol = EPSILON)
63{
64 return std::abs(a - b) < tol;
65}
66
67//============================================================================
68// Eepic_Plane Construction Tests
69//============================================================================
70
71class EepicPlaneTest : public ::testing::Test
72{
73protected:
74 void SetUp() override
75 {
76 plane_default = std::make_unique<Eepic_Plane>(500, 300);
77 plane_with_offset = std::make_unique<Eepic_Plane>(500, 300, 10, 20);
78 }
79
80 std::unique_ptr<Eepic_Plane> plane_default;
81 std::unique_ptr<Eepic_Plane> plane_with_offset;
82};
83
85{
86 EXPECT_EQ(plane_default->get_wide(), 500);
87 EXPECT_EQ(plane_default->get_height(), 300);
88 EXPECT_EQ(plane_default->get_xoffset(), 0);
89 EXPECT_EQ(plane_default->get_yoffset(), 0);
90}
91
93{
94 EXPECT_EQ(plane_with_offset->get_wide(), 500);
95 EXPECT_EQ(plane_with_offset->get_height(), 300);
96 EXPECT_EQ(plane_with_offset->get_xoffset(), 10);
97 EXPECT_EQ(plane_with_offset->get_yoffset(), 20);
98}
99
101{
102 plane_default->set_resolution(0.1);
103 EXPECT_EQ(plane_default->get_resolution(), 0.1);
104
105 plane_default->set_resolution(0.05);
106 EXPECT_EQ(plane_default->get_resolution(), 0.05);
107}
108
110{
111 double original = plane_default->get_shade_thickness();
112 plane_default->set_shade_thickness(2.0);
113 EXPECT_EQ(plane_default->get_shade_thickness(), 2.0);
114
115 plane_default->set_shade_thickness(original);
116 EXPECT_EQ(plane_default->get_shade_thickness(), original);
117}
118
120{
121 Eepic_Plane plane(500, 300);
122 plane.zoom(2.0);
123 EXPECT_EQ(plane.get_wide(), 1000);
124 EXPECT_EQ(plane.get_height(), 600);
125}
126
128{
129 Eepic_Plane plane(500, 300);
130 plane.zoom(0.5);
131 EXPECT_EQ(plane.get_wide(), 250);
132 EXPECT_EQ(plane.get_height(), 150);
133}
134
136{
137 Eepic_Plane plane(500, 300);
138 EXPECT_THROW(plane.zoom(0), std::domain_error);
139 EXPECT_THROW(plane.zoom(-1.0), std::domain_error);
140}
141
142//============================================================================
143// Eepic_Plane with Objects Tests
144//============================================================================
145
146class EepicPlaneWithObjectsTest : public ::testing::Test
147{
148protected:
149 void SetUp() override
150 {
151 plane = std::make_unique<Eepic_Plane>(500, 500);
152 }
153
154 std::unique_ptr<Eepic_Plane> plane;
155};
156
158{
159 // Was disabled: zero-range padding now handles single-point bounding box.
160 Point p(10, 20);
161 put_in_plane(*plane, p);
162
163 std::ostringstream output;
164 EXPECT_NO_THROW(plane->draw(output));
165
166 std::string result = output.str();
167 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
168 EXPECT_TRUE(result.find("\\end{picture}") != std::string::npos);
169}
170
172{
173 // Use two points to avoid zero-range bug
174 Point p1(10, 20);
175 Point p2(100, 80);
176 put_in_plane(*plane, p1);
177 put_in_plane(*plane, p2);
178
179 std::ostringstream output;
180 plane->draw(output);
181
182 std::string result = output.str();
183 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
184 EXPECT_TRUE(result.find("\\end{picture}") != std::string::npos);
185}
186
188{
189 Point p1(0, 0);
190 Point p2(100, 100);
191 Segment seg(p1, p2);
192 put_in_plane(*plane, seg);
193
194 std::ostringstream output;
195 plane->draw(output);
196
197 std::string result = output.str();
198 EXPECT_TRUE(result.find("\\path") != std::string::npos);
199}
200
202{
203 Point p1(0, 0);
204 Point p2(100, 50);
205 Arrow arrow(p1, p2);
206 put_in_plane(*plane, arrow);
207
208 std::ostringstream output;
209 plane->draw(output);
210
211 std::string result = output.str();
212 // Arrow should produce a path plus arrow edges
213 EXPECT_TRUE(result.find("\\path") != std::string::npos);
214}
215
217{
218 Point center(50, 50);
219 Ellipse ellipse(center, 20, 10);
220 put_in_plane(*plane, ellipse);
221
222 std::ostringstream output;
223 plane->draw(output);
224
225 std::string result = output.str();
226 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
227}
228
230{
231 Polygon poly;
232 poly.add_vertex(Point(0, 0));
233 poly.add_vertex(Point(100, 0));
234 poly.add_vertex(Point(100, 100));
235 poly.add_vertex(Point(0, 100));
236 poly.close();
237
238 put_in_plane(*plane, poly);
239
240 std::ostringstream output;
241 plane->draw(output);
242
243 std::string result = output.str();
244 EXPECT_TRUE(result.find("\\path") != std::string::npos);
245}
246
248{
249 Point p1(0, 0);
250 Point p2(100, 0);
251 Point p3(50, 100);
252 Triangle tri(p1, p2, p3);
253
254 put_in_plane(*plane, tri);
255
256 std::ostringstream output;
257 plane->draw(output);
258
259 std::string result = output.str();
260 EXPECT_TRUE(result.find("\\path") != std::string::npos);
261}
262
264{
265 // Add a segment first to provide coordinate range (avoid single-point bug)
266 put_in_plane(*plane, Segment(Point(0, 0), Point(100, 100)));
267
268 Point p(50, 50);
269 Text text(p, "Hello");
270 put_in_plane(*plane, text);
271
272 std::ostringstream output;
273 plane->draw(output);
274
275 std::string result = output.str();
276 EXPECT_TRUE(result.find("Hello") != std::string::npos);
277}
278
280{
281 Point p(50, 50);
282 put_in_plane(*plane, p);
283
284 Segment seg(Point(0, 0), Point(100, 100));
285 put_in_plane(*plane, seg);
286
287 Ellipse ellipse(Point(50, 50), 10, 10);
288 put_in_plane(*plane, ellipse);
289
290 std::ostringstream output;
291 plane->draw(output);
292
293 std::string result = output.str();
294 // Check that 3 objects were put in the plane
295 EXPECT_TRUE(result.find("3 geometric objects were put in the plane") !=
296 std::string::npos);
297}
298
299//============================================================================
300// Extreme Points Calculation Tests
301//============================================================================
302
303class ExtremePointsTest : public ::testing::Test
304{
305protected:
306 void SetUp() override
307 {
308 plane = std::make_unique<Eepic_Plane>(500, 500);
309 }
310
311 std::unique_ptr<Eepic_Plane> plane;
312};
313
314// NOTE: Single point causes assertion failure due to zero geom_wide/geom_height
316{
317 // Was disabled: zero-range padding now handles single-point bounding box.
318 Point p(50, 75);
319 put_in_plane(*plane, p);
320
321 std::ostringstream output;
322 EXPECT_NO_THROW(plane->draw(output));
323
324 // After draw, extreme points should be computed
325 EXPECT_EQ(plane->leftmost(), p);
326 EXPECT_EQ(plane->rightmost(), p);
327 EXPECT_EQ(plane->highest(), p);
328 EXPECT_EQ(plane->lowest(), p);
329}
330
332{
333 Point p1(10, 20);
334 Point p2(100, 150);
335 Segment seg(p1, p2);
336 put_in_plane(*plane, seg);
337
338 std::ostringstream output;
339 plane->draw(output);
340
341 EXPECT_EQ(plane->leftmost().get_x(), p1.get_x());
342 EXPECT_EQ(plane->rightmost().get_x(), p2.get_x());
343 EXPECT_EQ(plane->lowest().get_y(), p1.get_y());
344 EXPECT_EQ(plane->highest().get_y(), p2.get_y());
345}
346
348{
349 Point p1(-50, -25);
350 Point p2(150, 200);
351
352 put_in_plane(*plane, p1);
353 put_in_plane(*plane, p2);
354
355 std::ostringstream output;
356 plane->draw(output);
357
358 EXPECT_EQ(plane->leftmost().get_x(), Geom_Number(-50));
359 EXPECT_EQ(plane->rightmost().get_x(), Geom_Number(150));
360 EXPECT_EQ(plane->lowest().get_y(), Geom_Number(-25));
361 EXPECT_EQ(plane->highest().get_y(), Geom_Number(200));
362}
363
364//============================================================================
365// Segment Drawing Variants Tests
366//============================================================================
367
368class SegmentVariantsTest : public ::testing::Test
369{
370protected:
371 void SetUp() override
372 {
373 plane = std::make_unique<Eepic_Plane>(500, 500);
374 p1 = Point(0, 0);
375 p2 = Point(100, 100);
376 }
377
378 std::unique_ptr<Eepic_Plane> plane;
380};
381
383{
384 Thick_Segment thick_seg(p1, p2);
385 put_in_plane(*plane, thick_seg);
386
387 std::ostringstream output;
388 plane->draw(output);
389
390 std::string result = output.str();
391 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
392}
393
395{
397 put_in_plane(*plane, dotted_seg);
398
399 std::ostringstream output;
400 plane->draw(output);
401
402 std::string result = output.str();
403 EXPECT_TRUE(result.find("\\dottedline") != std::string::npos);
404}
405
407{
408 Dash_Segment dash_seg(p1, p2);
409 put_in_plane(*plane, dash_seg);
410
411 std::ostringstream output;
412 plane->draw(output);
413
414 std::string result = output.str();
415 EXPECT_TRUE(result.find("\\dashline") != std::string::npos);
416}
417
419{
421 put_in_plane(*plane, dotted_arrow);
422
423 std::ostringstream output;
424 plane->draw(output);
425
426 std::string result = output.str();
427 EXPECT_TRUE(result.find("\\dottedline") != std::string::npos);
428 // Should also have arrow edges
429 EXPECT_TRUE(result.find("arrow's edges") != std::string::npos);
430}
431
433{
434 Dash_Arrow dash_arrow(p1, p2);
435 put_in_plane(*plane, dash_arrow);
436
437 std::ostringstream output;
438 plane->draw(output);
439
440 std::string result = output.str();
441 EXPECT_TRUE(result.find("\\dashline") != std::string::npos);
442}
443
444//============================================================================
445// Arrow Edge Case Tests - Testing the vertical segment bug
446//============================================================================
447
448class ArrowEdgeCaseTest : public ::testing::Test
449{
450protected:
451 void SetUp() override
452 {
453 plane = std::make_unique<Eepic_Plane>(500, 500);
454 }
455
456 std::unique_ptr<Eepic_Plane> plane;
457};
458
460{
461 // Standard diagonal arrow - should work fine
462 Point p1(0, 0);
463 Point p2(100, 50);
464 Arrow arrow(p1, p2);
465 put_in_plane(*plane, arrow);
466
467 std::ostringstream output;
468 EXPECT_NO_THROW(plane->draw(output));
469
470 std::string result = output.str();
471 EXPECT_FALSE(result.find("nan") != std::string::npos);
472 EXPECT_FALSE(result.find("inf") != std::string::npos);
473}
474
475// Disabled due to zero-range bug when y1 == y2 (geom_height = 0)
477{
478 // Horizontal arrow (tgt_y == src_y) — was disabled due to zero-range bug
479 Point p1(0, 50);
480 Point p2(100, 50);
481 Arrow arrow(p1, p2);
482 put_in_plane(*plane, arrow);
483
484 std::ostringstream output;
485 EXPECT_NO_THROW(plane->draw(output));
486
487 std::string result = output.str();
488 EXPECT_FALSE(result.find("nan") != std::string::npos);
489 EXPECT_FALSE(result.find("inf") != std::string::npos);
490}
491
493{
494 // Nearly horizontal arrow with slight y difference to avoid zero-range bug
495 Point p1(0, 50);
496 Point p2(100, 50.001); // Slight y offset
497 Arrow arrow(p1, p2);
498 put_in_plane(*plane, arrow);
499
500 std::ostringstream output;
501 EXPECT_NO_THROW(plane->draw(output));
502
503 std::string result = output.str();
504 EXPECT_FALSE(result.find("nan") != std::string::npos);
505 EXPECT_FALSE(result.find("inf") != std::string::npos);
506}
507
509{
510 // Vertical arrow (tgt_x == src_x) — was disabled due to division by zero;
511 // fixed by replacing atan(dy/dx) with atan2(dy, dx).
512 Point p1(50, 0);
513 Point p2(50, 100);
514 Arrow arrow(p1, p2);
515 put_in_plane(*plane, arrow);
516
517 std::ostringstream output;
518 EXPECT_NO_THROW(plane->draw(output));
519
520 std::string result = output.str();
521 EXPECT_FALSE(result.find("nan") != std::string::npos);
522 EXPECT_FALSE(result.find("inf") != std::string::npos);
523}
524
526{
527 // Nearly vertical arrow - should work but may have precision issues
528 Point p1(50, 0);
529 Point p2(50.001, 100); // Very slight horizontal offset
530 Arrow arrow(p1, p2);
531 put_in_plane(*plane, arrow);
532
533 std::ostringstream output;
534 EXPECT_NO_THROW(plane->draw(output));
535}
536
537//============================================================================
538// Polygon Variants Tests
539//============================================================================
540
541class PolygonVariantsTest : public ::testing::Test
542{
543protected:
544 void SetUp() override
545 {
546 plane = std::make_unique<Eepic_Plane>(500, 500);
547
548 // Create a simple square polygon
550 base_poly.add_vertex(Point(100, 0));
551 base_poly.add_vertex(Point(100, 100));
552 base_poly.add_vertex(Point(0, 100));
554 }
555
556 std::unique_ptr<Eepic_Plane> plane;
558};
559
561{
562 Shade_Polygon shade_poly(base_poly);
563 put_in_plane(*plane, shade_poly);
564
565 std::ostringstream output;
566 plane->draw(output);
567
568 std::string result = output.str();
569 EXPECT_TRUE(result.find("\\shade") != std::string::npos);
570}
571
573{
574 Dotted_Polygon dotted_poly(base_poly);
575 put_in_plane(*plane, dotted_poly);
576
577 std::ostringstream output;
578 plane->draw(output);
579
580 std::string result = output.str();
581 EXPECT_TRUE(result.find("\\dottedline") != std::string::npos);
582}
583
585{
586 Dash_Polygon dash_poly(base_poly);
587 put_in_plane(*plane, dash_poly);
588
589 std::ostringstream output;
590 plane->draw(output);
591
592 std::string result = output.str();
593 EXPECT_TRUE(result.find("\\dashline") != std::string::npos);
594}
595
597{
598 Polygon_With_Points poly_pts(base_poly);
599 put_in_plane(*plane, poly_pts);
600
601 std::ostringstream output;
602 plane->draw(output);
603
604 std::string result = output.str();
605 // Should contain ellipses for the vertex points
606 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
607}
608
610{
611 Spline spline(base_poly);
612 put_in_plane(*plane, spline);
613
614 std::ostringstream output;
615 plane->draw(output);
616
617 std::string result = output.str();
618 EXPECT_TRUE(result.find("\\spline") != std::string::npos);
619}
620
622{
623 Spline_Arrow spline_arrow(base_poly);
624 put_in_plane(*plane, spline_arrow);
625
626 std::ostringstream output;
627 plane->draw(output);
628
629 std::string result = output.str();
630 EXPECT_TRUE(result.find("\\spline") != std::string::npos);
631}
632
633//============================================================================
634// Ellipse Variants Tests
635//============================================================================
636
637class EllipseVariantsTest : public ::testing::Test
638{
639protected:
640 void SetUp() override
641 {
642 plane = std::make_unique<Eepic_Plane>(500, 500);
643 center = Point(50, 50);
644 }
645
646 std::unique_ptr<Eepic_Plane> plane;
648};
649
651{
652 Ellipse ellipse(center, 20, 10);
653 put_in_plane(*plane, ellipse);
654
655 std::ostringstream output;
656 plane->draw(output);
657
658 std::string result = output.str();
659 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
660}
661
663{
664 Thick_Ellipse thick_ellipse(center, 20, 10);
666
667 std::ostringstream output;
668 plane->draw(output);
669
670 std::string result = output.str();
671 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
672 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
673}
674
676{
677 Shade_Ellipse shade_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("\\shade") != std::string::npos);
685}
686
688{
689 // When hradius == vradius, it's a circle
690 Ellipse circle(center, 15, 15);
691 put_in_plane(*plane, circle);
692
693 std::ostringstream output;
694 plane->draw(output);
695
696 std::string result = output.str();
697 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
698}
699
700//============================================================================
701// Text Variants Tests
702//============================================================================
703
704class TextVariantsTest : public ::testing::Test
705{
706protected:
707 void SetUp() override
708 {
709 plane = std::make_unique<Eepic_Plane>(500, 500);
710 pos = Point(50, 50);
711 // Add a segment to provide coordinate range (avoid single-point bug)
712 put_in_plane(*plane, Segment(Point(0, 0), Point(100, 100)));
713 }
714
715 std::unique_ptr<Eepic_Plane> plane;
717};
718
720{
721 Left_Text left_text(pos, "LeftAligned");
722 put_in_plane(*plane, left_text);
723
724 std::ostringstream output;
725 plane->draw(output);
726
727 std::string result = output.str();
728 EXPECT_TRUE(result.find("LeftAligned") != std::string::npos);
729}
730
732{
733 Right_Text right_text(pos, "RightAligned");
734 put_in_plane(*plane, right_text);
735
736 std::ostringstream output;
737 plane->draw(output);
738
739 std::string result = output.str();
740 EXPECT_TRUE(result.find("RightAligned") != std::string::npos);
741}
742
744{
745 Center_Text center_text(pos, "Centered");
746 put_in_plane(*plane, center_text);
747
748 std::ostringstream output;
749 plane->draw(output);
750
751 std::string result = output.str();
752 EXPECT_TRUE(result.find("Centered") != std::string::npos);
753}
754
756{
757 // Test with LaTeX special characters (should be handled by user)
758 Center_Text text(pos, "Test$LaTeX$");
759 put_in_plane(*plane, text);
760
761 std::ostringstream output;
762 plane->draw(output);
763
764 std::string result = output.str();
765 EXPECT_TRUE(result.find("Test$LaTeX$") != std::string::npos);
766}
767
768//============================================================================
769// Regular Polygon Tests
770//============================================================================
771
772class RegularPolygonTest : public ::testing::Test
773{
774protected:
775 void SetUp() override
776 {
777 plane = std::make_unique<Eepic_Plane>(500, 500);
778 center = Point(100, 100);
779 }
780
781 std::unique_ptr<Eepic_Plane> plane;
783};
784
786{
787 Regular_Polygon tri(center, 50, 3, 0);
788 Polygon poly(tri); // Convert to regular polygon
789 put_in_plane(*plane, poly);
790
791 std::ostringstream output;
792 plane->draw(output);
793
794 std::string result = output.str();
795 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
796}
797
799{
800 Regular_Polygon square(center, 50, 4, M_PI / 4); // 45 degree rotation
801 Polygon poly(square);
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 hexagon(center, 50, 6, 0);
814 Polygon poly(hexagon);
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
824//============================================================================
825// EEPIC Output Format Tests
826//============================================================================
827
828class EepicOutputFormatTest : public ::testing::Test
829{
830protected:
831 void SetUp() override
832 {
833 plane = std::make_unique<Eepic_Plane>(500, 500);
834 }
835
836 std::unique_ptr<Eepic_Plane> plane;
837};
838
840{
841 // Use segment to avoid single-point zero-range bug
842 Segment seg(Point(0, 0), Point(100, 100));
843 put_in_plane(*plane, seg);
844
845 plane->set_resolution(0.1);
846
847 std::ostringstream output;
848 plane->draw(output);
849
850 std::string result = output.str();
851 EXPECT_TRUE(result.find("\\setlength{\\unitlength}{0.1") != std::string::npos);
852}
853
855{
856 // Use segment to avoid single-point zero-range bug
857 Segment seg(Point(0, 0), Point(100, 100));
858 put_in_plane(*plane, seg);
859
860 plane->set_fill_type("gray");
861
862 std::ostringstream output;
863 plane->draw(output);
864
865 std::string result = output.str();
866 EXPECT_TRUE(result.find("\\filltype{gray}") != std::string::npos);
867}
868
870{
871 // Use segment to avoid single-point zero-range bug
872 Segment seg(Point(0, 0), Point(100, 100));
873 put_in_plane(*plane, seg);
874
875 std::ostringstream output;
876 plane->draw(output);
877
878 std::string result = output.str();
879
880 // Check for proper LaTeX picture environment
881 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
882 EXPECT_TRUE(result.find("\\end{picture}") != std::string::npos);
883
884 // Picture environment should come before end
885 size_t begin_pos = result.find("\\begin{picture}");
886 size_t end_pos = result.find("\\end{picture}");
888}
889
891{
892 Point p1(0, 0);
893 Point p2(100, 100);
894 Thick_Segment thick_seg(p1, p2);
895 put_in_plane(*plane, thick_seg);
896
897 std::ostringstream output;
898 plane->draw(output);
899
900 std::string result = output.str();
901 // Each object should be drawn with thinlines reset
902 EXPECT_TRUE(result.find("\\thinlines") != std::string::npos);
903}
904
906{
907 Point p1(10, 20);
908 Point p2(90, 80);
909 Segment seg(p1, p2);
910 put_in_plane(*plane, seg);
911
912 std::ostringstream output;
913 plane->draw(output);
914
915 std::string result = output.str();
916
917 // Output should contain comments about extreme points
918 EXPECT_TRUE(result.find("leftmost point") != std::string::npos);
919 EXPECT_TRUE(result.find("rightmost point") != std::string::npos);
920 EXPECT_TRUE(result.find("highest point") != std::string::npos);
921 EXPECT_TRUE(result.find("lowest point") != std::string::npos);
922}
923
924//============================================================================
925// Squarize Mode Tests
926//============================================================================
927
928class SquarizeModeTest : public ::testing::Test
929{
930protected:
931 void SetUp() override
932 {
933 plane = std::make_unique<Eepic_Plane>(500, 300);
934 }
935
936 std::unique_ptr<Eepic_Plane> plane;
937};
938
940{
941 Point p1(0, 0);
942 Point p2(100, 50);
943 Segment seg(p1, p2);
944 put_in_plane(*plane, seg);
945
946 std::ostringstream output;
947 plane->draw(output, true); // squarize = true
948
949 std::string result = output.str();
950 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
951}
952
954{
955 Point p1(0, 0);
956 Point p2(100, 50);
957 Segment seg(p1, p2);
958 put_in_plane(*plane, seg);
959
960 std::ostringstream output;
961 plane->draw(output, false); // squarize = false
962
963 std::string result = output.str();
964 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
965}
966
967//============================================================================
968// Cartesian Axis Tests
969//============================================================================
970
971class CartesianAxisTest : public ::testing::Test
972{
973protected:
974 void SetUp() override
975 {
976 plane = std::make_unique<Eepic_Plane>(500, 500);
977 }
978
979 std::unique_ptr<Eepic_Plane> plane;
980};
981
983{
984 // Add a segment to provide coordinate range (avoid zero-range bug)
985 Segment seg(Point(0, 0), Point(100, 100));
986 put_in_plane(*plane, seg);
987
988 plane->put_cartesian_axis();
989
990 std::ostringstream output;
991 plane->draw(output);
992
993 // The output should contain axis drawings
994 std::string result = output.str();
995 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
996}
997
998//============================================================================
999// Coordinate Transformation Tests
1000//============================================================================
1001
1002class CoordinateTransformTest : public ::testing::Test
1003{
1004protected:
1005 void SetUp() override
1006 {
1007 plane = std::make_unique<Eepic_Plane>(500, 500);
1008
1009 // Add some objects to set up coordinate system
1010 Point p1(0, 0);
1011 Point p2(100, 100);
1012 Segment seg(p1, p2);
1013 put_in_plane(*plane, seg);
1014
1015 // Force computation of extreme points
1016 std::ostringstream dummy;
1017 plane->draw(dummy);
1018 }
1019
1020 std::unique_ptr<Eepic_Plane> plane;
1021};
1022
1024{
1025 Point p(50, 50);
1026 std::string str = plane->point_string(p);
1027
1028 // Should be in format "(x,y)"
1029 EXPECT_TRUE(str.front() == '(');
1030 EXPECT_TRUE(str.back() == ')');
1031 EXPECT_TRUE(str.find(',') != std::string::npos);
1032}
1033
1035{
1036 Geom_Number x(50);
1037 double result = plane->h_geom_number_to_eepic(x);
1038
1039 // Result should be a valid coordinate
1040 EXPECT_TRUE(std::isfinite(result));
1041}
1042
1044{
1045 Geom_Number y(50);
1046 double result = plane->v_geom_number_to_eepic(y);
1047
1048 // Result should be a valid coordinate
1049 EXPECT_TRUE(std::isfinite(result));
1050}
1051
1052//============================================================================
1053// Clone and Polymorphism Tests
1054// Note: Eepic_* classes have private constructors. The public interface is
1055// put_in_plane(). These tests verify that cloning works correctly when
1056// objects are added to a plane.
1057//============================================================================
1058
1059// Disabled due to single-point zero-range bug
1061{
1062 Eepic_Plane plane(500, 500);
1063 Point p(10, 20);
1064 put_in_plane(plane, p);
1065
1066 std::ostringstream output;
1067 ASSERT_NO_THROW(plane.draw(output));
1068
1069 // After draw, extreme points should match the point
1070 EXPECT_EQ(plane.highest(), p);
1071 EXPECT_EQ(plane.lowest(), p);
1072 EXPECT_EQ(plane.leftmost(), p);
1073 EXPECT_EQ(plane.rightmost(), p);
1074}
1075
1077{
1078 Eepic_Plane plane(500, 500);
1079 Point p1(0, 0);
1080 Point p2(100, 50);
1081 Segment seg(p1, p2);
1082 put_in_plane(plane, seg);
1083
1084 std::ostringstream output;
1085 plane.draw(output);
1086
1087 // Verify extreme points
1088 EXPECT_EQ(plane.leftmost().get_x(), p1.get_x());
1089 EXPECT_EQ(plane.rightmost().get_x(), p2.get_x());
1090}
1091
1093{
1094 Eepic_Plane plane(500, 500);
1095 Point center(50, 50);
1096 Ellipse ellipse(center, 20, 10);
1097 put_in_plane(plane, ellipse);
1098
1099 std::ostringstream output;
1100 plane.draw(output);
1101
1102 // Ellipse extreme points are center +/- radii
1103 EXPECT_EQ(plane.leftmost().get_x(), Geom_Number(30)); // 50 - 20
1104 EXPECT_EQ(plane.rightmost().get_x(), Geom_Number(70)); // 50 + 20
1105 EXPECT_EQ(plane.lowest().get_y(), Geom_Number(40)); // 50 - 10
1106 EXPECT_EQ(plane.highest().get_y(), Geom_Number(60)); // 50 + 10
1107}
1108
1109//============================================================================
1110// Thick Segment Variants Tests
1111//============================================================================
1112
1113class ThickVariantsTest : public ::testing::Test
1114{
1115protected:
1116 void SetUp() override
1117 {
1118 plane = std::make_unique<Eepic_Plane>(500, 500);
1119 p1 = Point(0, 0);
1120 p2 = Point(100, 100);
1121 }
1122
1123 std::unique_ptr<Eepic_Plane> plane;
1125};
1126
1128{
1130 put_in_plane(*plane, thick_dash);
1131
1132 std::ostringstream output;
1133 plane->draw(output);
1134
1135 std::string result = output.str();
1136 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
1137 EXPECT_TRUE(result.find("\\dashline") != std::string::npos);
1138}
1139
1141{
1142 Thick_Arrow thick_arrow(p1, p2);
1143 put_in_plane(*plane, thick_arrow);
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}
1151
1153{
1156
1157 std::ostringstream output;
1158 plane->draw(output);
1159
1160 std::string result = output.str();
1161 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
1162 EXPECT_TRUE(result.find("\\dashline") != std::string::npos);
1163}
1164
1165//============================================================================
1166// Thick Polygon Variants Tests
1167//============================================================================
1168
1169class ThickPolygonVariantsTest : public ::testing::Test
1170{
1171protected:
1172 void SetUp() override
1173 {
1174 plane = std::make_unique<Eepic_Plane>(500, 500);
1175
1176 base_poly.add_vertex(Point(0, 0));
1177 base_poly.add_vertex(Point(100, 0));
1178 base_poly.add_vertex(Point(100, 100));
1179 base_poly.add_vertex(Point(0, 100));
1180 base_poly.close();
1181 }
1182
1183 std::unique_ptr<Eepic_Plane> plane;
1185};
1186
1188{
1189 Thick_Spline thick_spline(base_poly);
1190 put_in_plane(*plane, thick_spline);
1191
1192 std::ostringstream output;
1193 plane->draw(output);
1194
1195 std::string result = output.str();
1196 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
1197 EXPECT_TRUE(result.find("\\spline") != std::string::npos);
1198}
1199
1201{
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}
1211
1213{
1215 put_in_plane(*plane, thick_shade);
1216
1217 std::ostringstream output;
1218 plane->draw(output);
1219
1220 std::string result = output.str();
1221 EXPECT_TRUE(result.find("\\Thicklines") != std::string::npos);
1222 EXPECT_TRUE(result.find("\\shade") != std::string::npos);
1223}
1224
1225//============================================================================
1226// Edge Cases and Boundary Conditions
1227//============================================================================
1228
1229class EdgeCaseTest : public ::testing::Test
1230{
1231protected:
1232 std::unique_ptr<Eepic_Plane> plane;
1233};
1234
1236{
1237 plane = std::make_unique<Eepic_Plane>(500, 500);
1238
1239 Point p1(0.001, 0.001);
1240 Point p2(0.002, 0.002);
1241 Segment seg(p1, p2);
1242 put_in_plane(*plane, seg);
1243
1244 std::ostringstream output;
1245 EXPECT_NO_THROW(plane->draw(output));
1246}
1247
1249{
1250 plane = std::make_unique<Eepic_Plane>(500, 500);
1251
1252 Point p1(1000000, 1000000);
1253 Point p2(1000100, 1000100);
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(-100, -100);
1266 Point p2(100, 100);
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
1274// Disabled due to zero-range bug (zero-length segment has same start/end point)
1276{
1277 plane = std::make_unique<Eepic_Plane>(500, 500);
1278
1279 Point p(50, 50);
1280 Segment seg(p, p); // Zero-length segment
1281 put_in_plane(*plane, seg);
1282
1283 std::ostringstream output;
1284 EXPECT_NO_THROW(plane->draw(output));
1285}
1286
1288{
1289 plane = std::make_unique<Eepic_Plane>(500, 500);
1290
1291 Polygon poly;
1292 poly.add_vertex(Point(50, 50));
1293
1294 put_in_plane(*plane, poly);
1295
1296 std::ostringstream output;
1297 // Single-vertex polygon throws because Segment_Iterator requires >= 2 vertices
1298 EXPECT_THROW(plane->draw(output), std::domain_error);
1299}
1300
1302{
1303 plane = std::make_unique<Eepic_Plane>(500, 500);
1304
1305 Polygon poly;
1306 poly.add_vertex(Point(0, 0));
1307 poly.add_vertex(Point(100, 100));
1308 // Two vertex polygon is essentially a segment
1309
1310 put_in_plane(*plane, poly);
1311
1312 std::ostringstream output;
1313 EXPECT_NO_THROW(plane->draw(output));
1314}
1315
1316//============================================================================
1317// Memory Management Tests
1318//============================================================================
1319
1321{
1322 // Plane should properly clean up all objects on destruction
1323 {
1324 Eepic_Plane plane(500, 500);
1325
1326 for (int i = 0; i < 100; ++i)
1327 {
1328 Point p(i, i * 2);
1329 put_in_plane(plane, p);
1330 }
1331
1332 std::ostringstream output;
1333 plane.draw(output);
1334
1335 // Plane goes out of scope and should clean up
1336 }
1337
1338 // If we get here without crashes, memory management is working
1339 SUCCEED();
1340}
1341
1343{
1344 Eepic_Plane plane(500, 500);
1345
1346 Point p(50, 50);
1347 put_in_plane(plane, p);
1348
1349 // Multiple draw calls should work correctly
1350 for (int i = 0; i < 10; ++i)
1351 {
1352 std::ostringstream output;
1353 plane.draw(output);
1354 }
1355
1356 SUCCEED();
1357}
1358
1360{
1361 Eepic_Plane plane(500, 500);
1362
1363 // Use segment to avoid zero-range bug
1364 Segment seg(Point(0, 0), Point(100, 100));
1365 put_in_plane(plane, seg);
1366
1367 // Multiple draw calls should work correctly
1368 for (int i = 0; i < 10; ++i)
1369 {
1370 std::ostringstream output;
1371 plane.draw(output);
1372 }
1373
1374 SUCCEED();
1375}
1376
1377//============================================================================
1378// Integration Tests
1379//============================================================================
1380
1382{
1383 Eepic_Plane plane(1000, 800);
1384
1385 // Add various object types to create a complex diagram
1386
1387 // Points
1388 put_in_plane(plane, Point(100, 100));
1389 put_in_plane(plane, Point(500, 100));
1390 put_in_plane(plane, Point(300, 400));
1391
1392 // Segments and arrows
1393 put_in_plane(plane, Segment(Point(100, 100), Point(500, 100)));
1394 put_in_plane(plane, Arrow(Point(500, 100), Point(300, 400)));
1395 put_in_plane(plane, Dash_Segment(Point(300, 400), Point(100, 100)));
1396
1397 // Ellipse
1398 put_in_plane(plane, Ellipse(Point(300, 250), 50, 30));
1399
1400 // Polygon
1401 Polygon poly;
1402 poly.add_vertex(Point(600, 200));
1403 poly.add_vertex(Point(700, 200));
1404 poly.add_vertex(Point(700, 300));
1405 poly.add_vertex(Point(600, 300));
1406 poly.close();
1407 put_in_plane(plane, poly);
1408
1409 // Text
1410 put_in_plane(plane, Center_Text(Point(300, 50), "Title"));
1411
1412 std::ostringstream output;
1413 plane.draw(output);
1414
1415 std::string result = output.str();
1416
1417 // Verify complete output
1418 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
1419 EXPECT_TRUE(result.find("\\end{picture}") != std::string::npos);
1420 EXPECT_TRUE(result.find("Title") != std::string::npos);
1421 EXPECT_TRUE(result.find("\\ellipse") != std::string::npos);
1422
1423 // Should have recorded all objects
1424 EXPECT_TRUE(result.find("geometric objects were put in the plane") !=
1425 std::string::npos);
1426}
1427
1429{
1430 // Simulate a graph-like diagram with nodes and edges
1431 Eepic_Plane plane(800, 600);
1432
1433 // Node positions
1434 Point node1(100, 300);
1435 Point node2(400, 100);
1436 Point node3(400, 500);
1437 Point node4(700, 300);
1438
1439 // Draw nodes as ellipses
1440 double node_radius = 30;
1445
1446 // Draw edges as arrows
1447 put_in_plane(plane, Arrow(node1, node2));
1448 put_in_plane(plane, Arrow(node1, node3));
1449 put_in_plane(plane, Arrow(node2, node4));
1450 put_in_plane(plane, Arrow(node3, node4));
1451
1452 // Add node labels
1453 put_in_plane(plane, Center_Text(node1, "A"));
1454 put_in_plane(plane, Center_Text(node2, "B"));
1455 put_in_plane(plane, Center_Text(node3, "C"));
1456 put_in_plane(plane, Center_Text(node4, "D"));
1457
1458 std::ostringstream output;
1459 plane.draw(output);
1460
1461 std::string result = output.str();
1462 EXPECT_TRUE(result.find("\\begin{picture}") != std::string::npos);
1463 EXPECT_TRUE(result.find("12 geometric objects were put in the plane") !=
1464 std::string::npos);
1465}
1466
1467//============================================================================
1468// Main
1469//============================================================================
1470
1471int main(int argc, char **argv)
1472{
1473 ::testing::InitGoogleTest(&argc, argv);
1474 return RUN_ALL_TESTS();
1475}
An axis-aligned ellipse.
Definition point.H:2006
Represents a point with rectangular coordinates in a 2D plane.
Definition point.H:229
const Geom_Number & get_x() const noexcept
Gets the x-coordinate value.
Definition point.H:457
const Geom_Number & get_y() const noexcept
Gets the y-coordinate value.
Definition point.H:466
A general (irregular) 2D polygon defined by a sequence of vertices.
Definition polygon.H:246
void add_vertex(const Point &point)
Add a vertex to the polygon.
Definition polygon.H:677
void close()
Close the polygon.
Definition polygon.H:840
A regular polygon defined by center, side length, and vertex count.
Definition polygon.H:1132
Represents a line segment between two points.
Definition point.H:827
Represents a text string positioned at a 2D point.
Definition point.H:2739
A non-degenerate triangle defined by three points.
Definition point.H:1478
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:535
void zoom(const double &factor)
Scale the EEPIC plane in real points (zoom in/out).
Definition eepicgeom.H:397
const double & get_wide() const
Plane accessors.
Definition eepicgeom.H:532
const Point & highest() const
Definition eepicgeom.H:462
const Point & lowest() const
Definition eepicgeom.H:464
const Point & rightmost() const
Definition eepicgeom.H:460
void draw(std::ostream &output, const bool &squarize=true)
Emits a complete LaTeX picture environment containing the geometric objects.
Definition eepicgeom.H:484
const Point & leftmost() const
Definition eepicgeom.H:458
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
void SetUp() override
std::unique_ptr< Eepic_Plane > plane
#define TEST(name)
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
void put_in_plane(Tikz_Plane &plane, const Geom &geom_obj)
Insert any supported geometry type in a Tikz_Plane.
Definition tikzgeom.H:1456
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
Segment-drawing variants (types).
Definition eepicgeom.H:1214
ofstream output
Definition writeHeap.C:215