Description Usage Arguments Value Note Author(s) Examples
View source: R/deform-polygon.R
This function deforms a polygon by moving each vertex a specified distance.
If you want a smooth deformation of a polygon with few vertices (e.g. a square),
then interpolate_polygon
can be used to create an interpolated version
of the polygon (see example below).
1 | deform_polygon(vertex.df, deform.distance, method = "bisector")
|
vertex.df |
A data frame where each row corresponds to the vertex of a polygon.
It must contain the columns |
deform.distance |
The distance that each vertex is to be moved. Can either be a single value or a vector containing one value per vertex. If the value is positive, the vertex is moved "outwards", while a negative value moves the vertex "inwards". |
method |
Must be one of the following values:
|
The same data frame that is given in vertex.df
, the only difference
being that the x
- and y
-columns are changed due to the deformation.
This function is not robust, and can lead to strange results. While
method = "bisector"
generally looks better, it struggles in certain
situations (see example #3 below), and should only be used for expanding convex
polygons. If the polygon is concave and deform.distance
contains
both positive and negative values, method = "centroid"
might be a
better choice.
Mathias Isaksen mathiasleanderi@gmail.com
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | # Example 1: Deformation of rounded square
# Start with a square
square.df = data.frame(x = c(-1, 1, 1, -1), y = c(1, 1, -1, -1))
# Round the corners of the square
rounded.df = round_polygon_corners(square.df, corner.radius = 0.3)
# The rounded polygon has many vertices along the corners, but none along the
# straight edges. We need to resample!
# Create function that allows us to resample vertices along the boundary of the polygon
interpolation.function = interpolate_polygon(rounded.df)
# How many vertices should resampled polygon contain?
num.vertices = 1000
# Create vector with n values evenly spaced between 0 and 1
# (0 and 1 correspond to the same point, so the latter is removed)
time = seq(0, 1, length.out = num.vertices + 1)[-(num.vertices + 1)]
# Polygon that consists of 1000 vertices placed evenly along the boundary of
# the rounded polygon
resampled.df = interpolation.function(time)
# Function that gives the amount of deformation for time between 0 and 1
deform.function = function(t, freq) 0.1 + (0.35 - 0.1)*(1 + cos(freq*2*pi*t)) / 2
# Vector that gives the amount of deformation for each vertex in resampled.df
deform.amount = deform.function(time, 4)
# Deformed polygon
deform.df = deform_polygon(resampled.df, deform.amount, method = "bisector")
library(ggplot2)
ggplot()+
geom_polygon(data = square.df, aes(x = x, y = y, color = "1. Original"), fill = NA)+
geom_polygon(data = rounded.df, aes(x = x, y = y, color = "2. Rounded"), fill = NA)+
geom_polygon(data = deform.df, aes(x = x, y = y, color = "3. Deformed"), fill = NA)+
scale_color_manual(values = c("black", "blue", "red"))+
coord_fixed()
# Example 2: Comparison of "bisector" and "centroid" methods
# Start with a 2 x 10 rectangle
rectangle.df = data.frame(x = c(-1, 1, 1, -1), y = c(5, 5, -5, -5))
# Resample polygon, this time without rounding
interpolation.function = interpolate_polygon(rectangle.df)
resampled.df = interpolation.function(time)
# Deformation that oscillates faster than in example 1
deform.amount = deform.function(time, 20)
# Deformed polygons
bisector.df = deform_polygon(resampled.df, deform.amount, method = "bisector")
centroid.df = deform_polygon(resampled.df, deform.amount, method = "centroid")
# From left to right, the plot shows the original rectangle, and the deformed polygons
# from the "bisector" and "centroid" methods, respectively.
# The result from "bisector" looks better overall, but struggles at sharp corners,
# where the deformed polygon ends up having large gaps between the vertices.
# This is avoided by rounding the polygon before deformation.
# The deformed polygon from the "centroid" method handles the corners without problem,
# but the amount of deformation is not consistent along the vertical sides.
ggplot()+
geom_polygon(data = rectangle.df, aes(x = x, y = y), fill = "red")+
geom_polygon(data = bisector.df, aes(x = x + 3, y = y), fill = "red")+
geom_polygon(data = centroid.df, aes(x = x + 6, y = y), fill = "red")+
geom_point(data = bisector.df, aes(x = x + 3, y = y), color = "black", size = 0.5)+
geom_point(data = centroid.df, aes(x = x + 6, y = y), color = "black", size = 0.5)+
coord_fixed()
# Example 3: Situation where "bisector" method fails
set.seed(123)
# Generate random polygon using polar coordinates
num.vertices = 10
theta = seq(0, 2*pi, length.out = num.vertices + 1)[-(num.vertices + 1)]
radius = runif(num.vertices, 0.5, 1)
vertex.df = data.frame(x = radius*cos(theta), y = radius*sin(theta))
# How the original polygon looks:
ggplot()+
geom_polygon(data = vertex.df, aes(x = x, y = y), fill = NA, color = "black")+
coord_fixed()
# Resample polygon before deforming
interpolation.function = interpolate_polygon(vertex.df)
resampled.df = interpolation.function(time)
# Deform function goes from -0.2 to 0.2, and back to -0.2
deform.function = function(t) -0.2*cos(2*pi*t)
deform.amount = deform.function(time)
# Deform resampled polygon
deform.df = deform_polygon(resampled.df, deform.amount)
# How the deformed polygon looks:
ggplot()+
geom_polygon(data = deform.df, aes(x = x, y = y), fill = NA, color = "black")+
coord_fixed()
# The combinations convex corner/negative deformation (right side of plot)
# and concave corner/positive deformation (left side) leads to a shape that is
# self-intersecting.
|
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.