Skip to content

Commit 4d9eb9b

Browse files
committed
fix: handle crs differences
1 parent 3eeb46d commit 4d9eb9b

File tree

2 files changed

+339
-20
lines changed

2 files changed

+339
-20
lines changed

ORStools/gui/ORStoolsDialog.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -627,15 +627,15 @@ def load_vertices_from_layer(self, testing: str = "") -> None:
627627
geom.wkbType()
628628
):
629629
pt = geom.asPoint()
630-
self.create_vertex(pt, id, 4326)
630+
self.create_vertex(pt, id, layer.crs().postgisSrid())
631631
self.line_tool.create_rubber_band()
632632

633633
elif geom.type() == QgsWkbTypes.GeometryType.PointGeometry and QgsWkbTypes.isMultiType(
634634
geom.wkbType()
635635
):
636636
pts = geom.asMultiPoint()
637637
for pt in pts:
638-
self.create_vertex(pt, id)
638+
self.create_vertex(pt, id, layer.crs().postgisSrid())
639639
self.line_tool.create_rubber_band()
640640
except Exception:
641641
self._clear_annotations()

tests/test_gui.py

Lines changed: 337 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -371,41 +371,360 @@ def test_ORStoolsDialogConfig_url(self):
371371
next(layer.getFeatures()).geometry().asPolyline()[0].asWkt(),
372372
)
373373

374-
def test_load_valid_point_layer(self):
375-
"""Test loading vertices from valid point layer."""
374+
def test_load_valid_point_layer_single_geometry(self):
375+
"""Test loading vertices from valid point layer with single point geometries."""
376376
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
377-
377+
378378
dialog_main = ORStoolsDialogMain(IFACE)
379379
dialog_main._init_gui_control()
380-
381-
# Create test layers
382-
self.point_layer = QgsVectorLayer("Point?crs=EPSG:4326", "test_points", "memory")
383-
self.line_layer = QgsVectorLayer("LineString?crs=EPSG:4326", "test_lines", "memory")
384-
380+
381+
# Create test layer
382+
point_layer = QgsVectorLayer("Point?crs=EPSG:4326", "test_points", "memory")
383+
385384
# Add 3 features to point layer
386-
for coords in [(1, 2), (3, 4), (5, 6)]:
385+
for coords in [(1.0, 2.0), (3.0, 4.0), (5.0, 6.0)]:
387386
feat = QgsFeature()
388387
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(*coords)))
389-
self.point_layer.dataProvider().addFeature(feat)
390-
391-
QgsProject.instance().addMapLayers([self.point_layer, self.line_layer])
392-
388+
point_layer.dataProvider().addFeature(feat)
389+
390+
QgsProject.instance().addMapLayer(point_layer)
391+
393392
# Run test
394393
dialog_main.dlg.load_vertices_from_layer("ok")
395-
394+
396395
# Verify
397396
self.assertTrue(dialog_main.dlg.line_tool is not None)
398397
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 3)
399398
self.assertIsInstance(dialog_main.dlg.rubber_band, QgsRubberBand)
400-
401-
def test_user_cancels_operation(self):
399+
400+
# Verify coordinates
401+
self.assertEqual(
402+
dialog_main.dlg.routing_fromline_list.item(0).text(),
403+
"Point 0: 1.000000, 2.000000"
404+
)
405+
self.assertEqual(
406+
dialog_main.dlg.routing_fromline_list.item(1).text(),
407+
"Point 1: 3.000000, 4.000000"
408+
)
409+
self.assertEqual(
410+
dialog_main.dlg.routing_fromline_list.item(2).text(),
411+
"Point 2: 5.000000, 6.000000"
412+
)
413+
414+
def test_load_multipoint_geometry(self):
415+
"""Test loading vertices from layer with multipoint geometries."""
416+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
417+
418+
dialog_main = ORStoolsDialogMain(IFACE)
419+
dialog_main._init_gui_control()
420+
421+
# Create test layer with multipoint
422+
multipoint_layer = QgsVectorLayer("MultiPoint?crs=EPSG:4326", "test_multipoints", "memory")
423+
424+
# Add multipoint feature
425+
feat = QgsFeature()
426+
points = [QgsPointXY(1.0, 2.0), QgsPointXY(3.0, 4.0), QgsPointXY(5.0, 6.0)]
427+
feat.setGeometry(QgsGeometry.fromMultiPointXY(points))
428+
multipoint_layer.dataProvider().addFeature(feat)
429+
430+
QgsProject.instance().addMapLayer(multipoint_layer)
431+
432+
# Run test
433+
dialog_main.dlg.load_vertices_from_layer("ok")
434+
435+
# Verify - all points from multipoint should be loaded
436+
self.assertTrue(dialog_main.dlg.line_tool is not None)
437+
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 3)
438+
self.assertIsInstance(dialog_main.dlg.rubber_band, QgsRubberBand)
439+
440+
def test_load_layer_with_different_crs(self):
441+
"""Test loading vertices from layer with non-WGS84 CRS."""
442+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
443+
444+
dialog_main = ORStoolsDialogMain(IFACE)
445+
dialog_main._init_gui_control()
446+
447+
# Create test layer with Web Mercator CRS
448+
point_layer = QgsVectorLayer("Point?crs=EPSG:3857", "test_points_3857", "memory")
449+
450+
# Add features (coordinates in EPSG:3857)
451+
feat = QgsFeature()
452+
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(260102.8, 6251528.2)))
453+
point_layer.dataProvider().addFeature(feat)
454+
455+
QgsProject.instance().addMapLayer(point_layer)
456+
457+
# Run test
458+
dialog_main.dlg.load_vertices_from_layer("ok")
459+
460+
# Verify
461+
self.assertTrue(dialog_main.dlg.line_tool is not None)
462+
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 1)
463+
464+
# Verify transformation occurred (should be in WGS84)
465+
item_text = dialog_main.dlg.routing_fromline_list.item(0).text()
466+
self.assertTrue("Point 0:" in item_text)
467+
# Coordinates should be approximately 1.0, 2.0 after transformation
468+
coords = item_text.split(":")[1].strip()
469+
x, y = (float(i) for i in coords.split(", "))
470+
self.assertAlmostEqual(x, 2.3, places=1)
471+
self.assertAlmostEqual(y, 48.9, places=1)
472+
473+
def test_load_empty_layer(self):
474+
"""Test loading vertices from empty layer."""
475+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
476+
477+
dialog_main = ORStoolsDialogMain(IFACE)
478+
dialog_main._init_gui_control()
479+
480+
# Create empty layer
481+
point_layer = QgsVectorLayer("Point?crs=EPSG:4326", "empty_points", "memory")
482+
QgsProject.instance().addMapLayer(point_layer)
483+
484+
# Run test
485+
dialog_main.dlg.load_vertices_from_layer("ok")
486+
487+
# Verify - should handle empty layer gracefully
488+
self.assertTrue(dialog_main.dlg.line_tool is not None)
489+
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 0)
490+
491+
def test_load_layer_with_null_geometries(self):
492+
"""Test loading vertices from layer with null geometries."""
493+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
494+
495+
dialog_main = ORStoolsDialogMain(IFACE)
496+
dialog_main._init_gui_control()
497+
498+
# Create layer with null geometries
499+
point_layer = QgsVectorLayer("Point?crs=EPSG:4326", "test_points", "memory")
500+
501+
# Add feature with valid geometry
502+
feat1 = QgsFeature()
503+
feat1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(1.0, 2.0)))
504+
point_layer.dataProvider().addFeature(feat1)
505+
506+
# Add feature with null geometry
507+
feat2 = QgsFeature()
508+
feat2.setGeometry(QgsGeometry())
509+
point_layer.dataProvider().addFeature(feat2)
510+
511+
# Add another valid feature
512+
feat3 = QgsFeature()
513+
feat3.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(3.0, 4.0)))
514+
point_layer.dataProvider().addFeature(feat3)
515+
516+
QgsProject.instance().addMapLayer(point_layer)
517+
518+
# Run test
519+
dialog_main.dlg.load_vertices_from_layer("ok")
520+
521+
# Verify - should skip null geometry
522+
self.assertTrue(dialog_main.dlg.line_tool is not None)
523+
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 2)
524+
525+
def test_load_invalid_layer_type(self):
526+
"""Test loading vertices from non-point layer."""
527+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
528+
529+
dialog_main = ORStoolsDialogMain(IFACE)
530+
dialog_main._init_gui_control()
531+
532+
# Create line layer
533+
line_layer = QgsVectorLayer("LineString?crs=EPSG:4326", "test_lines", "memory")
534+
535+
feat = QgsFeature()
536+
feat.setGeometry(QgsGeometry.fromPolylineXY([QgsPointXY(0, 0), QgsPointXY(1, 1)]))
537+
line_layer.dataProvider().addFeature(feat)
538+
539+
QgsProject.instance().addMapLayer(line_layer)
540+
541+
# Run test
542+
dialog_main.dlg.load_vertices_from_layer("ok")
543+
544+
# Verify - should not load line geometries
545+
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 0)
546+
547+
def test_user_cancels_import_operation(self):
402548
"""Test when user cancels the dialog."""
403549
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
404-
550+
405551
dialog_main = ORStoolsDialogMain(IFACE)
406552
dialog_main._init_gui_control()
553+
554+
# Create valid layer
555+
point_layer = QgsVectorLayer("Point?crs=EPSG:4326", "test_points", "memory")
556+
feat = QgsFeature()
557+
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(1.0, 2.0)))
558+
point_layer.dataProvider().addFeature(feat)
559+
QgsProject.instance().addMapLayer(point_layer)
560+
407561
dialog_main.dlg.load_vertices_from_layer("not_ok")
408-
562+
409563
self.assertTrue(dialog_main.dlg.line_tool is not None)
410564
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 0)
411565
self.assertNotIsInstance(dialog_main.dlg.rubber_band, QgsRubberBand)
566+
567+
def test_load_layer_with_many_points(self):
568+
"""Test loading many points from layer."""
569+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
570+
571+
dialog_main = ORStoolsDialogMain(IFACE)
572+
dialog_main._init_gui_control()
573+
574+
# Create layer with 100 points
575+
point_layer = QgsVectorLayer("Point?crs=EPSG:4326", "many_points", "memory")
576+
n = 52
577+
578+
for i in range(n):
579+
feat = QgsFeature()
580+
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(float(i), float(i))))
581+
point_layer.dataProvider().addFeature(feat)
582+
583+
QgsProject.instance().addMapLayer(point_layer)
584+
585+
# Run test
586+
dialog_main.dlg.load_vertices_from_layer("ok")
587+
588+
# Verify
589+
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), n)
590+
self.assertIsInstance(dialog_main.dlg.rubber_band, QgsRubberBand)
591+
592+
def test_load_layer_replaces_existing_vertices(self):
593+
"""Test that loading a layer clears existing vertices."""
594+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
595+
596+
dialog_main = ORStoolsDialogMain(IFACE)
597+
dialog_main._init_gui_control()
598+
599+
# Add some vertices manually first
600+
dialog_main.dlg.routing_fromline_list.addItem("Point 0: 0.000000, 0.000000")
601+
dialog_main.dlg.routing_fromline_list.addItem("Point 1: 1.000000, 1.000000")
602+
603+
initial_count = dialog_main.dlg.routing_fromline_list.count()
604+
self.assertEqual(initial_count, 2)
605+
606+
# Create and load layer
607+
point_layer = QgsVectorLayer("Point?crs=EPSG:4326", "test_points", "memory")
608+
feat = QgsFeature()
609+
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(5.0, 5.0)))
610+
point_layer.dataProvider().addFeature(feat)
611+
QgsProject.instance().addMapLayer(point_layer)
612+
613+
dialog_main.dlg.load_vertices_from_layer("ok")
614+
615+
# Verify old vertices were cleared
616+
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 1)
617+
self.assertEqual(
618+
dialog_main.dlg.routing_fromline_list.item(0).text(),
619+
"Point 0: 5.000000, 5.000000"
620+
)
621+
622+
def test_load_layer_with_extreme_coordinates(self):
623+
"""Test loading vertices with extreme coordinate values."""
624+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
625+
626+
dialog_main = ORStoolsDialogMain(IFACE)
627+
dialog_main._init_gui_control()
628+
629+
# Create layer with extreme coordinates (but valid WGS84)
630+
point_layer = QgsVectorLayer("Point?crs=EPSG:4326", "extreme_coords", "memory")
631+
632+
# Add features at extremes
633+
extreme_coords = [
634+
(-180.0, -90.0), # Southwest corner
635+
(180.0, 90.0), # Northeast corner
636+
(0.0, 0.0), # Origin
637+
(-179.9, 89.9), # Near extremes
638+
]
639+
640+
for coords in extreme_coords:
641+
feat = QgsFeature()
642+
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(*coords)))
643+
point_layer.dataProvider().addFeature(feat)
644+
645+
QgsProject.instance().addMapLayer(point_layer)
646+
647+
# Run test
648+
dialog_main.dlg.load_vertices_from_layer("ok")
649+
650+
# Verify all points loaded
651+
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 4)
652+
653+
def test_load_layer_creates_annotations(self):
654+
"""Test that loading vertices creates map annotations."""
655+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
656+
657+
dialog_main = ORStoolsDialogMain(IFACE)
658+
dialog_main._init_gui_control()
659+
660+
# Create layer
661+
point_layer = QgsVectorLayer("Point?crs=EPSG:4326", "test_points", "memory")
662+
663+
for coords in [(1.0, 2.0), (3.0, 4.0)]:
664+
feat = QgsFeature()
665+
feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(*coords)))
666+
point_layer.dataProvider().addFeature(feat)
667+
668+
QgsProject.instance().addMapLayer(point_layer)
669+
670+
# Run test
671+
dialog_main.dlg.load_vertices_from_layer("ok")
672+
673+
# Verify annotations were created
674+
self.assertEqual(len(dialog_main.dlg.annotations), 2)
675+
676+
# Verify annotations are in project
677+
project_annotations = QgsProject.instance().annotationManager().annotations()
678+
for annotation in dialog_main.dlg.annotations:
679+
self.assertIn(annotation, project_annotations)
680+
681+
def test_load_layer_mixed_multipoint_and_single(self):
682+
"""Test loading from layer with mixed single and multipoint geometries."""
683+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
684+
685+
dialog_main = ORStoolsDialogMain(IFACE)
686+
dialog_main._init_gui_control()
687+
688+
# Create layer that can hold both
689+
point_layer = QgsVectorLayer("Point?crs=EPSG:4326", "mixed_points", "memory")
690+
691+
# Add single point
692+
feat1 = QgsFeature()
693+
feat1.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(1.0, 2.0)))
694+
point_layer.dataProvider().addFeature(feat1)
695+
696+
# Add single point
697+
feat2 = QgsFeature()
698+
feat2.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(3.0, 4.0)))
699+
point_layer.dataProvider().addFeature(feat2)
700+
701+
QgsProject.instance().addMapLayer(point_layer)
702+
703+
# Run test
704+
dialog_main.dlg.load_vertices_from_layer("ok")
705+
706+
# Verify correct count
707+
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 2)
708+
709+
def test_load_layer_exception_handling(self):
710+
"""Test exception handling when loading fails."""
711+
from ORStools.gui.ORStoolsDialog import ORStoolsDialogMain
712+
713+
dialog_main = ORStoolsDialogMain(IFACE)
714+
dialog_main._init_gui_control()
715+
716+
# Create a polygon layer (invalid for point loading)
717+
polygon_layer = QgsVectorLayer("Polygon?crs=EPSG:4326", "test_polygons", "memory")
718+
719+
feat = QgsFeature()
720+
points = [QgsPointXY(0, 0), QgsPointXY(1, 0), QgsPointXY(1, 1), QgsPointXY(0, 1), QgsPointXY(0, 0)]
721+
feat.setGeometry(QgsGeometry.fromPolygonXY([points]))
722+
polygon_layer.dataProvider().addFeature(feat)
723+
724+
QgsProject.instance().addMapLayer(polygon_layer)
725+
726+
# Run test - should handle gracefully
727+
dialog_main.dlg.load_vertices_from_layer("ok")
728+
729+
# Should not crash and list should be empty
730+
self.assertEqual(dialog_main.dlg.routing_fromline_list.count(), 0)

0 commit comments

Comments
 (0)