文章目录
作者:小猪快跑
基础数学&计算数学,从事优化领域5年+,主要研究方向:MIP求解器、整数规划、随机规划、智能优化算法
本文档介绍如何使用 Shapely Python 包 计算几何点面关系&距离。
如有错误,欢迎指正。如有更好的算法,也欢迎交流!!!——@小猪快跑
相关文献
基础
Point、LineString、Polygon的通用属性
object.area 返回对象的面积
object.bounds 返回包含对象的x、y的最大值最小值的元组
object.length 返回对象的长度
object.geom_type 返回图形的类型 字符串
object.distance(other) 返回两个对象的最小距离
object.hausdorff_distance(other) 返回两个对象之间的哈多夫距离
object.representative_point() 返回一个保证在对象上的点
创建Point、LineString、Polygon:
from shapely import Point, Polygon, GeometryCollection,LineString
point = Point(3, 3)
polygon = Polygon([(0, 5), (1, 1), (3, 0)])
circ = Point(4, 0).buffer(2)
line = LineString([(0, 0), (2, 2)])
polygon.intersection(circ)
GeometryCollection([point, polygon, circ,line])
Point对象
point = Point(0, 1) # 创建点对象,可以是三维的
print(point.area) # 0.0
print(point.length) # 0.0
print(point.bounds) # (0.0, 1.0, 0.0, 1.0)
print(point.geom_type) # Point
print(point.coords) # <shapely.coords.CoordinateSequence object at 0x00000204DDC2B370>
print(point.coords[:]) # [(0.0, 1.0)]
print(list(point.coords)) # [(0.0, 1.0)]
print(point.x, point.y) # 0.0 1.0
LineString对象
# 可以自己相交
line = LineString([(0, 0), (1, 1)])
print(line.area) # 0.0
print(line.length) # 1.4142135623730951
print(line.bounds) # (0.0, 0.0, 1.0, 1.0)
print(line.geom_type) # LineString
print(line.coords) # <shapely.coords.CoordinateSequence object at 0x00000204DEA0C7F0>
print(line.coords[:], type(line.coords[:])) # [(0.0, 0.0), (1.0, 1.0)] <class 'list'>
Polygon对象
# 可以传入两个参数,第一个是有序的外边缘轮廓,第二个是无序的内边缘轮廓,多边形内所有的环形最多只能有一个焦点,否则都是无效的
polygon = Polygon([(0, 0), (-1, 1), (2, 1), (3, -2)])
print(polygon.area) # 5.0
print(polygon.length) # 11.182042498005464
print(polygon.bounds) # (-1.0, -2.0, 3.0, 1.0)
x_min, y_min, x_max, y_max = polygon.bounds
print(x_min, y_min, x_max, y_max) # -1.0 -2.0 3.0 1.0
print(polygon.geom_type) # Polygon
print(polygon.exterior.coords) # <shapely.coords.CoordinateSequence object at 0x00000208A0C5D510>
print(polygon.exterior.coords[:]) # [(0.0, 0.0), (-1.0, 1.0), (2.0, 1.0), (3.0, -2.0), (0.0, 0.0)]
print(polygon.interiors) # <shapely.geometry.polygon.InteriorRingSequence object at 0x00000208A0C5D510>
print(polygon.interiors[:]) # []
一元判定
has_z 判断是否有z坐标
p = Point(0, 0)
print(p.has_z) # False
p = Point(0, 0, 0)
print(p.has_z) # True
is_ccw 判断是否是逆时针的
lr = LinearRing([(1, 0), (1, 1), (0, 0)])
print(lr.is_ccw) # True
lr = LinearRing([(1, 0), (0, 0), (1, 1)])
print(lr.is_ccw) # False
is_ring 闭合返回TRUE
line = LineString([(0, 0), (1, 1), (1, 0)])
print(line.is_ring) # False
line = LineString([(0, 0), (1, 1), (1, 0), (0, 0)])
print(line.is_ring) # True
lr = LinearRing([(0, 0), (1, 1), (1, 0)])
print(lr.is_ring) # True
lr = LinearRing([(0, 0), (1, 1), (1, 0), (0, 0)])
print(lr.is_ring) # True
is_empty 返回TRUE如果内部和边界都是空
p = Point()
print(p.is_empty) # True
p = Point(0, 0)
print(p.is_empty) # False
is_simple 自己不相交,返回TRUE
line = LineString([(0, 0), (1, 1), (1, -1), (0, 1)])
print(line.is_simple) # False
line = LineString([(0, 0), (0, 1), (1, 1), (1, 0)])
print(line.is_simple) # True
二元判定
object.__eq__(other) # 类型和坐标点相同返回TRUE,和坐标点顺序有关
object.equals(other) # boundary, interior, and exterior完全相同返回TRUE,和坐标点顺序无关
object.almost_equals(other[, decimal=6]) # 近似相等返回TRUE decimal是小数点的位数完全相同,和坐标点的顺序有关
object.contains(other) # other里没有点在object的exterior,且other的interior里至少有一个点在object的interior,和坐标点的顺序无关
object.crosses(other) # object的interior与other的interior相交,且不包含他,该判断只适用于图形与线之间的判定
object.disjoint(other) # object的interior和boundary 和other的interior和boundary都不想交 返回True,完全不相交才返回True,有一个点都不行
object.intersects(other) # object的interior或者boundary和other的interior或者boundary相交 返回TRUE
object.overlaps(other) # object的interior或者boundary和other的interior或者boundary相交,且不包含他, 返回TRUE
object.touches(other) # other和object至少有一个共同的点,且他们的interior不相交,也就是说在边界上
contains
a = Point(1, 1)
b = Point(3, 3)
print(a.contains(b))
a = Point(2, 2)
b = Point(2, 2)
print(a.contains(b))
a = Point(2, 1)
b = LineString([(1, 2), (3, 2)])
print(a.contains(b))
a = Point(2, 2)
b = LineString([(1, 2), (3, 2)])
print(a.contains(b))
a = Point(3, 1)
b = Point(2, 2).buffer(1)
print(a.contains(b))
a = Point(2, 2)
b = Point(2, 2).buffer(1)
print(a.contains(b))
a = Point(2, 1)
b = Point(2, 2).buffer(1)
print(a.contains(b))
a = LineString([(1, 1), (3, 1)])
b = LineString([(1, 3), (3, 3)])
print(a.contains(b))
a = LineString([(1, 2), (3, 2)])
b = LineString([(2, 1), (2, 3)])
print(a.contains(b))
a = LineString([(1, 0.5), (3, 0.5)])
b = Point(2, 2).buffer(1)
print(a.contains(b))
a = LineString([(1, 1), (3, 1)])
b = Point(2, 2).buffer(1)
print(a.contains(b))
a = LineString([(1, 1), (2, 2)])
b = Point(2, 2).buffer(1)
print(a.contains(b))
a = Point(1, 1).buffer(1)
b = Point(3, 3).buffer(1)
print(a.contains(b))
a = Polygon([(2, 2), (2, 3), (3, 3), (3, 2)])
b = Polygon([(1, 1), (1, 2), (2, 2), (2, 1)])
print(a.contains(b))
a = Point(1, 1).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.contains(b))
a = Point(2, 2).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.contains(b))
crosses
a = Point(1, 1)
b = Point(3, 3)
print(a.crosses(b))
a = Point(2, 2)
b = Point(2, 2)
print(a.crosses(b))
a = Point(2, 1)
b = LineString([(1, 2), (3, 2)])
print(a.crosses(b))
a = Point(2, 2)
b = LineString([(1, 2), (3, 2)])
print(a.crosses(b))
a = Point(3, 1)
b = Point(2, 2).buffer(1)
print(a.crosses(b))
a = Point(2, 2)
b = Point(2, 2).buffer(1)
print(a.crosses(b))
a = Point(2, 1)
b = Point(2, 2).buffer(1)
print(a.crosses(b))
a = LineString([(1, 1), (3, 1)])
b = LineString([(1, 3), (3, 3)])
print(a.crosses(b))
a = LineString([(1, 2), (3, 2)])
b = LineString([(2, 1), (2, 3)])
print(a.crosses(b))
a = LineString([(1, 0.5), (3, 0.5)])
b = Point(2, 2).buffer(1)
print(a.crosses(b))
a = LineString([(1, 1), (3, 1)])
b = Point(2, 2).buffer(1)
print(a.crosses(b))
a = LineString([(1, 1), (2, 2)])
b = Point(2, 2).buffer(1)
print(a.crosses(b))
a = Point(1, 1).buffer(1)
b = Point(3, 3).buffer(1)
print(a.crosses(b))
a = Polygon([(2, 2), (2, 3), (3, 3), (3, 2)])
b = Polygon([(1, 1), (1, 2), (2, 2), (2, 1)])
print(a.crosses(b))
a = Point(1, 1).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.crosses(b))
a = Point(2, 2).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.crosses(b))
disjoint
a = Point(1, 1)
b = Point(3, 3)
print(a.disjoint(b))
a = Point(2, 2)
b = Point(2, 2)
print(a.disjoint(b))
a = Point(2, 1)
b = LineString([(1, 2), (3, 2)])
print(a.disjoint(b))
a = Point(2, 2)
b = LineString([(1, 2), (3, 2)])
print(a.disjoint(b))
a = Point(3, 1)
b = Point(2, 2).buffer(1)
print(a.disjoint(b))
a = Point(2, 2)
b = Point(2, 2).buffer(1)
print(a.disjoint(b))
a = Point(2, 1)
b = Point(2, 2).buffer(1)
print(a.disjoint(b))
a = LineString([(1, 1), (3, 1)])
b = LineString([(1, 3), (3, 3)])
print(a.disjoint(b))
a = LineString([(1, 2), (3, 2)])
b = LineString([(2, 1), (2, 3)])
print(a.disjoint(b))
a = LineString([(1, 0.5), (3, 0.5)])
b = Point(2, 2).buffer(1)
print(a.disjoint(b))
a = LineString([(1, 1), (3, 1)])
b = Point(2, 2).buffer(1)
print(a.disjoint(b))
a = LineString([(1, 1), (2, 2)])
b = Point(2, 2).buffer(1)
print(a.disjoint(b))
a = Point(1, 1).buffer(1)
b = Point(3, 3).buffer(1)
print(a.disjoint(b))
a = Polygon([(2, 2), (2, 3), (3, 3), (3, 2)])
b = Polygon([(1, 1), (1, 2), (2, 2), (2, 1)])
print(a.disjoint(b))
a = Point(1, 1).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.disjoint(b))
a = Point(2, 2).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.disjoint(b))
intersects
a = Point(1, 1)
b = Point(3, 3)
print(a.intersects(b))
a = Point(2, 2)
b = Point(2, 2)
print(a.intersects(b))
a = Point(2, 1)
b = LineString([(1, 2), (3, 2)])
print(a.intersects(b))
a = Point(2, 2)
b = LineString([(1, 2), (3, 2)])
print(a.intersects(b))
a = Point(3, 1)
b = Point(2, 2).buffer(1)
print(a.intersects(b))
a = Point(2, 2)
b = Point(2, 2).buffer(1)
print(a.intersects(b))
a = Point(2, 1)
b = Point(2, 2).buffer(1)
print(a.intersects(b))
a = LineString([(1, 1), (3, 1)])
b = LineString([(1, 3), (3, 3)])
print(a.intersects(b))
a = LineString([(1, 2), (3, 2)])
b = LineString([(2, 1), (2, 3)])
print(a.intersects(b))
a = LineString([(1, 0.5), (3, 0.5)])
b = Point(2, 2).buffer(1)
print(a.intersects(b))
a = LineString([(1, 1), (3, 1)])
b = Point(2, 2).buffer(1)
print(a.intersects(b))
a = LineString([(1, 1), (2, 2)])
b = Point(2, 2).buffer(1)
print(a.intersects(b))
a = Point(1, 1).buffer(1)
b = Point(3, 3).buffer(1)
print(a.intersects(b))
a = Polygon([(2, 2), (2, 3), (3, 3), (3, 2)])
b = Polygon([(1, 1), (1, 2), (2, 2), (2, 1)])
print(a.intersects(b))
a = Point(1, 1).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.intersects(b))
a = Point(2, 2).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.intersects(b))
overlaps
a = Point(1, 1)
b = Point(3, 3)
print(a.overlaps(b))
a = Point(2, 2)
b = Point(2, 2)
print(a.overlaps(b))
a = Point(2, 1)
b = LineString([(1, 2), (3, 2)])
print(a.overlaps(b))
a = Point(2, 2)
b = LineString([(1, 2), (3, 2)])
print(a.overlaps(b))
a = Point(3, 1)
b = Point(2, 2).buffer(1)
print(a.overlaps(b))
a = Point(2, 2)
b = Point(2, 2).buffer(1)
print(a.overlaps(b))
a = Point(2, 1)
b = Point(2, 2).buffer(1)
print(a.overlaps(b))
a = LineString([(1, 1), (3, 1)])
b = LineString([(1, 3), (3, 3)])
print(a.overlaps(b))
a = LineString([(1, 2), (3, 2)])
b = LineString([(2, 1), (2, 3)])
print(a.overlaps(b))
a = LineString([(1, 0.5), (3, 0.5)])
b = Point(2, 2).buffer(1)
print(a.overlaps(b))
a = LineString([(1, 1), (3, 1)])
b = Point(2, 2).buffer(1)
print(a.overlaps(b))
a = LineString([(1, 1), (2, 2)])
b = Point(2, 2).buffer(1)
print(a.overlaps(b))
a = Point(1, 1).buffer(1)
b = Point(3, 3).buffer(1)
print(a.overlaps(b))
a = Polygon([(2, 2), (2, 3), (3, 3), (3, 2)])
b = Polygon([(1, 1), (1, 2), (2, 2), (2, 1)])
print(a.overlaps(b))
a = Point(1, 1).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.overlaps(b))
a = Point(2, 2).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.overlaps(b))
touches
a = Point(1, 1)
b = Point(3, 3)
print(a.touches(b))
a = Point(2, 2)
b = Point(2, 2)
print(a.touches(b))
a = Point(2, 1)
b = LineString([(1, 2), (3, 2)])
print(a.touches(b))
a = Point(2, 2)
b = LineString([(1, 2), (3, 2)])
print(a.touches(b))
a = Point(3, 1)
b = Point(2, 2).buffer(1)
print(a.touches(b))
a = Point(2, 2)
b = Point(2, 2).buffer(1)
print(a.touches(b))
a = Point(2, 1)
b = Point(2, 2).buffer(1)
print(a.touches(b))
a = LineString([(1, 1), (3, 1)])
b = LineString([(1, 3), (3, 3)])
print(a.touches(b))
a = LineString([(1, 2), (3, 2)])
b = LineString([(2, 1), (2, 3)])
print(a.touches(b))
a = LineString([(1, 0.5), (3, 0.5)])
b = Point(2, 2).buffer(1)
print(a.touches(b))
a = LineString([(1, 1), (3, 1)])
b = Point(2, 2).buffer(1)
print(a.touches(b))
a = LineString([(1, 1), (2, 2)])
b = Point(2, 2).buffer(1)
print(a.touches(b))
a = Point(1, 1).buffer(1)
b = Point(3, 3).buffer(1)
print(a.touches(b))
a = Polygon([(2, 2), (2, 3), (3, 3), (3, 2)])
b = Polygon([(1, 1), (1, 2), (2, 2), (2, 1)])
print(a.touches(b))
a = Point(1, 1).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.touches(b))
a = Point(2, 2).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.touches(b))
计算距离
distance
from shapely.geometry import Point, LineString, Polygon
a = Point(1, 1)
b = Point(3, 3)
print(a.distance(b))
a = Point(2, 2)
b = Point(2, 2)
print(a.distance(b))
a = Point(2, 1)
b = LineString([(1, 2), (3, 2)])
print(a.distance(b))
a = Point(2, 2)
b = LineString([(1, 2), (3, 2)])
print(a.distance(b))
a = Point(3, 1)
b = Point(2, 2).buffer(1)
print(a.distance(b))
a = Point(2, 2)
b = Point(2, 2).buffer(1)
print(a.distance(b))
a = Point(2, 1)
b = Point(2, 2).buffer(1)
print(a.distance(b))
a = LineString([(1, 1), (3, 1)])
b = LineString([(1, 3), (3, 2)])
print(a.distance(b))
a = LineString([(1, 2), (3, 2)])
b = LineString([(2, 1), (2, 3)])
print(a.distance(b))
a = LineString([(1, 0.5), (3, 0.5)])
b = Point(2, 2).buffer(1)
print(a.distance(b))
a = LineString([(1, 1), (3, 1)])
b = Point(2, 2).buffer(1)
print(a.distance(b))
a = LineString([(1, 1), (2, 2)])
b = Point(2, 2).buffer(1)
print(a.distance(b))
a = Point(1, 1).buffer(1)
b = Point(3, 3).buffer(1)
print(a.distance(b))
a = Polygon([(2, 2), (2, 3), (3, 3), (3, 2)])
b = Polygon([(1, 1), (1, 2), (2, 2), (2, 1)])
print(a.distance(b))
a = Point(1, 1).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.distance(b))
a = Point(2, 2).buffer(1)
b = Point(2, 2).buffer(1.5)
print(a.distance(b))
点面关系图代码
# figures.py
from math import sqrt
from shapely import affinity
GM = (sqrt(5)-1.0)/2.0
W = 8.0
H = W*GM
SIZE = (W, H)
BLUE = '#6699cc'
GRAY = '#999999'
DARKGRAY = '#333333'
YELLOW = '#ffcc33'
GREEN = '#339933'
RED = '#ff3333'
BLACK = '#000000'
def add_origin(ax, geom, origin):
x, y = xy = affinity.interpret_origin(geom, origin, 2)
ax.plot(x, y, 'o', color=GRAY, zorder=1)
ax.annotate(str(xy), xy=xy, ha='center',
textcoords='offset points', xytext=(0, 8))
def set_limits(ax, x0, xN, y0, yN):
ax.set_xlim(x0, xN)
ax.set_xticks(range(x0, xN+1))
ax.set_ylim(y0, yN)
ax.set_yticks(range(y0, yN+1))
ax.set_aspect("equal")
# main.py
import matplotlib.pyplot as plt
from shapely.geometry import Point, LineString, Polygon
from shapely.plotting import plot_polygon, plot_points, plot_line
from figures import BLUE, GRAY, set_limits
fig = plt.figure(1, figsize=(9, 9), dpi=300)
fig.subplots_adjust(wspace=0.5, hspace=0.5) # 调整边距和子图的间距
ax = fig.add_subplot(4, 4, 1)
a = Point(1, 1)
b = Point(3, 3)
plot_points(a, ax=ax, color=GRAY)
plot_points(b, ax=ax, color=GRAY)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 2)
a = Point(2, 2)
b = Point(2, 2)
plot_points(a, ax=ax, color=GRAY)
plot_points(b, ax=ax, color=GRAY)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 3)
a = Point(2, 1)
b = LineString([(1, 2), (3, 2)])
plot_points(a, ax=ax, color=GRAY)
plot_line(b, ax=ax, color=GRAY)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 4)
a = Point(2, 2)
b = LineString([(1, 2), (3, 2)])
plot_points(a, ax=ax, color=GRAY)
plot_line(b, ax=ax, color=GRAY)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 5)
a = Point(3, 1)
b = Point(2, 2).buffer(1)
plot_points(a, ax=ax, color=GRAY)
plot_polygon(b, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 6)
a = Point(2, 2)
b = Point(2, 2).buffer(1)
plot_points(a, ax=ax, color=GRAY)
plot_polygon(b, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 7)
a = Point(2, 1)
b = Point(2, 2).buffer(1)
plot_points(a, ax=ax, color=GRAY)
plot_polygon(b, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 8)
a = LineString([(1, 1), (3, 1)])
b = LineString([(1, 3), (3, 3)])
plot_line(a, ax=ax, color=GRAY)
plot_line(b, ax=ax, color=GRAY)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 9)
a = LineString([(1, 2), (3, 2)])
b = LineString([(2, 1), (2, 3)])
plot_line(a, ax=ax, color=GRAY)
plot_line(b, ax=ax, color=GRAY)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 10)
a = LineString([(1, 0.5), (3, 0.5)])
b = Point(2, 2).buffer(1)
plot_line(a, ax=ax, color=GRAY)
plot_polygon(b, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 11)
a = LineString([(1, 1), (3, 1)])
b = Point(2, 2).buffer(1)
plot_line(a, ax=ax, color=GRAY)
plot_polygon(b, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_line(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 12)
a = LineString([(1, 1), (2, 2)])
b = Point(2, 2).buffer(1)
plot_line(a, ax=ax, color=GRAY)
plot_polygon(b, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_line(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 13)
a = Point(1, 1).buffer(1)
b = Point(3, 3).buffer(1)
plot_polygon(a, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_polygon(b, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 14)
a = Polygon([(2, 2), (2, 3), (3, 3), (3, 2)])
b = Polygon([(1, 1), (1, 2), (2, 2), (2, 1)])
plot_polygon(a, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_polygon(b, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_points(a.intersection(b), ax=ax, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 15)
a = Point(1, 1).buffer(1)
b = Point(2, 2).buffer(1.5)
plot_polygon(a, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_polygon(b, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_polygon(a.intersection(b), ax=ax, add_points=False, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
ax = fig.add_subplot(4, 4, 16)
a = Point(2, 2).buffer(1)
b = Point(2, 2).buffer(1.5)
plot_polygon(a, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_polygon(b, ax=ax, add_points=False, color=GRAY, alpha=0.2)
plot_polygon(a.intersection(b), ax=ax, add_points=False, color=BLUE)
ax.set_title(f'a.touches(b):{a.touches(b)}')
set_limits(ax, 0, 4, 0, 4)
plt.savefig('output.png')
plt.show()