Search code examples
algorithmmathlanguage-agnosticangle

Combine two segments on the same circle if they overlap or intersect


I am try to combine two segments if they overlap or intersect.My question is similar to this and this. However, what I want is to combine two segments.

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;
    }
}

I am trying to write a 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
}

Expected Result

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)

Solution

  • You can use approach described in my answer in you second link.

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

    To check whether intersection exists and what kind o intersection takes place, find 4 boolean values

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

    These combinations could form 16 possible results (not all are reliable). I'd combine these results as bits of 4-bit value and treat them in the case statement.

    For example, if the first and the last values are true (value 0b1001 = 9), you have simple intersection like your seg1-seg2 case - so get AStart ans starting point, BEnd as ending point and normalize them (add 360 to BEnd if it is less than AStart).

    Pre-normalization step should provide BEnd>=BStart and AEnd>=AStart (for example, transform (3,1) arc into (3, 361) with middle point 182 and semi-angle 179)

    Possible results (two extra cases, 4 simple end combinations, 4 one-end coinciding cases):

     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
    

    One-bit combinations and 1010, 0101 look impossible

    with wildcards, as author proposed:

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