use vertex converter as antigrain project
add a Stroke2 and Fill2 method to GraphicContext (comparison purpose: different algorithm)
This commit is contained in:
parent
184115e3e1
commit
0bff8ca6ee
13 changed files with 566 additions and 207 deletions
|
@ -1,6 +1,6 @@
|
|||
package draw2d
|
||||
|
||||
import(
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
|
@ -15,25 +15,25 @@ func Rect(path Path, x1, y1, x2, y2 float) {
|
|||
}
|
||||
|
||||
func RoundRect(path Path, x1, y1, x2, y2, arcWidth, arcHeight float) {
|
||||
arcWidth = arcWidth/2;
|
||||
arcHeight = arcHeight/2;
|
||||
path.MoveTo(x1, y1+ arcHeight);
|
||||
path.QuadCurveTo(x1, y1, x1 + arcWidth, y1);
|
||||
path.LineTo(x2-arcWidth, y1);
|
||||
path.QuadCurveTo(x2, y1, x2, y1 + arcHeight);
|
||||
path.LineTo(x2, y2-arcHeight);
|
||||
path.QuadCurveTo(x2, y2, x2 - arcWidth, y2);
|
||||
path.LineTo(x1 + arcWidth, y2);
|
||||
path.QuadCurveTo(x1, y2, x1, y2 - arcHeight);
|
||||
arcWidth = arcWidth / 2
|
||||
arcHeight = arcHeight / 2
|
||||
path.MoveTo(x1, y1+arcHeight)
|
||||
path.QuadCurveTo(x1, y1, x1+arcWidth, y1)
|
||||
path.LineTo(x2-arcWidth, y1)
|
||||
path.QuadCurveTo(x2, y1, x2, y1+arcHeight)
|
||||
path.LineTo(x2, y2-arcHeight)
|
||||
path.QuadCurveTo(x2, y2, x2-arcWidth, y2)
|
||||
path.LineTo(x1+arcWidth, y2)
|
||||
path.QuadCurveTo(x1, y2, x1, y2-arcHeight)
|
||||
path.Close()
|
||||
}
|
||||
|
||||
func Ellipse(path Path, cx, cy, rx, ry float) {
|
||||
path.ArcTo(cx, cy, rx, ry, 0, -math.Pi * 2)
|
||||
path.ArcTo(cx, cy, rx, ry, 0, -math.Pi*2)
|
||||
path.Close()
|
||||
}
|
||||
|
||||
func Circle(path Path, cx, cy, radius float) {
|
||||
path.ArcTo(cx, cy, radius, radius, 0, -math.Pi * 2)
|
||||
path.ArcTo(cx, cy, radius, radius, 0, -math.Pi*2)
|
||||
path.Close()
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 21/11/2010 by Laurent Le Goff
|
||||
|
||||
package draw2d
|
||||
|
||||
|
||||
func arc(t LineTracer, x, y, rx, ry, start, angle, scale float) {
|
||||
func arc(t VertexConverter, x, y, rx, ry, start, angle, scale float) (lastX, lastY float) {
|
||||
end := start + angle
|
||||
clockWise := true
|
||||
if angle < 0 {
|
||||
|
@ -22,13 +20,13 @@ func arc(t LineTracer, x, y, rx, ry, start, angle, scale float) {
|
|||
if (angle < end-da/4) != clockWise {
|
||||
curX = x + cos(end)*rx
|
||||
curY = y + sin(end)*ry
|
||||
t.LineTo(curX, curY)
|
||||
break
|
||||
return curX, curY
|
||||
}
|
||||
curX = x + cos(angle)*rx
|
||||
curY = y + sin(angle)*ry
|
||||
|
||||
angle += da
|
||||
t.LineTo(curX, curY)
|
||||
t.Vertex(curX, curY)
|
||||
}
|
||||
return curX, curY
|
||||
}
|
||||
|
|
|
@ -33,25 +33,22 @@ var (
|
|||
The more this value is the less sharp turns will be cut.
|
||||
Typically it should not exceed 10-15 degrees.
|
||||
*/
|
||||
|
||||
func cubicBezier(v LineTracer, x1, y1, x2, y2, x3, y3, x4, y4, approximationScale, angleTolerance, cuspLimit float) {
|
||||
func cubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4, approximationScale, angleTolerance, cuspLimit float) {
|
||||
cuspLimit = computeCuspLimit(cuspLimit)
|
||||
distanceToleranceSquare := 0.5 / approximationScale
|
||||
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
||||
recursiveCubicBezier(v, x1, y1, x2, y2, x3, y3, x4, y4, 0, distanceToleranceSquare, angleTolerance, cuspLimit)
|
||||
v.LineTo(x4, y4)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* see cubicBezier comments for approximationScale and angleTolerance definition
|
||||
*/
|
||||
func quadraticBezier(v LineTracer, x1, y1, x2, y2, x3, y3, approximationScale, angleTolerance float) {
|
||||
func quadraticBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, approximationScale, angleTolerance float) {
|
||||
distanceToleranceSquare := 0.5 / approximationScale
|
||||
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
||||
|
||||
recursiveQuadraticBezierBezier(v, x1, y1, x2, y2, x3, y3, 0, distanceToleranceSquare, angleTolerance)
|
||||
v.LineTo(x3, y3)
|
||||
}
|
||||
|
||||
|
||||
|
@ -68,7 +65,7 @@ func computeCuspLimit(v float) (r float) {
|
|||
/**
|
||||
* http://www.antigrain.com/research/adaptive_bezier/index.html
|
||||
*/
|
||||
func recursiveQuadraticBezierBezier(v LineTracer, x1, y1, x2, y2, x3, y3 float, level int, distanceToleranceSquare, angleTolerance float) {
|
||||
func recursiveQuadraticBezierBezier(v VertexConverter, x1, y1, x2, y2, x3, y3 float, level int, distanceToleranceSquare, angleTolerance float) {
|
||||
if level > CurveRecursionLimit {
|
||||
return
|
||||
}
|
||||
|
@ -94,7 +91,7 @@ func recursiveQuadraticBezierBezier(v LineTracer, x1, y1, x2, y2, x3, y3 float,
|
|||
// we tend to finish subdivisions.
|
||||
//----------------------
|
||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
||||
v.LineTo(x123, y123)
|
||||
v.Vertex(x123, y123)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -108,7 +105,7 @@ func recursiveQuadraticBezierBezier(v LineTracer, x1, y1, x2, y2, x3, y3 float,
|
|||
if da < angleTolerance {
|
||||
// Finally we can stop the recursion
|
||||
//----------------------
|
||||
v.LineTo(x123, y123)
|
||||
v.Vertex(x123, y123)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -134,7 +131,7 @@ func recursiveQuadraticBezierBezier(v LineTracer, x1, y1, x2, y2, x3, y3 float,
|
|||
}
|
||||
}
|
||||
if d < distanceToleranceSquare {
|
||||
v.LineTo(x2, y2)
|
||||
v.Vertex(x2, y2)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +145,7 @@ func recursiveQuadraticBezierBezier(v LineTracer, x1, y1, x2, y2, x3, y3 float,
|
|||
/**
|
||||
* http://www.antigrain.com/research/adaptive_bezier/index.html
|
||||
*/
|
||||
func recursiveCubicBezier(v LineTracer, x1, y1, x2, y2, x3, y3, x4, y4 float, level int, distanceToleranceSquare, angleTolerance, cuspLimit float) {
|
||||
func recursiveCubicBezier(v VertexConverter, x1, y1, x2, y2, x3, y3, x4, y4 float, level int, distanceToleranceSquare, angleTolerance, cuspLimit float) {
|
||||
if level > CurveRecursionLimit {
|
||||
return
|
||||
}
|
||||
|
@ -215,12 +212,12 @@ func recursiveCubicBezier(v LineTracer, x1, y1, x2, y2, x3, y3, x4, y4 float, le
|
|||
}
|
||||
if d2 > d3 {
|
||||
if d2 < distanceToleranceSquare {
|
||||
v.LineTo(x2, y2)
|
||||
v.Vertex(x2, y2)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if d3 < distanceToleranceSquare {
|
||||
v.LineTo(x3, y3)
|
||||
v.Vertex(x3, y3)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +228,7 @@ func recursiveCubicBezier(v LineTracer, x1, y1, x2, y2, x3, y3, x4, y4 float, le
|
|||
//----------------------
|
||||
if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) {
|
||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
||||
v.LineTo(x23, y23)
|
||||
v.Vertex(x23, y23)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -243,14 +240,14 @@ func recursiveCubicBezier(v LineTracer, x1, y1, x2, y2, x3, y3, x4, y4 float, le
|
|||
}
|
||||
|
||||
if da1 < angleTolerance {
|
||||
v.LineTo(x2, y2)
|
||||
v.LineTo(x3, y3)
|
||||
v.Vertex(x2, y2)
|
||||
v.Vertex(x3, y3)
|
||||
return
|
||||
}
|
||||
|
||||
if cuspLimit != 0.0 {
|
||||
if da1 > cuspLimit {
|
||||
v.LineTo(x3, y3)
|
||||
v.Vertex(x3, y3)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -262,7 +259,7 @@ func recursiveCubicBezier(v LineTracer, x1, y1, x2, y2, x3, y3, x4, y4 float, le
|
|||
//----------------------
|
||||
if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) {
|
||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
||||
v.LineTo(x23, y23)
|
||||
v.Vertex(x23, y23)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -274,14 +271,14 @@ func recursiveCubicBezier(v LineTracer, x1, y1, x2, y2, x3, y3, x4, y4 float, le
|
|||
}
|
||||
|
||||
if da1 < angleTolerance {
|
||||
v.LineTo(x2, y2)
|
||||
v.LineTo(x3, y3)
|
||||
v.Vertex(x2, y2)
|
||||
v.Vertex(x3, y3)
|
||||
return
|
||||
}
|
||||
|
||||
if cuspLimit != 0.0 {
|
||||
if da1 > cuspLimit {
|
||||
v.LineTo(x2, y2)
|
||||
v.Vertex(x2, y2)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -296,7 +293,7 @@ func recursiveCubicBezier(v LineTracer, x1, y1, x2, y2, x3, y3, x4, y4 float, le
|
|||
// we tend to finish subdivisions.
|
||||
//----------------------
|
||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
||||
v.LineTo(x23, y23)
|
||||
v.Vertex(x23, y23)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -315,18 +312,18 @@ func recursiveCubicBezier(v LineTracer, x1, y1, x2, y2, x3, y3, x4, y4 float, le
|
|||
if da1+da2 < angleTolerance {
|
||||
// Finally we can stop the recursion
|
||||
//----------------------
|
||||
v.LineTo(x23, y23)
|
||||
v.Vertex(x23, y23)
|
||||
return
|
||||
}
|
||||
|
||||
if cuspLimit != 0.0 {
|
||||
if da1 > cuspLimit {
|
||||
v.LineTo(x2, y2)
|
||||
v.Vertex(x2, y2)
|
||||
return
|
||||
}
|
||||
|
||||
if da2 > cuspLimit {
|
||||
v.LineTo(x3, y3)
|
||||
v.Vertex(x3, y3)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +1,49 @@
|
|||
package draw2d
|
||||
|
||||
import(
|
||||
"freetype-go.googlecode.com/hg/freetype/raster"
|
||||
)
|
||||
|
||||
type DashAdder struct {
|
||||
adder raster.Adder
|
||||
type DashVertexConverter struct {
|
||||
command VertexCommand
|
||||
next VertexConverter
|
||||
x, y, distance float
|
||||
dash []float
|
||||
currentDash int
|
||||
dashOffset float
|
||||
}
|
||||
|
||||
func traceDashPath(dash []float, dashOffset float, approximationScale float, adder raster.Adder, paths ...*PathStorage) {
|
||||
var dasher DashAdder
|
||||
if dash != nil && len(dash) > 0 {
|
||||
func NewDashConverter(dash []float, dashOffset float, converter VertexConverter) *DashVertexConverter {
|
||||
var dasher DashVertexConverter
|
||||
dasher.dash = dash
|
||||
} else {
|
||||
dasher.dash = nil
|
||||
}
|
||||
dasher.currentDash = 0
|
||||
dasher.dashOffset = dashOffset
|
||||
dasher.adder = adder
|
||||
for _, path := range paths {
|
||||
path.TraceLine(&dasher, approximationScale)
|
||||
dasher.next = converter
|
||||
return &dasher
|
||||
}
|
||||
|
||||
func (dasher *DashVertexConverter) NextCommand(cmd VertexCommand) {
|
||||
dasher.command = cmd
|
||||
if(dasher.command == VertexStopCommand) {
|
||||
dasher.next.NextCommand(VertexStopCommand)
|
||||
}
|
||||
}
|
||||
|
||||
func (dasher *DashAdder) MoveTo(x, y float) {
|
||||
dasher.adder.Start(floatToPoint(x, y))
|
||||
func (dasher *DashVertexConverter) Vertex(x, y float) {
|
||||
switch dasher.command {
|
||||
case VertexStartCommand:
|
||||
dasher.start(x, y)
|
||||
default:
|
||||
dasher.lineTo(x, y)
|
||||
}
|
||||
dasher.command = VertexNoCommand
|
||||
}
|
||||
|
||||
func (dasher *DashVertexConverter) start(x, y float) {
|
||||
dasher.next.NextCommand(VertexStartCommand)
|
||||
dasher.next.Vertex(x, y)
|
||||
dasher.x, dasher.y = x, y
|
||||
dasher.distance = dasher.dashOffset
|
||||
dasher.currentDash = 0
|
||||
}
|
||||
|
||||
func (dasher *DashAdder) LineTo(x, y float) {
|
||||
func (dasher *DashVertexConverter) lineTo(x, y float) {
|
||||
rest := dasher.dash[dasher.currentDash] - dasher.distance
|
||||
for rest < 0 {
|
||||
dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
|
||||
|
@ -48,10 +57,12 @@ func (dasher *DashAdder) LineTo(x, y float) {
|
|||
ly := dasher.y + k*(y-dasher.y)
|
||||
if dasher.currentDash%2 == 0 {
|
||||
// line
|
||||
dasher.adder.Add1(floatToPoint(lx, ly))
|
||||
dasher.next.Vertex(lx, ly)
|
||||
} else {
|
||||
// gap
|
||||
dasher.adder.Start(floatToPoint(lx, ly))
|
||||
dasher.next.NextCommand(VertexStopCommand)
|
||||
dasher.next.NextCommand(VertexStartCommand)
|
||||
dasher.next.Vertex(lx, ly)
|
||||
}
|
||||
d = d - rest
|
||||
dasher.x, dasher.y = lx, ly
|
||||
|
@ -60,9 +71,13 @@ func (dasher *DashAdder) LineTo(x, y float) {
|
|||
}
|
||||
dasher.distance = d
|
||||
if dasher.currentDash%2 == 0 {
|
||||
dasher.adder.Add1(floatToPoint(x, y))
|
||||
// line
|
||||
dasher.next.Vertex(x, y)
|
||||
} else {
|
||||
dasher.adder.Start(floatToPoint(x, y))
|
||||
// gap
|
||||
dasher.next.NextCommand(VertexStopCommand)
|
||||
dasher.next.NextCommand(VertexStartCommand)
|
||||
dasher.next.Vertex(x, y)
|
||||
}
|
||||
if dasher.distance >= dasher.dash[dasher.currentDash] {
|
||||
dasher.distance = dasher.distance - dasher.dash[dasher.currentDash]
|
||||
|
|
20
draw2d/src/pkg/draw2d/demux_converter.go
Normal file
20
draw2d/src/pkg/draw2d/demux_converter.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package draw2d
|
||||
|
||||
type DemuxConverter struct {
|
||||
converters []VertexConverter
|
||||
}
|
||||
|
||||
func NewDemuxConverter(converters ...VertexConverter) *DemuxConverter {
|
||||
return &DemuxConverter{converters}
|
||||
}
|
||||
|
||||
func (dc *DemuxConverter) NextCommand(cmd VertexCommand) {
|
||||
for _, converter := range dc.converters {
|
||||
converter.NextCommand(cmd)
|
||||
}
|
||||
}
|
||||
func (dc *DemuxConverter) Vertex(x, y float) {
|
||||
for _, converter := range dc.converters {
|
||||
converter.Vertex(x, y)
|
||||
}
|
||||
}
|
|
@ -16,25 +16,10 @@ const (
|
|||
FillRuleWinding
|
||||
)
|
||||
|
||||
type Cap int
|
||||
|
||||
const (
|
||||
RoundCap Cap = iota
|
||||
ButtCap
|
||||
SquareCap
|
||||
)
|
||||
|
||||
type Join int
|
||||
|
||||
const (
|
||||
BevelJoin Join = iota
|
||||
RoundJoin
|
||||
MiterJoin
|
||||
)
|
||||
|
||||
type GraphicContext struct {
|
||||
PaintedImage *image.RGBA
|
||||
rasterizer *raster.Rasterizer
|
||||
fillRasterizer *raster.Rasterizer
|
||||
strokeRasterizer *raster.Rasterizer
|
||||
current *contextStack
|
||||
}
|
||||
|
||||
|
@ -59,7 +44,8 @@ func NewGraphicContext(pi *image.RGBA) *GraphicContext {
|
|||
gc := new(GraphicContext)
|
||||
gc.PaintedImage = pi
|
||||
width, height := gc.PaintedImage.Bounds().Dx(), gc.PaintedImage.Bounds().Dy()
|
||||
gc.rasterizer = raster.NewRasterizer(width, height)
|
||||
gc.fillRasterizer = raster.NewRasterizer(width, height)
|
||||
gc.strokeRasterizer = raster.NewRasterizer(width, height)
|
||||
|
||||
gc.current = new(contextStack)
|
||||
|
||||
|
@ -205,55 +191,124 @@ func (gc *GraphicContext) Close() {
|
|||
gc.current.path.Close()
|
||||
}
|
||||
|
||||
func (gc *GraphicContext) paint(color image.Color) {
|
||||
func (gc *GraphicContext) paint(rasterizer *raster.Rasterizer, color image.Color) {
|
||||
painter := raster.NewRGBAPainter(gc.PaintedImage)
|
||||
painter.SetColor(color)
|
||||
gc.rasterizer.Rasterize(painter)
|
||||
gc.rasterizer.Clear()
|
||||
rasterizer.Rasterize(painter)
|
||||
rasterizer.Clear()
|
||||
gc.current.path = new(PathStorage)
|
||||
}
|
||||
|
||||
/**** first method ****/
|
||||
func (gc *GraphicContext) Stroke(paths ...*PathStorage) {
|
||||
paths = append(paths, gc.current.path)
|
||||
gc.rasterizer.UseNonZeroWinding = true
|
||||
gc.strokeRasterizer.UseNonZeroWinding = true
|
||||
|
||||
rasterPath := new(raster.Path)
|
||||
if(gc.current.dash == nil) {
|
||||
tracePath(gc.current.tr.GetMaxAbsScaling(), rasterPath, paths...)
|
||||
|
||||
var pathConverter *PathConverter
|
||||
if gc.current.dash != nil && len(gc.current.dash) > 0 {
|
||||
dasher := NewDashConverter(gc.current.dash, gc.current.dashOffset, NewVertexAdder(rasterPath))
|
||||
pathConverter = NewPathConverter(dasher)
|
||||
} else {
|
||||
traceDashPath(gc.current.dash, gc.current.dashOffset, gc.current.tr.GetMaxAbsScaling(), rasterPath, paths...)
|
||||
pathConverter = NewPathConverter(NewVertexAdder(rasterPath))
|
||||
}
|
||||
mta := NewMatrixTransformAdder(gc.current.tr, gc.rasterizer)
|
||||
|
||||
pathConverter.ApproximationScale = gc.current.tr.GetMaxAbsScaling()
|
||||
pathConverter.Convert(paths...)
|
||||
|
||||
mta := NewMatrixTransformAdder(gc.current.tr, gc.strokeRasterizer)
|
||||
raster.Stroke(mta, *rasterPath, raster.Fix32(gc.current.lineWidth*256), gc.current.cap.capper(), gc.current.join.joiner())
|
||||
gc.paint(gc.current.strokeColor)
|
||||
|
||||
gc.paint(gc.strokeRasterizer, gc.current.strokeColor)
|
||||
}
|
||||
|
||||
/**** second method ****/
|
||||
func (gc *GraphicContext) Stroke2(paths ...*PathStorage) {
|
||||
paths = append(paths, gc.current.path)
|
||||
gc.strokeRasterizer.UseNonZeroWinding = true
|
||||
|
||||
stroker := NewLineStroker(NewVertexMatrixTransform(gc.current.tr, NewVertexAdder(gc.strokeRasterizer)))
|
||||
stroker.HalfLineWidth = gc.current.lineWidth / 2
|
||||
var pathConverter *PathConverter
|
||||
if gc.current.dash != nil && len(gc.current.dash) > 0 {
|
||||
dasher := NewDashConverter(gc.current.dash, gc.current.dashOffset, stroker)
|
||||
pathConverter = NewPathConverter(dasher)
|
||||
} else {
|
||||
pathConverter = NewPathConverter(stroker)
|
||||
}
|
||||
pathConverter.ApproximationScale = gc.current.tr.GetMaxAbsScaling()
|
||||
pathConverter.Convert(paths...)
|
||||
|
||||
gc.paint(gc.strokeRasterizer, gc.current.strokeColor)
|
||||
}
|
||||
|
||||
/**** first method ****/
|
||||
func (gc *GraphicContext) Fill(paths ...*PathStorage) {
|
||||
paths = append(paths, gc.current.path)
|
||||
gc.rasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule()
|
||||
mta := NewMatrixTransformAdder(gc.current.tr, gc.rasterizer)
|
||||
tracePath(gc.current.tr.GetMaxAbsScaling(), mta, paths...)
|
||||
gc.paint(gc.current.fillColor)
|
||||
gc.fillRasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule()
|
||||
|
||||
pathConverter := NewPathConverter(NewVertexAdder(NewMatrixTransformAdder(gc.current.tr, gc.fillRasterizer)))
|
||||
pathConverter.ApproximationScale = gc.current.tr.GetMaxAbsScaling()
|
||||
pathConverter.Convert(paths...)
|
||||
gc.paint(gc.fillRasterizer, gc.current.fillColor)
|
||||
}
|
||||
|
||||
/**** second method ****/
|
||||
func (gc *GraphicContext) Fill2(paths ...*PathStorage) {
|
||||
paths = append(paths, gc.current.path)
|
||||
gc.fillRasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule()
|
||||
|
||||
/**** first method ****/
|
||||
pathConverter := NewPathConverter(NewVertexMatrixTransform(gc.current.tr, NewVertexAdder(gc.fillRasterizer)))
|
||||
pathConverter.ApproximationScale = gc.current.tr.GetMaxAbsScaling()
|
||||
pathConverter.Convert(paths...)
|
||||
gc.paint(gc.fillRasterizer, gc.current.fillColor)
|
||||
}
|
||||
|
||||
func (gc *GraphicContext) FillStroke(paths ...*PathStorage) {
|
||||
paths = append(paths, gc.current.path)
|
||||
mta := NewMatrixTransformAdder(gc.current.tr, gc.rasterizer)
|
||||
tracePath(gc.current.tr.GetMaxAbsScaling(), mta, paths...)
|
||||
gc.fillRasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule()
|
||||
gc.strokeRasterizer.UseNonZeroWinding = true
|
||||
|
||||
gc.rasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule()
|
||||
gc.paint(gc.current.fillColor)
|
||||
|
||||
gc.rasterizer.UseNonZeroWinding = true
|
||||
filler := NewVertexMatrixTransform(gc.current.tr, NewVertexAdder(gc.fillRasterizer))
|
||||
rasterPath := new(raster.Path)
|
||||
if(gc.current.dash == nil) {
|
||||
tracePath(gc.current.tr.GetMaxAbsScaling(), rasterPath, paths...)
|
||||
} else {
|
||||
traceDashPath(gc.current.dash, gc.current.dashOffset, gc.current.tr.GetMaxAbsScaling(), rasterPath, paths...)
|
||||
}
|
||||
stroker := NewVertexAdder(rasterPath)
|
||||
|
||||
demux := NewDemuxConverter(filler, stroker)
|
||||
|
||||
pathConverter := NewPathConverter(demux)
|
||||
pathConverter.ApproximationScale = gc.current.tr.GetMaxAbsScaling()
|
||||
pathConverter.Convert(paths...)
|
||||
|
||||
mta := NewMatrixTransformAdder(gc.current.tr, gc.strokeRasterizer)
|
||||
raster.Stroke(mta, *rasterPath, raster.Fix32(gc.current.lineWidth*256), gc.current.cap.capper(), gc.current.join.joiner())
|
||||
gc.paint(gc.current.strokeColor)
|
||||
|
||||
gc.paint(gc.fillRasterizer, gc.current.fillColor)
|
||||
gc.paint(gc.strokeRasterizer, gc.current.strokeColor)
|
||||
}
|
||||
|
||||
/* second method */
|
||||
func (gc *GraphicContext) FillStroke2(paths ...*PathStorage) {
|
||||
gc.fillRasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule()
|
||||
gc.strokeRasterizer.UseNonZeroWinding = true
|
||||
|
||||
filler := NewVertexMatrixTransform(gc.current.tr, NewVertexAdder(gc.fillRasterizer))
|
||||
|
||||
stroker := NewLineStroker(NewVertexMatrixTransform(gc.current.tr, NewVertexAdder(gc.strokeRasterizer)))
|
||||
stroker.HalfLineWidth = gc.current.lineWidth / 2
|
||||
|
||||
demux := NewDemuxConverter(filler, stroker)
|
||||
paths = append(paths, gc.current.path)
|
||||
pathConverter := NewPathConverter(demux)
|
||||
pathConverter.ApproximationScale = gc.current.tr.GetMaxAbsScaling()
|
||||
pathConverter.Convert(paths...)
|
||||
|
||||
gc.paint(gc.fillRasterizer, gc.current.fillColor)
|
||||
gc.paint(gc.strokeRasterizer, gc.current.strokeColor)
|
||||
}
|
||||
|
||||
|
||||
func (f FillRule) fillRule() bool {
|
||||
switch f {
|
||||
case FillRuleEvenOdd:
|
||||
|
@ -285,4 +340,3 @@ func (j Join) joiner() raster.Joiner {
|
|||
}
|
||||
return raster.RoundJoiner
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,10 @@ func distance(x1, y1, x2, y2 float) float {
|
|||
return float(math.Sqrt(float64(dx*dx + dy*dy)))
|
||||
}
|
||||
|
||||
func vectorDistance(dx, dy float) float {
|
||||
return float(math.Sqrt(float64(dx*dx + dy*dy)))
|
||||
}
|
||||
|
||||
func squareDistance(x1, y1, x2, y2 float) float {
|
||||
dx := x2 - x1
|
||||
dy := y2 - y1
|
||||
|
|
|
@ -17,8 +17,18 @@ type Path interface {
|
|||
Close()
|
||||
}
|
||||
|
||||
type LineTracer interface {
|
||||
MoveTo(x, y float)
|
||||
LineTo(x, y float)
|
||||
}
|
||||
|
||||
type VertexCommand byte
|
||||
|
||||
const (
|
||||
VertexNoCommand VertexCommand = iota
|
||||
VertexStartCommand
|
||||
VertexJoinCommand
|
||||
VertexCloseCommand
|
||||
VertexStopCommand
|
||||
)
|
||||
|
||||
type VertexConverter interface {
|
||||
NextCommand(cmd VertexCommand)
|
||||
Vertex(x, y float)
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package draw2d
|
||||
|
||||
|
||||
import(
|
||||
import (
|
||||
"freetype-go.googlecode.com/hg/freetype/raster"
|
||||
)
|
||||
|
||||
|
||||
type PathAdder struct {
|
||||
type VertexAdder struct {
|
||||
command VertexCommand
|
||||
adder raster.Adder
|
||||
}
|
||||
|
||||
|
@ -15,17 +16,21 @@ func floatToPoint(x, y float) raster.Point {
|
|||
return raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)}
|
||||
}
|
||||
|
||||
func tracePath(approximationScale float, adder raster.Adder, paths ...*PathStorage) {
|
||||
pathAdder := &PathAdder{adder}
|
||||
for _, path := range paths {
|
||||
path.TraceLine(pathAdder, approximationScale)
|
||||
|
||||
func NewVertexAdder(adder raster.Adder) *VertexAdder {
|
||||
return &VertexAdder{VertexNoCommand, adder}
|
||||
}
|
||||
|
||||
func (vertexAdder *VertexAdder) NextCommand(cmd VertexCommand) {
|
||||
vertexAdder.command = cmd
|
||||
}
|
||||
|
||||
func (vertexAdder *VertexAdder) Vertex(x, y float) {
|
||||
switch vertexAdder.command {
|
||||
case VertexStartCommand:
|
||||
vertexAdder.adder.Start(floatToPoint(x, y))
|
||||
default:
|
||||
vertexAdder.adder.Add1(floatToPoint(x, y))
|
||||
}
|
||||
}
|
||||
|
||||
func (pathAdder *PathAdder) MoveTo(x, y float) {
|
||||
pathAdder.adder.Start(floatToPoint(x, y))
|
||||
}
|
||||
|
||||
func (pathAdder *PathAdder) LineTo(x, y float) {
|
||||
pathAdder.adder.Add1(floatToPoint(x, y))
|
||||
vertexAdder.command = VertexNoCommand
|
||||
}
|
||||
|
|
153
draw2d/src/pkg/draw2d/path_converter.go
Normal file
153
draw2d/src/pkg/draw2d/path_converter.go
Normal file
|
@ -0,0 +1,153 @@
|
|||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||
// created: 06/12/2010 by Laurent Le Goff
|
||||
package draw2d
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
type PathConverter struct {
|
||||
converter VertexConverter
|
||||
ApproximationScale, AngleTolerance, CuspLimit float
|
||||
startX, startY, x, y float
|
||||
}
|
||||
|
||||
func NewPathConverter(converter VertexConverter) *PathConverter {
|
||||
return &PathConverter{converter, 1, 0, 0, 0, 0, 0, 0}
|
||||
}
|
||||
|
||||
func (c *PathConverter) Convert(paths ...*PathStorage) {
|
||||
for _, path := range paths {
|
||||
j := 0
|
||||
for _, cmd := range path.commands {
|
||||
j = j + c.ConvertCommand(cmd, path.vertices[j:]...)
|
||||
}
|
||||
c.converter.NextCommand(VertexStopCommand)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (c *PathConverter) ConvertCommand(cmd PathCmd, vertices ...float) int {
|
||||
switch cmd {
|
||||
case MoveTo:
|
||||
c.MoveTo(vertices[0], vertices[1])
|
||||
return 2
|
||||
case LineTo:
|
||||
c.LineTo(vertices[0], vertices[1])
|
||||
return 2
|
||||
case QuadCurveTo:
|
||||
c.QuadCurveTo(vertices[0], vertices[1], vertices[2], vertices[3])
|
||||
return 4
|
||||
case CubicCurveTo:
|
||||
c.CubicCurveTo(vertices[0], vertices[1], vertices[2], vertices[3], vertices[4], vertices[5])
|
||||
return 6
|
||||
case ArcTo:
|
||||
c.x, c.y = arc(c.converter, vertices[0], vertices[1], vertices[2], vertices[3], vertices[4], vertices[5], c.ApproximationScale)
|
||||
if c.startX == c.x && c.startY == c.y {
|
||||
c.converter.NextCommand(VertexCloseCommand)
|
||||
}
|
||||
c.converter.Vertex(c.x, c.y)
|
||||
return 6
|
||||
case Close:
|
||||
c.Close()
|
||||
return 0
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (c *PathConverter) MoveTo(x, y float) *PathConverter {
|
||||
c.x, c.y = x, y
|
||||
c.startX, c.startY = c.x, c.y
|
||||
c.converter.NextCommand(VertexStopCommand)
|
||||
c.converter.NextCommand(VertexStartCommand)
|
||||
c.converter.Vertex(c.x, c.y)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *PathConverter) RMoveTo(dx, dy float) *PathConverter {
|
||||
c.MoveTo(c.x+dx, c.y+dy)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *PathConverter) LineTo(x, y float) *PathConverter {
|
||||
c.x, c.y = x, y
|
||||
if c.startX == c.x && c.startY == c.y {
|
||||
c.converter.NextCommand(VertexCloseCommand)
|
||||
}
|
||||
c.converter.Vertex(c.x, c.y)
|
||||
c.converter.NextCommand(VertexJoinCommand)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *PathConverter) RLineTo(dx, dy float) *PathConverter {
|
||||
c.LineTo(c.x+dx, c.y+dy)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *PathConverter) QuadCurveTo(cx, cy, x, y float) *PathConverter {
|
||||
quadraticBezier(c.converter, c.x, c.y, cx, cy, x, y, c.ApproximationScale, c.AngleTolerance)
|
||||
c.x, c.y = x, y
|
||||
if c.startX == c.x && c.startY == c.y {
|
||||
c.converter.NextCommand(VertexCloseCommand)
|
||||
}
|
||||
c.converter.Vertex(c.x, c.y)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *PathConverter) RQuadCurveTo(dcx, dcy, dx, dy float) *PathConverter {
|
||||
c.QuadCurveTo(c.x+dcx, c.y+dcy, c.x+dx, c.y+dy)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *PathConverter) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float) *PathConverter {
|
||||
cubicBezier(c.converter, c.x, c.y, cx1, cy1, cx2, cy2, x, y, c.ApproximationScale, c.AngleTolerance, c.CuspLimit)
|
||||
c.x, c.y = x, y
|
||||
if c.startX == c.x && c.startY == c.y {
|
||||
c.converter.NextCommand(VertexCloseCommand)
|
||||
}
|
||||
c.converter.Vertex(c.x, c.y)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *PathConverter) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float) *PathConverter {
|
||||
c.CubicCurveTo(c.x+dcx1, c.y+dcy1, c.x+dcx2, c.y+dcy2, c.x+dx, c.y+dy)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *PathConverter) ArcTo(cx, cy, rx, ry, startAngle, angle float) *PathConverter {
|
||||
endAngle := startAngle + angle
|
||||
clockWise := true
|
||||
if angle < 0 {
|
||||
clockWise = false
|
||||
}
|
||||
// normalize
|
||||
if clockWise {
|
||||
for endAngle < startAngle {
|
||||
endAngle += math.Pi * 2.0
|
||||
}
|
||||
} else {
|
||||
for startAngle < endAngle {
|
||||
startAngle += math.Pi * 2.0
|
||||
}
|
||||
}
|
||||
startX := cx + cos(startAngle)*rx
|
||||
startY := cy + sin(startAngle)*ry
|
||||
c.MoveTo(startX, startY)
|
||||
c.x, c.y = arc(c.converter, cx, cy, rx, ry, startAngle, angle, c.ApproximationScale)
|
||||
if c.startX == c.x && c.startY == c.y {
|
||||
c.converter.NextCommand(VertexCloseCommand)
|
||||
}
|
||||
c.converter.Vertex(c.x, c.y)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *PathConverter) RArcTo(dcx, dcy, rx, ry, startAngle, angle float) *PathConverter {
|
||||
c.ArcTo(c.x+dcx, c.y+dcy, rx, ry, startAngle, angle)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *PathConverter) Close() *PathConverter {
|
||||
c.converter.NextCommand(VertexCloseCommand)
|
||||
c.converter.Vertex(c.startX, c.startY)
|
||||
return c
|
||||
}
|
|
@ -137,44 +137,6 @@ func (p *PathStorage) RArcTo(dcx, dcy, rx, ry, startAngle, angle float) *PathSto
|
|||
return p
|
||||
}
|
||||
|
||||
func (p *PathStorage) TraceLine(tracer LineTracer, approximationScale float) {
|
||||
j := 0
|
||||
x, y := 0.0, 0.0
|
||||
firstX, firstY := x, y
|
||||
if len(p.commands) > 0 {
|
||||
if p.commands[0] == MoveTo {
|
||||
firstX, firstY = p.vertices[0], p.vertices[1]
|
||||
}
|
||||
}
|
||||
for _, cmd := range p.commands {
|
||||
switch cmd {
|
||||
case MoveTo:
|
||||
tracer.MoveTo(p.vertices[j], p.vertices[j+1])
|
||||
x, y = p.vertices[j], p.vertices[j+1]
|
||||
firstX, firstY = x, y
|
||||
j = j + 2
|
||||
case LineTo:
|
||||
tracer.LineTo(p.vertices[j], p.vertices[j+1])
|
||||
x, y = p.vertices[j], p.vertices[j+1]
|
||||
j = j + 2
|
||||
case QuadCurveTo:
|
||||
quadraticBezier(tracer, x, y, p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], approximationScale, 0)
|
||||
x, y = p.vertices[j+2], p.vertices[j+3]
|
||||
j = j + 4
|
||||
case CubicCurveTo:
|
||||
cubicBezier(tracer, x, y, p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5], approximationScale, 0, 0)
|
||||
x, y = p.vertices[j+4], p.vertices[j+5]
|
||||
j = j + 6
|
||||
case ArcTo:
|
||||
arc(tracer, p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], p.vertices[j+4], p.vertices[j+5], approximationScale)
|
||||
j = j + 6
|
||||
case Close:
|
||||
tracer.LineTo(firstX, firstY)
|
||||
x, y = firstX, firstY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PathStorage) String() string {
|
||||
s := ""
|
||||
j := 0
|
||||
|
|
120
draw2d/src/pkg/draw2d/stroker.go
Normal file
120
draw2d/src/pkg/draw2d/stroker.go
Normal file
|
@ -0,0 +1,120 @@
|
|||
package draw2d
|
||||
|
||||
type Cap int
|
||||
|
||||
const (
|
||||
RoundCap Cap = iota
|
||||
ButtCap
|
||||
SquareCap
|
||||
)
|
||||
|
||||
type Join int
|
||||
|
||||
const (
|
||||
BevelJoin Join = iota
|
||||
RoundJoin
|
||||
MiterJoin
|
||||
)
|
||||
|
||||
|
||||
type LineStroker struct {
|
||||
Next VertexConverter
|
||||
HalfLineWidth float
|
||||
Cap Cap
|
||||
Join Join
|
||||
vertices []float
|
||||
rewind []float
|
||||
x, y, nx, ny float
|
||||
command VertexCommand
|
||||
}
|
||||
|
||||
func NewLineStroker(converter VertexConverter) *LineStroker {
|
||||
l := new(LineStroker)
|
||||
l.Next = converter
|
||||
l.HalfLineWidth = 0.5
|
||||
l.vertices = make([]float, 0)
|
||||
l.rewind = make([]float, 0)
|
||||
l.Cap = ButtCap
|
||||
l.Join = MiterJoin
|
||||
l.command = VertexNoCommand
|
||||
return l
|
||||
}
|
||||
|
||||
|
||||
func (l *LineStroker) NextCommand(command VertexCommand) {
|
||||
l.command = command
|
||||
if command == VertexStopCommand {
|
||||
l.Next.NextCommand(VertexStartCommand)
|
||||
for i, j := 0, 1; j < len(l.vertices); i, j = i+2, j+2 {
|
||||
l.Next.Vertex(l.vertices[i], l.vertices[j])
|
||||
l.Next.NextCommand(VertexNoCommand)
|
||||
}
|
||||
for i, j := len(l.rewind)-2, len(l.rewind)-1; j > 0; i, j = i-2, j-2 {
|
||||
l.Next.NextCommand(VertexNoCommand)
|
||||
l.Next.Vertex(l.rewind[i], l.rewind[j])
|
||||
}
|
||||
if len(l.vertices) > 1 {
|
||||
l.Next.NextCommand(VertexNoCommand)
|
||||
l.Next.Vertex(l.vertices[0], l.vertices[1])
|
||||
}
|
||||
l.Next.NextCommand(VertexStopCommand)
|
||||
// reinit vertices
|
||||
l.vertices = make([]float, 0)
|
||||
l.rewind = make([]float, 0)
|
||||
l.x, l.y, l.nx, l.ny = 0, 0, 0, 0
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LineStroker) Vertex(x, y float) {
|
||||
switch l.command {
|
||||
case VertexNoCommand:
|
||||
l.line(l.x, l.y, x, y)
|
||||
case VertexStartCommand:
|
||||
l.x, l.y = x, y
|
||||
case VertexJoinCommand:
|
||||
l.joinLine(l.x, l.y, l.nx, l.ny, x, y)
|
||||
case VertexCloseCommand:
|
||||
l.line(l.x, l.y, x, y)
|
||||
l.joinLine(l.x, l.y, l.nx, l.ny, x, y)
|
||||
l.closePolygon()
|
||||
}
|
||||
l.command = VertexNoCommand
|
||||
}
|
||||
|
||||
func (l *LineStroker) closePolygon() {
|
||||
if len(l.vertices) > 1 {
|
||||
l.vertices = append(l.vertices, l.vertices[0], l.vertices[1])
|
||||
l.rewind = append(l.rewind, l.rewind[0], l.rewind[1])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func (l *LineStroker) line(x1, y1, x2, y2 float) {
|
||||
dx := (x2 - x1)
|
||||
dy := (y2 - y1)
|
||||
d := vectorDistance(dx, dy)
|
||||
if d != 0 {
|
||||
nx := dy * l.HalfLineWidth / d
|
||||
ny := -(dx * l.HalfLineWidth / d)
|
||||
l.vertices = append(l.vertices, x1+nx, y1+ny, x2+nx, y2+ny)
|
||||
l.rewind = append(l.rewind, x1-nx, y1-ny, x2-nx, y2-ny)
|
||||
l.x, l.y, l.nx, l.ny = x2, y2, nx, ny
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LineStroker) joinLine(x1, y1, nx1, ny1, x2, y2 float) {
|
||||
dx := (x2 - x1)
|
||||
dy := (y2 - y1)
|
||||
d := vectorDistance(dx, dy)
|
||||
|
||||
if d != 0 {
|
||||
nx := dy * l.HalfLineWidth / d
|
||||
ny := -(dx * l.HalfLineWidth / d)
|
||||
/* l.join(x1, y1, x1 + nx, y1 - ny, nx, ny, x1 + ny2, y1 + nx2, nx2, ny2)
|
||||
l.join(x1, y1, x1 - ny1, y1 - nx1, nx1, ny1, x1 - ny2, y1 - nx2, nx2, ny2)*/
|
||||
|
||||
l.vertices = append(l.vertices, x1+nx, y1+ny, x2+nx, y2+ny)
|
||||
l.rewind = append(l.rewind, x1-nx, y1-ny, x2-nx, y2-ny)
|
||||
l.x, l.y, l.nx, l.ny = x2, y2, nx, ny
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
// created: 21/11/2010 by Laurent Le Goff
|
||||
|
||||
package draw2d
|
||||
|
||||
import (
|
||||
"freetype-go.googlecode.com/hg/freetype/raster"
|
||||
)
|
||||
|
@ -125,35 +126,35 @@ func (tr1 MatrixTransform) Multiply(tr2 MatrixTransform) MatrixTransform {
|
|||
}
|
||||
|
||||
|
||||
func (tr *MatrixTransform) Scale(sx, sy float) (*MatrixTransform){
|
||||
tr[0] = tr[0]*sx;
|
||||
tr[1] = tr[1]*sx;
|
||||
tr[4] = tr[4]*sx;
|
||||
tr[2] = tr[2]*sy;
|
||||
tr[3] = tr[3]*sy;
|
||||
tr[5] = tr[5]*sy;
|
||||
return tr;
|
||||
func (tr *MatrixTransform) Scale(sx, sy float) *MatrixTransform {
|
||||
tr[0] = tr[0] * sx
|
||||
tr[1] = tr[1] * sx
|
||||
tr[4] = tr[4] * sx
|
||||
tr[2] = tr[2] * sy
|
||||
tr[3] = tr[3] * sy
|
||||
tr[5] = tr[5] * sy
|
||||
return tr
|
||||
}
|
||||
|
||||
func (tr *MatrixTransform) Translate(tx, ty float) (*MatrixTransform){
|
||||
func (tr *MatrixTransform) Translate(tx, ty float) *MatrixTransform {
|
||||
tr[4] = tr[4] + tx
|
||||
tr[5] = tr[5] + ty
|
||||
return tr;
|
||||
return tr
|
||||
}
|
||||
|
||||
func (tr *MatrixTransform) Rotate(angle float) (*MatrixTransform){
|
||||
ca := cos(angle);
|
||||
sa := sin(angle);
|
||||
t0 := tr[0] * ca - tr[1] * sa;
|
||||
t2 := tr[1] * ca - tr[3] * sa;
|
||||
t4 := tr[4] * ca - tr[5] * sa;
|
||||
tr[1] = tr[0] * sa + tr[1] * ca;
|
||||
tr[3] = tr[2] * sa + tr[3] * ca;
|
||||
tr[5] = tr[4] * sa + tr[5] * ca;
|
||||
tr[0] = t0;
|
||||
tr[2] = t2;
|
||||
tr[4] = t4;
|
||||
return tr;
|
||||
func (tr *MatrixTransform) Rotate(angle float) *MatrixTransform {
|
||||
ca := cos(angle)
|
||||
sa := sin(angle)
|
||||
t0 := tr[0]*ca - tr[1]*sa
|
||||
t2 := tr[1]*ca - tr[3]*sa
|
||||
t4 := tr[4]*ca - tr[5]*sa
|
||||
tr[1] = tr[0]*sa + tr[1]*ca
|
||||
tr[3] = tr[2]*sa + tr[3]*ca
|
||||
tr[5] = tr[4]*sa + tr[5]*ca
|
||||
tr[0] = t0
|
||||
tr[2] = t2
|
||||
tr[4] = t4
|
||||
return tr
|
||||
}
|
||||
|
||||
func (tr MatrixTransform) GetTranslation() (x, y float) {
|
||||
|
@ -167,7 +168,7 @@ func (tr MatrixTransform) GetScaling() (x, y float) {
|
|||
func (tr MatrixTransform) GetMaxAbsScaling() (s float) {
|
||||
sx := fabs(tr[0])
|
||||
sy := fabs(tr[3])
|
||||
if(sx > sy) {
|
||||
if sx > sy {
|
||||
return sx
|
||||
}
|
||||
return sy
|
||||
|
@ -176,7 +177,7 @@ func (tr MatrixTransform) GetMaxAbsScaling() (s float) {
|
|||
func (tr MatrixTransform) GetMinAbsScaling() (s float) {
|
||||
sx := fabs(tr[0])
|
||||
sy := fabs(tr[3])
|
||||
if(sx > sy) {
|
||||
if sx > sy {
|
||||
return sy
|
||||
}
|
||||
return sx
|
||||
|
@ -221,13 +222,34 @@ func fequals(float1, float2 float) bool {
|
|||
return fabs(float1-float2) <= epsilon
|
||||
}
|
||||
|
||||
// this VertexConverter apply the Matrix transformation tr
|
||||
type VertexMatrixTransform struct {
|
||||
tr MatrixTransform
|
||||
Next VertexConverter
|
||||
}
|
||||
|
||||
func NewVertexMatrixTransform(tr MatrixTransform, converter VertexConverter) *VertexMatrixTransform {
|
||||
return &VertexMatrixTransform{tr, converter}
|
||||
}
|
||||
|
||||
// Vertex Matrix Transform
|
||||
func (vmt *VertexMatrixTransform) NextCommand(command VertexCommand) {
|
||||
vmt.Next.NextCommand(command)
|
||||
}
|
||||
|
||||
func (vmt *VertexMatrixTransform) Vertex(x, y float) {
|
||||
vmt.tr.Transform(&x, &y)
|
||||
vmt.Next.Vertex(x, y)
|
||||
}
|
||||
|
||||
|
||||
// this adder apply a Matrix transformation to points
|
||||
type MatrixTransformAdder struct {
|
||||
tr MatrixTransform
|
||||
next raster.Adder
|
||||
}
|
||||
|
||||
func NewMatrixTransformAdder(tr MatrixTransform, adder raster.Adder) (*MatrixTransformAdder) {
|
||||
func NewMatrixTransformAdder(tr MatrixTransform, adder raster.Adder) *MatrixTransformAdder {
|
||||
return &MatrixTransformAdder{tr, adder}
|
||||
}
|
||||
|
||||
|
@ -255,4 +277,3 @@ func (mta MatrixTransformAdder) Add3(b, c, d raster.Point) {
|
|||
mta.tr.TransformRasterPoint(&b, &c, &d)
|
||||
mta.next.Add3(b, c, d)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue