- add draw (android, gopher)

- resolve some point on matrix transformation
This commit is contained in:
legoff.laurent 2010-12-06 11:44:36 +00:00
parent ccd47dd883
commit 2928dfe411
6 changed files with 396 additions and 129 deletions

View file

@ -0,0 +1,136 @@
package main
import (
"fmt"
"log"
"os"
"bufio"
"time"
"math"
"image"
"image/png"
//"draw2d"
"draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d"
)
const (
width, height = 500, 300
)
var (
lastTime int64
folder = "../../../../wiki/test_results/"
)
func initGc(w, h int) (image.Image, *draw2d.GraphicContext) {
i := image.NewRGBA(w, h)
gc := draw2d.NewGraphicContext(i)
lastTime = time.Nanoseconds()
gc.SetStrokeColor(image.Black)
gc.SetFillColor(image.White)
// fill the background
//gc.Clear()
return i, gc
}
func saveToPngFile(TestName string, m image.Image) {
dt := time.Nanoseconds() - lastTime
fmt.Printf("%s during: %f ms\n", TestName, float(dt)*10e-6)
filePath := folder + TestName + ".png"
f, err := os.Open(filePath, os.O_CREAT|os.O_WRONLY, 0600)
if err != nil {
log.Println(err)
os.Exit(1)
}
defer f.Close()
b := bufio.NewWriter(f)
err = png.Encode(b, m)
if err != nil {
log.Println(err)
os.Exit(1)
}
err = b.Flush()
if err != nil {
log.Println(err)
os.Exit(1)
}
fmt.Printf("Wrote %s OK.\n", filePath)
}
func gordon(gc *draw2d.GraphicContext, x, y, w, h float) {
h23 := (h * 2) / 3
blf := image.RGBAColor{0, 0, 0, 0xff}
wf := image.RGBAColor{0xff, 0xff, 0xff, 0xff}
nf := image.RGBAColor{0x8B, 0x45, 0x13, 0xff}
brf := image.RGBAColor{0x8B, 0x45, 0x13, 0x99}
brb := image.RGBAColor{0x8B, 0x45, 0x13, 0xBB}
gc.MoveTo(x, y+h)
gc.CubicCurveTo(x, y+h, x+w/2, y-h, x+w, y+h)
gc.Close()
gc.SetFillColor(brb)
gc.Fill()
gc.RoundRect(x, y+h, x+ w, y+h+h, 10, 10)
gc.Fill()
gc.Circle(x, y+h, w/12) // left ear
gc.SetFillColor(brf)
gc.Fill()
gc.Circle(x, y+h, w/12-10)
gc.SetFillColor(nf)
gc.Fill()
gc.Circle(x+w, y+h, w/12) // right ear
gc.SetFillColor(brf)
gc.Fill()
gc.Circle(x+w, y+h, w/12-10)
gc.SetFillColor(nf)
gc.Fill()
gc.Circle(x+w/3, y+h23, w/9) // left eye
gc.SetFillColor(wf)
gc.Fill()
gc.Circle(x+w/3+10, y+h23, w / 10 - 10)
gc.SetFillColor(blf)
gc.Fill()
gc.Circle(x+w/3+15, y+h23, 5)
gc.SetFillColor(wf)
gc.Fill()
gc.Circle(x+w-w/3, y+h23, w/9) // right eye
gc.Fill()
gc.Circle(x+w-w/3+10, y+h23, w / 10 - 10)
gc.SetFillColor(blf)
gc.Fill()
gc.Circle(x+w-(w/3)+15, y+h23, 5)
gc.SetFillColor(wf)
gc.Fill()
gc.SetFillColor(wf)
gc.RoundRect(x+w/2-w/8, y+h+30, x+w/2-w/8 + w/8, y+h+30 + w/6, 5, 5) // left tooth
gc.Fill()
gc.RoundRect(x+w/2, y+h+30, x+w/2+w/8, y+h+30+w/6, 5, 5) // right tooth
gc.Fill()
gc.Ellipse(x+(w/2), y+h+30, w/6, w/12) // snout
gc.SetFillColor(nf)
gc.Fill()
gc.Ellipse(x+(w/2), y+h+10, w/10, w/12) // nose
gc.SetFillColor(blf)
gc.Fill()
}
func main() {
i, gc := initGc(width, height)
gc.Clear()
gc.Translate(100, 100)
gc.Rotate(-30 * (math.Pi / 180.0))
gordon(gc, 48, 48, 240, 72)
saveToPngFile("TestGopher", i)
}

View file

@ -0,0 +1,98 @@
package main
import (
"fmt"
"log"
"os"
"bufio"
"time"
"math"
"image"
"image/png"
//"draw2d"
"draw2d.googlecode.com/svn/trunk/draw2d/src/pkg/draw2d"
)
const (
width, height = 500, 500
)
var (
lastTime int64
folder = "../../../../wiki/test_results/"
)
func initGc(w, h int) (image.Image, *draw2d.GraphicContext) {
i := image.NewRGBA(w, h)
gc := draw2d.NewGraphicContext(i)
lastTime = time.Nanoseconds()
gc.SetStrokeColor(image.Black)
gc.SetFillColor(image.White)
// fill the background
//gc.Clear()
return i, gc
}
func saveToPngFile(TestName string, m image.Image) {
dt := time.Nanoseconds() - lastTime
fmt.Printf("%s during: %f ms\n", TestName, float(dt)*10e-6)
filePath := folder + TestName + ".png"
f, err := os.Open(filePath, os.O_CREAT|os.O_WRONLY, 0600)
if err != nil {
log.Println(err)
os.Exit(1)
}
defer f.Close()
b := bufio.NewWriter(f)
err = png.Encode(b, m)
if err != nil {
log.Println(err)
os.Exit(1)
}
err = b.Flush()
if err != nil {
log.Println(err)
os.Exit(1)
}
fmt.Printf("Wrote %s OK.\n", filePath)
}
func android(gc *draw2d.GraphicContext, x, y float) {
gc.SetLineCap(draw2d.RoundCap)
gc.SetLineWidth(5)
gc.ArcTo(x+80, y+70, 50, 50, 180 * (math.Pi/180), 360 * (math.Pi/180)) // head
gc.FillStroke()
gc.MoveTo(x+60, y+25)
gc.LineTo(x+50, y+10)
gc.MoveTo(x+100, y+25)
gc.LineTo( x+110, y+10)
gc.Stroke()
gc.Circle(x+60, y+45, 5) // left eye
gc.FillStroke()
gc.Circle(x+100, y+45, 5) // right eye
gc.FillStroke()
gc.RoundRect(x+30, y+75, x+30+100, y+75+90, 10, 10) // body
gc.FillStroke()
gc.Rect(x+30, y+75, x+30+100, y+75+80)
gc.FillStroke()
gc.RoundRect(x+5, y+80, x+5+20, y+80+70, 10, 10) // left arm
gc.FillStroke()
gc.RoundRect(x+135, y+80, x+135+20, y+80+70, 10, 10) // right arm
gc.FillStroke()
gc.RoundRect(x+50, y+150, x+50+20, y+150+50, 10, 10) // left leg
gc.FillStroke()
gc.RoundRect(x+90, y+150, x+90+20, y+150+50, 10, 10) // right leg
gc.FillStroke()
}
func main() {
i, gc := initGc(width, height)
android(gc, 100, 100)
saveToPngFile("TestAndroid", i)
}

View file

@ -193,7 +193,7 @@ func TestCurveRectangle() {
gc.CubicCurveTo(x0, y1, x0, y1, x0, y1-radius) gc.CubicCurveTo(x0, y1, x0, y1, x0, y1-radius)
} }
} }
gc.ClosePath() gc.Close()
gc.SetFillColor(image.RGBAColor{0x80, 0x80, 0xFF, 0xFF}) gc.SetFillColor(image.RGBAColor{0x80, 0x80, 0xFF, 0xFF})
gc.SetStrokeColor(image.RGBAColor{0x80, 0, 0, 0x80}) gc.SetStrokeColor(image.RGBAColor{0x80, 0, 0, 0x80})
@ -261,13 +261,13 @@ func TestFillStroke() {
gc.LineTo(230.4, 230.4) gc.LineTo(230.4, 230.4)
gc.RLineTo(-102.4, 0.0) gc.RLineTo(-102.4, 0.0)
gc.CubicCurveTo(51.2, 230.4, 51.2, 128.0, 128.0, 128.0) gc.CubicCurveTo(51.2, 230.4, 51.2, 128.0, 128.0, 128.0)
gc.ClosePath() gc.Close()
gc.MoveTo(64.0, 25.6) gc.MoveTo(64.0, 25.6)
gc.RLineTo(51.2, 51.2) gc.RLineTo(51.2, 51.2)
gc.RLineTo(-51.2, 51.2) gc.RLineTo(-51.2, 51.2)
gc.RLineTo(-51.2, -51.2) gc.RLineTo(-51.2, -51.2)
gc.ClosePath() gc.Close()
gc.SetLineWidth(10.0) gc.SetLineWidth(10.0)
gc.SetFillColor(image.RGBAColor{0, 0, 0xFF, 0xFF}) gc.SetFillColor(image.RGBAColor{0, 0, 0xFF, 0xFF})
@ -341,7 +341,7 @@ func TestRoundRectangle() {
gc.ArcTo(x+width-radius, y+height-radius, radius, radius, 0*degrees, 90*degrees) gc.ArcTo(x+width-radius, y+height-radius, radius, radius, 0*degrees, 90*degrees)
gc.ArcTo(x+radius, y+height-radius, radius, radius, 90*degrees, 90*degrees) gc.ArcTo(x+radius, y+height-radius, radius, radius, 90*degrees, 90*degrees)
gc.ArcTo(x+radius, y+radius, radius, radius, 180*degrees, 90*degrees) gc.ArcTo(x+radius, y+radius, radius, radius, 180*degrees, 90*degrees)
gc.ClosePath() gc.Close()
gc.SetFillColor(image.RGBAColor{0x80, 0x80, 0xFF, 0xFF}) gc.SetFillColor(image.RGBAColor{0x80, 0x80, 0xFF, 0xFF})
gc.SetStrokeColor(image.RGBAColor{0x80, 0, 0, 0x80}) gc.SetStrokeColor(image.RGBAColor{0x80, 0, 0, 0x80})
@ -419,13 +419,14 @@ func TestBubble() {
func TestStar() { func TestStar() {
i, gc := initGc(w, h) i, gc := initGc(w, h)
for i := 0.0 ; i < 360; i = i + 10 {// Go from 0 to 360 degrees in 10 degree steps for i := 0.0 ; i < 360; i = i + 10 {// Go from 0 to 360 degrees in 10 degree steps
gc.BeginPath() // Start a new path gc.Save()
gc.Save() // Keep rotations temporary gc.SetLineWidth(5) // Keep rotations temporary
gc.MoveTo(144, 144) gc.Translate(144, 144)
gc.Rotate(i * (math.Pi / 180.0)) // Rotate by degrees on stack from 'for' gc.Rotate(i * (math.Pi / 180.0)) // Rotate by degrees on stack from 'for'
gc.RLineTo(72, 0) gc.MoveTo(0, 0)
gc.LineTo(72, 0)
gc.Stroke() gc.Stroke()
gc.Restore() // Get back the unrotated state gc.Restore()
} }
saveToPngFile("TestStar", i) saveToPngFile("TestStar", i)
} }
@ -440,7 +441,7 @@ func TestTransform() {
gc.RLineTo(72,0) gc.RLineTo(72,0)
gc.RLineTo(0, 72) gc.RLineTo(0, 72)
gc.RLineTo(-72,0) gc.RLineTo(-72,0)
gc.ClosePath() gc.Close()
gc.Stroke() gc.Stroke()
gc.Restore() gc.Restore()
@ -452,7 +453,7 @@ func TestTransform() {
gc.RLineTo(72,0) gc.RLineTo(72,0)
gc.RLineTo(0, 72) gc.RLineTo(0, 72)
gc.RLineTo(-72,0) gc.RLineTo(-72,0)
gc.ClosePath() // Draw box... gc.Close() // Draw box...
gc.Stroke() gc.Stroke()
gc.Restore() gc.Restore()
@ -464,7 +465,7 @@ func TestTransform() {
gc.RLineTo(72,0) gc.RLineTo(72,0)
gc.RLineTo(0, 72) gc.RLineTo(0, 72)
gc.RLineTo(-72,0) gc.RLineTo(-72,0)
gc.ClosePath() // Draw box... gc.Close() // Draw box...
gc.Stroke() gc.Stroke()
gc.Restore() gc.Restore()
@ -477,13 +478,22 @@ func TestTransform() {
gc.RLineTo(72,0) gc.RLineTo(72,0)
gc.RLineTo(0, 72) gc.RLineTo(0, 72)
gc.RLineTo(-72,0) gc.RLineTo(-72,0)
gc.ClosePath() // Draw box gc.Close() // Draw box
gc.Stroke() gc.Stroke()
gc.Restore() gc.Restore()
saveToPngFile("TestTransform", i) saveToPngFile("TestTransform", i)
} }
func TestPathTransform() {
i, gc := initGc(800, 600)
gc.SetLineWidth(20)
gc.Scale(1,5)
gc.ArcTo(200, 50, 50, 50, 0, math.Pi * 2)
gc.Stroke()
saveToPngFile("TestPathTransform", i)
}
func main() { func main() {
TestPath() TestPath()
TestDrawArc() TestDrawArc()
@ -500,4 +510,5 @@ func main() {
TestBubble() TestBubble()
TestStar() TestStar()
TestTransform() TestTransform()
TestPathTransform()
} }

View file

@ -6,7 +6,7 @@ package draw2d
import ( import (
"exp/draw" "exp/draw"
"image" "image"
//"math" "math"
"freetype-go.googlecode.com/hg/freetype/raster" "freetype-go.googlecode.com/hg/freetype/raster"
) )
@ -163,68 +163,83 @@ func (gc *GraphicContext) BeginPath() {
} }
func (gc *GraphicContext) MoveTo(x, y float) { func (gc *GraphicContext) MoveTo(x, y float) {
gc.current.tr.Transform(&x, &y)
gc.current.path.MoveTo(x, y) gc.current.path.MoveTo(x, y)
} }
func (gc *GraphicContext) RMoveTo(dx, dy float) { func (gc *GraphicContext) RMoveTo(dx, dy float) {
gc.current.tr.VectorTransform(&dx, &dy)
gc.current.path.RMoveTo(dx, dy) gc.current.path.RMoveTo(dx, dy)
} }
func (gc *GraphicContext) LineTo(x, y float) { func (gc *GraphicContext) LineTo(x, y float) {
gc.current.tr.Transform(&x, &y)
gc.current.path.LineTo(x, y) gc.current.path.LineTo(x, y)
} }
func (gc *GraphicContext) RLineTo(dx, dy float) { func (gc *GraphicContext) RLineTo(dx, dy float) {
gc.current.tr.VectorTransform(&dx, &dy)
gc.current.path.RLineTo(dx, dy) gc.current.path.RLineTo(dx, dy)
} }
func (gc *GraphicContext) Rect(x1, y1, x2, y2 float) {
gc.current.tr.Transform(&x1, &y1, &x2, &y2)
gc.current.path.Rect(x1, y1, x2, y2)
}
func (gc *GraphicContext) RRect(dx1, dy1, dx2, dy2 float) {
gc.current.tr.VectorTransform(&dx1, &dy1, &dx2, &dy2)
gc.current.path.RRect(dx1, dy1, dx2, dy2)
}
func (gc *GraphicContext) QuadCurveTo(cx, cy, x, y float) { func (gc *GraphicContext) QuadCurveTo(cx, cy, x, y float) {
gc.current.tr.Transform(&cx, &cy, &x, &y)
gc.current.path.QuadCurveTo(cx, cy, x, y) gc.current.path.QuadCurveTo(cx, cy, x, y)
} }
func (gc *GraphicContext) RQuadCurveTo(dcx, dcy, dx, dy float) { func (gc *GraphicContext) RQuadCurveTo(dcx, dcy, dx, dy float) {
gc.current.tr.VectorTransform(&dcx, &dcy, &dx, &dy)
gc.current.path.RQuadCurveTo(dcx, dcy, dx, dy) gc.current.path.RQuadCurveTo(dcx, dcy, dx, dy)
} }
func (gc *GraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float) { func (gc *GraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float) {
gc.current.tr.Transform(&cx1, &cy1, &cx2, &cy2, &x, &y)
gc.current.path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y) gc.current.path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y)
} }
func (gc *GraphicContext) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float) { func (gc *GraphicContext) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float) {
gc.current.tr.VectorTransform(&dcx1, &dcy1, &dcx2, &dcy2, &dx, &dy)
gc.current.path.RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy) gc.current.path.RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy)
} }
func (gc *GraphicContext) ArcTo(cx, cy, rx, ry, startAngle, angle float) { func (gc *GraphicContext) ArcTo(cx, cy, rx, ry, startAngle, angle float) {
gc.current.tr.Transform(&cx, &cy)
gc.current.tr.VectorTransform(&rx, &ry)
gc.current.path.ArcTo(cx, cy, rx, ry, startAngle, angle) gc.current.path.ArcTo(cx, cy, rx, ry, startAngle, angle)
} }
func (gc *GraphicContext) RArcTo(dcx, dcy, rx, ry, startAngle, angle float) { func (gc *GraphicContext) RArcTo(dcx, dcy, rx, ry, startAngle, angle float) {
gc.current.tr.VectorTransform(&dcx, &dcy)
gc.current.tr.VectorTransform(&rx, &ry)
gc.current.path.RArcTo(dcx, dcy, rx, ry, startAngle, angle) gc.current.path.RArcTo(dcx, dcy, rx, ry, startAngle, angle)
} }
func (gc *GraphicContext) ClosePath() { //high level path creation
func (gc *GraphicContext) Rect(x1, y1, x2, y2 float) {
if gc.current.path.isEmpty() {
gc.current.path.MoveTo(x1, y1)
} else {
gc.current.path.LineTo(x1, y1)
}
gc.current.path.LineTo(x2, y1)
gc.current.path.LineTo(x2, y2)
gc.current.path.LineTo(x1, y2)
gc.current.path.Close()
}
func (gc *GraphicContext) RoundRect(x1, y1, x2, y2, arcWidth, arcHeight float) {
arcWidth = arcWidth/2;
arcHeight = arcHeight/2;
gc.MoveTo(x1, y1+ arcHeight);
gc.QuadCurveTo(x1, y1, x1 + arcWidth, y1);
gc.LineTo(x2-arcWidth, y1);
gc.QuadCurveTo(x2, y1, x2, y1 + arcHeight);
gc.LineTo(x2, y2-arcHeight);
gc.QuadCurveTo(x2, y2, x2 - arcWidth, y2);
gc.LineTo(x1 + arcWidth, y2);
gc.QuadCurveTo(x1, y2, x1, y2 - arcHeight);
gc.Close()
}
func (gc *GraphicContext) Ellipse(cx, cy, rx, ry float) {
gc.current.path.ArcTo(cx, cy, rx, ry, 0, -math.Pi * 2)
gc.current.path.Close()
}
func (gc *GraphicContext) Circle(cx, cy, radius float) {
gc.current.path.ArcTo(cx, cy, radius, radius, 0, -math.Pi * 2)
gc.current.path.Close()
}
func (gc *GraphicContext) Close() {
gc.current.path.Close() gc.current.path.Close()
} }
@ -236,35 +251,44 @@ func (gc *GraphicContext) paint(color image.Color) {
gc.current.path = new(Path) gc.current.path = new(Path)
} }
func (gc *GraphicContext) Stroke(paths ...*Path) { func (gc *GraphicContext) Stroke(paths ...*Path) {
paths = append(paths, gc.current.path) paths = append(paths, gc.current.path)
rasterPath := tracePath(gc.current.dash, gc.current.dashOffset, paths...)
gc.rasterizer.UseNonZeroWinding = true gc.rasterizer.UseNonZeroWinding = true
gc.rasterizer.AddStroke(*rasterPath, raster.Fix32(gc.current.lineWidth*256), gc.current.cap.capper(), gc.current.join.joiner()) 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...)
}
mta := NewMatrixTransformAdder(gc.current.tr, gc.rasterizer)
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.current.strokeColor)
} }
func (gc *GraphicContext) Fill(paths ...*Path) { func (gc *GraphicContext) Fill(paths ...*Path) {
paths = append(paths, gc.current.path) paths = append(paths, gc.current.path)
rasterPath := tracePath(nil, 0, paths...)
gc.rasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule() gc.rasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule()
gc.rasterizer.AddPath(*rasterPath) mta := NewMatrixTransformAdder(gc.current.tr, gc.rasterizer)
tracePath(gc.current.tr.GetMaxAbsScaling(), mta, paths...)
gc.paint(gc.current.fillColor) gc.paint(gc.current.fillColor)
} }
func (gc *GraphicContext) FillStroke(paths ...*Path) { func (gc *GraphicContext) FillStroke(paths ...*Path) {
paths = append(paths, gc.current.path) paths = append(paths, gc.current.path)
rasterPath := tracePath(nil, 0, paths...) mta := NewMatrixTransformAdder(gc.current.tr, gc.rasterizer)
tracePath(gc.current.tr.GetMaxAbsScaling(), mta, paths...)
gc.rasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule() gc.rasterizer.UseNonZeroWinding = gc.current.fillRule.fillRule()
gc.rasterizer.AddPath(*rasterPath)
gc.paint(gc.current.fillColor) gc.paint(gc.current.fillColor)
if gc.current.dash != nil {
rasterPath = tracePath(gc.current.dash, gc.current.dashOffset, paths...)
}
gc.rasterizer.UseNonZeroWinding = true gc.rasterizer.UseNonZeroWinding = true
gc.rasterizer.AddStroke(*rasterPath, raster.Fix32(gc.current.lineWidth*256), gc.current.cap.capper(), gc.current.join.joiner()) 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...)
}
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.current.strokeColor)
} }
@ -300,79 +324,3 @@ func (j Join) joiner() raster.Joiner {
return raster.RoundJoiner return raster.RoundJoiner
} }
type PathAdapter struct {
path *raster.Path
x, y, distance float
dash []float
currentDash int
dashOffset float
}
func tracePath(dash []float, dashOffset float, paths ...*Path) *raster.Path {
var adapter PathAdapter
if dash != nil && len(dash) > 0 {
adapter.dash = dash
} else {
adapter.dash = nil
}
adapter.currentDash = 0
adapter.dashOffset = dashOffset
adapter.path = new(raster.Path)
for _, path := range paths {
path.TraceLine(&adapter)
}
return adapter.path
}
func floatToPoint(x, y float) raster.Point {
return raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)}
}
func (p *PathAdapter) MoveTo(x, y float) {
p.path.Start(floatToPoint(x, y))
p.x, p.y = x, y
p.distance = p.dashOffset
p.currentDash = 0
}
func (p *PathAdapter) LineTo(x, y float) {
if p.dash != nil {
rest := p.dash[p.currentDash] - p.distance
for rest < 0 {
p.distance = p.distance - p.dash[p.currentDash]
p.currentDash = (p.currentDash + 1) % len(p.dash)
rest = p.dash[p.currentDash] - p.distance
}
d := distance(p.x, p.y, x, y)
for d >= rest {
k := rest / d
lx := p.x + k*(x-p.x)
ly := p.y + k*(y-p.y)
if p.currentDash%2 == 0 {
// line
p.path.Add1(floatToPoint(lx, ly))
} else {
// gap
p.path.Start(floatToPoint(lx, ly))
}
d = d - rest
p.x, p.y = lx, ly
p.currentDash = (p.currentDash + 1) % len(p.dash)
rest = p.dash[p.currentDash]
}
p.distance = d
if p.currentDash%2 == 0 {
p.path.Add1(floatToPoint(x, y))
} else {
p.path.Start(floatToPoint(x, y))
}
if p.distance >= p.dash[p.currentDash] {
p.distance = p.distance - p.dash[p.currentDash]
p.currentDash = (p.currentDash + 1) % len(p.dash)
}
} else {
p.path.Add1(floatToPoint(x, y))
}
p.x, p.y = x, y
}

View file

@ -47,6 +47,10 @@ func (p *Path) LastPoint() (x, y float) {
return p.x, p.y return p.x, p.y
} }
func (p *Path) isEmpty() bool {
return len(p.commands) == 0
}
func (p *Path) Close() *Path { func (p *Path) Close() *Path {
p.appendToPath(Close) p.appendToPath(Close)
return p return p
@ -159,7 +163,7 @@ func (p *Path) RArcTo(dcx, dcy, rx, ry, startAngle, angle float) *Path {
return p return p
} }
func (p *Path) TraceLine(tracer LineTracer) { func (p *Path) TraceLine(tracer LineTracer, approximationScale float) {
j := 0 j := 0
x, y := 0.0, 0.0 x, y := 0.0, 0.0
firstX, firstY := x, y firstX, firstY := x, y
@ -180,15 +184,15 @@ func (p *Path) TraceLine(tracer LineTracer) {
x, y = p.vertices[j], p.vertices[j+1] x, y = p.vertices[j], p.vertices[j+1]
j = j + 2 j = j + 2
case QuadCurveTo: case QuadCurveTo:
quadraticBezier(tracer, x, y, p.vertices[j], p.vertices[j+1], p.vertices[j+2], p.vertices[j+3], 1.0, 0.0) 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] x, y = p.vertices[j+2], p.vertices[j+3]
j = j + 4 j = j + 4
case CubicCurveTo: 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], 1.0, 0.0, 0.0) 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] x, y = p.vertices[j+4], p.vertices[j+5]
j = j + 6 j = j + 6
case ArcTo: 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], 1) 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 j = j + 6
case Close: case Close:
tracer.LineTo(firstX, firstY) tracer.LineTo(firstX, firstY)

View file

@ -2,6 +2,9 @@
// created: 21/11/2010 by Laurent Le Goff // created: 21/11/2010 by Laurent Le Goff
package draw2d package draw2d
import (
"freetype-go.googlecode.com/hg/freetype/raster"
)
type MatrixTransform [6]float type MatrixTransform [6]float
@ -22,6 +25,15 @@ func (tr MatrixTransform) Transform(points ...*float) {
} }
} }
func (tr MatrixTransform) TransformRasterPoint(points ...*raster.Point) {
for _, point := range points {
x := float(point.X) / 256
y := float(point.Y) / 256
point.X = raster.Fix32((x*tr[0] + y*tr[2] + tr[4]) * 256)
point.Y = raster.Fix32((x*tr[1] + y*tr[3] + tr[5]) * 256)
}
}
func (tr MatrixTransform) InverseTransform(points ...*float) { func (tr MatrixTransform) InverseTransform(points ...*float) {
d := tr.Determinant() // matrix determinant d := tr.Determinant() // matrix determinant
for i, j := 0, 1; j < len(points); i, j = i+2, j+2 { for i, j := 0, 1; j < len(points); i, j = i+2, j+2 {
@ -148,6 +160,28 @@ func (tr MatrixTransform) GetTranslation() (x, y float) {
return tr[4], tr[5] return tr[4], tr[5]
} }
func (tr MatrixTransform) GetScaling() (x, y float) {
return tr[0], tr[3]
}
func (tr MatrixTransform) GetMaxAbsScaling() (s float) {
sx := fabs(tr[0])
sy := fabs(tr[3])
if(sx > sy) {
return sx
}
return sy
}
func (tr MatrixTransform) GetMinAbsScaling() (s float) {
sx := fabs(tr[0])
sy := fabs(tr[3])
if(sx > sy) {
return sy
}
return sx
}
// ******************** Testing ******************** // ******************** Testing ********************
/** /**
@ -186,3 +220,39 @@ func (tr MatrixTransform) IsTranslation() bool {
func fequals(float1, float2 float) bool { func fequals(float1, float2 float) bool {
return fabs(float1-float2) <= epsilon return fabs(float1-float2) <= epsilon
} }
// this adder apply a Matrix transformation to points
type MatrixTransformAdder struct {
tr MatrixTransform
next raster.Adder
}
func NewMatrixTransformAdder(tr MatrixTransform, adder raster.Adder) (*MatrixTransformAdder) {
return &MatrixTransformAdder{tr, adder}
}
// Start starts a new curve at the given point.
func (mta MatrixTransformAdder) Start(a raster.Point) {
mta.tr.TransformRasterPoint(&a)
mta.next.Start(a)
}
// Add1 adds a linear segment to the current curve.
func (mta MatrixTransformAdder) Add1(b raster.Point) {
mta.tr.TransformRasterPoint(&b)
mta.next.Add1(b)
}
// Add2 adds a quadratic segment to the current curve.
func (mta MatrixTransformAdder) Add2(b, c raster.Point) {
mta.tr.TransformRasterPoint(&b, &c)
mta.next.Add2(b, c)
}
// Add3 adds a cubic segment to the current curve.
func (mta MatrixTransformAdder) Add3(b, c, d raster.Point) {
mta.tr.TransformRasterPoint(&b, &c, &d)
mta.next.Add3(b, c, d)
}