Qigong dur avec des signes conventionnels ou pourquoi vous avez besoin d'un générateur de géométrie


Les exigences des clients pour les symboles sur les cartes vous semblent-elles irréalistes? Plus loin, vous apprendrez à utiliser le générateur de géométrie, QGIS et Python pour optimiser vos conditionneurs.


introduction


! , , , , , QGIS Python PyQt. , , () . QGIS , geometry generator — . . , .


«» ?


QGIS MVC . , .. , Model-Based PyQt . , . , .


QGIS:


Exemples de styles de point, ligne et polygone


?


99% . ! , (, ), (, ), , .


, :



«» :


"Les dents"


. , , , ( ). QGIS Python.



, , -, , , , (!) , , ! , .



  • QGIS 3.10.6 Ubuntu 18.04.
  • «» UTM 37N, .
  • GitHub .
  • «» , .
  • , , , .

geometry generator


— .
, : /, /, /. , , , , . : , , .


«»?


, , (expression), . Expressions, Python Expressions, Filtering and Calculating Values.


, , . — , . Python, . QGIS. , a .


: . - , .


, , QGIS, , , , . . .


...


, .


, ( , ), , , , , , :


Un objet avec des styles différents.


: , , ; , , — , . points.


geometry_n(), :


geometry_n($geometry, 1)

$geometry — , .


, :


if(
    @geometry_part_num > 1, --     
    geometry_n($geometry,  @geometry_part_num ), --   
    NULL
)

, if()— . 2 @geometry_part_num, , ( @). NULL . , , , .


— , :


if(
    @geometry_part_num > 1, --       
    with_variable(
        'inputs',
        array(
            10000, --        
            length( --       
                make_line(
                    start_point($geometry),
                    geometry_n($geometry, @geometry_part_num)
                )
            ),
            azimuth( --       
                geometry_n($geometry, @geometry_part_num),
                start_point($geometry)
            )
        ),
        if(
            @inputs[0] < @inputs[1], --    
            make_line(
                geometry_n($geometry, @geometry_part_num), --  
                project(
                    geometry_n($geometry, @geometry_part_num), --  
                    @inputs[1] - @inputs[0], --  
                    @inputs[2] -- 
                )
            ),
            NULL --     ,   .
        )
    ),
    NULL
)

. , , , NULL.


— . , . , . , .


with_variable(), : , , . , - , with_variable, . .


— inputs array() — 0. — , . — , :


...
length( --       
    make_line(
        start_point($geometry),
        geometry_n($geometry, @geometry_part_num)
    )
),
azimuth( --       
    geometry_n($geometry, @geometry_part_num),
    start_point($geometry)
)
...

length(), , make_line() — start_point($geometry), ( ). azimuth() , !


, . if() , , . @inputs , , «» NULL.


:


...
make_line(
    geometry_n($geometry, @geometry_part_num), --     
    project(
        geometry_n($geometry, @geometry_part_num), --  
        @inputs[1] - @inputs[0], --  
        @inputs[2] -- 
    )
)
...

project(), , . , .



, Klas Karlsson, QGIS. , , , , :


Route


, . , WKT , , «||», . , , . :


  • , ;
  • , .

( lines1). , :


  • ( ).
  • .

:


collect_geometries(
    array_foreach(
        generate_series(1, num_points($geometry)),
        point_n($geometry, @element)
    )
)

«» . . generate_series(), () 1 num_points($geometry), . . . array_foreach(). array_foreach , point_n($geometry, @element), . . (point_n() — ), @element — . , . — , collect_geometries(). ( ).


. «/». :


with_variable(
    'minimal_length',  --  ,     
    7000.0,
    collect_geometries(  --  
        array_foreach(
            generate_series(1, num_points($geometry) - 1),  --   
            with_variable(
                'inputs',
                array(
                    azimuth( --      
                        point_n($geometry, @element),
                        point_n($geometry, @element + 1)
                    ),
                    length( --      
                        make_line(
                            point_n($geometry, @element),
                            point_n($geometry, @element + 1)
                        )
                    )
                ),
                if(
                    @inputs[1] - @minimal_length * 2 > 0,  -- .  
                    line_substring( --     
                        make_line(
                            point_n($geometry, @element),
                            point_n($geometry, @element+1)
                        ),
                        @minimal_length, @inputs[1] - @minimal_length
                    ),
                    geom_from_wkt('LINESTRING EMPTY') --  
                )
            )
        )
    )
)

, . @minimal_length. collect_geometries , array_foreach , . , , @inputs: .


. , @minimal_length ( ). , , :


geom_from_wkt('LINESTRING EMPTY')

, , NULL, . , . WKT «LINESTRING EMPTY», WKT QGIS geom_from_wkt().


. line_subtring(), . , .



? , , . (. lines2).


, buffer(), : , 1. .. :



, .



, , , . , . , . :


with_variable(
    'distance',
    4000, --  
    with_variable(
        'offset_lines', --     
        array(
            extend(
                offset_curve($geometry, @distance, join:=2),
                @distance, @distance
            ),
            extend(
                offset_curve($geometry, -@distance, join:=2),
                @distance, @distance
            )
        ),
        collect_geometries(
            @offset_lines[0], --  1
            @offset_lines[1], --  2
            make_line( --     1   2
                start_point(@offset_lines[0]),
                start_point(@offset_lines[1])
            ),
            make_line( --     1   2
                end_point(@offset_lines[0]),
                end_point(@offset_lines[1])
            )
        )
    )
)

, with_variable, , , . . @offset_lines , , ( offset_curve()), extend(). , — start_point() — end_point().


— , —


, , . (. lines3). , :


with_variable(
    'lines',
    segments_to_lines($geometry),
    collect_geometries(
        array_foreach(
            generate_series(2, num_geometries(@lines), 2),
            geometry_n(@lines, @element)
        )
    )
)

segments_to_lines() , — , . , generate_series. :




. , ( poly2).



«/» :


with_variable(
    'points_num',
    --     
    num_points($geometry) - 1, -- 
    collect_geometries(
        array_foreach(
            --     
            generate_series(1, round(@points_num / 2.0)),
            make_line(
                point_n( --  
                    $geometry,
                    @element
                ), 
                point_n( --  
                    $geometry,
                    @element + floor(@points_num / 2.0)
                )
            )
        )
    )
)

«» , generate_series() . .



, ( poly3):


:


collect_geometries(
    array_foreach(
        generate_series(1, num_points($geometry) - 1),
        make_line(
            centroid($geometry),
            point_n($geometry, @element)
        )
    )
)

, centroid(), , , .



— poly4. , , «», . «» — , , , . :



, , . . . , :


with_variable(
    'lines',
    segments_to_lines($geometry), --    
    collect_geometries(
        array_foreach(
            segments_between_sides_nums( --   Python
                array_foreach(
                    generate_series(1, num_geometries(@lines)),
                    --   [ ,  ]
                    array(
                        @element,
                        length(
                            geometry_n(@lines, @element)
                        )
                    )
                )
            ),
            geometry_n(@lines, @element)
        )
    )
)

, . , , .


segments_between_sides_num(). QGIS Python ( custom.py ~/.local/share/QGIS/QGIS3/profiles/default/python/expressions):


@qgsfunction(args="auto", group="")
def segments_between_sides_nums(sides, feature, parent):
    """
            
    .
    sides -     ( ,  )
    """
    sorted_sides = sorted(sides, key=lambda x: x[1])
    return list(range(int(sorted_sides[0][0]) + 1, int(sorted_sides[1][0])))

Python , .. ( ), .


. , Python?



, : QGIS Python? . , .



  • test_poly 100000 , 3 20.

create_poly_lyr.py, ( ).



  • , , «». , ( ).

Python, QGIS, Python. expression_benchmarking.py:


EXPRESSION = """
collect_geometries(
    array_foreach(
        generate_series(1, num_points($geometry)),
        make_line(
            centroid($geometry),
            point_n($geometry, @element)
        )
    )
)
"""
…
for counter, poly in enumerate(lyr_polys.getFeatures()):
    exp = QgsExpression(EXPRESSION)
    context = QgsExpressionContext()
    context.setFeature(poly)
    star = exp.evaluate(context)

python_benchmarking.py:


for counter, poly in enumerate(lyr_polys.getFeatures()):
    centroid = QgsPoint(poly.geometry().centroid().asPoint())
    star = QgsMultiLineString()
    for vertex in poly.geometry().vertices():
        line = QgsLineString(centroid, vertex)
        star.addGeometry(line)



Python 5,3 , 23,16 . Python 4,5 . , , , .



:


  • . «» , , «- 1» , Python, .
  • QGIS, . . , .

:


  • Python.
  • .

Python:


  • .
  • Python.

Python:


  • () *.py .
  • Python , .
  • Python, , ( Windows).

, QGIS . , , , , . , «» Python.



? .


: WGS84 (/), — . , , . , . , :


Tampon en degrés


: , , . , . poly3 «» :


Polygone de trou


, .


, , /? , :


Hachures parallèles


«» , ? , , .


«», ?


, , . , , .


Les générateurs offrent des possibilités presque illimitées, plus précisément, les possibilités ne sont limitées que par les performances et sont un outil indispensable pour créer des panneaux conventionnels vraiment complexes.


J'espère que l'article vous sera utile, et nous pourrons considérer des cas complexes dans le prochain article. Merci pour l'attention.


Références



All Articles