diff --git a/example/main.go b/example/main.go index d609922..c2e317f 100644 --- a/example/main.go +++ b/example/main.go @@ -30,6 +30,11 @@ const ( PlotTypeMerged ) +type Superplot struct { + Plot *plot.Plot + NumElements int +} + var ( openBracket = "[" closeBracket = "]" @@ -119,7 +124,7 @@ func convertToPlotterXYs(intervals []*interval.Interval) plotter.XYs { return pxys } -func alignPlots(plotItems []*plot.Plot) *vgimg.Canvas { +func alignPlots(plotItems []*Superplot) *vgimg.Canvas { rows, cols := len(plotItems), 1 plots := make([][]*plot.Plot, rows) for j := 0; j < rows; j++ { @@ -128,10 +133,10 @@ func alignPlots(plotItems []*plot.Plot) *vgimg.Canvas { p := plotItems[j] // make sure the horizontal scales match - p.X.Min = MinX - p.X.Max = MaxX + p.Plot.X.Min = MinX + p.Plot.X.Max = MaxX - plots[j][i] = p + plots[j][i] = p.Plot } } @@ -171,7 +176,7 @@ func createFileFromCanvas(path string, img *vgimg.Canvas) error { return nil } -func createPlot(title string, xys plotter.XYs, plotType PlotType) (*plot.Plot, error) { +func createPlot(title string, xys plotter.XYs, plotType PlotType) (*Superplot, error) { p, err := plot.New() if err != nil { return nil, fmt.Errorf("could not create plot: %v", err) @@ -181,15 +186,15 @@ func createPlot(title string, xys plotter.XYs, plotType PlotType) (*plot.Plot, e p.Add(plotter.NewGrid()) p.Title.Text = title p.HideY() - // p.X.Label.Text = "values" p.X.Padding = vg.Length(5) p.Y.Padding = vg.Length(20) + plotIntervals(p, plotType, xys) - return p, nil + return &Superplot{p, xys.Len()}, nil } func plotData(path string, intervals interval.Intervals) error { - plots := []*plot.Plot{} + plots := []*Superplot{} // create Intervals plot xysIntervals := convertToPlotterXYs(intervals.Get()) diff --git a/find.go b/find.go index 424c0c2..c7092f1 100644 --- a/find.go +++ b/find.go @@ -1,5 +1,7 @@ package interval +import "fmt" + func (intvls *intervals) FindIntervalsForValue(value int) []*Interval { // sort intervals (if necessary) intvls.Sort() @@ -7,7 +9,11 @@ func (intvls *intervals) FindIntervalsForValue(value int) []*Interval { var matches []*Interval for _, intvl := range intvls.Intervals { // convert if necessary exclusive low/high values into inclusive ones - low, high := intvls.getInclusives(intvl.Low, intvl.High) + low, high, err := intvls.getInclusives(intvl.Low, intvl.High) + if err != nil { + fmt.Printf("FindIntervalsForValue - unable to get inclusives: %v", err) + continue + } // check if we have to stop searching if low > value { diff --git a/gaps.go b/gaps.go index 35cbccd..03ada6c 100644 --- a/gaps.go +++ b/gaps.go @@ -1,5 +1,7 @@ package interval +import "fmt" + func (intvls *intervals) HasGaps() bool { intvls.Gaps() if intvls.GapsList != nil && len(intvls.GapsList) > 0 { @@ -27,7 +29,11 @@ func (intvls *intervals) calculateGaps() []*Interval { gapThreshold := intvls.MinLow for _, intvl := range intvls.Intervals { // convert if necessary exclusive low/high values into inclusive ones - low, high := intvls.getInclusives(intvl.Low, intvl.High) + low, high, err := intvls.getInclusives(intvl.Low, intvl.High) + if err != nil { + fmt.Printf("calculateGaps - unable to get inclusives: %v", err) + continue + } // if the current Low is higher than the last maximal High, means that there is a gap so we add this gap to the list if low > gapThreshold { diff --git a/inclusives.go b/inclusives.go index 340fdb0..7a7fea4 100644 --- a/inclusives.go +++ b/inclusives.go @@ -1,15 +1,22 @@ package interval -func (intvls *intervals) getInclusives(intervalLow, intervalHigh int) (int, int) { +import ( + "fmt" +) + +func (intvls *intervals) getInclusives(intervalLow, intervalHigh int) (int, int, error) { low := intvls.getInclusiveLow(intervalLow) high := intvls.getInclusiveHigh(intervalHigh) - if high < low { - high = low - } + + // if we get an incoherent result it's because it's invalid, for example in this case: + // (low,high)=(0,1) --> if we add 1 to the Low and substract 1 to the High ends with (1,0) which is not valid if low > high { - low = high + return 0, 0, fmt.Errorf("low (%v) can not be bigger than high (%v)", low, high) } - return low, high + if high < low { + return 0, 0, fmt.Errorf("high (%v) can not be smaller than low (%v)", high, low) + } + return low, high, nil } func (intvls *intervals) getInclusiveLow(value int) int { diff --git a/merge.go b/merge.go index bfc3b01..2e2a4eb 100644 --- a/merge.go +++ b/merge.go @@ -1,5 +1,7 @@ package interval +import "github.com/labstack/gommon/log" + func (intvls *intervals) Merge() []*Interval { if intvls.MergeList == nil { intvls.MergeList = intvls.calculateMerged() @@ -18,14 +20,20 @@ func (intvls *intervals) calculateMerged() []*Interval { var currentMinLow int var currentMaxHigh int - for i, intvl := range intvls.Intervals { + firstInitDone := false + for _, intvl := range intvls.Intervals { // convert if necessary exclusive low/high values into inclusive ones - low, high := intvls.getInclusives(intvl.Low, intvl.High) + low, high, err := intvls.getInclusives(intvl.Low, intvl.High) + if err != nil { + log.Errorf("calculateMerged - unable to get inclusives: %v", err) + continue + } // in the first iteration it's for sure that don't exists merge, we just initialize variables - if i == 0 { + if !firstInitDone { currentMinLow = low currentMaxHigh = high + firstInitDone = true continue } diff --git a/overlap.go b/overlap.go index 1db2b8b..9376bc1 100644 --- a/overlap.go +++ b/overlap.go @@ -1,6 +1,9 @@ package interval -import "math" +import ( + "fmt" + "math" +) func (intvls *intervals) HasOverlapped() bool { intvls.Overlapped() @@ -28,12 +31,17 @@ func (intvls *intervals) calculateOverlapped() []*Interval { lastMinLow := math.MaxInt64 lastMaxHigh := math.MinInt64 - for i, intvl := range intvls.Intervals { + firstInitDone := false + for _, intvl := range intvls.Intervals { // convert if necessary exclusive low/high values into inclusive ones - low, high := intvls.getInclusives(intvl.Low, intvl.High) + low, high, err := intvls.getInclusives(intvl.Low, intvl.High) + if err != nil { + fmt.Printf("calculateOverlapped - unable to get inclusives: %v", err) + continue + } // for the first iteration make no sense those operations - if i > 0 { + if firstInitDone { // check if the front or back side of the current segment overlaps with the previous one lowInBetween := isLowInBetweenInclusive(lastMinLow, lastMaxHigh, low, high) highInBetween := isHighInBetweenInclusive(lastMinLow, lastMaxHigh, low, high) @@ -51,6 +59,7 @@ func (intvls *intervals) calculateOverlapped() []*Interval { if high > lastMaxHigh { lastMaxHigh = high } + firstInitDone = true } return list }