Spis wypocin

Google Maps API - dodawanie punktów w środku polilinii

Google Maps API - udostępnia metody pozwalające na rysowanie na mapie polilinii, zwanych przeze mnie dalej "łamanymi". Taką łamaną możemy bardzo łatwo rozszerzać o kolejne punkty, dodawane jednak jedynie na jej końcu. Co jeśli chcielibyśmy dodać punkt w jakimś jej dowolnym fragmencie? Sami musimy napisać rozwiązanie, gdyż API nie udostępnia stosownej metody.

Działający przykład

Najłatwiej będzie jeśli od razu zaprezentuję gotowe rozwiązanie. W przykładzie wykorzystałem funkcje MooTools ułatwiające programowanie obiektowe w JS. Żeby wszystko działało należało też wyświetlić stronę jako "text/html" zamiast standardowego tutaj "application/xhtml+xml".

dodawanie wierzchołka

Łamana wraz z zaznaczonym miejscem w którym chcemy dodać wierzchołek.

wierzchołek dodany

Wierzchołek dodany w "środku" odcinka.

Omówienie

Idea rozwiązania polega na tym, że po kliknięciu na łamaną (polilinię), dla każdego jej odcinka wyznaczamy prostokątny obszar zawierający ten odcinek (korzystamy z funkcji z API). Równierz z pomocą funkcji z API, sprawdzamy czy punkt w którym klikneliśmy leży wenątrz tego prostokąta. Jeśli leży, to mamy informację o tym, pomiędzy którymi dwoma punktami następiło kliknięcie. Do wyznaczenie tychże punktów sprowadza się rozwiązanie. Dalej bowiem jest już z górki:

Na potrzeby przykładu zdefiniowane zostały 2 obiekty. Trasa oraz ElementyTrasy.
ElementTrasy - to prosty obiekt, reprezentujący punkt opisany dwoma współrzędnymi. Wierzchołki łamanej są zdefiniowane jako kolekcja elementów tego typu.
Trasa - to obiekt reprezentujący łamaną, posiadający zdefiniowane metody odpowiedzialne za takie operacje jak:

Jak widać, rysowanie po mapie jest jedynie odwzorowaniem danych zawartych w obiekcie Trasa. Cały mechanizm dodawania, usuwania, zmiany kształtu łamanej wykonuje się na obiekcie Trasa, który sam siebie potrafi narysować :)

Nie wypisuję tutaj kodu źródłowego, gdyż jest on dosyć krótki i zaopatrzony w komentarze, więc każdy może zajrzeć do źródła działającego przykładu.

przykład błędnego działania

Próba dodania wirzchołka w oznaczonym miejscu.

błędne działanie algorytmu

Wierzchołek został dodany, ale nie w odcinku o który chodziło.

Błędy

Istnieją sytuację kiedy algorytm nie zadziała poprawnie. Dotyczy to sytuacji (przedstawionej na rysunku), kiedy prostokątny obszar będzie zawierał więcej niż jeden segment. Wyszukiwanie wierzchołków pomiędzy którymi nastąpiło kliknięcie odbywa się od początku łamanej, stąd jeżeli współrzędne tego punktu zawierają się w więcej niż jednym obszarze, to i tak wierzchołek zostanie dodany do pierwszego z nich (pomiędzy 2 wierzchołki tworzące obszar).

Rozwiązań tego problemu na pewno jest kilka. Pewnym pomysłem jest wyznaczenie współczynnika kierunkowego każdego odcinka i sprawdzenie, czy kliknięty punkt należy do prostej o tym współczynniku. Takie rozwiązanie dalej będzie podatne na opisany błąd, ale jedynie dla odcinków które są idelanie równoległe i zawierają się w jednym segmencie. O taki przypadek jest już jednak znacznie trudniej.

Innym pomysłem jest wylicznie najmniejszej odległości międdzy klikniętym punktem a każdym z odcinków.

Ogólnie rzecz ujmując, dokładniejsze rozwiązania na pewno będą działały wolniej. Należy więc wybrać kompromis pomiędzy szybkością działania, a dokładnością.

Post Scriptum

Opisywaną funkcję napisałem przy okazji tworzenia systemu wyszukiwania i wizualizacji połączeń tramwajowych w Gdańsku. Zlecenie otrzymała oczywiście firma w której jestem zatrudniony.

Na potrzeby systemu musiałem stworzyć edytor tras i przystanków tramwajowych. W dużym uproszczeniu była to aplikacja pozwalająca rysować sobie na mapie wspomniane łamane. Łamane reprezentowały trasy tramwajowe, stąd konieczna byłą możliwość dodawania punktu (przystanku) na już istniejącej łamanej (trasie).