...

Source file src/github.com/golang/freetype/raster/geom.go

Documentation: github.com/golang/freetype/raster

     1  // Copyright 2010 The Freetype-Go Authors. All rights reserved.
     2  // Use of this source code is governed by your choice of either the
     3  // FreeType License or the GNU General Public License version 2 (or
     4  // any later version), both of which can be found in the LICENSE file.
     5  
     6  package raster
     7  
     8  import (
     9  	"fmt"
    10  	"math"
    11  
    12  	"golang.org/x/image/math/fixed"
    13  )
    14  
    15  // maxAbs returns the maximum of abs(a) and abs(b).
    16  func maxAbs(a, b fixed.Int26_6) fixed.Int26_6 {
    17  	if a < 0 {
    18  		a = -a
    19  	}
    20  	if b < 0 {
    21  		b = -b
    22  	}
    23  	if a < b {
    24  		return b
    25  	}
    26  	return a
    27  }
    28  
    29  // pNeg returns the vector -p, or equivalently p rotated by 180 degrees.
    30  func pNeg(p fixed.Point26_6) fixed.Point26_6 {
    31  	return fixed.Point26_6{-p.X, -p.Y}
    32  }
    33  
    34  // pDot returns the dot product p·q.
    35  func pDot(p fixed.Point26_6, q fixed.Point26_6) fixed.Int52_12 {
    36  	px, py := int64(p.X), int64(p.Y)
    37  	qx, qy := int64(q.X), int64(q.Y)
    38  	return fixed.Int52_12(px*qx + py*qy)
    39  }
    40  
    41  // pLen returns the length of the vector p.
    42  func pLen(p fixed.Point26_6) fixed.Int26_6 {
    43  	// TODO(nigeltao): use fixed point math.
    44  	x := float64(p.X)
    45  	y := float64(p.Y)
    46  	return fixed.Int26_6(math.Sqrt(x*x + y*y))
    47  }
    48  
    49  // pNorm returns the vector p normalized to the given length, or zero if p is
    50  // degenerate.
    51  func pNorm(p fixed.Point26_6, length fixed.Int26_6) fixed.Point26_6 {
    52  	d := pLen(p)
    53  	if d == 0 {
    54  		return fixed.Point26_6{}
    55  	}
    56  	s, t := int64(length), int64(d)
    57  	x := int64(p.X) * s / t
    58  	y := int64(p.Y) * s / t
    59  	return fixed.Point26_6{fixed.Int26_6(x), fixed.Int26_6(y)}
    60  }
    61  
    62  // pRot45CW returns the vector p rotated clockwise by 45 degrees.
    63  //
    64  // Note that the Y-axis grows downwards, so {1, 0}.Rot45CW is {1/√2, 1/√2}.
    65  func pRot45CW(p fixed.Point26_6) fixed.Point26_6 {
    66  	// 181/256 is approximately 1/√2, or sin(π/4).
    67  	px, py := int64(p.X), int64(p.Y)
    68  	qx := (+px - py) * 181 / 256
    69  	qy := (+px + py) * 181 / 256
    70  	return fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)}
    71  }
    72  
    73  // pRot90CW returns the vector p rotated clockwise by 90 degrees.
    74  //
    75  // Note that the Y-axis grows downwards, so {1, 0}.Rot90CW is {0, 1}.
    76  func pRot90CW(p fixed.Point26_6) fixed.Point26_6 {
    77  	return fixed.Point26_6{-p.Y, p.X}
    78  }
    79  
    80  // pRot135CW returns the vector p rotated clockwise by 135 degrees.
    81  //
    82  // Note that the Y-axis grows downwards, so {1, 0}.Rot135CW is {-1/√2, 1/√2}.
    83  func pRot135CW(p fixed.Point26_6) fixed.Point26_6 {
    84  	// 181/256 is approximately 1/√2, or sin(π/4).
    85  	px, py := int64(p.X), int64(p.Y)
    86  	qx := (-px - py) * 181 / 256
    87  	qy := (+px - py) * 181 / 256
    88  	return fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)}
    89  }
    90  
    91  // pRot45CCW returns the vector p rotated counter-clockwise by 45 degrees.
    92  //
    93  // Note that the Y-axis grows downwards, so {1, 0}.Rot45CCW is {1/√2, -1/√2}.
    94  func pRot45CCW(p fixed.Point26_6) fixed.Point26_6 {
    95  	// 181/256 is approximately 1/√2, or sin(π/4).
    96  	px, py := int64(p.X), int64(p.Y)
    97  	qx := (+px + py) * 181 / 256
    98  	qy := (-px + py) * 181 / 256
    99  	return fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)}
   100  }
   101  
   102  // pRot90CCW returns the vector p rotated counter-clockwise by 90 degrees.
   103  //
   104  // Note that the Y-axis grows downwards, so {1, 0}.Rot90CCW is {0, -1}.
   105  func pRot90CCW(p fixed.Point26_6) fixed.Point26_6 {
   106  	return fixed.Point26_6{p.Y, -p.X}
   107  }
   108  
   109  // pRot135CCW returns the vector p rotated counter-clockwise by 135 degrees.
   110  //
   111  // Note that the Y-axis grows downwards, so {1, 0}.Rot135CCW is {-1/√2, -1/√2}.
   112  func pRot135CCW(p fixed.Point26_6) fixed.Point26_6 {
   113  	// 181/256 is approximately 1/√2, or sin(π/4).
   114  	px, py := int64(p.X), int64(p.Y)
   115  	qx := (-px + py) * 181 / 256
   116  	qy := (-px - py) * 181 / 256
   117  	return fixed.Point26_6{fixed.Int26_6(qx), fixed.Int26_6(qy)}
   118  }
   119  
   120  // An Adder accumulates points on a curve.
   121  type Adder interface {
   122  	// Start starts a new curve at the given point.
   123  	Start(a fixed.Point26_6)
   124  	// Add1 adds a linear segment to the current curve.
   125  	Add1(b fixed.Point26_6)
   126  	// Add2 adds a quadratic segment to the current curve.
   127  	Add2(b, c fixed.Point26_6)
   128  	// Add3 adds a cubic segment to the current curve.
   129  	Add3(b, c, d fixed.Point26_6)
   130  }
   131  
   132  // A Path is a sequence of curves, and a curve is a start point followed by a
   133  // sequence of linear, quadratic or cubic segments.
   134  type Path []fixed.Int26_6
   135  
   136  // String returns a human-readable representation of a Path.
   137  func (p Path) String() string {
   138  	s := ""
   139  	for i := 0; i < len(p); {
   140  		if i != 0 {
   141  			s += " "
   142  		}
   143  		switch p[i] {
   144  		case 0:
   145  			s += "S0" + fmt.Sprint([]fixed.Int26_6(p[i+1:i+3]))
   146  			i += 4
   147  		case 1:
   148  			s += "A1" + fmt.Sprint([]fixed.Int26_6(p[i+1:i+3]))
   149  			i += 4
   150  		case 2:
   151  			s += "A2" + fmt.Sprint([]fixed.Int26_6(p[i+1:i+5]))
   152  			i += 6
   153  		case 3:
   154  			s += "A3" + fmt.Sprint([]fixed.Int26_6(p[i+1:i+7]))
   155  			i += 8
   156  		default:
   157  			panic("freetype/raster: bad path")
   158  		}
   159  	}
   160  	return s
   161  }
   162  
   163  // Clear cancels any previous calls to p.Start or p.AddXxx.
   164  func (p *Path) Clear() {
   165  	*p = (*p)[:0]
   166  }
   167  
   168  // Start starts a new curve at the given point.
   169  func (p *Path) Start(a fixed.Point26_6) {
   170  	*p = append(*p, 0, a.X, a.Y, 0)
   171  }
   172  
   173  // Add1 adds a linear segment to the current curve.
   174  func (p *Path) Add1(b fixed.Point26_6) {
   175  	*p = append(*p, 1, b.X, b.Y, 1)
   176  }
   177  
   178  // Add2 adds a quadratic segment to the current curve.
   179  func (p *Path) Add2(b, c fixed.Point26_6) {
   180  	*p = append(*p, 2, b.X, b.Y, c.X, c.Y, 2)
   181  }
   182  
   183  // Add3 adds a cubic segment to the current curve.
   184  func (p *Path) Add3(b, c, d fixed.Point26_6) {
   185  	*p = append(*p, 3, b.X, b.Y, c.X, c.Y, d.X, d.Y, 3)
   186  }
   187  
   188  // AddPath adds the Path q to p.
   189  func (p *Path) AddPath(q Path) {
   190  	*p = append(*p, q...)
   191  }
   192  
   193  // AddStroke adds a stroked Path.
   194  func (p *Path) AddStroke(q Path, width fixed.Int26_6, cr Capper, jr Joiner) {
   195  	Stroke(p, q, width, cr, jr)
   196  }
   197  
   198  // firstPoint returns the first point in a non-empty Path.
   199  func (p Path) firstPoint() fixed.Point26_6 {
   200  	return fixed.Point26_6{p[1], p[2]}
   201  }
   202  
   203  // lastPoint returns the last point in a non-empty Path.
   204  func (p Path) lastPoint() fixed.Point26_6 {
   205  	return fixed.Point26_6{p[len(p)-3], p[len(p)-2]}
   206  }
   207  
   208  // addPathReversed adds q reversed to p.
   209  // For example, if q consists of a linear segment from A to B followed by a
   210  // quadratic segment from B to C to D, then the values of q looks like:
   211  // index: 01234567890123
   212  // value: 0AA01BB12CCDD2
   213  // So, when adding q backwards to p, we want to Add2(C, B) followed by Add1(A).
   214  func addPathReversed(p Adder, q Path) {
   215  	if len(q) == 0 {
   216  		return
   217  	}
   218  	i := len(q) - 1
   219  	for {
   220  		switch q[i] {
   221  		case 0:
   222  			return
   223  		case 1:
   224  			i -= 4
   225  			p.Add1(
   226  				fixed.Point26_6{q[i-2], q[i-1]},
   227  			)
   228  		case 2:
   229  			i -= 6
   230  			p.Add2(
   231  				fixed.Point26_6{q[i+2], q[i+3]},
   232  				fixed.Point26_6{q[i-2], q[i-1]},
   233  			)
   234  		case 3:
   235  			i -= 8
   236  			p.Add3(
   237  				fixed.Point26_6{q[i+4], q[i+5]},
   238  				fixed.Point26_6{q[i+2], q[i+3]},
   239  				fixed.Point26_6{q[i-2], q[i-1]},
   240  			)
   241  		default:
   242  			panic("freetype/raster: bad path")
   243  		}
   244  	}
   245  }
   246  

View as plain text