Math 快速放大三角形的方法

Math 快速放大三角形的方法,math,geometry,transform,computational-geometry,Math,Geometry,Transform,Computational Geometry,我有一个三角形,由它的3个(假设为整数)坐标定义,比如: A(ax, ay) B(bx, by) C(cx, cy) 如何将ABC三角形“放大”以获得一个新的(DEF)三角形,即具有整数坐标的最小(最小面积)三角形,该三角形包含上一个三角形的所有顶点 例如,如果我有三角形ABC,如何获得三角形DEF 在python 2.7中采用以下方法可能是解决问题的公平方法 from itertools import combinations, product import matplotlib.pyplo

我有一个三角形,由它的3个(假设为整数)坐标定义,比如:

A(ax, ay) B(bx, by) C(cx, cy)
如何将
ABC
三角形“放大”以获得一个新的(
DEF
)三角形,即具有整数坐标的最小(最小面积)三角形,该三角形包含上一个三角形的所有顶点

例如,如果我有三角形ABC,如何获得三角形DEF


python 2.7中采用以下方法可能是解决问题的公平方法

from itertools import combinations, product
import matplotlib.pyplot as plt
import numpy as np

class Triangle(object):

    def __str__(self):
        return "Triangle: " + str(self.vertices)

    def __init__(self,A,B,C):
        """ Creates a Triangle of vertices A,B,C """
        self.A = A
        self.B = B
        self.C = C
        self.vertices = [A,B,C]

    def area(self):
        """ Area of the triangle """
        x1 = self.A[0]
        y1 = self.A[1]
        x2 = self.B[0]
        y2 = self.B[1]
        x3 = self.C[0]
        y3 = self.C[1]
        return abs((x1 * (y2 - y3) + x2 * (y3 - y1)
                + x3 * (y1 - y2)) / 2.0)

    def isInside(self,X):
        """ Function to check whether X lies inside the triangle """
        area = self.area()
        area1 = Triangle(X,self.B,self.C).area()
        area2 = Triangle(self.A,X,self.C).area()
        area3 = Triangle(self.A,self.B,X).area()
        # Check if sum of area1, area2 and area3 is same as area
        if(area == area1 + area2 + area3):
            return True
        else:
            return False

    def findPosibleIntegerTriangles(self):
        """ Find posible triangles moving vertices to next integer values (512 posible triangles) """
        posibleA = posiblePoints(self.A)
        posibleB = posiblePoints(self.B)
        posibleC = posiblePoints(self.C)
        listPosibleVertices =  list(product(*[posibleA, posibleB, posibleC]))
        posibleTriangles = [Triangle(A,B,C) for A,B,C in listPosibleVertices ]
        return posibleTriangles

    def findPosibleIncludingIntegerTriangles(self):
        """ Find those posible triangles that include the original triangle """
        posibleIncludingTriangles = list()
        posibleTriangles = self.findPosibleIntegerTriangles()
        for triangle in posibleTriangles:
            if self.isTriangleIncluded(triangle):
                posibleIncludingTriangles.append(triangle)
        return posibleIncludingTriangles

    def isTriangleIncluded(self,triangle):
        """ Checks if it's included in the triangle selected (DEF) """
        DNotInside = not self.isInside(triangle.A)
        ENotInside = not self.isInside(triangle.B)
        FNotInside = not self.isInside(triangle.C)
        D = triangle.A
        E = triangle.B
        F = triangle.C
        ABdoNotIntersectDE = not segmentsIntersect(self.A,self.B,D,E)
        ABdoNotIntersectEF = not segmentsIntersect(self.A,self.B,E,F)
        ABdoNotIntersectFD = not segmentsIntersect(self.A,self.B,F,D)
        BCdoNotIntersectDE = not segmentsIntersect(self.B,self.C,D,E)
        BCdoNotIntersectEF = not segmentsIntersect(self.B,self.C,E,F)
        BCdoNotIntersectFD = not segmentsIntersect(self.B,self.C,F,D)
        CAdoNotIntersectDE = not segmentsIntersect(self.C,self.A,D,E)
        CAdoNotIntersectEF = not segmentsIntersect(self.C,self.A,E,F)
        CAdoNotIntersectFD = not segmentsIntersect(self.C,self.A,F,D)
        return DNotInside and ENotInside and FNotInside and \
                ABdoNotIntersectDE and ABdoNotIntersectEF and ABdoNotIntersectFD and \
                BCdoNotIntersectDE and BCdoNotIntersectEF and BCdoNotIntersectFD and \
                CAdoNotIntersectDE and CAdoNotIntersectEF and CAdoNotIntersectFD

    def findMinimumIntegerTriangle(self):
        """ Find the minimum triangle enlarged by integer values that includes the original triangle """
        minimumIntegerTriangle = None
        area = None
        for triangle in self.findPosibleIncludingIntegerTriangles():
            if area == None:
                area = triangle.area()
                minimumIntegerTriangle = triangle
            else:
                if triangle.area() < area:
                    area = triangle.area
                    minimumIntegerTriangle = triangle

        return minimumIntegerTriangle

    def plot(self, color = "blue"):
        pol = plt.Polygon(np.array(self.vertices),color = color)
        plt.gca().add_patch(pol)
        plt.autoscale()

def posiblePoints(P):
    """ Determine posible points to move to """
    posibleX = range(P[0]-1,P[0]+2)
    posibleY = range(P[1]-1,P[1]+2)
    posibleP = []
    for x in posibleX:
        for y in posibleY:
            if x!=P[0] or y!=P[1]:
                posibleP.append((x,y))
    return posibleP

def segmentsIntersect(A,B,C,D):
    """ Check if segment AB instersects with CD """
    def ccw(A,B,C):
        return (C[1]-A[1]) * (B[0]-A[0]) > (B[1]-A[1]) * (C[0]-A[0])
    return ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D)

# Select the vertices of original triangle
A = (-2,0)
B = (4,0)
C = (-1,3)

# Define the triangle
T = Triangle(A,B,C)

# Find the minimum triangle enlarged by integer values that includes the original triangle and print it
Tmin = T.findMinimumIntegerTriangle()
print Tmin

# Plot the found minimum triangle and the original one
Tmin.plot("red")
T.plot("blue")
plt.axis('equal')
plt.grid()
plt.show()

部分答案:

新三角形的顶点必须属于原始三角形的外角(通过延长边获得)

然后,当移动一条平行于另一个角的边的线时,找到新的候选顶点作为第一个网格点

我不确定这是否一定会给出最佳解决方案。为了安全起见,您可以尝试候选对象的近邻,并检查是否有任何组合产生较小的面积。

如果要均匀缩放三角形,此答案仅适用于
让我们平移三角形,使顶点
A(ax,ay)
成为原点
(0,0)

现在平移的顶点是
B'(bx-ax,by-ay)=(ux,uy)
C'=(cx-ax,cy-ay)=(vx,vy)
。 当比例因子
F
应用于坐标
x'=x·F
时,我们有一个增量
d=x'-x
。所以我们也可以说
x'=x+d
,因此
F=x'/x=(x+d)/x=1+d/x

让我们对翻译的
B'
C'
应用相同的比例:

F= 1 + d1/ux
F= 1 + d2/uy
F= 1 + d3/vx
F= 1 + d4/vy
因为
F
对于我们的四个等式是相同的:

d2/uy = d1/ux   ==>>   d2·ux = d1·uy  ==>> d2·ux - d1·uy = 0
d3/vx = d1/ux   ==>>   d3·ux = d1·vx  ==>> d3·ux - d1·vx = 0
d4/vy = d1/ux   ==>>   d4·ux = d1·vy  ==>> d4·ux - d1·vy = 0
任何形式为ax+by=0的方程都有
(-b,a)
解。因此:

d1 = ux
d2 = uy
d3 = vx
d4 = vy
如果
ux、uy、vx、vy
有一个最大公约数
g
,则我们找到最小的比例因子:
从第一个等式开始:

ux = ux'·g   ==>> g= ux/ux'
uy = uy'·g
d2·ux'·g - d1·uy'·g = 0   ==>>   d2·ux' - d1·uy' = 0
这意味着
d1=ux'
也是一种解决方案

比例系数为:

F= (ux + d1)/ux = 1 + ux'/ux  =  1 + 1/g
回传我们拥有的坐标,例如顶点
B

b_scaled_x = (bx-ax) · F + ax
b_scaled_y = (by-ay) · F + ay

请注意,所有坐标和增量
di
和最大公因数
g
都是整数值。比例因子
F
是一个有理数。因此,演算必须在“浮点数”而不是“整数”上进行。

这是一个有趣的问题。你有没有尝试过这个问题,你有没有代码可以显示?您是否尝试过在8个主要方向(向上、向上、向右、向右等)中的每一个方向上移动每个顶点一步,并检查每个生成的三角形?也许检查如何移动是一个好的开始。任何坐标是否保持不变?在你的例子中,如果
D
移动到(-3,0),F=B,E=C,这是一个解决方案吗?我认为你最好在第一时间问这个问题,注意有些三角形没有对应的“最小三角形”。e、 g.三角形
[(-2,2)、(4,0),(-1,3)]
。我不确定他们应该满足什么条件才能确保有解决方案。我还怀疑,随着三角形的“纵横比”越来越严重,你可能需要考虑的不仅仅是最近的整数点。例如,考虑[[(0,0),(999999999999999,2),(999999999999999,1)]……显然,在长轴附近的2个整数步的长度上的微小延伸对总面积有显著的影响。我从我发布的程序中得到的信息是:
Triangle:[(1,1),(10000000000000l,3),(99999999999999998l,2)]
@cedriccopolo-Heh。我实际上并没有想出一个反例,我只是想说明一下大概的想法。对于一个充分倾斜的三角形,“最近的整数”可能不如“与最长轴精确对齐”重要,我认为正确的解决方案就在这个方向上;这与寻找包含一组点的最小凸包的算法是一致的。为了达到最佳效果,它可能需要一种通过三角形边的长度以某种方式对角区域的搜索进行加权的方法。
b_scaled_x = (bx-ax) · F + ax
b_scaled_y = (by-ay) · F + ay