github.com/kintar/etxt@v0.0.9/emask/outline_segment.go (about)

     1  package emask
     2  
     3  type outlineSegment struct {
     4  	// starting position
     5  	ox float64
     6  	oy float64
     7  	fx float64
     8  	fy float64
     9  
    10  	// coefficients for line equations in the form Ax + By + C = 0
    11  	a  float64 // a1 and a2 are the same, lines are parallel
    12  	b  float64 // b1 and b2 are the same, lines are parallel
    13  	c1 float64
    14  	c2 float64
    15  }
    16  
    17  func (self *outlineSegment) Fill(buffer *buffer, prevSegment, nextSegment *outlineSegment) { //, maxOutDist float64) {
    18  	oxOut, oyOut, oxIn, oyIn, oxx, oxy := prevSegment.intersect(self)
    19  	fxOut, fyOut, fxIn, fyIn, fxx, fxy := self.intersect(nextSegment)
    20  
    21  	// TODO: would still need further triangle clipping for thickness
    22  	//       shorter than segment len cases
    23  	_, _ = oxx, oxy
    24  	_, _ = fxx, fxy
    25  
    26  	// if outer points get too far away, clamp them
    27  	// TODO: this clamping must also be mirrored on CutHead and CutTail
    28  	//       once I confirm it's working...
    29  	// TODO: the mirroring is unlikely to be ok here.
    30  	// TODO: if this starts getting more complex, consider reimplementing
    31  	//       CutHead and CutTail as Fills with synthetic outlineSegments.
    32  	// TODO: I should have a clearer idea of the whole, complete strategy
    33  	//       before I go into any other bs
    34  
    35  	// maxOutDist2 := maxOutDist*maxOutDist
    36  	// oDist2 := dist2(self.ox, self.oy, oxOut, oyOut)
    37  	// if oDist2 > maxOutDist2 {
    38  	// 	factor := math.Sqrt(oDist2)/maxOutDist
    39  	// 	oxOut, oyOut = lerp(self.ox, self.oy, oxOut, oyOut, factor)
    40  	// 	buffer.FillConvexQuad(oxOut, oyOut, oxOut, oyOut, oxIn, oyIn, oxx, oxy)
    41  	// 	oxOut, oyOut = oxx, oxy
    42  	// }
    43  	// fDist2 := dist2(self.fx, self.fy, fxOut, fyOut)
    44  	// if fDist2 > maxOutDist2 {
    45  	// 	factor := math.Sqrt(fDist2)/maxOutDist
    46  	// 	fxOut, fyOut = lerp(self.fx, self.fy, fxOut, fyOut, factor)
    47  	// 	buffer.FillConvexQuad(fxOut, fyOut, fxOut, fyOut, fxIn, fyIn, fxx, fxy)
    48  	// 	fxOut, fyOut = fxx, fxy
    49  	// }
    50  
    51  	// main quad fill
    52  	buffer.FillConvexQuad(oxOut, oyOut, oxIn, oyIn, fxOut, fyOut, fxIn, fyIn)
    53  }
    54  
    55  func (self *outlineSegment) CutHead(buffer *buffer, prevSegment *outlineSegment) { //, maxOutDist float64) {
    56  	oxOut, oyOut, oxIn, oyIn, oxx, oxy := prevSegment.intersect(self)
    57  	_, _ = oxx, oxy
    58  	// maxOutDist2 := maxOutDist*maxOutDist
    59  	// oDist2 := dist2(self.ox, self.oy, oxOut, oyOut)
    60  	// if oDist2 > maxOutDist2 { // clamping for the outer point
    61  	// 	factor := math.Sqrt(oDist2)/maxOutDist
    62  	// 	oxOut, oyOut = lerp(self.ox, self.oy, oxOut, oyOut, factor)
    63  	// 	buffer.FillConvexQuad(oxOut, oyOut, oxOut, oyOut, oxIn, oyIn, oxx, oxy)
    64  	// 	oxOut, oyOut = oxx, oxy
    65  	// }
    66  
    67  	a, b, oc := perpendicularABC(self.a, self.b, self.fx, self.fy)
    68  	xdiv := a*self.b - self.a*b
    69  	ox1, oy1 := shortCramer(xdiv, a, b, oc, self.a, self.b, self.c1)
    70  	ox2, oy2 := shortCramer(xdiv, a, b, oc, self.a, self.b, self.c2)
    71  	buffer.FillConvexQuad(oxOut, oyOut, oxIn, oyIn, ox1, oy1, ox2, oy2)
    72  }
    73  
    74  func (self *outlineSegment) CutTail(buffer *buffer, nextSegment *outlineSegment) { //, maxOutDist float64) {
    75  	a, b, oc := perpendicularABC(self.a, self.b, self.ox, self.oy)
    76  	xdiv := a*self.b - self.a*b
    77  	ox1, oy1 := shortCramer(xdiv, a, b, oc, self.a, self.b, self.c1)
    78  	ox2, oy2 := shortCramer(xdiv, a, b, oc, self.a, self.b, self.c2)
    79  	fxOut, fyOut, fxIn, fyIn, fxx, fxy := self.intersect(nextSegment)
    80  
    81  	_, _ = fxx, fxy
    82  	// maxOutDist2 := maxOutDist*maxOutDist
    83  	// fDist2 := dist2(self.fx, self.fy, fxOut, fyOut)
    84  	// if fDist2 > maxOutDist2 { // clamping for the outer point
    85  	// 	factor := math.Sqrt(fDist2)/maxOutDist
    86  	// 	fxOut, fyOut = lerp(self.fx, self.fy, fxOut, fyOut, factor)
    87  	// 	buffer.FillConvexQuad(fxOut, fyOut, fxOut, fyOut, fxIn, fyIn, fxx, fxy)
    88  	// 	fxOut, fyOut = fxx, fxy
    89  	// }
    90  
    91  	buffer.FillConvexQuad(ox1, oy1, ox2, oy2, fxOut, fyOut, fxIn, fyIn)
    92  }
    93  
    94  func (self *outlineSegment) Cut(buffer *buffer) {
    95  	a, b, oc := perpendicularABC(self.a, self.b, self.ox, self.oy)
    96  	xdiv := a*self.b - self.a*b
    97  	ox1, oy1 := shortCramer(xdiv, a, b, oc, self.a, self.b, self.c1)
    98  	ox2, oy2 := shortCramer(xdiv, a, b, oc, self.a, self.b, self.c2)
    99  	fc := -(a*self.fx + b*self.fy) // ax + by + c = 0
   100  	fx1, fy1 := shortCramer(xdiv, a, b, fc, self.a, self.b, self.c1)
   101  	fx2, fy2 := shortCramer(xdiv, a, b, fc, self.a, self.b, self.c2)
   102  	buffer.FillConvexQuad(ox1, oy1, ox2, oy2, fx1, fy1, fx2, fy2)
   103  }
   104  
   105  // Intersects two outline segments and determines the inner and outer
   106  // points at which they intersect. The returned values are outer vertex
   107  // x and outer vertex y, inner vertex x and inner vertex y, and the
   108  // other intersecting vertex on self before outer x/y.
   109  func (self *outlineSegment) intersect(other *outlineSegment) (float64, float64, float64, float64, float64, float64) {
   110  	// find 4 intersection points
   111  	xdiv := self.a*other.b - other.a*self.b
   112  	x11, y11 := shortCramer(xdiv, self.a, self.b, self.c1, other.a, other.b, other.c1)
   113  	x12, y12 := shortCramer(xdiv, self.a, self.b, self.c1, other.a, other.b, other.c2)
   114  	x21, y21 := shortCramer(xdiv, self.a, self.b, self.c2, other.a, other.b, other.c1)
   115  	x22, y22 := shortCramer(xdiv, self.a, self.b, self.c2, other.a, other.b, other.c2)
   116  
   117  	// determine which point among the 4 intersection points falls
   118  	// at each side of the line equations to determine inner and
   119  	// outer vertices
   120  	ac, bc := -(self.a*self.fx + self.b*self.fy), -(other.a*self.fx + other.b*self.fy)
   121  	boa := (self.b*other.fy > -self.a*other.fx-ac)
   122  	bob := (other.b*self.oy > -other.a*self.ox-bc)
   123  	var inX, inY, outX, outY float64
   124  	var auxX, auxY float64
   125  	for _, pt := range []struct{ x, y float64 }{{x11, y11}, {x12, y12}, {x21, y21}, {x22, y22}} {
   126  		jaCmp := (self.b*pt.y > -self.a*pt.x-ac)
   127  		jbCmp := (other.b*pt.y > -other.a*pt.x-bc)
   128  		if (boa == jaCmp) == (bob == jbCmp) {
   129  			if boa == jaCmp {
   130  				inX, inY = pt.x, pt.y
   131  			} else {
   132  				outX, outY = pt.x, pt.y
   133  			}
   134  		} else if boa != jaCmp {
   135  			auxX, auxY = pt.x, pt.y
   136  		}
   137  	}
   138  	return outX, outY, inX, inY, auxX, auxY
   139  }