【问题标题】:Function that returns intersection of two TShapes, including TPaths?返回两个 TShapes 的交集的函数,包括 TPaths?
【发布时间】:2015-09-01 05:52:30
【问题描述】:

任何人都知道返回两个 TShape 的交集 TPath 的函数吗?尤其是返回两个 TPath 的交集 TPath。

例如:

pthIntersection := PathIntersection(Path1,Path2);

【问题讨论】:

标签: delphi firemonkey


【解决方案1】:

没有内置函数。
但我认为你正在尝试做的是:

给定一个由线连接的不同点组成的多边形(又名 TPath)。
返回位于 ShapeB 内的 ShapeA 中的所有点。

交点
这可以使用PointInObjectLocal 来完成。
运行一个循环访问PathA 中的所有点,并查看PathB 中是否有任何点。

线交点
如果您想知道所有重叠的顶点,您首先必须 Flatten(两个 TPath 的副本),然后对两个形状中的所有线运行线相交算法。
这会将所有曲线转换为直线。

以下是执行此操作的例程:
来自:http://www.partow.net/projects/fastgeo/index.html

function Intersect(const x1, y1, x2, y2, x3, y3, x4, y4: TFloat; out ix, iy: TFloat): boolean;
var
  UpperX, UpperY, LowerX, LowerY: TFloat;
  Ax, Bx, Cx, Ay, By, Cy: TFloat;
  D, F, E, Ratio: TFloat;
begin
  Result:= false;

  Ax:= x2 - x1;
  Bx:= x3 - x4;

  if Ax < Zero then begin
    LowerX:= x2;
    UpperX:= x1;
  end else begin
    UpperX:= x2;
    LowerX:= x1;
  end;

  if Bx > Zero then begin
    if (UpperX < x4) or (x3 < LowerX) then Exit;
  end else if (UpperX < x3) or (x4 < LowerX) then Exit;

  Ay:= y2 - y1;
  By:= y3 - y4;

  if Ay < Zero then begin
    LowerY:= y2;
    UpperY:= y1;
  end else begin
    UpperY:= y2;
    LowerY:= y1;
  end;

  if By > Zero then begin
    if (UpperY < y4) or (y3 < LowerY) then Exit;
  end else if (UpperY < y3) or (y4 < LowerY) then Exit;

  Cx:= x1 - x3;
  Cy:= y1 - y3;
  D:= (By * Cx) - (Bx * Cy);
  F:= (Ay * Bx) - (Ax * By);

  if F > Zero then begin
    if (D < Zero) or (D > F) then Exit;
  end else if (D > Zero) or (D < F) then Exit;

  E:= (Ax * Cy) - (Ay * Cx);

  if F > Zero then begin
    if (E < Zero) or (E > F) then Exit;
  end else if (E > Zero) or (E < F) then Exit;

  Result:= true;

  Ratio:= (Ax * -By) - (Ay * -Bx);

  if NotEqual(Ratio, Zero) then begin
    Ratio:= ((Cy * -Bx) - (Cx * -By)) / Ratio;
    ix:= x1 + (Ratio * Ax);
    iy:= y1 + (Ratio * Ay);
  end else begin
    //if Collinear(x1,y1,x2,y2,x3,y3) then
    if IsEqual((Ax * -Cy), ( -Cx * Ay)) then begin
      ix:= x3;
      iy:= y3;
    end else begin
      ix:= x4;
      iy:= y4;
    end;
  end;
end;

function Intersect(const Segment1,Segment2:TSegment2D; out ix, iy : TFloat):Boolean;
begin
  Result := Intersect(Segment1[1].x,Segment1[1].y,Segment1[2].x,Segment1[2].y,Segment2[1].x,Segment2[1].y,Segment2[2].x,Segment2[2].y,ix,iy);
end;

只需将 TFloat x,y 对转换为 TPointF 即可。 该例程的最酷之处在于它还可以告诉您线条重叠的确切点。

如果您跟随线条,直到两条线重叠,然后从那里开始跟踪重叠线和 PointInShape,您可以构建两个形状重叠的精确图像。

让它更快
如果扁平化和相应增加的线段数量使您的代码太慢,您可以保留曲线并查看一条线/曲线是否与另一条曲线相交。
为此,您可以将曲线转换为 bezier curves 并使用 De_Casteljau's algorithm

更多信息
另请参阅this questionlink to Delphi source code 在其第一个或第二个答案中。

【讨论】:

  • 丹基,约翰。在没有人提供 TPath 解决方案之后,我担心我不得不走这条艰难的道路并且已经开始沿着这条道路(不是双关语)。由于我的问题主要涉及贝塞尔曲线,因此我也会查看链接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-31
  • 2020-07-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多