1+ using XML
2+
3+ import WellKnownGeometry
4+ import GeoFormatTypes as GFT
5+ import GeometryOps as GO
6+ import GeoInterface as GI
7+
8+ """
9+ jts_wkt_to_geom(wkt::String)
10+
11+ Convert a JTS WKT string to a GeometryOps geometry, via WellKnownGeometry.jl and GO.tuples.
12+
13+ The reason this exists is because WellKnownGeometry doesn't work well with newlines in subsidiary geometries,
14+ so this sanitizes the input before parsing and converting.
15+ """
16+ function jts_wkt_to_geom (wkt:: String )
17+ sanitized_wkt = join (strip .(split (wkt, " \n " )), " " )
18+ geom = GFT. WellKnownText (GFT. Geom (), sanitized_wkt)
19+ return GO. tuples (geom)
20+ end
21+
22+ struct TestItem{T}
23+ operation:: String
24+ arg1:: GO.GI.Wrappers.WrapperGeometry
25+ arg2:: GO.GI.Wrappers.WrapperGeometry
26+ expected_result:: T
27+ end
28+
29+ Base. show (io:: IO , :: MIME"text/plain" , item:: TestItem ) = print (io, " TestItem(operation = $(item. operation) , expects $(GI. trait (item. expected_result)) )" )
30+ Base. show (io:: IO , item:: TestItem ) = show (io, MIME " text/plain" (), item)
31+
32+ struct Case
33+ description:: String
34+ geom_a:: GO.GI.Wrappers.WrapperGeometry
35+ geom_b:: GO.GI.Wrappers.WrapperGeometry
36+ items:: Vector{TestItem}
37+ end
38+
39+ function load_test_cases (filepath:: String )
40+ doc = read (filepath, XML. Node) # lazy parsing
41+ run = only (children (doc))
42+ test_cases = Case[]
43+ for case in children (run)
44+ if tag (case) != " case"
45+ continue
46+ end
47+ push! (test_cases, parse_case (case))
48+ end
49+ return test_cases
50+ end
51+
52+ function parse_case (case:: XML.Node )
53+ description = value (only (children (case. children[1 ])))
54+ a = jts_wkt_to_geom (value (only (children (case. children[2 ]))))
55+ b = jts_wkt_to_geom (value (only (children (case. children[3 ]))))
56+
57+ items = TestItem[]
58+ for item in children (case)[4 : end ]
59+ ops = children (item)
60+ for op in ops
61+ op_attrs = XML. attributes (op)
62+ operation = op_attrs[" name" ]
63+ arg1 = op_attrs[" arg1" ]
64+ arg2 = op_attrs[" arg2" ]
65+ expected_result = jts_wkt_to_geom (value (only (op. children)))
66+ push! (items, TestItem (operation, lowercase (arg1) == " a" ? a : b, lowercase (arg2) == " a" ? a : b, expected_result))
67+ end
68+ end
69+ return Case (description, a, b, items)
70+ end
71+
72+
73+ testfile = " /Users/anshul/.julia/dev/geo/jts/modules/tests/src/test/resources/testxml/general/TestOverlayAA.xml"
74+
75+ cases = load_test_cases (testfile)
76+
77+ using Test
78+
79+ for case in cases
80+ @testset " $(case. description) " begin
81+ for item in case. items
82+ @testset " $(item. operation) " begin
83+ result = if item. operation == " union"
84+ GO. union (item. arg1, item. arg2; target = GO. PolygonTrait ())
85+ elseif item. operation == " difference"
86+ GO. difference (item. arg1, item. arg2; target = GO. PolygonTrait ())
87+ elseif item. operation == " intersection"
88+ GO. intersection (item. arg1, item. arg2; target = GO. PolygonTrait ())
89+ elseif item. operation == " symdifference"
90+ continue
91+ else
92+ continue
93+ end
94+
95+ finalresult = if length (result) == 0
96+ nothing
97+ elseif length (result) == 1
98+ only (result)
99+ else
100+ GI. MultiPolygon (result)
101+ end
102+
103+ if isnothing (finalresult)
104+ @warn (" No result" )
105+ continue
106+ end
107+
108+ if GI. geomtrait (item. expected_result) isa Union{GI. MultiPolygonTrait, GI. PolygonTrait}
109+ difference_in_areas = GO. area (GO. difference (finalresult, item. expected_result; target = GO. PolygonTrait ()))
110+ if difference_in_areas > 1
111+ @warn (" Difference in areas: $(difference_in_areas) " )
112+ f, a, p = poly (finalresult; label = " Final result (GO)" , axis = (; title = " $(case. description) - $(item. operation) " ))
113+ poly! (a, item. expected_result; label = " Expected result (JTS)" )
114+ display (f)
115+ end
116+ # @test difference_in_areas < 1
117+ else
118+ @test_broken GO. equals (finalresult, item. expected_result)
119+ end
120+ end
121+ end
122+ end
123+ end
0 commit comments