def calc_seg_intersect(xa, ya, xb, yb, xc, yc, xd, yd): s_abc = cross(xb - xa, yb - ya, xc - xa, yc - ya) c_abc = dblcmp(s_abc) c_cda = dblcmp(cross(xd - xc, yd - yc, xa - xc, ya - yc)) if c_abc == 0: f = between(xc, yc, xa, ya, xb, yb) if f is not None: return xc, yc, f, 0.0, (c_cda == 1), False if c_cda == 0: f = between(xa, ya, xc, yc, xd, yd) if f is not None: return xa, ya, 0.0, f, False, (c_abc == 1) s_abd = cross(xb - xa, yb - ya, xd - xa, yd - ya) c_abd = dblcmp(s_abd) c_cdb = dblcmp(cross(xd - xc, yd - yc, xb - xc, yb - yc)) if c_abd * c_abc < 0 and c_cda * c_cdb < 0: i = 1.0 * s_abc / (s_abc - s_abd) j = 1.0 - i res_x = xc * j + xd * i res_y = yc * j + yd * i return res_x, res_y, between(res_x, res_y, xa, ya, xb, yb), i, (c_cda == 1), (c_abc == 1) return None, None, None, None, (c_cda == 1), (c_abc == 1)
def get_seg_proper_intersect(xa, ya, xb, yb, xc, yc, xd, yd): s_abd = cross(xb - xa, yb - ya, xd - xa, yd - ya) c_abd = dblcmp(s_abd) s_abc = cross(xb - xa, yb - ya, xc - xa, yc - ya) c_abc = dblcmp(s_abc) c_cda = dblcmp(cross(xd - xc, yd - yc, xa - xc, ya - yc)) c_cdb = dblcmp(cross(xd - xc, yd - yc, xb - xc, yb - yc)) if c_abd * c_abc >= 0 or c_cda * c_cdb >= 0: return None i = 1.0 * s_abd / (s_abd - s_abc) j = 1.0 - i return xd * i + xc * j, yd * i + yc * j
def is_seg_intersect(xa, ya, xb, yb, xc, yc, xd, yd): c_abd = dblcmp(cross(xb - xa, yb - ya, xd - xa, yd - ya)) if c_abd == 0 and between(xd, yd, xa, ya, xb, yb) <= 0: return True c_abc = dblcmp(cross(xb - xa, yb - ya, xc - xa, yc - ya)) if c_abc == 0 and between(xc, yc, xa, ya, xb, yb) <= 0: return True c_cda = dblcmp(cross(xd - xc, yd - yc, xa - xc, ya - yc)) if c_cda == 0 and between(xa, ya, xc, yc, xd, yd) <= 0: return True c_cdb = dblcmp(cross(xd - xc, yd - yc, xb - xc, yb - yc)) if c_cdb == 0 and between(xb, yb, xc, yc, xd, yd) <= 0: return True return c_abd * c_abc < 0 and c_cda * c_cdb < 0
def between(xc, yc, xa, ya, xb, yb): if math.fabs(xb - xa) > math.fabs(yb - ya): da = xa - xc db = xb - xc else: da = ya - yc db = yb - yc sa = dblcmp(da) if sa == 0: return 0.0 sb = dblcmp(db) if sb == 0: return None if sa * sb < 0: return 1.0 * da / (da - db) return None
def get_seg_intersect(xa, ya, xb, yb, xc, yc, xd, yd): res = [] s_abd = cross(xb - xa, yb - ya, xd - xa, yd - ya) c_abd = dblcmp(s_abd) if c_abd == 0 and between(xd, yd, xa, ya, xb, yb) <= 0: res.append((xd, yd)) s_abc = cross(xb - xa, yb - ya, xc - xa, yc - ya) c_abc = dblcmp(s_abc) if c_abc == 0 and between(xc, yc, xa, ya, xb, yb) <= 0: res.append((xc, yc)) c_cda = dblcmp(cross(xd - xc, yd - yc, xa - xc, ya - yc)) if c_cda == 0 and between(xa, ya, xc, yc, xd, yd) < 0: res.append((xa, ya)) c_cdb = dblcmp(cross(xd - xc, yd - yc, xb - xc, yb - yc)) if c_cdb == 0 and between(xb, yb, xc, yc, xd, yd) < 0: res.append((xb, yb)) # 如果至少有一个点与另一条线段共线,那么此时可以断定交点已经全部求完 if len(res) > 0: return res if c_abd * c_abc < 0 and c_cda * c_cdb < 0: i = 1.0 * s_abd / (s_abd - s_abc) j = 1.0 - i res.append((xd * i + xc * j, yd * i + yc * j)) return res
def is_seg_proper_intersect(xa, ya, xb, yb, xc, yc, xd, yd): c_abd = dblcmp(cross(xb - xa, yb - ya, xd - xa, yd - ya)) c_abc = dblcmp(cross(xb - xa, yb - ya, xc - xa, yc - ya)) c_cda = dblcmp(cross(xd - xc, yd - yc, xa - xc, ya - yc)) c_cdb = dblcmp(cross(xd - xc, yd - yc, xb - xc, yb - yc)) return c_abd * c_abc < 0 and c_cda * c_cdb < 0
def between(xc, yc, xa, ya, xb, yb): if math.fabs(xb - xa) > math.fabs(yb - ya): return dblcmp(xa - xc) * dblcmp(xb - xc) else: return dblcmp(ya - yc) * dblcmp(yb - yc)
def decal_2d(rect, tri): p0, p1, p2, p3 = rect pa, pb, pc = tri cw = dblcmp(cross(pb[0] - pa[0], pb[1] - pa[1], pc[0] - pb[0], pc[1] - pb[1])) if cw == 0: # 三角形面积为0 return () if cw < 0: pb, pc = pc, pb tri = (pa, pb, pc) rect_e = ((p0, p1), (p1, p2), (p2, p3), (p3, p0)) tri_e = ((pa, pb), (pb, pc), (pc, pa)) rect_p_seq = ([], [], [], []) tri_p_seq = ([], [], []) rp_inside = [True] * 4 pid = 0 for j, te in enumerate(tri_e): tp_inside = True # 三角形的顶点是否在矩形的内部 for i, re in enumerate(rect_e): x, y, f1, f2, tp_on_left, rp_on_left = calc_seg_intersect( te[0][0], te[0][1], te[1][0], te[1][1], re[0][0], re[0][1], re[1][0], re[1][1],) if x is not None: tri_p_seq[j].append((f1, (x, y), pid, i)) rect_p_seq[i].append((f2, (x, y), pid, j)) pid += 1 if not tp_on_left: # 只要有不在任意一条边的左侧,都out tp_inside = False if not rp_on_left: rp_inside[i] = False if tp_inside: tri_p_seq[j].append((0.0, tri[j], pid, None)) pid += 1 for i in range(4): if rp_inside[i]: rect_p_seq[i].append((0.0, rect[i], pid, None)) pid += 1 if pid < 3: return () # 排序,并找一个点作为起始点 start_pid = None seq = None p_index = None for i, seg_p_seq in enumerate(tri_p_seq): seg_p_seq.sort() if start_pid is None and seg_p_seq: start_pid = seg_p_seq[0][2] seq = tri_p_seq p_index = (i, 0) for i, seg_p_seq in enumerate(rect_p_seq): seg_p_seq.sort() if start_pid is None and seg_p_seq: start_pid = seg_p_seq[0][2] seq = rect_p_seq p_index = (i, 0) ret = [] while True: i, j = p_index f, p, pid, rev_i = seq[i][j] ret.append(p) # 需要切换到另外一个序列上 if rev_i is not None and j == len(seq[i]) - 1: next_p_seq = seq[(i + 1) % len(seq)] if not next_p_seq or dblcmp(next_p_seq[0][0]) != 0: if seq == tri_p_seq: seq = rect_p_seq else: seq = tri_p_seq for k, (_f, _p, _pid, _rev_i) in enumerate(seq[rev_i]): if pid == _pid: i, j = p_index = (rev_i, k) break # 找下一个顶点,此时可以允许换边 j += 1 if j < len(seq[i]): p_index = (i, j) else: i = i + 1 if i >= len(seq): i = 0 j = 0 p_index = (i, j) try: pid = seq[i][j][2] except IndexError: print ("f*****g algorithm error") return () if pid == start_pid: break return ret