I have created random points in a polygon and further created a square buffer around them. Now, I want to generate smaller polygons by keeping 100m distance on one side and keeping 200m distance on the other side of the existing polygons. How is it possible in QGIS 3 or PyQGIS? I suppose 'Geometry by Expression' tool can be useful but not able to frame the expression.
1 Answer
Not sure if you want to store/create the geometry or if it is just for display. Using geometry generator, you can combine two buffers the one on the exterior side and the other on the interior. The expression should be the same if using "Geometry by Expression".
To do that, you can use something like below in the expression. Caution: screenshots display the original border for demonstration purpose but the polygon buffer is continuous
with_variable('buffer_out', 100,
with_variable('buffer_in', -200,
with_variable('exterior_ring', exterior_ring($geometry), /* convert to linestring */
with_variable('sub_line', /* Get a portion of line from last endpoints to first ones*/
array_foreach(
array_filter(
array_foreach(
generate_series(-2, 2),
@element
),
@element != 0
),
point_n(@exterior_ring, @element)
),
/* Combined both geom*/
union(
/* Combined inside/outside buffer using single_sided_buffer*/
union(
single_sided_buffer(@exterior_ring, @buffer_out, 8, 2),
single_sided_buffer(@exterior_ring, @buffer_in, 8, 2)
),
/* Do the same, inside/outside buffer but for substring */
union(
single_sided_buffer(make_line(@sub_line), @buffer_out, 8, 2),
single_sided_buffer(make_line(@sub_line), @buffer_in, 8, 2)
)
)
)
)
)
)
I've done a first attempt with the following but the buffer was not generated for the start/end point, hence the approach with "sub-line"
with_variable('buffer_out', 100,
with_variable('buffer_in', -200,
with_variable('exterior_ring', exterior_ring($geometry), /* convert to linestring */
with_variable('sub_line', /* Get a portion of line from last endpoints to first ones*/
array_foreach(
array_filter(
array_foreach(
generate_series(-2, 2),
@element
),
@element != 0
),
point_n(@exterior_ring, @element)
),
/* Combined inside/outside buffer using single_sided_buffer*/
union(
single_sided_buffer(@exterior_ring, @buffer_out, 8, 2),
single_sided_buffer(@exterior_ring, @buffer_in, 8, 2)
)
)
)
)
)