stuff.
This commit is contained in:
parent
5936b89e89
commit
04a4edcb46
49
_examples/overlap/main.go
Normal file
49
_examples/overlap/main.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
chart "github.com/wcharczuk/go-chart"
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
)
|
||||
|
||||
func conditionalColor(condition bool, trueColor drawing.Color, falseColor drawing.Color) drawing.Color {
|
||||
if condition {
|
||||
return trueColor
|
||||
}
|
||||
return falseColor
|
||||
}
|
||||
|
||||
func drawChart(res http.ResponseWriter, req *http.Request) {
|
||||
r, _ := chart.PNG(1024, 1024)
|
||||
|
||||
b0 := chart.Box{Left: 100, Top: 100, Right: 400, Bottom: 200}
|
||||
b1 := chart.Box{Left: 500, Top: 100, Right: 900, Bottom: 200}
|
||||
b0r := b0.Corners().Rotate(45).Shift(0, 200)
|
||||
|
||||
chart.Draw.Box(r, b0, chart.Style{
|
||||
StrokeColor: drawing.ColorRed,
|
||||
StrokeWidth: 2,
|
||||
FillColor: conditionalColor(b0.Corners().Overlaps(b1.Corners()), drawing.ColorRed, drawing.ColorTransparent),
|
||||
})
|
||||
|
||||
chart.Draw.Box(r, b1, chart.Style{
|
||||
StrokeColor: drawing.ColorBlue,
|
||||
StrokeWidth: 2,
|
||||
FillColor: conditionalColor(b1.Corners().Overlaps(b0.Corners()), drawing.ColorRed, drawing.ColorTransparent),
|
||||
})
|
||||
|
||||
chart.Draw.Box2d(r, b0r, chart.Style{
|
||||
StrokeColor: drawing.ColorGreen,
|
||||
StrokeWidth: 2,
|
||||
FillColor: conditionalColor(b0r.Overlaps(b0.Corners()), drawing.ColorRed, drawing.ColorTransparent),
|
||||
})
|
||||
|
||||
res.Header().Set("Content-Type", "image/png")
|
||||
r.Save(res)
|
||||
}
|
||||
|
||||
func main() {
|
||||
http.HandleFunc("/", drawChart)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
}
|
51
box_2d.go
51
box_2d.go
|
@ -99,51 +99,22 @@ func (bc Box2d) Equals(other Box2d) bool {
|
|||
|
||||
// Overlaps returns if two boxes overlap.
|
||||
func (bc Box2d) Overlaps(other Box2d) bool {
|
||||
for _, polygon := range []Box2d{bc, other} {
|
||||
points := polygon.Points()
|
||||
for i1 := 0; i1 < len(points); i1++ {
|
||||
i2 := (i1 + 1) % len(points)
|
||||
pa := bc.Points()
|
||||
pb := other.Points()
|
||||
for i := 0; i < 4; i++ {
|
||||
for j := 0; j < 4; j++ {
|
||||
pa0 := pa[i]
|
||||
pa1 := pa[(i+1)%4]
|
||||
|
||||
p1 := polygon.Points()[i1]
|
||||
p2 := polygon.Points()[i2]
|
||||
pb0 := pb[j]
|
||||
pb1 := pb[(j+1)%4]
|
||||
|
||||
normal := Point{X: p2.Y - p1.Y, Y: p1.X - p2.X}
|
||||
|
||||
minA := math.MaxFloat64
|
||||
maxA := -math.MaxFloat64
|
||||
|
||||
for _, p := range bc.Points() {
|
||||
projected := normal.X*p.X + normal.Y*p.Y
|
||||
|
||||
if projected < minA {
|
||||
minA = projected
|
||||
}
|
||||
if projected > maxA {
|
||||
maxA = projected
|
||||
}
|
||||
}
|
||||
|
||||
minB := math.MaxFloat64
|
||||
maxB := -math.MaxFloat64
|
||||
|
||||
for _, p := range other.Points() {
|
||||
projected := normal.X*p.X + normal.Y*p.Y
|
||||
|
||||
if projected < minB {
|
||||
minB = projected
|
||||
}
|
||||
if projected > maxB {
|
||||
maxB = projected
|
||||
}
|
||||
}
|
||||
|
||||
if maxA < minB || maxB < minA {
|
||||
return false
|
||||
if util.Math.LinesIntersect(pa0.X, pa0.Y, pa1.X, pa1.Y, pb0.X, pb0.Y, pb1.X, pb1.Y) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
return false
|
||||
}
|
||||
|
||||
func (bc Box2d) String() string {
|
||||
|
|
|
@ -35,43 +35,50 @@ type CandlestickSeries struct {
|
|||
Style Style
|
||||
YAxis YAxisType
|
||||
|
||||
XValues []time.Time
|
||||
YValues []float64
|
||||
// CandleValues will be used in place of creating them from the `InnerSeries`.
|
||||
CandleValues []CandleValue
|
||||
|
||||
// InnerSeries is used if the `CandleValues` are not set.
|
||||
InnerSeries ValuesProvider
|
||||
}
|
||||
|
||||
// GetName implements Series.GetName.
|
||||
func (cs CandlestickSeries) GetName() string {
|
||||
func (cs *CandlestickSeries) GetName() string {
|
||||
return cs.Name
|
||||
}
|
||||
|
||||
// GetStyle implements Series.GetStyle.
|
||||
func (cs CandlestickSeries) GetStyle() Style {
|
||||
func (cs *CandlestickSeries) GetStyle() Style {
|
||||
return cs.Style
|
||||
}
|
||||
|
||||
// GetYAxis returns which yaxis the series is mapped to.
|
||||
func (cs CandlestickSeries) GetYAxis() YAxisType {
|
||||
func (cs *CandlestickSeries) GetYAxis() YAxisType {
|
||||
return cs.YAxis
|
||||
}
|
||||
|
||||
// Len returns the length of the series.
|
||||
func (cs CandlestickSeries) Len() int {
|
||||
return util.Math.MinInt(len(cs.XValues), len(cs.YValues))
|
||||
func (cs *CandlestickSeries) Len() int {
|
||||
return len(cs.GetCandleValues())
|
||||
}
|
||||
|
||||
// GetValues returns the values at a given index.
|
||||
func (cs CandlestickSeries) GetValues(index int) (float64, float64) {
|
||||
return util.Time.ToFloat64(cs.XValues[index]), cs.YValues[index]
|
||||
// GetBoundedValues returns the bounded values at a given index.
|
||||
func (cs *CandlestickSeries) GetBoundedValues(index int) (x, y0, y1 float64) {
|
||||
value := cs.GetCandleValues()[index]
|
||||
return util.Time.ToFloat64(value.Timestamp), value.Low, value.High
|
||||
}
|
||||
|
||||
// GetRawValues returns the values at a given index.
|
||||
func (cs CandlestickSeries) GetRawValues(index int) (time.Time, float64) {
|
||||
return cs.XValues[index], cs.YValues[index]
|
||||
// GetCandleValues returns the candle values.
|
||||
func (cs CandlestickSeries) GetCandleValues() []CandleValue {
|
||||
if cs.CandleValues == nil {
|
||||
cs.CandleValues = cs.GenerateCandleValues()
|
||||
}
|
||||
return cs.CandleValues
|
||||
}
|
||||
|
||||
// CandleValues returns the candlestick values for each day represented by the inner series.
|
||||
func (cs CandlestickSeries) CandleValues() []CandleValue {
|
||||
totalValues := cs.Len()
|
||||
// GenerateCandleValues returns the candlestick values for each day represented by the inner series.
|
||||
func (cs CandlestickSeries) GenerateCandleValues() []CandleValue {
|
||||
totalValues := cs.InnerSeries.Len()
|
||||
if totalValues == 0 {
|
||||
return nil
|
||||
}
|
||||
|
@ -81,9 +88,10 @@ func (cs CandlestickSeries) CandleValues() []CandleValue {
|
|||
var year, month, day int
|
||||
|
||||
var t time.Time
|
||||
var lv, v float64
|
||||
var tv, lv, v float64
|
||||
|
||||
t, v = cs.GetRawValues(0)
|
||||
tv, v = cs.InnerSeries.GetValues(0)
|
||||
t = util.Time.FromFloat64(tv)
|
||||
year, month, day = t.Year(), int(t.Month()), t.Day()
|
||||
|
||||
lastYear, lastMonth, lastDay = year, month, day
|
||||
|
@ -97,7 +105,8 @@ func (cs CandlestickSeries) CandleValues() []CandleValue {
|
|||
lv = v
|
||||
|
||||
for i := 1; i < totalValues; i++ {
|
||||
t, v = cs.GetRawValues(i)
|
||||
tv, v = cs.InnerSeries.GetValues(0)
|
||||
t = util.Time.FromFloat64(tv)
|
||||
year, month, day = t.Year(), int(t.Month()), t.Day()
|
||||
|
||||
// if we've transitioned to a new day or we're on the last value
|
||||
|
@ -137,11 +146,8 @@ func (cs CandlestickSeries) Render(r Renderer, canvasBox Box, xrange, yrange Ran
|
|||
|
||||
// Validate validates the series.
|
||||
func (cs CandlestickSeries) Validate() error {
|
||||
if cs.XValues == nil {
|
||||
return fmt.Errorf("candlestick series requires `XValues` to be set")
|
||||
}
|
||||
if cs.YValues == nil {
|
||||
return fmt.Errorf("candlestick series requires `YValues` to be set")
|
||||
if cs.CandleValues == nil && cs.InnerSeries == nil {
|
||||
return fmt.Errorf("candlestick series requires either `CandleValues` or `InnerSeries` to be set")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -40,11 +40,13 @@ func TestCandlestickSeriesCandleValues(t *testing.T) {
|
|||
|
||||
xdata, ydata := generateDummyStockData()
|
||||
|
||||
candleSeries := CandlestickSeries{
|
||||
XValues: xdata,
|
||||
YValues: ydata,
|
||||
candleSeries := &CandlestickSeries{
|
||||
InnerSeries: TimeSeries{
|
||||
XValues: xdata,
|
||||
YValues: ydata,
|
||||
},
|
||||
}
|
||||
|
||||
values := candleSeries.CandleValues()
|
||||
values := candleSeries.GetCandleValues()
|
||||
assert.Len(values, 43) // should be 60 days per the generator.
|
||||
}
|
||||
|
|
2
draw.go
2
draw.go
|
@ -173,7 +173,7 @@ func (d draw) CandlestickSeries(r Renderer, canvasBox Box, xrange, yrange Range,
|
|||
return
|
||||
}
|
||||
|
||||
candleValues := cs.CandleValues()
|
||||
candleValues := cs.GetCandleValues()
|
||||
|
||||
cb := canvasBox.Bottom
|
||||
cl := canvasBox.Left
|
||||
|
|
14
util/math.go
14
util/math.go
|
@ -251,3 +251,17 @@ func (m mathUtil) RotateCoordinate(cx, cy, x, y int, thetaRadians float64) (rx,
|
|||
ry = int(rotatedY) + cy
|
||||
return
|
||||
}
|
||||
|
||||
func (m mathUtil) LinesIntersect(l0x0, l0y0, l0x1, l0y1, l1x0, l1y0, l1x1, l1y1 float64) bool {
|
||||
var s0x, s0y, s1x, s1y float64
|
||||
s0x = l0x1 - l0x0
|
||||
s0y = l0y1 - l0y0
|
||||
s1x = l1x1 - l1x0
|
||||
s1y = l1y1 - l1y0
|
||||
|
||||
var s, t float64
|
||||
s = (-s0y*(l0x0-l1x0) + s0x*(l0y0-l1y0)) / (-s1x*s0y + s0x*s1y)
|
||||
t = (s1x*(l0y0-l1y0) - s1y*(l0x0-l1x0)) / (-s1x*s0y + s0x*s1y)
|
||||
|
||||
return s >= 0 && s <= 1 && t >= 0 && t <= 1
|
||||
}
|
||||
|
|
|
@ -182,3 +182,27 @@ func TestRotateCoordinate45(t *testing.T) {
|
|||
assert.Equal(7, rx)
|
||||
assert.Equal(7, ry)
|
||||
}
|
||||
|
||||
func TestLinesIntersect(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
p0x := 1.0
|
||||
p0y := 1.0
|
||||
|
||||
p1x := 3.0
|
||||
p1y := 1.0
|
||||
|
||||
p2x := 2.0
|
||||
p2y := 2.0
|
||||
|
||||
p3x := 2.0
|
||||
p3y := 0.0
|
||||
|
||||
p4x := 2.0
|
||||
p4y := 2.0
|
||||
p5x := 3.0
|
||||
p5y := 2.0
|
||||
|
||||
assert.True(Math.LinesIntersect(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y))
|
||||
assert.False(Math.LinesIntersect(p0x, p0y, p1x, p1y, p4x, p4y, p5x, p5y))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user