github.com/pavlo67/common@v0.5.3/common/mathlib/plane/lines.go (about)

     1  package plane
     2  
     3  import (
     4  	"math"
     5  
     6  	"github.com/pavlo67/common/common/mathlib"
     7  )
     8  
     9  type Intersection struct {
    10  	Angle  float64
    11  	X0, X1 float64
    12  }
    13  
    14  func Cross(p1, p2 Point2) float64 {
    15  	return p1.X*p2.Y - p1.Y*p2.X
    16  }
    17  
    18  func (s Segment) TurnAroundAxis(p2 Point2) Point2 {
    19  	axisDX, axisDY := s[1].X-s[0].X, s[1].Y-s[0].Y
    20  	var axisDerivative float64
    21  
    22  	if axisDX == 0 {
    23  		if axisDY == 0 {
    24  			// TODO!!! be careful, it's a very non-standard case
    25  			return Point2{s[0].X*2 - p2.X, s[0].Y*2 - p2.Y}
    26  		}
    27  		return Point2{s[0].X*2 - p2.X, p2.Y}
    28  	} else if axisDerivative = axisDY / axisDX; math.IsInf(axisDerivative, 0) {
    29  		return Point2{s[0].X*2 - p2.X, p2.Y}
    30  	} else if axisDY == 0 || math.IsInf(1/axisDerivative, 0) {
    31  		return Point2{p2.X, s[0].Y*2 - p2.Y}
    32  	}
    33  
    34  	pIntersection := s.LinesIntersection(Segment{p2, Point2{p2.X + 1, p2.Y - 1/axisDerivative}})
    35  	return Point2{pIntersection.X*2 - p2.X, pIntersection.Y*2 - p2.Y}
    36  
    37  }
    38  
    39  func (s Segment) TurnAroundAxisMultiple(p2s ...Point2) []Point2 {
    40  	axisDX, axisDY := s[1].X-s[0].X, s[1].Y-s[0].Y
    41  	var axisDerivative float64
    42  
    43  	p2sTurned := make([]Point2, len(p2s))
    44  
    45  	if axisDX == 0 {
    46  		if axisDY == 0 {
    47  			// TODO!!! be careful, it's a very non-standard case
    48  			for i, p2 := range p2s {
    49  				p2sTurned[i] = Point2{s[0].X*2 - p2.X, s[0].Y*2 - p2.Y}
    50  			}
    51  		} else {
    52  			for i, p2 := range p2s {
    53  				p2sTurned[i] = Point2{s[0].X*2 - p2.X, p2.Y}
    54  			}
    55  		}
    56  	} else if axisDerivative = axisDY / axisDX; math.IsInf(axisDerivative, 0) {
    57  		for i, p2 := range p2s {
    58  			p2sTurned[i] = Point2{s[0].X*2 - p2.X, p2.Y}
    59  		}
    60  	} else if axisDY == 0 || math.IsInf(1/axisDerivative, 0) {
    61  		for i, p2 := range p2s {
    62  			p2sTurned[i] = Point2{p2.X, s[0].Y*2 - p2.Y}
    63  		}
    64  	} else {
    65  		for i, p2 := range p2s {
    66  			pIntersection := s.LinesIntersection(Segment{p2, Point2{p2.X + 1, p2.Y - 1/axisDerivative}})
    67  			p2sTurned[i] = Point2{pIntersection.X*2 - p2.X, pIntersection.Y*2 - p2.Y}
    68  		}
    69  	}
    70  
    71  	return p2sTurned
    72  }
    73  
    74  func (s Segment) LinesIntersection(s1 Segment) *Point2 {
    75  	// https://stackoverflow.com/questions/7446126/opencv-2d-line-intersection-helper-function
    76  	// https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
    77  
    78  	r := Point2{s[1].X - s[0].X, s[1].Y - s[0].Y}
    79  	l := Point2{s1[1].X - s1[0].X, s1[1].Y - s1[0].Y}
    80  
    81  	cr := Cross(r, l)
    82  	if cr > -mathlib.Eps && cr < mathlib.Eps {
    83  		// lines are about parallel (they may be collinear!)
    84  		return nil
    85  	}
    86  
    87  	q := Point2{s1[0].X - s[0].X, s1[0].Y - s[0].Y}
    88  	t := Cross(q, l) / cr
    89  
    90  	return &Point2{s[0].X + t*r.X, s[0].Y + t*r.Y}
    91  
    92  }
    93  
    94  func (s Segment) DivideByLine(p0, p1 Point2) *Point2 {
    95  	pIntersect := s.LinesIntersection(Segment{p0, p1})
    96  	if pIntersect == nil {
    97  		return nil
    98  	}
    99  
   100  	if p1.X > p0.X {
   101  		if pIntersect.X > p0.X && pIntersect.X < p1.X {
   102  			return pIntersect
   103  		}
   104  	} else if p1.X < p0.X {
   105  		if pIntersect.X > p1.X && pIntersect.X < p0.X {
   106  			return pIntersect
   107  		}
   108  	} else if p1.Y > p0.Y {
   109  		if pIntersect.Y > p0.Y && pIntersect.Y < p1.Y {
   110  			return pIntersect
   111  		}
   112  	} else {
   113  		if pIntersect.Y > p1.Y && pIntersect.Y < p0.Y {
   114  			return pIntersect
   115  		}
   116  	}
   117  
   118  	// log.Print(p0, p1, pIntersect)
   119  
   120  	return nil
   121  }