好的,我在寻找解决方案方面遇到了一些麻烦,这似乎是一个简单的几何问题。
我有一个形成方角的三重坐标列表。
在所有这些三重坐标之间,我想找到一对形成正方形的对象。
我相信我能做的最好的例证就是展示一张图片:
对于每个三重坐标,我有中间点,角度在哪里,另外两个点描述形成角度的两个分段。
总结一下,给出6个点,2个对角线+ 4个其他点,我怎样才能找到这些是否为正方形?
obs:制作角度的两条线是一致的但不具有相同的尺寸。
obs2:来自不同三元组的线可能不相交
感谢您抽出时间,提供任何帮助和见解。
如果我使用的任何术语不正确或者只是很难理解,请告诉我,我不是母语为英语的人。
编辑:现有代码。
//for all triples
for (size_t i = 0; i < toTry.size() - 1; i++) {
Vec2i center_i = toTry[i].avg;
//NormalizedDiagonal = ((Side1 - Center) + (Side2 - Center));
Vec2i a = toTry[i].p, b = toTry[i].q;
Vec2f normalized_i = normalizedDiagonal(center_i, toTry[i].p, toTry[i].q);
for (size_t j = i + 1; j < toTry.size(); j++) {
Vec2i center_j = toTry[j].avg;
//Se os pontos sao proximos, nao importam
if (areClose(center_i, center_j, 25))
continue;
Vec2f normalized_j = normalizedDiagonal(center_j, toTry[j].p, toTry[j].q);
line(src, Point(center_i[0], center_i[1]), Point(center_i[0] + 1 * normalized_i[0], center_i[1] + 1 * normalized_i[1]), Scalar(255, 255, 255), 1);
//test if antiparallel
if (abs(normalized_i[0] - normalized_j[0]) > 0.1 || abs(normalized_i[1] - normalized_j[1] > 0.1))
continue;
Vec2f delta;
delta[0] = center_j[0] - center_i[0]; delta[1] = center_j[1] - center_i[1];
double dd = sqrt(pow((center_i[0] - center_j[0]), 2) + pow((center_i[1] - center_j[1]), 2));
//delta[0] = delta[0] / dd;
//delta[1] = delta[1] / dd;
float dotProduct = normalized_i[0] * delta[0] + normalized_i[1] * delta[1];
//test if do product < 0
if (dotProduct < 0)
continue;
float deltaDotDiagonal = delta[0] * normalized_i[0] + delta[1] * normalized_i[1];
menor_d[0] = delta[0] - deltaDotDiagonal * normalized_i[0];
menor_d[1] = delta[1] - deltaDotDiagonal * normalized_i[1];
dd = sqrt(pow((center_j[0] - menor_d[0]), 2) + pow((center_j[1] - menor_d[1]), 2));
if(dd < 25)
[...]
答案 0 :(得分:1)
解决这个问题有两种方法。一种是非常直接的方法,涉及找到两行段的交集。
您只需使用三坐标来计算中点,以及从中突出的两个线段(平凡)。对两个三组都这样做。
现在计算延伸线段的所有四种可能排列的交叉点(如果存在)。从最初的答案到类似的问题:
您可以查看我为Computational Geometry in C编写的代码, 它详细讨论了这个问题(第1章,第5节)。该 代码可以从该网站的链接以SegSegInt的形式获得。
简而言之,我建议采用不同的方法,使用签名区域 三角形。然后比较适当的三点,一个可以 区分正确的交叉点和所有退化的交叉点 案例。一旦他们被区分,找到交叉点 很容易。
另一种图像处理方法是渲染线条,为线条定义一种独特的颜色,然后将种子/填充填充算法应用于找到的第一个白色区域,将新的独特颜色应用于未来区域,直到你填充一个没有触及图像边界的封闭区域。
祝你好运!<强>参考强>
<https://math.stackexchange.com/questions/276735/finding-the-intersection-of-two-line-segments-in-2d-with-potential-degeneracies>
答案 1 :(得分:1)
答案 2 :(得分:1)
为了清楚起见,侧段的实际长度是无关紧要的,对吧?你关心的是两个三元组的侧段形成的半无限线是否形成一个正方形?或者实际的片段是否需要交叉?
假设前者,检查两个三元组是否形成正方形的方法如下。让我们使用Point3D
命名空间中的Vector3D
和System.Windows.Media.Media3D
来定义一些术语,因为它们是支持基本线性代数方法的通用3d双精度点和向量。这些是c#所以你不能直接使用它们,但我希望能够参考那里提到的一些基本方法。
以下是检查两个三元组是否相交的基本方法:
按如下方式定义三元组:Center,Side1和Side2为三个Point3D结构。
对于每个三元组,将标准化对角线矢量定义为
NormalizedDiagonal = ((Side1 - Center) + (Side2 - Center));
NormalizedDiagonal.Normalize()
(您可能希望将其缓存以提高性能。)
检查两个中心在您定义的某个线性容差范围内是否相等。如果相等,则返回false - 这是一个退化的情况。
检查两个对角线矢量是否在您定义的某个角度公差范围内反平行。 (即NormalizedDiagonal1 == -NormalizedDiagonal2
有一定宽容。)如果没有,则返回false,而不是正方形。
计算从triple2.Center到triple2.Center的向量:delta = triple2.Center - triple1.Center
。
如果double deltaDotDiagonal = DotProduct(delta, triple1.NormalizedDiagonal) < 0
,则返回false - 两个三元组相互指远。
最后,计算从triple2的中心到穿过中心triple1的(无限)对角线的距离。如果为零(在线性公差范围内),则它们形成一个正方形。
计算该距离:distance = (delta - deltaDotDiagonal*triple1.NormalizedDiagonal).Length
注意:deltaDotDiagonal*triple1.NormalizedDiagonal
是delta
向量到triple1.NormalizedDiagonal
的投影,因此delta - deltaDotDiagonal*triple1.NormalizedDiagonal
是delta
的垂直于该对角线的组件。它的长度是我们寻求的距离。
最后,如果你对方形的定义要求实际的侧面段相交,你可以额外检查所有侧面段的长度是否小于sqrt(2) * delta.Length
。
此方法检查两个三元组是否形成正方形。找到形成正方形的所有三元组当然是O(N平方)。如果这是一个问题,您可以将它们放在一个数组中,然后按angle = Atan2(NormalizedDiagonal.Y, NormalizedDiagonal.X)
进行排序。完成后,您可以在角度公差范围内找到可能形成具有给定三元组的正方形的三元组,通过二进制搜索数组,从当前三元组的角度使用角度= +/-π进行三元组搜索。 (当角度接近π时,您需要检查数组的开头和结尾。)
<强>更新强>
好的,让我们看看我是否可以在课堂上做这件事。我没有Vec2i
和Vec2f
的定义,所以我可能会弄错...
double getLength(Vec2f vector)
{
return sqrt(pow(vector[0], 2) + pow(vector[1], 2));
}
Vec2f scaleVector(Vec2f vec, float scale)
{
Vec2f scaled;
scaled[0] = vec[0] * scale;
scaled[1] = vec[1] * scale;
return scaled;
}
Vec2f subtractVectorsAsFloat(Vec2i first, Vec2i second)
{
// return first - second as float.
Vec2f diff;
diff[0] = first[0] - second[0];
diff[1] = first[1] - second[1];
return diff;
}
Vec2f subtractVectorsAsFloat(Vec2f first, Vec2f second)
{
// return first - second as float.
Vec2f diff;
diff[0] = first[0] - second[0];
diff[1] = first[1] - second[1];
return diff;
}
double dot(Vec2f first, Vec2f second)
{
return first[0] * second[0] + first[1] * second[1];
}
//for all triples
for (size_t i = 0; i < toTry.size() - 1; i++) {
Vec2i center_i = toTry[i].avg;
//NormalizedDiagonal = ((Side1 - Center) + (Side2 - Center));
Vec2i a = toTry[i].p, b = toTry[i].q;
Vec2f normalized_i = normalizedDiagonal(center_i, toTry[i].p, toTry[i].q);
for (size_t j = i + 1; j < toTry.size(); j++) {
Vec2i center_j = toTry[j].avg;
//Se os pontos sao proximos, nao importam
if (areClose(center_i, center_j, 25))
continue;
Vec2f normalized_j = normalizedDiagonal(center_j, toTry[j].p, toTry[j].q);
//test if antiparallel
if (abs(normalized_i[0] - normalized_j[0]) > 0.1 || abs(normalized_i[1] - normalized_j[1] > 0.1))
continue;
// get a vector pointing from center_i to center_j.
Vec2f delta = subtractVectorsAsFloat(center_j, center_i);
//test if do product < 0
float deltaDotDiagonal = dot(delta, normalized_i);
if (deltaDotDiagonal < 0)
continue;
Vec2f deltaProjectedOntoDiagonal = scaleVector(normalized_i, deltaDotDiagonal);
// Subtracting the dot product of delta projected onto normalized_i will leave the component
// of delta which is perpendicular to normalized_i...
Vec2f distanceVec = subtractVectorsAsFloat(deltaProjectedOntoDiagonal, center_j);
// ... the length of which is the distance from center_j
// to the diagonal through center_i.
double distance = getLength(distanceVec);
if(distance < 25) {
}
}