refactoring mv path things in path package
This commit is contained in:
parent
1d191b3eaf
commit
0b7a049f3e
15 changed files with 185 additions and 583 deletions
68
arc.go
68
arc.go
|
@ -1,68 +0,0 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
|
||||||
// created: 21/11/2010 by Laurent Le Goff
|
|
||||||
|
|
||||||
package draw2d
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"code.google.com/p/freetype-go/freetype/raster"
|
|
||||||
)
|
|
||||||
|
|
||||||
func arc(t LineBuilder, x, y, rx, ry, start, angle, scale float64) (lastX, lastY float64) {
|
|
||||||
end := start + angle
|
|
||||||
clockWise := true
|
|
||||||
if angle < 0 {
|
|
||||||
clockWise = false
|
|
||||||
}
|
|
||||||
ra := (math.Abs(rx) + math.Abs(ry)) / 2
|
|
||||||
da := math.Acos(ra/(ra+0.125/scale)) * 2
|
|
||||||
//normalize
|
|
||||||
if !clockWise {
|
|
||||||
da = -da
|
|
||||||
}
|
|
||||||
angle = start + da
|
|
||||||
var curX, curY float64
|
|
||||||
for {
|
|
||||||
if (angle < end-da/4) != clockWise {
|
|
||||||
curX = x + math.Cos(end)*rx
|
|
||||||
curY = y + math.Sin(end)*ry
|
|
||||||
return curX, curY
|
|
||||||
}
|
|
||||||
curX = x + math.Cos(angle)*rx
|
|
||||||
curY = y + math.Sin(angle)*ry
|
|
||||||
|
|
||||||
angle += da
|
|
||||||
t.LineTo(curX, curY)
|
|
||||||
}
|
|
||||||
return curX, curY
|
|
||||||
}
|
|
||||||
|
|
||||||
func arcAdder(adder raster.Adder, x, y, rx, ry, start, angle, scale float64) raster.Point {
|
|
||||||
end := start + angle
|
|
||||||
clockWise := true
|
|
||||||
if angle < 0 {
|
|
||||||
clockWise = false
|
|
||||||
}
|
|
||||||
ra := (math.Abs(rx) + math.Abs(ry)) / 2
|
|
||||||
da := math.Acos(ra/(ra+0.125/scale)) * 2
|
|
||||||
//normalize
|
|
||||||
if !clockWise {
|
|
||||||
da = -da
|
|
||||||
}
|
|
||||||
angle = start + da
|
|
||||||
var curX, curY float64
|
|
||||||
for {
|
|
||||||
if (angle < end-da/4) != clockWise {
|
|
||||||
curX = x + math.Cos(end)*rx
|
|
||||||
curY = y + math.Sin(end)*ry
|
|
||||||
return raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)}
|
|
||||||
}
|
|
||||||
curX = x + math.Cos(angle)*rx
|
|
||||||
curY = y + math.Sin(angle)*ry
|
|
||||||
|
|
||||||
angle += da
|
|
||||||
adder.Add1(raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)})
|
|
||||||
}
|
|
||||||
return raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)}
|
|
||||||
}
|
|
38
curve/arc.go
38
curve/arc.go
|
@ -5,10 +5,12 @@ package curve
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"code.google.com/p/freetype-go/freetype/raster"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TraceArc trace an arc using a LineBuilder
|
// TraceArc trace an arc using a LineBuilder
|
||||||
func TraceArc(t LineBuilder, x, y, rx, ry, start, angle, scale float64) {
|
func TraceArc(t LineBuilder, x, y, rx, ry, start, angle, scale float64) (lastX, lastY float64) {
|
||||||
end := start + angle
|
end := start + angle
|
||||||
clockWise := true
|
clockWise := true
|
||||||
if angle < 0 {
|
if angle < 0 {
|
||||||
|
@ -26,7 +28,7 @@ func TraceArc(t LineBuilder, x, y, rx, ry, start, angle, scale float64) {
|
||||||
if (angle < end-da/4) != clockWise {
|
if (angle < end-da/4) != clockWise {
|
||||||
curX = x + math.Cos(end)*rx
|
curX = x + math.Cos(end)*rx
|
||||||
curY = y + math.Sin(end)*ry
|
curY = y + math.Sin(end)*ry
|
||||||
break
|
return curX, curY
|
||||||
}
|
}
|
||||||
curX = x + math.Cos(angle)*rx
|
curX = x + math.Cos(angle)*rx
|
||||||
curY = y + math.Sin(angle)*ry
|
curY = y + math.Sin(angle)*ry
|
||||||
|
@ -34,5 +36,35 @@ func TraceArc(t LineBuilder, x, y, rx, ry, start, angle, scale float64) {
|
||||||
angle += da
|
angle += da
|
||||||
t.LineTo(curX, curY)
|
t.LineTo(curX, curY)
|
||||||
}
|
}
|
||||||
t.LineTo(curX, curY)
|
return curX, curY
|
||||||
|
}
|
||||||
|
|
||||||
|
// TraceArc trace an arc using a Freetype
|
||||||
|
func TraceArcFt(adder raster.Adder, x, y, rx, ry, start, angle, scale float64) raster.Point {
|
||||||
|
end := start + angle
|
||||||
|
clockWise := true
|
||||||
|
if angle < 0 {
|
||||||
|
clockWise = false
|
||||||
|
}
|
||||||
|
ra := (math.Abs(rx) + math.Abs(ry)) / 2
|
||||||
|
da := math.Acos(ra/(ra+0.125/scale)) * 2
|
||||||
|
//normalize
|
||||||
|
if !clockWise {
|
||||||
|
da = -da
|
||||||
|
}
|
||||||
|
angle = start + da
|
||||||
|
var curX, curY float64
|
||||||
|
for {
|
||||||
|
if (angle < end-da/4) != clockWise {
|
||||||
|
curX = x + math.Cos(end)*rx
|
||||||
|
curY = y + math.Sin(end)*ry
|
||||||
|
return raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)}
|
||||||
|
}
|
||||||
|
curX = x + math.Cos(angle)*rx
|
||||||
|
curY = y + math.Sin(angle)*ry
|
||||||
|
|
||||||
|
angle += da
|
||||||
|
adder.Add1(raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)})
|
||||||
|
}
|
||||||
|
return raster.Point{raster.Fix32(curX * 256), raster.Fix32(curY * 256)}
|
||||||
}
|
}
|
||||||
|
|
336
curves.go
336
curves.go
|
@ -1,336 +0,0 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
|
||||||
// created: 21/11/2010 by Laurent Le Goff
|
|
||||||
|
|
||||||
package draw2d
|
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
CurveRecursionLimit = 32
|
|
||||||
CurveCollinearityEpsilon = 1e-30
|
|
||||||
CurveAngleToleranceEpsilon = 0.01
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
The function has the following parameters:
|
|
||||||
approximationScale :
|
|
||||||
Eventually determines the approximation accuracy. In practice we need to transform points from the World coordinate system to the Screen one.
|
|
||||||
It always has some scaling coefficient.
|
|
||||||
The curves are usually processed in the World coordinates, while the approximation accuracy should be eventually in pixels.
|
|
||||||
Usually it looks as follows:
|
|
||||||
curved.approximationScale(transform.scale());
|
|
||||||
where transform is the affine matrix that includes all the transformations, including viewport and zoom.
|
|
||||||
angleTolerance :
|
|
||||||
You set it in radians.
|
|
||||||
The less this value is the more accurate will be the approximation at sharp turns.
|
|
||||||
But 0 means that we don't consider angle conditions at all.
|
|
||||||
cuspLimit :
|
|
||||||
An angle in radians.
|
|
||||||
If 0, only the real cusps will have bevel cuts.
|
|
||||||
If more than 0, it will restrict the sharpness.
|
|
||||||
The more this value is the less sharp turns will be cut.
|
|
||||||
Typically it should not exceed 10-15 degrees.
|
|
||||||
*/
|
|
||||||
func cubicBezier(v LineBuilder, x1, y1, x2, y2, x3, y3, x4, y4, approximationScale, angleTolerance, cuspLimit float64) {
|
|
||||||
cuspLimit = computeCuspLimit(cuspLimit)
|
|
||||||
distanceToleranceSquare := 0.5 / approximationScale
|
|
||||||
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
|
||||||
recursiveCubicBezier(v, x1, y1, x2, y2, x3, y3, x4, y4, 0, distanceToleranceSquare, angleTolerance, cuspLimit)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* see cubicBezier comments for approximationScale and angleTolerance definition
|
|
||||||
*/
|
|
||||||
func quadraticBezier(v LineBuilder, x1, y1, x2, y2, x3, y3, approximationScale, angleTolerance float64) {
|
|
||||||
distanceToleranceSquare := 0.5 / approximationScale
|
|
||||||
distanceToleranceSquare = distanceToleranceSquare * distanceToleranceSquare
|
|
||||||
|
|
||||||
recursiveQuadraticBezierBezier(v, x1, y1, x2, y2, x3, y3, 0, distanceToleranceSquare, angleTolerance)
|
|
||||||
}
|
|
||||||
|
|
||||||
func computeCuspLimit(v float64) (r float64) {
|
|
||||||
if v == 0.0 {
|
|
||||||
r = 0.0
|
|
||||||
} else {
|
|
||||||
r = math.Pi - v
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* http://www.antigrain.com/research/adaptive_bezier/index.html
|
|
||||||
*/
|
|
||||||
func recursiveQuadraticBezierBezier(v LineBuilder, x1, y1, x2, y2, x3, y3 float64, level int, distanceToleranceSquare, angleTolerance float64) {
|
|
||||||
if level > CurveRecursionLimit {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate all the mid-points of the line segments
|
|
||||||
//----------------------
|
|
||||||
x12 := (x1 + x2) / 2
|
|
||||||
y12 := (y1 + y2) / 2
|
|
||||||
x23 := (x2 + x3) / 2
|
|
||||||
y23 := (y2 + y3) / 2
|
|
||||||
x123 := (x12 + x23) / 2
|
|
||||||
y123 := (y12 + y23) / 2
|
|
||||||
|
|
||||||
dx := x3 - x1
|
|
||||||
dy := y3 - y1
|
|
||||||
d := math.Abs(((x2-x3)*dy - (y2-y3)*dx))
|
|
||||||
|
|
||||||
if d > CurveCollinearityEpsilon {
|
|
||||||
// Regular case
|
|
||||||
//-----------------
|
|
||||||
if d*d <= distanceToleranceSquare*(dx*dx+dy*dy) {
|
|
||||||
// If the curvature doesn't exceed the distanceTolerance value
|
|
||||||
// we tend to finish subdivisions.
|
|
||||||
//----------------------
|
|
||||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
|
||||||
v.LineTo(x123, y123)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Angle & Cusp Condition
|
|
||||||
//----------------------
|
|
||||||
da := math.Abs(math.Atan2(y3-y2, x3-x2) - math.Atan2(y2-y1, x2-x1))
|
|
||||||
if da >= math.Pi {
|
|
||||||
da = 2*math.Pi - da
|
|
||||||
}
|
|
||||||
|
|
||||||
if da < angleTolerance {
|
|
||||||
// Finally we can stop the recursion
|
|
||||||
//----------------------
|
|
||||||
v.LineTo(x123, y123)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Collinear case
|
|
||||||
//------------------
|
|
||||||
da := dx*dx + dy*dy
|
|
||||||
if da == 0 {
|
|
||||||
d = squareDistance(x1, y1, x2, y2)
|
|
||||||
} else {
|
|
||||||
d = ((x2-x1)*dx + (y2-y1)*dy) / da
|
|
||||||
if d > 0 && d < 1 {
|
|
||||||
// Simple collinear case, 1---2---3
|
|
||||||
// We can leave just two endpoints
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if d <= 0 {
|
|
||||||
d = squareDistance(x2, y2, x1, y1)
|
|
||||||
} else if d >= 1 {
|
|
||||||
d = squareDistance(x2, y2, x3, y3)
|
|
||||||
} else {
|
|
||||||
d = squareDistance(x2, y2, x1+d*dx, y1+d*dy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if d < distanceToleranceSquare {
|
|
||||||
v.LineTo(x2, y2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue subdivision
|
|
||||||
//----------------------
|
|
||||||
recursiveQuadraticBezierBezier(v, x1, y1, x12, y12, x123, y123, level+1, distanceToleranceSquare, angleTolerance)
|
|
||||||
recursiveQuadraticBezierBezier(v, x123, y123, x23, y23, x3, y3, level+1, distanceToleranceSquare, angleTolerance)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* http://www.antigrain.com/research/adaptive_bezier/index.html
|
|
||||||
*/
|
|
||||||
func recursiveCubicBezier(v LineBuilder, x1, y1, x2, y2, x3, y3, x4, y4 float64, level int, distanceToleranceSquare, angleTolerance, cuspLimit float64) {
|
|
||||||
if level > CurveRecursionLimit {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate all the mid-points of the line segments
|
|
||||||
//----------------------
|
|
||||||
x12 := (x1 + x2) / 2
|
|
||||||
y12 := (y1 + y2) / 2
|
|
||||||
x23 := (x2 + x3) / 2
|
|
||||||
y23 := (y2 + y3) / 2
|
|
||||||
x34 := (x3 + x4) / 2
|
|
||||||
y34 := (y3 + y4) / 2
|
|
||||||
x123 := (x12 + x23) / 2
|
|
||||||
y123 := (y12 + y23) / 2
|
|
||||||
x234 := (x23 + x34) / 2
|
|
||||||
y234 := (y23 + y34) / 2
|
|
||||||
x1234 := (x123 + x234) / 2
|
|
||||||
y1234 := (y123 + y234) / 2
|
|
||||||
|
|
||||||
// Try to approximate the full cubic curve by a single straight line
|
|
||||||
//------------------
|
|
||||||
dx := x4 - x1
|
|
||||||
dy := y4 - y1
|
|
||||||
|
|
||||||
d2 := math.Abs(((x2-x4)*dy - (y2-y4)*dx))
|
|
||||||
d3 := math.Abs(((x3-x4)*dy - (y3-y4)*dx))
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case d2 <= CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
|
|
||||||
// All collinear OR p1==p4
|
|
||||||
//----------------------
|
|
||||||
k := dx*dx + dy*dy
|
|
||||||
if k == 0 {
|
|
||||||
d2 = squareDistance(x1, y1, x2, y2)
|
|
||||||
d3 = squareDistance(x4, y4, x3, y3)
|
|
||||||
} else {
|
|
||||||
k = 1 / k
|
|
||||||
da1 := x2 - x1
|
|
||||||
da2 := y2 - y1
|
|
||||||
d2 = k * (da1*dx + da2*dy)
|
|
||||||
da1 = x3 - x1
|
|
||||||
da2 = y3 - y1
|
|
||||||
d3 = k * (da1*dx + da2*dy)
|
|
||||||
if d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1 {
|
|
||||||
// Simple collinear case, 1---2---3---4
|
|
||||||
// We can leave just two endpoints
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if d2 <= 0 {
|
|
||||||
d2 = squareDistance(x2, y2, x1, y1)
|
|
||||||
} else if d2 >= 1 {
|
|
||||||
d2 = squareDistance(x2, y2, x4, y4)
|
|
||||||
} else {
|
|
||||||
d2 = squareDistance(x2, y2, x1+d2*dx, y1+d2*dy)
|
|
||||||
}
|
|
||||||
|
|
||||||
if d3 <= 0 {
|
|
||||||
d3 = squareDistance(x3, y3, x1, y1)
|
|
||||||
} else if d3 >= 1 {
|
|
||||||
d3 = squareDistance(x3, y3, x4, y4)
|
|
||||||
} else {
|
|
||||||
d3 = squareDistance(x3, y3, x1+d3*dx, y1+d3*dy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if d2 > d3 {
|
|
||||||
if d2 < distanceToleranceSquare {
|
|
||||||
v.LineTo(x2, y2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if d3 < distanceToleranceSquare {
|
|
||||||
v.LineTo(x3, y3)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case d2 <= CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
|
|
||||||
// p1,p2,p4 are collinear, p3 is significant
|
|
||||||
//----------------------
|
|
||||||
if d3*d3 <= distanceToleranceSquare*(dx*dx+dy*dy) {
|
|
||||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
|
||||||
v.LineTo(x23, y23)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Angle Condition
|
|
||||||
//----------------------
|
|
||||||
da1 := math.Abs(math.Atan2(y4-y3, x4-x3) - math.Atan2(y3-y2, x3-x2))
|
|
||||||
if da1 >= math.Pi {
|
|
||||||
da1 = 2*math.Pi - da1
|
|
||||||
}
|
|
||||||
|
|
||||||
if da1 < angleTolerance {
|
|
||||||
v.LineTo(x2, y2)
|
|
||||||
v.LineTo(x3, y3)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if cuspLimit != 0.0 {
|
|
||||||
if da1 > cuspLimit {
|
|
||||||
v.LineTo(x3, y3)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case d2 > CurveCollinearityEpsilon && d3 <= CurveCollinearityEpsilon:
|
|
||||||
// p1,p3,p4 are collinear, p2 is significant
|
|
||||||
//----------------------
|
|
||||||
if d2*d2 <= distanceToleranceSquare*(dx*dx+dy*dy) {
|
|
||||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
|
||||||
v.LineTo(x23, y23)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Angle Condition
|
|
||||||
//----------------------
|
|
||||||
da1 := math.Abs(math.Atan2(y3-y2, x3-x2) - math.Atan2(y2-y1, x2-x1))
|
|
||||||
if da1 >= math.Pi {
|
|
||||||
da1 = 2*math.Pi - da1
|
|
||||||
}
|
|
||||||
|
|
||||||
if da1 < angleTolerance {
|
|
||||||
v.LineTo(x2, y2)
|
|
||||||
v.LineTo(x3, y3)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if cuspLimit != 0.0 {
|
|
||||||
if da1 > cuspLimit {
|
|
||||||
v.LineTo(x2, y2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
|
|
||||||
case d2 > CurveCollinearityEpsilon && d3 > CurveCollinearityEpsilon:
|
|
||||||
// Regular case
|
|
||||||
//-----------------
|
|
||||||
if (d2+d3)*(d2+d3) <= distanceToleranceSquare*(dx*dx+dy*dy) {
|
|
||||||
// If the curvature doesn't exceed the distanceTolerance value
|
|
||||||
// we tend to finish subdivisions.
|
|
||||||
//----------------------
|
|
||||||
if angleTolerance < CurveAngleToleranceEpsilon {
|
|
||||||
v.LineTo(x23, y23)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Angle & Cusp Condition
|
|
||||||
//----------------------
|
|
||||||
k := math.Atan2(y3-y2, x3-x2)
|
|
||||||
da1 := math.Abs(k - math.Atan2(y2-y1, x2-x1))
|
|
||||||
da2 := math.Abs(math.Atan2(y4-y3, x4-x3) - k)
|
|
||||||
if da1 >= math.Pi {
|
|
||||||
da1 = 2*math.Pi - da1
|
|
||||||
}
|
|
||||||
if da2 >= math.Pi {
|
|
||||||
da2 = 2*math.Pi - da2
|
|
||||||
}
|
|
||||||
|
|
||||||
if da1+da2 < angleTolerance {
|
|
||||||
// Finally we can stop the recursion
|
|
||||||
//----------------------
|
|
||||||
v.LineTo(x23, y23)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if cuspLimit != 0.0 {
|
|
||||||
if da1 > cuspLimit {
|
|
||||||
v.LineTo(x2, y2)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if da2 > cuspLimit {
|
|
||||||
v.LineTo(x3, y3)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Continue subdivision
|
|
||||||
//----------------------
|
|
||||||
recursiveCubicBezier(v, x1, y1, x12, y12, x123, y123, x1234, y1234, level+1, distanceToleranceSquare, angleTolerance, cuspLimit)
|
|
||||||
recursiveCubicBezier(v, x1234, y1234, x234, y234, x34, y34, x4, y4, level+1, distanceToleranceSquare, angleTolerance, cuspLimit)
|
|
||||||
|
|
||||||
}
|
|
|
@ -275,56 +275,64 @@ func (gc *ImageGraphicContext) paint(rasterizer *raster.Rasterizer, color color.
|
||||||
gc.Current.Path.Clear()
|
gc.Current.Path.Clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**** second method ****/
|
|
||||||
func (gc *ImageGraphicContext) Stroke(paths ...*path.Path) {
|
func (gc *ImageGraphicContext) Stroke(paths ...*path.Path) {
|
||||||
paths = append(paths, gc.Current.Path)
|
paths = append(paths, gc.Current.Path)
|
||||||
gc.strokeRasterizer.UseNonZeroWinding = true
|
gc.strokeRasterizer.UseNonZeroWinding = true
|
||||||
|
|
||||||
stroker := NewLineStroker(gc.Current.Cap, gc.Current.Join, NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.strokeRasterizer)))
|
stroker := path.NewLineStroker(gc.Current.Cap, gc.Current.Join, NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.strokeRasterizer)))
|
||||||
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
||||||
var pathConverter *PathConverter
|
|
||||||
|
var liner path.LineBuilder
|
||||||
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
||||||
dasher := NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
liner = path.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
||||||
pathConverter = NewPathConverter(dasher)
|
|
||||||
} else {
|
} else {
|
||||||
pathConverter = NewPathConverter(stroker)
|
liner = stroker
|
||||||
|
}
|
||||||
|
for _, p := range paths {
|
||||||
|
p.Flatten(liner, gc.Current.Tr.GetScale())
|
||||||
}
|
}
|
||||||
pathConverter.ApproximationScale = gc.Current.Tr.GetScale()
|
|
||||||
pathConverter.Convert(paths...)
|
|
||||||
|
|
||||||
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**** second method ****/
|
|
||||||
func (gc *ImageGraphicContext) Fill(paths ...*path.Path) {
|
func (gc *ImageGraphicContext) Fill(paths ...*path.Path) {
|
||||||
paths = append(paths, gc.Current.Path)
|
paths = append(paths, gc.Current.Path)
|
||||||
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
|
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
|
||||||
|
|
||||||
/**** first method ****/
|
/**** first method ****/
|
||||||
pathConverter := NewPathConverter(NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.fillRasterizer)))
|
flattener := NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.fillRasterizer))
|
||||||
pathConverter.ApproximationScale = gc.Current.Tr.GetScale()
|
for _, p := range paths {
|
||||||
pathConverter.Convert(paths...)
|
p.Flatten(flattener, gc.Current.Tr.GetScale())
|
||||||
|
}
|
||||||
|
|
||||||
gc.paint(gc.fillRasterizer, gc.Current.FillColor)
|
gc.paint(gc.fillRasterizer, gc.Current.FillColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* second method */
|
|
||||||
func (gc *ImageGraphicContext) FillStroke(paths ...*path.Path) {
|
func (gc *ImageGraphicContext) FillStroke(paths ...*path.Path) {
|
||||||
|
paths = append(paths, gc.Current.Path)
|
||||||
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
|
gc.fillRasterizer.UseNonZeroWinding = gc.Current.FillRule.UseNonZeroWinding()
|
||||||
gc.strokeRasterizer.UseNonZeroWinding = true
|
gc.strokeRasterizer.UseNonZeroWinding = true
|
||||||
|
|
||||||
filler := NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.fillRasterizer))
|
flattener := NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.fillRasterizer))
|
||||||
|
|
||||||
stroker := NewLineStroker(gc.Current.Cap, gc.Current.Join, NewVertexMatrixTransform(gc.Current.Tr, NewVertexAdder(gc.strokeRasterizer)))
|
stroker := path.NewLineStroker(gc.Current.Cap, gc.Current.Join, NewVertexMatrixTransform(gc.Current.Tr, path.NewFtLineBuilder(gc.strokeRasterizer)))
|
||||||
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
stroker.HalfLineWidth = gc.Current.LineWidth / 2
|
||||||
|
|
||||||
demux := NewLineBuilders(filler, stroker)
|
var liner path.LineBuilder
|
||||||
paths = append(paths, gc.Current.Path)
|
if gc.Current.Dash != nil && len(gc.Current.Dash) > 0 {
|
||||||
pathConverter := NewPathConverter(demux)
|
liner = path.NewDashConverter(gc.Current.Dash, gc.Current.DashOffset, stroker)
|
||||||
pathConverter.ApproximationScale = gc.Current.Tr.GetScale()
|
} else {
|
||||||
pathConverter.Convert(paths...)
|
liner = stroker
|
||||||
|
}
|
||||||
|
|
||||||
|
demux := path.NewLineBuilders(flattener, liner)
|
||||||
|
for _, p := range paths {
|
||||||
|
p.Flatten(demux, gc.Current.Tr.GetScale())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill
|
||||||
gc.paint(gc.fillRasterizer, gc.Current.FillColor)
|
gc.paint(gc.fillRasterizer, gc.Current.FillColor)
|
||||||
|
// Stroke
|
||||||
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
gc.paint(gc.strokeRasterizer, gc.Current.StrokeColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,25 +345,3 @@ func (f FillRule) UseNonZeroWinding() bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Cap) Convert() raster.Capper {
|
|
||||||
switch c {
|
|
||||||
case RoundCap:
|
|
||||||
return raster.RoundCapper
|
|
||||||
case ButtCap:
|
|
||||||
return raster.ButtCapper
|
|
||||||
case SquareCap:
|
|
||||||
return raster.SquareCapper
|
|
||||||
}
|
|
||||||
return raster.RoundCapper
|
|
||||||
}
|
|
||||||
|
|
||||||
func (j Join) Convert() raster.Joiner {
|
|
||||||
switch j {
|
|
||||||
case RoundJoin:
|
|
||||||
return raster.RoundJoiner
|
|
||||||
case BevelJoin:
|
|
||||||
return raster.BevelJoiner
|
|
||||||
}
|
|
||||||
return raster.RoundJoiner
|
|
||||||
}
|
|
4
gc.go
4
gc.go
|
@ -30,8 +30,8 @@ type GraphicContext interface {
|
||||||
SetFillColor(c color.Color)
|
SetFillColor(c color.Color)
|
||||||
SetFillRule(f FillRule)
|
SetFillRule(f FillRule)
|
||||||
SetLineWidth(lineWidth float64)
|
SetLineWidth(lineWidth float64)
|
||||||
SetLineCap(cap Cap)
|
SetLineCap(cap path.Cap)
|
||||||
SetLineJoin(join Join)
|
SetLineJoin(join path.Join)
|
||||||
SetLineDash(dash []float64, dashOffset float64)
|
SetLineDash(dash []float64, dashOffset float64)
|
||||||
SetFontSize(fontSize float64)
|
SetFontSize(fontSize float64)
|
||||||
GetFontSize() float64
|
GetFontSize() float64
|
||||||
|
|
14
math.go
14
math.go
|
@ -3,20 +3,6 @@
|
||||||
|
|
||||||
package draw2d
|
package draw2d
|
||||||
|
|
||||||
import (
|
|
||||||
"math"
|
|
||||||
)
|
|
||||||
|
|
||||||
func distance(x1, y1, x2, y2 float64) float64 {
|
|
||||||
dx := x2 - x1
|
|
||||||
dy := y2 - y1
|
|
||||||
return float64(math.Sqrt(dx*dx + dy*dy))
|
|
||||||
}
|
|
||||||
|
|
||||||
func vectorDistance(dx, dy float64) float64 {
|
|
||||||
return float64(math.Sqrt(dx*dx + dy*dy))
|
|
||||||
}
|
|
||||||
|
|
||||||
func squareDistance(x1, y1, x2, y2 float64) float64 {
|
func squareDistance(x1, y1, x2, y2 float64) float64 {
|
||||||
dx := x2 - x1
|
dx := x2 - x1
|
||||||
dy := y2 - y1
|
dy := y2 - y1
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
// created: 13/12/2010 by Laurent Le Goff
|
// created: 13/12/2010 by Laurent Le Goff
|
||||||
|
|
||||||
package draw2d
|
package path
|
||||||
|
|
||||||
type DashVertexConverter struct {
|
type DashVertexConverter struct {
|
||||||
next LineBuilder
|
next LineBuilder
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
// created: 21/11/2010 by Laurent Le Goff
|
// created: 06/12/2010 by Laurent Le Goff
|
||||||
|
|
||||||
package draw2d
|
package path
|
||||||
|
|
||||||
// LineBuilder defines drawing line methods
|
// LineBuilder defines drawing line methods
|
||||||
type LineBuilder interface {
|
type LineBuilder interface {
|
|
@ -1,36 +1,36 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
// created: 13/12/2010 by Laurent Le Goff
|
// created: 13/12/2010 by Laurent Le Goff
|
||||||
|
|
||||||
package draw2d
|
package path
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"code.google.com/p/freetype-go/freetype/raster"
|
"code.google.com/p/freetype-go/freetype/raster"
|
||||||
"github.com/llgcode/draw2d/path"
|
"github.com/llgcode/draw2d/curve"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VertexAdder struct {
|
type FtLineBuilder struct {
|
||||||
adder raster.Adder
|
adder raster.Adder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVertexAdder(adder raster.Adder) *VertexAdder {
|
func NewFtLineBuilder(adder raster.Adder) *FtLineBuilder {
|
||||||
return &VertexAdder{adder}
|
return &FtLineBuilder{adder}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vertexAdder *VertexAdder) MoveTo(x, y float64) {
|
func (FtLineBuilder *FtLineBuilder) MoveTo(x, y float64) {
|
||||||
vertexAdder.adder.Start(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
FtLineBuilder.adder.Start(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vertexAdder *VertexAdder) LineTo(x, y float64) {
|
func (FtLineBuilder *FtLineBuilder) LineTo(x, y float64) {
|
||||||
vertexAdder.adder.Add1(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
FtLineBuilder.adder.Add1(raster.Point{raster.Fix32(x * 256), raster.Fix32(y * 256)})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vertexAdder *VertexAdder) LineJoin() {
|
func (FtLineBuilder *FtLineBuilder) LineJoin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vertexAdder *VertexAdder) Close() {
|
func (FtLineBuilder *FtLineBuilder) Close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vertexAdder *VertexAdder) End() {
|
func (FtLineBuilder *FtLineBuilder) End() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PathAdder struct {
|
type PathAdder struct {
|
||||||
|
@ -43,29 +43,29 @@ func NewPathAdder(adder raster.Adder) *PathAdder {
|
||||||
return &PathAdder{adder, raster.Point{0, 0}, 1}
|
return &PathAdder{adder, raster.Point{0, 0}, 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pathAdder *PathAdder) Convert(paths ...*path.Path) {
|
func (pathAdder *PathAdder) Convert(paths ...*Path) {
|
||||||
for _, apath := range paths {
|
for _, apath := range paths {
|
||||||
j := 0
|
j := 0
|
||||||
for _, cmd := range apath.Components {
|
for _, cmd := range apath.Components {
|
||||||
switch cmd {
|
switch cmd {
|
||||||
case path.MoveToCmp:
|
case MoveToCmp:
|
||||||
pathAdder.firstPoint = raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)}
|
pathAdder.firstPoint = raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)}
|
||||||
pathAdder.adder.Start(pathAdder.firstPoint)
|
pathAdder.adder.Start(pathAdder.firstPoint)
|
||||||
j += 2
|
j += 2
|
||||||
case path.LineToCmp:
|
case LineToCmp:
|
||||||
pathAdder.adder.Add1(raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)})
|
pathAdder.adder.Add1(raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)})
|
||||||
j += 2
|
j += 2
|
||||||
case path.QuadCurveToCmp:
|
case QuadCurveToCmp:
|
||||||
pathAdder.adder.Add2(raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)}, raster.Point{raster.Fix32(apath.Points[j+2] * 256), raster.Fix32(apath.Points[j+3] * 256)})
|
pathAdder.adder.Add2(raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)}, raster.Point{raster.Fix32(apath.Points[j+2] * 256), raster.Fix32(apath.Points[j+3] * 256)})
|
||||||
j += 4
|
j += 4
|
||||||
case path.CubicCurveToCmp:
|
case CubicCurveToCmp:
|
||||||
pathAdder.adder.Add3(raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)}, raster.Point{raster.Fix32(apath.Points[j+2] * 256), raster.Fix32(apath.Points[j+3] * 256)}, raster.Point{raster.Fix32(apath.Points[j+4] * 256), raster.Fix32(apath.Points[j+5] * 256)})
|
pathAdder.adder.Add3(raster.Point{raster.Fix32(apath.Points[j] * 256), raster.Fix32(apath.Points[j+1] * 256)}, raster.Point{raster.Fix32(apath.Points[j+2] * 256), raster.Fix32(apath.Points[j+3] * 256)}, raster.Point{raster.Fix32(apath.Points[j+4] * 256), raster.Fix32(apath.Points[j+5] * 256)})
|
||||||
j += 6
|
j += 6
|
||||||
case path.ArcToCmp:
|
case ArcToCmp:
|
||||||
lastPoint := arcAdder(pathAdder.adder, apath.Points[j], apath.Points[j+1], apath.Points[j+2], apath.Points[j+3], apath.Points[j+4], apath.Points[j+5], pathAdder.ApproximationScale)
|
lastPoint := curve.TraceArcFt(pathAdder.adder, apath.Points[j], apath.Points[j+1], apath.Points[j+2], apath.Points[j+3], apath.Points[j+4], apath.Points[j+5], pathAdder.ApproximationScale)
|
||||||
pathAdder.adder.Add1(lastPoint)
|
pathAdder.adder.Add1(lastPoint)
|
||||||
j += 6
|
j += 6
|
||||||
case path.CloseCmp:
|
case CloseCmp:
|
||||||
pathAdder.adder.Add1(pathAdder.firstPoint)
|
pathAdder.adder.Add1(pathAdder.firstPoint)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,63 +0,0 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
|
||||||
// created: 06/12/2010 by Laurent Le Goff
|
|
||||||
|
|
||||||
package path
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/llgcode/draw2d/curve"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PathConverter struct {
|
|
||||||
converter LineBuilder
|
|
||||||
ApproximationScale float64
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPathConverter(converter LineBuilder) *PathConverter {
|
|
||||||
return &PathConverter{converter, 1, 0, 0, 0, 0}
|
|
||||||
}
|
|
||||||
|
|
||||||
// may not been in path instead put it in a troke package thing
|
|
||||||
func (c *PathConverter) Interpret(liner LineBuilder, scale float64, paths ...*Path) {
|
|
||||||
// First Point
|
|
||||||
var startX, startY float64 = 0, 0
|
|
||||||
// Current Point
|
|
||||||
var x, y float64 = 0, 0
|
|
||||||
for _, path := range paths {
|
|
||||||
i := 0
|
|
||||||
for _, cmd := range path.Components {
|
|
||||||
switch cmd {
|
|
||||||
case MoveToCmp:
|
|
||||||
x, y = path.Points[i], path.Points[i+1]
|
|
||||||
startX, startY = x, y
|
|
||||||
if i != 0 {
|
|
||||||
liner.End()
|
|
||||||
}
|
|
||||||
liner.MoveTo(x, y)
|
|
||||||
i += 2
|
|
||||||
case LineToCmp:
|
|
||||||
x, y = path.Points[i], path.Points[i+1]
|
|
||||||
liner.LineTo(x, y)
|
|
||||||
liner.LineJoin()
|
|
||||||
i += 2
|
|
||||||
case QuadCurveToCmp:
|
|
||||||
curve.TraceQuad(liner, path.Points[i-2:], 0.5)
|
|
||||||
x, y = path.Points[i+2], path.Points[i+3]
|
|
||||||
liner.LineTo(x, y)
|
|
||||||
i += 4
|
|
||||||
case CubicCurveToCmp:
|
|
||||||
curve.TraceCubic(liner, path.Points[i-2:], 0.5)
|
|
||||||
x, y = path.Points[i+4], path.Points[i+5]
|
|
||||||
liner.LineTo(x, y)
|
|
||||||
i += 6
|
|
||||||
case ArcToCmp:
|
|
||||||
x, y = arc(liner, path.Points[i], path.Points[i+1], path.Points[i+2], path.Points[i+3], path.Points[i+4], path.Points[i+5], scale)
|
|
||||||
liner.LineTo(x, y)
|
|
||||||
i += 6
|
|
||||||
case CloseCmp:
|
|
||||||
liner.LineTo(startX, startY)
|
|
||||||
liner.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
liner.End()
|
|
||||||
}
|
|
||||||
}
|
|
45
path/path.go
45
path/path.go
|
@ -6,6 +6,7 @@ package path
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/llgcode/draw2d/curve"
|
||||||
"math"
|
"math"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -174,3 +175,47 @@ func (p *Path) String() string {
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flatten convert curves in straight segments keeping join segements
|
||||||
|
func (path *Path) Flatten(liner LineBuilder, scale float64) {
|
||||||
|
// First Point
|
||||||
|
var startX, startY float64 = 0, 0
|
||||||
|
// Current Point
|
||||||
|
var x, y float64 = 0, 0
|
||||||
|
i := 0
|
||||||
|
for _, cmd := range path.Components {
|
||||||
|
switch cmd {
|
||||||
|
case MoveToCmp:
|
||||||
|
x, y = path.Points[i], path.Points[i+1]
|
||||||
|
startX, startY = x, y
|
||||||
|
if i != 0 {
|
||||||
|
liner.End()
|
||||||
|
}
|
||||||
|
liner.MoveTo(x, y)
|
||||||
|
i += 2
|
||||||
|
case LineToCmp:
|
||||||
|
x, y = path.Points[i], path.Points[i+1]
|
||||||
|
liner.LineTo(x, y)
|
||||||
|
liner.LineJoin()
|
||||||
|
i += 2
|
||||||
|
case QuadCurveToCmp:
|
||||||
|
curve.TraceQuad(liner, path.Points[i-2:], 0.5)
|
||||||
|
x, y = path.Points[i+2], path.Points[i+3]
|
||||||
|
liner.LineTo(x, y)
|
||||||
|
i += 4
|
||||||
|
case CubicCurveToCmp:
|
||||||
|
curve.TraceCubic(liner, path.Points[i-2:], 0.5)
|
||||||
|
x, y = path.Points[i+4], path.Points[i+5]
|
||||||
|
liner.LineTo(x, y)
|
||||||
|
i += 6
|
||||||
|
case ArcToCmp:
|
||||||
|
x, y = curve.TraceArc(liner, path.Points[i], path.Points[i+1], path.Points[i+2], path.Points[i+3], path.Points[i+4], path.Points[i+5], scale)
|
||||||
|
liner.LineTo(x, y)
|
||||||
|
i += 6
|
||||||
|
case CloseCmp:
|
||||||
|
liner.LineTo(startX, startY)
|
||||||
|
liner.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
liner.End()
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
// Copyright 2010 The draw2d Authors. All rights reserved.
|
// Copyright 2010 The draw2d Authors. All rights reserved.
|
||||||
// created: 13/12/2010 by Laurent Le Goff
|
// created: 13/12/2010 by Laurent Le Goff
|
||||||
|
|
||||||
package draw2d
|
package path
|
||||||
|
|
||||||
|
import (
|
||||||
|
"code.google.com/p/freetype-go/freetype/raster"
|
||||||
|
)
|
||||||
|
|
||||||
type Cap int
|
type Cap int
|
||||||
|
|
||||||
|
@ -11,6 +15,18 @@ const (
|
||||||
SquareCap
|
SquareCap
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (c Cap) Convert() raster.Capper {
|
||||||
|
switch c {
|
||||||
|
case RoundCap:
|
||||||
|
return raster.RoundCapper
|
||||||
|
case ButtCap:
|
||||||
|
return raster.ButtCapper
|
||||||
|
case SquareCap:
|
||||||
|
return raster.SquareCapper
|
||||||
|
}
|
||||||
|
return raster.RoundCapper
|
||||||
|
}
|
||||||
|
|
||||||
type Join int
|
type Join int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -19,6 +35,16 @@ const (
|
||||||
MiterJoin
|
MiterJoin
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func (j Join) Convert() raster.Joiner {
|
||||||
|
switch j {
|
||||||
|
case RoundJoin:
|
||||||
|
return raster.RoundJoiner
|
||||||
|
case BevelJoin:
|
||||||
|
return raster.BevelJoiner
|
||||||
|
}
|
||||||
|
return raster.RoundJoiner
|
||||||
|
}
|
||||||
|
|
||||||
type LineStroker struct {
|
type LineStroker struct {
|
||||||
Next LineBuilder
|
Next LineBuilder
|
||||||
HalfLineWidth float64
|
HalfLineWidth float64
|
13
path/utils.go
Normal file
13
path/utils.go
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
package path
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func distance(x1, y1, x2, y2 float64) float64 {
|
||||||
|
return vectorDistance(x2-x1, y2-y1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func vectorDistance(dx, dy float64) float64 {
|
||||||
|
return float64(math.Sqrt(dx*dx + dy*dy))
|
||||||
|
}
|
38
stack_gc.go
38
stack_gc.go
|
@ -24,8 +24,8 @@ type ContextStack struct {
|
||||||
StrokeColor color.Color
|
StrokeColor color.Color
|
||||||
FillColor color.Color
|
FillColor color.Color
|
||||||
FillRule FillRule
|
FillRule FillRule
|
||||||
Cap Cap
|
Cap path.Cap
|
||||||
Join Join
|
Join path.Join
|
||||||
FontSize float64
|
FontSize float64
|
||||||
FontData FontData
|
FontData FontData
|
||||||
|
|
||||||
|
@ -44,13 +44,13 @@ func NewStackGraphicContext() *StackGraphicContext {
|
||||||
gc := &StackGraphicContext{}
|
gc := &StackGraphicContext{}
|
||||||
gc.Current = new(ContextStack)
|
gc.Current = new(ContextStack)
|
||||||
gc.Current.Tr = NewIdentityMatrix()
|
gc.Current.Tr = NewIdentityMatrix()
|
||||||
gc.Current.Path = NewPathStorage()
|
gc.Current.Path = new(path.Path)
|
||||||
gc.Current.LineWidth = 1.0
|
gc.Current.LineWidth = 1.0
|
||||||
gc.Current.StrokeColor = image.Black
|
gc.Current.StrokeColor = image.Black
|
||||||
gc.Current.FillColor = image.White
|
gc.Current.FillColor = image.White
|
||||||
gc.Current.Cap = RoundCap
|
gc.Current.Cap = path.RoundCap
|
||||||
gc.Current.FillRule = FillRuleEvenOdd
|
gc.Current.FillRule = FillRuleEvenOdd
|
||||||
gc.Current.Join = RoundJoin
|
gc.Current.Join = path.RoundJoin
|
||||||
gc.Current.FontSize = 10
|
gc.Current.FontSize = 10
|
||||||
gc.Current.FontData = defaultFontData
|
gc.Current.FontData = defaultFontData
|
||||||
return gc
|
return gc
|
||||||
|
@ -96,12 +96,12 @@ func (gc *StackGraphicContext) SetLineWidth(LineWidth float64) {
|
||||||
gc.Current.LineWidth = LineWidth
|
gc.Current.LineWidth = LineWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetLineCap(Cap Cap) {
|
func (gc *StackGraphicContext) SetLineCap(cap path.Cap) {
|
||||||
gc.Current.Cap = Cap
|
gc.Current.Cap = cap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetLineJoin(Join Join) {
|
func (gc *StackGraphicContext) SetLineJoin(join path.Join) {
|
||||||
gc.Current.Join = Join
|
gc.Current.Join = join
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) SetLineDash(Dash []float64, DashOffset float64) {
|
func (gc *StackGraphicContext) SetLineDash(Dash []float64, DashOffset float64) {
|
||||||
|
@ -141,42 +141,22 @@ func (gc *StackGraphicContext) MoveTo(x, y float64) {
|
||||||
gc.Current.Path.MoveTo(x, y)
|
gc.Current.Path.MoveTo(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) RMoveTo(dx, dy float64) {
|
|
||||||
gc.Current.Path.RMoveTo(dx, dy)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gc *StackGraphicContext) LineTo(x, y float64) {
|
func (gc *StackGraphicContext) LineTo(x, y float64) {
|
||||||
gc.Current.Path.LineTo(x, y)
|
gc.Current.Path.LineTo(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) RLineTo(dx, dy float64) {
|
|
||||||
gc.Current.Path.RLineTo(dx, dy)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gc *StackGraphicContext) QuadCurveTo(cx, cy, x, y float64) {
|
func (gc *StackGraphicContext) QuadCurveTo(cx, cy, x, y float64) {
|
||||||
gc.Current.Path.QuadCurveTo(cx, cy, x, y)
|
gc.Current.Path.QuadCurveTo(cx, cy, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) RQuadCurveTo(dcx, dcy, dx, dy float64) {
|
|
||||||
gc.Current.Path.RQuadCurveTo(dcx, dcy, dx, dy)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gc *StackGraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) {
|
func (gc *StackGraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) {
|
||||||
gc.Current.Path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y)
|
gc.Current.Path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy float64) {
|
|
||||||
gc.Current.Path.RCubicCurveTo(dcx1, dcy1, dcx2, dcy2, dx, dy)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gc *StackGraphicContext) ArcTo(cx, cy, rx, ry, startAngle, angle float64) {
|
func (gc *StackGraphicContext) ArcTo(cx, cy, rx, ry, startAngle, angle float64) {
|
||||||
gc.Current.Path.ArcTo(cx, cy, rx, ry, startAngle, angle)
|
gc.Current.Path.ArcTo(cx, cy, rx, ry, startAngle, angle)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gc *StackGraphicContext) RArcTo(dcx, dcy, rx, ry, startAngle, angle float64) {
|
|
||||||
gc.Current.Path.RArcTo(dcx, dcy, rx, ry, startAngle, angle)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gc *StackGraphicContext) Close() {
|
func (gc *StackGraphicContext) Close() {
|
||||||
gc.Current.Path.Close()
|
gc.Current.Path.Close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"code.google.com/p/freetype-go/freetype/raster"
|
"code.google.com/p/freetype-go/freetype/raster"
|
||||||
|
"github.com/llgcode/draw2d/path"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MatrixTransform [6]float64
|
type MatrixTransform [6]float64
|
||||||
|
@ -254,10 +255,10 @@ func fequals(float1, float2 float64) bool {
|
||||||
// this VertexConverter apply the Matrix transformation tr
|
// this VertexConverter apply the Matrix transformation tr
|
||||||
type VertexMatrixTransform struct {
|
type VertexMatrixTransform struct {
|
||||||
tr MatrixTransform
|
tr MatrixTransform
|
||||||
Next LineBuilder
|
Next path.LineBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewVertexMatrixTransform(tr MatrixTransform, converter LineBuilder) *VertexMatrixTransform {
|
func NewVertexMatrixTransform(tr MatrixTransform, converter path.LineBuilder) *VertexMatrixTransform {
|
||||||
return &VertexMatrixTransform{tr, converter}
|
return &VertexMatrixTransform{tr, converter}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue