# How to shrink polygon on two sides?

I have a polygon which I know is a rectangle, although it may be at any orientation: I want to shrink this polygon by a third of the width from two sides, so that I just get the strip in the middle - ending up with a result like the red area in this image: I can't think how to go about doing this easily. If I try and negatively buffer the polygon then it will be shrunk on all sides. I have many tens of thousands of these polygons to do - so obviously can't do them manually.

Any ideas? I have access to ArcGIS, QGIS and am relatively experienced at Python programming - if that helps.

• How do you decide which sides are the "sides" and which the "ends"? Is it always going to end up with a red section more vertical than horizontal? – Spacedman Apr 1 '14 at 12:42
• Can you provide a sample shapefile/other file format with a few features in? – Spacedman Apr 1 '14 at 12:47
• Good question. The red section should always be more vertical. I was wondering if there was a way round this that didn't involve iterating through all of the polygons and changing vertices manually - I can imagine that being a pain to get properly right (particularly for polygons that go across the equator/greenwich meridian). – robintw Apr 1 '14 at 12:49
• There's another complication. Are these in lat-long? Are they "large"? Are they rectangles in lat-long, and hence not really rectangles? Hmmm – Spacedman Apr 1 '14 at 12:58
• Quick question, how is the polygon constructed? Is it 4 vertices, one for each corner or was it constructed through a rasterization process so actually its loads of vertices but in a straight line? – Hornbydd Apr 1 '14 at 14:32

Here's some R code that does the job, the caveat being we are in cartesian coordinates. The input matrix `coords` is a 5x2 matrix of x,y columns, with the last point being coincident with the first point. This is what you get out of spatial objects in R when you read a shapefile, for example.

``````thinrect <- function(coords, factor=1/3){
dx = diff(coords[,1])
dy = diff(coords[,2])
## test if slope(1-2) is > slope(2-3)
w = diff(atan2(abs(dx[1:2]), abs(dy[1:2])) %% pi) > 0
## if it is, then wrap it round so the first side is the steepest
if(w){
coords = rbind(coords[-1,], coords[1,])
dx = c(dx[-1],dx)
dy = c(dy[-1],dy)
}
## now its just four points offset from corners 1 and 3
dxy = c(dx,dy)
p1 = coords[1,] + factor*dxy
p2 = coords[1,] + (0.5+factor/2)*dxy
p3 = coords[3,] - (factor)*dxy
p4 = coords[3,] - (0.5+factor/2)*dxy

rbind(p1, p2, p3, p4, p1)
}
``````

Here's the output on a rectangle under various rotations. Note how the selected rectangle changes to stay parallel to the steepest side. Simple usage, creating a 5x2 matrix of a unit square:

``````> coords=matrix(c(0,0,0,1,1,1,1,0,0,0),ncol=2,byrow=TRUE)
> coords
[,1] [,2]
[1,]    0    0
[2,]    0    1
[3,]    1    1
[4,]    1    0
[5,]    0    0
> thinrect(coords)
[,1] [,2]
p1 0.3333333    1
p2 0.6666667    1
p3 0.6666667    0
p4 0.3333333    0
p1 0.3333333    1
> plot(coords)
> polygon(thinrect(coords))
``````

Looping this over a shapefile is pretty trivial.

The algorithm could be ported to Python pretty simply too.

• I am very interested in understanding your answer. I am not a mathematician and I have never used R. What I am struggling with is your matrix input and what a 5x2 matrix actually holds. Could you update your answer to show a simple example and the sort of data it would hold? – Hornbydd Apr 7 '14 at 8:01
• Thanks for the example, I will go away and have a good think as I can see this approach would be orders of magnitude faster than my model builder approach! – Hornbydd Apr 7 '14 at 12:05

This can be solved with a model but there are 4 caveats:

• This model assumes your rectangle is a rectangle so the 2 vertical sides are longer
• Your rectangle is constructed from 4 vertices only
• If you want to automate this then all your rectangles must have the same dimensions So after running this model you you are left with the remaining centre rectangle as shown in this image: You would need to wrap this up with an iterator and adjust the various parameters as you require.

I created an ArcGIS Create Custom Grid tool that could be useful for this. However, it might have trouble if any of the rectangles are oriented like a diamond shape.

You would set the vertical division to 3 and leave the horizontal to 0.

After the tool is ran you need to use the Split Polygons tool in the Advanced Editing toolbar.

If you use it, let me know if you have any problems.

You can download the toolbox at the top of the page here: