diff --git a/path.go b/path.go index 4ff3087..e0f09ec 100644 --- a/path.go +++ b/path.go @@ -62,12 +62,12 @@ func (fillRule FillRule) String() string { // TODO: make CloseCmd a LineTo + CloseCmd, where CloseCmd is only a command value, no coordinates // TODO: optimize command memory layout in paths: we need three bits to represent each command, thus 6 to specify command going forward and going backward. The remaining 58 bits, or 28 per direction, should specify the index into Path.d of the end of the sequence of coordinates. MoveTo should have an index to the end of the subpath. Use math.Float64bits. For long flat paths this will reduce memory usage in half since besides all coordinates, the only overhead is: 64 bits first MoveTo, 64 bits end of MoveTo and start of LineTo, 64 bits end of LineTo and start of Close, 64 bits end of Close. const ( - MoveToCmd = 1.0 << iota // 1.0 - LineToCmd // 2.0 - QuadToCmd // 4.0 - CubeToCmd // 8.0 - ArcToCmd // 16.0 - CloseCmd // 32.0 + MoveToCmd = 1.0 + LineToCmd = 2.0 + QuadToCmd = 4.0 + CubeToCmd = 8.0 + ArcToCmd = 16.0 + CloseCmd = 32.0 ) var cmdLens = [6]int{4, 4, 6, 8, 8, 4} diff --git a/util.go b/util.go index ff02240..822baeb 100644 --- a/util.go +++ b/util.go @@ -424,6 +424,19 @@ func (r Rect) Translate(x, y float64) Rect { return r } +// Transform transforms the rectangle by affine transformation matrix m and returns the new bounds of that rectangle. +func (r Rect) Transform(m Matrix) Rect { + p0 := m.Dot(Point{r.X0, r.Y0}) + p1 := m.Dot(Point{r.X1, r.Y0}) + p2 := m.Dot(Point{r.X1, r.Y1}) + p3 := m.Dot(Point{r.X0, r.Y1}) + x0 := math.Min(p0.X, math.Min(p1.X, math.Min(p2.X, p3.X))) + y0 := math.Min(p0.Y, math.Min(p1.Y, math.Min(p2.Y, p3.Y))) + x1 := math.Max(p0.X, math.Max(p1.X, math.Max(p2.X, p3.X))) + y1 := math.Max(p0.Y, math.Max(p1.Y, math.Max(p2.Y, p3.Y))) + return Rect{x0, y0, x1, y1} +} + // Add returns a rect that encompasses both the current rect and the given rect. func (r Rect) Add(q Rect) Rect { x0 := math.Min(r.X0, q.X0) @@ -451,19 +464,6 @@ func (r Rect) Expand(d float64) Rect { return r } -// Transform transforms the rectangle by affine transformation matrix m and returns the new bounds of that rectangle. -func (r Rect) Transform(m Matrix) Rect { - p0 := m.Dot(Point{r.X0, r.Y0}) - p1 := m.Dot(Point{r.X1, r.Y0}) - p2 := m.Dot(Point{r.X1, r.Y1}) - p3 := m.Dot(Point{r.X0, r.Y1}) - x0 := math.Min(p0.X, math.Min(p1.X, math.Min(p2.X, p3.X))) - y0 := math.Min(p0.Y, math.Min(p1.Y, math.Min(p2.Y, p3.Y))) - x1 := math.Max(p0.X, math.Max(p1.X, math.Max(p2.X, p3.X))) - y1 := math.Max(p0.Y, math.Max(p1.Y, math.Max(p2.Y, p3.Y))) - return Rect{x0, y0, x1, y1} -} - // ContainsPoint returns true if the rectangles contains a point, not if it touches an edge. func (r Rect) ContainsPoint(p Point) bool { if p.X < r.X0 || r.X1 < p.X {