【问题标题】:Combine two segments on the same circle if they overlap or intersect如果两个线段重叠或相交,则将它们组合在同一个圆上
【发布时间】:2017-03-27 20:19:55
【问题描述】:

如果两个部分重叠或相交,我会尝试合并它们。我的问题类似于thisthis。但是,我想要的是结合两个部分。

public class Segment
{
    private readonly double _from;
    private readonly double _to;
    public Segment(double from, double to)
    {
        _from = Normalize(from); // 0 <= x < 360
        _to = Normalize(to);
    }

    public bool Inside(double target)
    {
        if (_from < _to)
            return _from <= target && target <= _to;
        return _from <= target || target <= _to;
    }
}

我正在尝试写一个TryCombine()

public bool TryCombine(Segment other, out Segment result)
{
    // if not intersect
    // return false

    // else if overlap
    // return true, out larger one

    // else if intersect
    // return true, out a new one with merged bound
}

预期结果

var seg1 = new Segment(0, 100);
var seg2 = new Segment(50, 150);
var seg3 = new Segment(110, -100);
var seg4 = new Segment(10, 50);
Segment result;

seg1.TryCombine(seg2, result); // True, result = Segment(0, 150)
seg1.TryCombine(seg3, result); // False
seg1.TryCombine(seg4, result); // True, result = Segment(0, 100)
seg2.TryCombine(seg3, result); // True, result = Segment(260, 150)

【问题讨论】:

    标签: algorithm math language-agnostic angle


    【解决方案1】:

    您可以使用我在第二个链接中的回答中描述的方法。

    ma = (a2 + a1)/ 2  
    mb = (b2 + b1)/ 2  
    cda = Cos(da)
    cdb = Cos(db)
    

    要检查是否存在交集以及发生什么样的交集,找到4个布尔值

     BStartInsideA = (Cos(ma - b1) >= cda)
     BEndInsideA  =  (Cos(ma - b2) >= cda)
     AStartInsideB = (Cos(mb - a1) >= cdb)
     AEndInsideB =   (Cos(mb - a2) >= cdb)
    

    这些组合可以形成 16 种可能的结果(并非所有结果都是可靠的)。我会将这些结果组合为 4 位值的位,并在 case 语句中处理它们。

    例如,如果第一个值和最后一个值为真(值0b1001 = 9),则您有像 seg1-seg2 情况一样的简单交集 - 所以将 AStart 作为起点,BEnd 作为终点并将它们标准化(添加 360如果它小于 AStart,则为 BEnd)。

    预归一化步骤应提供 BEnd>=BStart 和 AEnd>=AStart(例如,将 (3,1) 弧转换为 (3, 361),中点为 182,半角为 179)

    可能的结果(两个额外的情况,4个简单的末端组合,4个单端重合的情况):

     0000: no intersection
     1111: full circle
    
     0011: AStart-AEnd
     1001: AStart-BEnd
     0110: BStart-AEnd
     1100: BStart-BEnd
    
     0111: AStart-AEnd
     1011: AStart-AEnd
     1110: BStart-BEnd
     1101: BStart-BEnd
    

    一位组合和 1010、0101 看起来不可能

    使用通配符,正如作者建议的那样:

     At first check for 
       0000: no intersection
       1111: full circle
     then
       **11: AStart-AEnd
       1001: AStart-BEnd
       0110: BStart-AEnd
       11**: BStart-BEnd
    

    【讨论】:

    • 问题是 A 中的 BStart 和 A 中的 BEnd 并不意味着 A 与 B 重叠。如果 A 是 (0, 5) 而 B 是 (3, 1),那么结果应该是完整的圆圈。
    • 这种情况应该在“规范化”期间被“捕获”
    • 正常化过程中被捕获是什么意思?有两种可能的角度来计算顺时针 (0, 15) 或逆时针 (15, 0) 的角度,这是两个不同的间隔。
    • 对于 A =(0, 5),B = (3, 1):如果 b2
    • 我认为您的回答是正确的,但我想再问一个问题。假设我使用您的订单来表示二进制标志。我的情况正确吗? 0b0000 没有相交。 0b1111 整圈。 0b11?? B 在 A 中。0b??11 A 在 B 中。0b1??1 返回 AStart 和 BEnd。 0b?11? 返回 BStart 和 AEnd。这些情况按? 表示通配符的顺序检查。它是否涵盖了所有可能的情况?还是有一些我错过的案例?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-05
    • 2020-05-09
    • 1970-01-01
    相关资源
    最近更新 更多