Odpowiedzi:
Tak, wykonalne. Zwykle sugerowałbym częściowo przezroczysty bufor, ale rozumiem, dlaczego chcesz to zrobić kartograficznie.
Może to być powolne i musisz ręcznie zdecydować, dokąd mają iść etykiety - ale kartograficznie rzecz biorąc, to nie jest złe!
Oto zrzut ekranu ...
Jak widać, brak buforów. Raster pod spodem pozostaje niezmieniony. Uwzględniłem cieńsze pośrednie linie konturu i nadałem im styl, aby były wyświetlane tylko, gdy ELEV% 50 <> 0
Zrobiłem to w QGIS 2.12 ... Twój przebieg może się różnić w zależności od wcześniejszych wersji.
Zakładam, że masz pole „ELEV” na każdej linii konturu.
Podziel kontury na segmenty
Użyj przetwarzania i algorytmu GRASS v.split.length, aby podzielić kontury na segmenty o równej długości. Musisz wybrać długość, która będzie zbliżona do rozmiaru etykiety w jednostkach mapy, przy założeniu, że używasz mierników. Tutaj wykorzystałem 200m.
Uważaj na to, ponieważ spowoduje to, że plik będzie znacznie, znacznie większy (zwróć uwagę na tę funkcję na zrzucie ekranu).
Aby obejść ten problem, możesz wygenerować tylko te linie konturu, które chcesz stylizować (np. Co 50 lub 100 metrów), aby uniknąć przetwarzania wszystkich pośrednich linii konturu.
Do tej warstwy dodaj 1-cyfrowe pole liczby całkowitej o nazwie showLabel . Domyślnie 0 lub NULL.
Zmień etykietę, aby wyświetlała się tylko w segmencie, w którym to pole jest ustawione na 1. Użyj tego wyrażenia tekstu etykiety ...
if ( "showlabel" is not null, "ELEV", "")
Myślę, że jeśli (wyrażenie, wartość prawdziwa, wartość fałszywa) jest dość nowe; jeśli używasz starszej wersji, możesz użyć CASE-ELSE
Zmień styl linii, aby wszystkie odcinki o stałej długości były rysowane, z wyjątkiem odcinków, w których wyświetlana jest etykieta. Używaj więc renderowania opartego na regułach z dwiema regułami
Rule 1: "showLabel" is null
Black, 0% transparent
Rule 2: "showLabel" is not null
Any colour, 100% transparent
Teraz wszystkie kontury będą wyświetlane domyślnie, ale nie będzie etykiet.
Ręcznie edytuj segmenty, w których chcesz wyświetlać etykiety
Przejdź do trybu edycji i ręcznie wybierz segmenty, w których chcesz wyświetlić wartości konturu, i ustaw wartość showLabel
1 dla wybranych operacji. Możesz użyć Ctrl+ select (w Ubuntu / Win, Cmd+ Ctrl+ Click / na Mac?), Aby wybrać wiele segmentów, aby przyspieszyć.
Powinno to teraz „przyciąć” kontury tam, gdzie etykiety mają być pokazywane, a etykiety pojawią się w przerwach.
W tym przypadku ustawienia mojej etykiety były następujące:
CRS: EPSG 27700 (Local UTM for UK, in meters)
Text size: 50 map units
Placement: Parallel, On Line
Mam nadzieję, że to pomaga!
Korzystam z opcji „Bufor” w zakładce „Ustawienie etykiety”. (Za pomocą przycisku etykiet, a nie starej opcji etykiet w oknie dialogowym właściwości warstwy). Nie usuwa to linii konturu, jak sądzę, że chcesz, ale czyni czytelną etykietę.
Myślę, że najbliższe, jakie może uzyskać przy obecnych zdolnościach QGIS, jest użycie efektu halo (lub tła) z kolorem pochodzącym z tabeli, który będzie oparty na wartości elewacji i schemacie kolorów takim samym, jak w przypadku siatki bazowej. Oczywiście nie uwzględniłoby to cienia wzgórza i wszystkiego innego poniżej aureoli na mapie. Przykład losowego koloru: Przy odrobinie kodu można to przepisać jako funkcję odzwierciedlającą kolor siatki.
Teoretycznie powinno być możliwe użycie niestandardowego wzoru linii i powtórzenie etykiety + przesunięcie . Niestety nie ma ustawienia przesunięcia etykiety.
Po tym, jak ostatnio napotkałem ten sam problem, przygotowałem skrypt QGIS Python, aby przeprowadzić ciężkie podnoszenie. Skrypt zawierający niektóre dane testowe (Wielka Brytania), plik Readme (przewodnik) i użyte arkusze stylów można znaleźć na stronie https://github.com/pjgeng/Contour-Labels
Krótko mówiąc, skrypt używa dwóch warstw wektorowych jako danych wejściowych - z adnotowaną warstwą konturową i warstwą „prowadzącą”. Ten ostatni składa się z polilinii przecinających kontury w pożądanych lokalizacjach etykiet.
Skrypt następnie działa na podstawie odległości między konturami i indeksem konturu, które etykiety mają zostać zastosowane, dodaje wartość obrotu do punktów etykiety i ostatecznie przycina oryginalną warstwę konturu, aby utworzyć przerwy.
Podejście to działa szczególnie dobrze, gdy użytkownik musi tworzyć mapy konturowe w różnych odstępach czasu w tym samym obszarze (tzn. Prowadnice się nie zmieniają). Wadą jest niemożność zmiany pozycji etykiety po zakończeniu skryptu. W tym celu użytkownik musiałby dostosować linie pomocnicze i ponownie uruchomić skrypt względem oryginalnego wejścia. Wcześniej często pracowałem z buforami wokół etykiet, aby stworzyć efekt przerwania, ale okazało się to nieprzyjemne estetycznie na mapach opartych na danych wektorowych.
Niestety nie mogę teraz dodać więcej zdjęć, aby udokumentować lub zilustrować proces.
PS: W przypadku korzystania z warstw stylów zawartych w repozytorium użytkownicy mogą potrzebować „aktywować” niestandardowe pola „Obrót”, „Pokaż etykietę” i „Zawsze pokazuj” w menu etykietowania. W niektórych instalacjach QGIS są one stosowane automatycznie z arkusza stylów - jeszcze nie dowiedziałem się, co to powoduje.
Oto inne rozwiązanie problemu maskowania etykiet konturowych QGIS, w którym wykorzystuję funkcjonalność QGIS Spatialite (obecnie QGIS 3.x) wraz z generatorem geometrii do umieszczania etykiet.
To bardzo dynamiczne rozwiązanie pozwala nam natychmiast zmieniać wszystkie rozmiary i położenia etykiet, a nawet przetrwać eksport plików PDF!
Aby było to możliwe, potrzebujemy następujących części:
Warstwa wirtualna o nazwie np. „Contours_with_labels” ze stylem opartym na regułach:
Zasada 2: ELSE… prosta linia
oraz tekst etykiety warunkowej dla reguły 1:
SPRAWA, GDY etykieta = 1 NASTĘPNIE POZOSTAŁA KONIEC
make_line (punkt_początkowy (geometria $), punkt_końcowy (geometria $))
atrybut (get_feature („ustawienia”, „zmienna”, „contourlabel_size”), „wartość”)
i na koniec, oto zapytanie SQL dla warstwy wirtualnej:
------------------------------------------------------------------------
-- select all contour lines that do not intersect any scratch lines
------------------------------------------------------------------------
select c.geometry,c.elev,0 as label
from contours c,
(select st_union(geometry) as geom from scratch_lines) as scr
where not st_intersects(c.geometry,scr.geom)
------------------------------------------------------------------------
UNION
--------------------------------------------------------------------------------------------------------
-- create buffers around all scratch lines (bufferwidth = length(elevation_text) * txtsize/3),
-- get st_difference between contour lines and buffers
-- and set attribute "label" to 0
--------------------------------------------------------------------------------------------------------
select st_difference(c.geometry,buf.geom) as geom,c.elev,0 as label
from
(select c.fid,st_union(st_buffer(scr.geometry,length(c.elev) * txtsize.value / 3)) as geom
from scratch_lines scr,
contours c,
(select cast(value as integer) as value from settings where variable = 'contourlabel_size') txtsize
where st_intersects(scr.geometry,c.geometry)
group by c.fid) as buf,
contours c
where c.fid = buf.fid
group by c.fid
--------------------------------------------------------------------------------------------------------
UNION
--------------------------------------------------------------------------------------------------------
-- create buffers around all scratch lines (bufferwidth = length(elevation_text) * txtsize/3),
-- get st_intersection between contour lines and buffers
-- and set attribute "label" to 1
--------------------------------------------------------------------------------------------------------
select st_intersection(st_buffer(scr.geometry,length(c.elev) * txtsize.value / 3),c.geometry) as geom,c.elev,1 as label
from scratch_lines scr,
contours c,
(select cast(value as integer) as value from settings where variable = 'contourlabel_size') txtsize
where st_intersects(c.geometry,scr.geometry)
to jest to!
Ogromne podziękowania dla wszystkich entuzjastycznych ludzi, którzy sprawiają, że jest to możliwe!
Czy pamiętasz ten wątek Martin? Jedynym sposobem, w jaki mogę podejść do rozwiązania problemu, jest nałożenie warstwy konturowej na przyciętą warstwę konturową, użycie tego do etykietowania i zmiana koloru linii na neutralny, który zamaskowałby kontury pod etykietami, ma się nadzieję, nie będąc zbyt nachalnym. N.
Dodano później: warto spojrzeć na ten wątek , drugą odpowiedź. Być może łamanie linii konturu może być odpowiedzią, być może przy użyciu warstwy buforowej używanej do obcinania konturów?
Aby etykiety były bardziej doskonałe, zmieniłem zapytanie SQL warstwy wirtualnej, aby uwzględnić linie rysujące biegnące równolegle do linii konturowych (patrz rozwiązanie poniżej):
A oto nowy SQL dla warstwy wirtualnej:
------------------------------------------------------------------------
-- select all contour lines that do not intersect any scratch lines
------------------------------------------------------------------------
select c.geometry,c.elev,0 as label
from contours c,
(select st_union(geometry) as geom from scratch_lines) as scr
where not st_intersects(c.geometry,scr.geom)
------------------------------------------------------------------------
UNION
--------------------------------------------------------------------------------------------------------
-- create buffers around all intersection points (bufferwidth = length(elevation_text) * txtsize/2.5),
-- get st_difference between contour lines and buffers
-- and set attribute "label" to 0
--------------------------------------------------------------------------------------------------------
select st_difference(c.geometry,buf.geom) as geom,c.elev,0 as label
from contours c,
(select c.fid,st_union(st_buffer(st_intersection(c.geometry,scr.geometry),length(c.elev) * txtsize.value / 3)) as geom
from contours c, scratch_lines scr, (select cast(value as integer) as value from settings where variable = 'contourlabel_size') txtsize
where st_intersects(c.geometry,scr.geometry)
group by c.fid) as buf
where c.fid = buf.fid
--------------------------------------------------------------------------------------------------------
UNION
--------------------------------------------------------------------------------------------------------
-- create buffers around all intersection points (bufferwidth = length(elevation_text) * txtsize/2.5),
-- get st_intersection between contour lines and buffers
-- and set attribute "label" to 1
--------------------------------------------------------------------------------------------------------
select st_intersection(c.geometry,st_buffer(st_intersection(c.geometry,scr.geometry),length(c.elev) * txtsize.value / 3)) as geom,c.elev,1 as label
from contours c,
scratch_lines scr,
(select cast(value as integer) as value from settings where variable = 'contourlabel_size') txtsize
where st_intersects(c.geometry,scr.geometry)
Wpis na blogu ESRI: http://blogs.esri.com/esri/arcgis/2011/11/28/variable-depth-masking-contour-label-example/
Maskowanie o zmiennej głębokości dla etykiet konturów obejmuje trzy etapy:
1 tworzenie adnotacji z etykiet, 2 korzystanie z narzędzia Maski konspektu do tworzenia masek oraz 3 korzystanie z Zaawansowanych opcji rysowania> Ustawienia maskowania, aby określić, które warstwy będą maskowane.