- add draw (android, gopher)
- resolve some point on matrix transformation
This commit is contained in:
parent
ccd47dd883
commit
2928dfe411
6 changed files with 396 additions and 129 deletions
136
draw2d/src/cmd/test_gopher.go
Normal file
136
draw2d/src/cmd/test_gopher.go
Normal 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)
|
||||||
|
}
|
98
draw2d/src/cmd/testandroid.go
Normal file
98
draw2d/src/cmd/testandroid.go
Normal 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)
|
||||||
|
}
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue