# coding:utf-8 import numpy as np from functools import partial from shapely.geometry import Point, LineString from shapely.affinity import rotate, scale from shapely.ops import split, linemerge, snap import geopandas as gpd class arcBase3pnts(): # 基于3点构建圆/弧 def __init__(self, pnts): p1, p2, p3 = pnts self.p1 = p1 self.p2 = p2 self.p3 = p3 def getCenterAndRadius(self): # pnts = [[x1,y1],[x2,y2],[x3,y3]] p1, p2, p3 = self.p1, self.p2, self.p3 ls1, ls2 = LineString([p2, p3]), LineString([p1, p3]) fx = partial(scale, xfact=3, yfact=3) ls1, ls2 = fx(ls1), fx(ls2) vs1, vs2 = rotate(ls1, 90), rotate(ls2, 90) cp = vs1.intersection(vs2) r = cp.distance(Point(p1)) return cp, r def getCircle(self): # pnts = [[x1,y1],[x2,y2],[x3,y3]] cp, r = self.getCenterAndRadius() return cp.buffer(r) def getArc(self): # 获取过三点的弧长 # 要求弧长过点的顺序按照点的顺序,即中间点在弧长的中间部分 p1, p2, p3 = self.p1, self.p2, self.p3 circle = self.getCircle() ls3 = LineString([p1, p2]) parts = split(circle, ls3) for part in parts: if part.distance(Point(p3)) < 1e-6: res = circle.boundary.intersection(part) tmp = [] for i in range(len(res)): # 处理可能出行的多线情况 if res[i].geom_type=="LineString": tmp.append(res[i]) res2 = linemerge(tmp) break return res2 def getLastArc(self): # 获取过后两个点之间的弧 p2, p3 = self.p2, self.p3 arc = self.getArc() pp2, pp3 = Point(p2), Point(p3) arc = snap(arc, pp3, tolerance=0.1) parcs = split(arc, pp3) index = 0 if parcs[0].distance(pp2)<parcs[0].distance(pp2) else 1 return parcs[index] if __name__ == "__main__": pnts = [0, 1], [1, 0], [np.sqrt(1/2), np.sqrt(1/2)] oarc = arcBase3pnts(pnts=pnts) arc = oarc.getArc() prc = oarc.getLastArc()