0

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)
Community
  • 1
  • 1
Joshua
  • 5,901
  • 2
  • 32
  • 52

1 Answers1

2

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
MBo
  • 77,366
  • 5
  • 53
  • 86
  • The problem is BStart inside A and BEnd inside A do not imply A overlap B. if A is (0, 5) and B is (3, 1), then the result should be full circle. – Joshua Nov 14 '16 at 09:23
  • This situation should be 'caught' during 'normalization' – MBo Nov 14 '16 at 09:50
  • What do you mean caught during normalization? There is two possible to count the angle clockwise (0, 15)or anti-clockwise (15, 0) which is two different intervals. – Joshua Nov 14 '16 at 10:03
  • For A =(0, 5),B = (3, 1): if b2 – MBo Nov 14 '16 at 10:32
  • I think you answer is correct but I would like to ask one more question. Assume I am using your order to represent binary flag. Are my cases correct? `0b0000` no intersect. `0b1111` full circle. `0b11??` B inside A. `0b??11` A inside B. `0b1??1` return AStart with BEnd. `0b?11?` return BStart with AEnd. The cases check in order where `?` representing wild card. Does it cover all possible cases? or are there some cases that I missed? – Joshua Nov 15 '16 at 05:52
  • @Joshua I also made 6 possible results, added to answer. – MBo Nov 15 '16 at 06:20
  • I just make sure I don't miss anything =). – Joshua Nov 15 '16 at 06:22
  • Something wrong about your cases though. `AStart-AEnd` is not necessary `0011`. Consider (0, 30) and (0,15), it will result in `1011`. That's why I use wild card in my comment above. – Joshua Nov 15 '16 at 06:28
  • Emm, yes... I thought that contain-results should be symmetric - it is wrong. Don't sure that wildcard usage is the best way. For example, (0, 30) and (0,15) is `0b0111` and might be considered both as AStart-AEnd and as BStart-AEnd – MBo Nov 15 '16 at 06:35
  • AStart-AEnd and BStart-AEnd should be the same as AStart = BStart. – Joshua Nov 15 '16 at 06:45
  • Just one more thing, why does the cos works? Is there any math theory that I can look up? – Joshua Nov 15 '16 at 09:37
  • Cos(ma - b1) >= Cos(da) when `da >= absolute value of difference` and properly treats periodicity, because Cos is even (abs value), periodic and is descending function at [0..180] – MBo Nov 15 '16 at 11:02