private final List<Point2D> getPointsFrom( GraphSettings gInfo, Graph g, Year startYear, int nYears, int bottom) { // index into our data values for this particular year int idx = startYear.diff(g.graph.getStart().add(g.xoffset)); // make a list of points // this is ok, because we know points are continuous List<Point2D> points = new ArrayList<Point2D>(nYears); // the year the plot starts Year plotStartYear = gInfo.getDrawBounds().getStart(); // the adjusted range of this graph Range graphRange = g.getRange(); int yearWidth = gInfo.getYearWidth(); float unitScale = gInfo.getHundredUnitHeight() / 100.0f; for (int i = 0; i <= nYears; i++) { // skip points that don't exist if (!graphRange.contains(startYear.add(i))) continue; int value = g.graph.getRingWidthData().get(idx + i).intValue(); int x = getXValue(g, plotStartYear, yearWidth, idx + i); int y = getYValue(g, unitScale, value, bottom); points.add(new Point2D.Float(x, y)); } return points; }
private final List<Point2D> getPointsFrom( GraphSettings gInfo, Graph g, Year startYear, int nYears, int bottom) { // make a list of points // this is ok, because we know points are continuous List<Point2D> points = new ArrayList<Point2D>(nYears); int yearWidth = gInfo.getYearWidth(); float unitScale = gInfo.getHundredUnitHeight() / 100.0f; List<? extends Number> data = g.graph.getRingWidthData(); double[] dataDbl = new double[data.size()]; for (int i = 0; i < data.size(); i++) { Integer intval = (Integer) data.get(i); dataDbl[i] = (double) intval; } int x = yearWidth * (g.graph.getStart().diff(gInfo.getDrawBounds().getStart()) + g.xoffset); // int value1 = yTransform((float) stats.getMean()); int value1 = yTransform((float) baselineY); int meanYVal = bottom - (int) (value1 * unitScale) - (int) (g.yoffset * unitScale); try { // x-position int x1 = x; int x2 = yearWidth * (g.graph.getStart().diff(gInfo.getDrawBounds().getStart()) + g.xoffset + g.graph.getRingWidthData().size()); points.add(new Point2D.Float(x1, meanYVal)); points.add(new Point2D.Float(x2, meanYVal)); } catch (ClassCastException cce) { } return points; }
public boolean contact(GraphSettings gInfo, Graph g, Point p, int bottom) { // snap to year int yearWidth = gInfo.getYearWidth(); int firstYearIdx = (p.x / yearWidth) - 1; int nYears = 3; // Check three years' worth of data: the year prior to and after the year the mouse is inside Year startYear = gInfo.getDrawBounds().getStart().add(firstYearIdx); List<Point2D> points = this.getPointsFrom(gInfo, g, startYear, nYears, bottom); int nLines = points.size() - 1; for (int i = 0; i < nLines; i++) { Line2D line = new Line2D.Float(points.get(i), points.get(i + 1)); int distance = Math.round((float) line.ptSegDist(p)); if (distance <= NEAR) return true; } return false; }
public void draw( GraphSettings gInfo, Graphics2D g2, int bottom, Graph g, int thickness, int xscroll) { // cache yearsize, we use this a lot int yearWidth = gInfo.getYearWidth(); // the size of a year, in pixels float unitScale = gInfo.getHundredUnitHeight() / 100.0f; // the size of 1 "unit" in pixels. // set pen boolean dotted = (gInfo.isDottedIndexes() && (g.graph instanceof Index)); g2.setStroke(makeStroke(thickness, dotted)); // left/right int l = g2.getClipBounds().x; int r = l + g2.getClipBounds().width; // Image img1 = // Toolkit.getDefaultToolkit().getImage("/home/pwb48/dev/java5/tellervo-desktop/src/main/resources/Icons/256x256/tellervo-application.png"); // g2.drawImage(img1, 10, 10, null); // baseline if (gInfo.isShowBaselines()) { int y = bottom - (int) (g.yoffset * unitScale); g2.drawLine(xscroll, y, xscroll + 10 * yearWidth, y); // 1 decade wide -- ok? } // hundred percent line if (gInfo.isShowHundredpercentlines() && (g.graph instanceof Sample) && ((Sample) g.graph).isIndexed()) { Color oldcolor = g2.getColor(); g2.setColor(ColorUtils.blend(oldcolor, gInfo.getBackgroundColor())); // x is 0 if we aren't drawing graph names... // x is the pixel at the end of the empty range if we are. int x = (gInfo.isShowGraphNames()) ? yearWidth * (gInfo.getEmptyBounds().getSpan() - 1) : 0; int y = bottom - (int) (yTransform(1000 * g.scale) * unitScale) - (int) (g.yoffset * unitScale); g2.drawLine((x > xscroll) ? x : xscroll, y, r, y); g2.setColor(oldcolor); } // no data? stop. if (g.graph.getRingWidthData().isEmpty()) return; // compare g.getClipBounds() to [x,0]..[x+yearSize*data.size(),bottom] tempRect.x = yearWidth * (g.graph.getStart().diff(gInfo.getDrawBounds().getStart()) + g.xoffset); // REDUNDANT! see x later tempRect.y = 0; // - g.yoffset, IF you're sure there are no negative values (but there are) tempRect.width = yearWidth * (g.graph.getRingWidthData().size() - 1); tempRect.height = bottom; // TODO: compute top/bottom as min/max? // REFACTOR: will this be obsolete with the start/end stuff below? if (!tempRect.intersects(g2.getClipBounds())) { // skip this graph, it's off the screen return; } // compute sapwood int sapwoodIndex, sapwoodCount = 0; if (g.graph instanceof Sample) { Sample sample = (Sample) g.graph; if (sample.meta().hasSapwood()) sapwoodCount = sample.meta().getNumberOfSapwoodRings(); } sapwoodIndex = g.graph.getRingWidthData().size() - sapwoodCount + 1; // my path GeneralPath p = new GeneralPath(); // x-position int x = yearWidth * (g.graph.getStart().diff(gInfo.getDrawBounds().getStart()) + g.xoffset); // move to the first point -- THIS IS NOT REALLY A SPECIAL CASE! int value; try { value = ((Number) g.graph.getRingWidthData().get(0)).intValue(); value = yTransform(value * g.scale); } catch (ClassCastException cce) { value = yTransform(0); // BAD! instead: (1) just continue now, and (2) NEXT point is a move-to. } p.moveTo(x, bottom - (int) (value * unitScale) - (int) (g.yoffset * unitScale)); /* -- i really want to start at year max(graph.start, bounds.start) -- there are 3 things going on: ---- x is the pixel position ---- i is the index into data[] ---- y is the year -- y isn't updated each time through the loop, so that's not too bad -- but: starting y is easy to compute; from that, i and x are easy */ // connect the lines through the rest of the graph int n = g.graph .getRingWidthData() .size(); // THIS is the third time it's called; why not use it above? for (int i = 1; i < n; i++) { // new x-position for this point x += yearWidth; // if we're past the end, draw what we've got, and say goodbye // (go +_yearsize so the line going off the screen is visible) if (x > r + yearWidth) { break; } // sapwood? draw what we've got, and start a new (thicker) path // but only do it if sapwoodThicker() is enabled! if (gInfo.isThickerSapwood() && i == sapwoodIndex) { g2.draw(p); g2.setStroke(makeStroke(2 * thickness, false)); p = new GeneralPath(); p.moveTo( yearWidth * (i - 1 + g.graph.getStart().diff(gInfo.getDrawBounds().getStart()) + g.xoffset), bottom - (int) (value * unitScale) - (int) (g.yoffset * unitScale)); } // y-position for this point try { value = yTransform(((Number) g.graph.getRingWidthData().get(i)).intValue() * g.scale); } catch (ClassCastException cce) { value = yTransform(0); // e.g., if it's being edited, it's still a string // BAD! instead: (1) draw what i've got so far, and (2) NEXT point is a move-to. // -- try to parse String as an integer? } // Try and paint remark icons try { List<TridasRemark> remarks = g.graph.getTridasValues().get(i).getRemarks(); int xcoord = (yearWidth * (i + g.graph.getStart().diff(gInfo.getDrawBounds().getStart()))); int ycoord = (bottom - (int) (value * unitScale) - (int) (g.yoffset * unitScale)); Graph.drawRemarkIcons(g2, gInfo, remarks, g.graph.getTridasValues().get(i), xcoord, ycoord); } catch (Exception e) { log.error("Exception drawing icons to graph: " + e.getClass()); } int y = bottom - (int) (value * unitScale) - (int) (g.yoffset * unitScale); // if we're not where this sample starts, don't bother drawing yet if (x < l - yearWidth) { p.moveTo(x, y); continue; } // if MR, draw a vertical line -- use Sample.MR, for now if (g.graph instanceof Sample && !validValue(value)) g2.drawLine(x, y - 20, x, y + 20); // draw a line to this point p.lineTo(x, y); } // draw it! g2.draw(p); }
public void draw( GraphSettings gInfo, Graphics2D g2, int bottom, Graph g, int thickness, int xscroll) { // cache yearsize, we use this a lot int yearWidth = gInfo.getYearWidth(); // the size of a year, in pixels float unitScale = gInfo.getHundredUnitHeight() / 100.0f; // the size of 1 "unit" in pixels. // set pen boolean dotted = (gInfo.isDottedIndexes() && (g.graph instanceof Index)); g2.setStroke(makeStroke(thickness, dotted)); // If it's a chronology, point bones down /*if(g.graph instanceof Sample) { if (((Sample) g.graph).getSeries() instanceof TridasDerivedSeries) { this.areBonesBelowLine = true; } }*/ // left/right int l = g2.getClipBounds().x; int r = l + g2.getClipBounds().width; // no data? stop. if (g.graph.getRingWidthData().isEmpty()) return; // compare g.getClipBounds() to [x,0]..[x+yearSize*data.size(),bottom] tempRect.x = yearWidth * (g.graph.getStart().diff(gInfo.getDrawBounds().getStart()) + g.xoffset); // REDUNDANT! see x later tempRect.y = 0; // - g.yoffset, IF you're sure there are no negative values (but there are) tempRect.width = yearWidth * (g.graph.getRingWidthData().size() - 1); tempRect.height = bottom; // TODO: compute top/bottom as min/max? // REFACTOR: will this be obsolete with the start/end stuff below? if (!tempRect.intersects(g2.getClipBounds())) { // skip this graph, it's off the screen return; } // Draw standard line int x = yearWidth * (g.graph.getStart().diff(gInfo.getDrawBounds().getStart()) + g.xoffset); // int value1 = yTransform((float) getMeanValue(g)); int value1 = yTransform((float) baselineY); int baseYVal = bottom - (int) (value1 * unitScale) - (int) (g.yoffset * unitScale); try { // x-position int x1 = x; int x2 = yearWidth * (g.graph.getStart().diff(gInfo.getDrawBounds().getStart()) + g.xoffset + g.graph.getRingWidthData().size()); // if we're past the end, draw only as far as we need if (x2 > r + yearWidth) { x2 = r + yearWidth; } // log.debug("Drawing mean line: "+x1+", "+meanYVal+", "+x2+", "+meanYVal); g2.drawLine(x1, baseYVal, x2, baseYVal); // Calcs for start/end triangles int YLineHeight = 50; int YTriangleHeight = 25; int XTriangleWidth = 15; if (areBonesBelowLine) { YLineHeight = -50; YTriangleHeight = -25; } // Draw start triangle g2.drawLine(x1, baseYVal, x1, baseYVal - YTriangleHeight); g2.drawLine(x1, baseYVal, x1 - XTriangleWidth, baseYVal - YTriangleHeight); g2.drawLine(x1 - XTriangleWidth, baseYVal - YTriangleHeight, x1, baseYVal - YTriangleHeight); g2.drawLine(x1, baseYVal, x1, baseYVal - YLineHeight); // Draw end triangle g2.drawLine(x2, baseYVal, x2, baseYVal - YTriangleHeight); g2.drawLine(x2, baseYVal, x2 + XTriangleWidth, baseYVal - YTriangleHeight); g2.drawLine(x2 + XTriangleWidth, baseYVal - YTriangleHeight, x2, baseYVal - YTriangleHeight); g2.drawLine(x2, baseYVal, x2, baseYVal - YLineHeight); } catch (ClassCastException cce) { } int value; try { value = ((Number) g.graph.getRingWidthData().get(0)).intValue(); value = yTransform(value * g.scale); } catch (ClassCastException cce) { value = yTransform(0); } int n = g.graph.getRingWidthData().size(); for (int i = 1; i < n; i++) { // new x-position for this point x += yearWidth; // if we're past the end, draw what we've got, and say goodbye // (go +_yearsize so the line going off the screen is visible) if (x > r + yearWidth) { break; } // Extract the window of interest int ringsEitherSideOfFocus = (App.prefs.getIntPref(PrefKey.STATS_SKELETON_PLOT_WINDOW_SIZE, 7) - 1) / 2; // Convert to ArrayList first as its easier to handle ArrayList<Double> ringWidths = new ArrayList<Double>(); for (int z = 0; z < n; z++) { ringWidths.add((double) g.graph.getRingWidthData().get(z).intValue()); } int firstind = i - 1 - ringsEitherSideOfFocus; int lastind = i + ringsEitherSideOfFocus; if (firstind < 0) firstind = 0; if (lastind > n) lastind = n; int size = lastind - firstind; double[] window = new double[size]; int t = 0; for (int w = firstind; w < lastind; w++) { window[t] = ringWidths.get(w); t++; } DescriptiveStatistics windowStats = new DescriptiveStatistics(window); /*if(i<7 ) { log.debug("Stats for ring: "+i); try{ log.debug(" Window 0: "+window[0]); log.debug(" Window 1: "+window[1]); log.debug(" Window 2: "+window[2]); log.debug(" Window 3: "+window[3]); log.debug(" Window 4: "+window[4]); log.debug(" Window 5: "+window[5]); log.debug(" Window 6: "+window[6]); } catch (ArrayIndexOutOfBoundsException e){} log.debug(" Mean is "+i+" - "+(int) windowStats.getMean()); log.debug(" Min is "+i+" - "+(int) windowStats.getMin()); log.debug(" Std is "+i+" - "+(int) windowStats.getStandardDeviation()); log.debug(" Std/2 is "+i+" - "+(int) windowStats.getStandardDeviation()/2); }*/ // y-position for this point try { value = yTransform(((Number) g.graph.getRingWidthData().get(i)).intValue() * g.scale); } catch (ClassCastException cce) { value = yTransform(0); // e.g., if it's being edited, it's still a string // BAD! instead: (1) draw what i've got so far, and (2) NEXT point is a move-to. // -- try to parse String as an integer? } int y = bottom - (int) (value * unitScale) - (int) (g.yoffset * unitScale); // Calculate skeleton category Integer skeletonCateogory = null; String prefAlg = App.prefs.getPref( PrefKey.STATS_SKELETON_PLOT_ALGORITHM, SkeletonPlotAlgorithm.PERCENTILES.toString()); if (prefAlg.equals(SkeletonPlotAlgorithm.PERCENTILES.toString())) { skeletonCateogory = getSkeletonCategoryFromPercentiles(value, windowStats); } else if (prefAlg.equals(SkeletonPlotAlgorithm.CROPPER1979_0POINT5.toString())) { skeletonCateogory = getSkeletonCategoryFromCropper1979(value, windowStats, 0.5); } else if (prefAlg.equals(SkeletonPlotAlgorithm.CROPPER1979_0POINT75.toString())) { skeletonCateogory = getSkeletonCategoryFromCropper1979(value, windowStats, 0.75); } // Draw the skeleton line if (areBonesBelowLine) { g2.drawLine(x, baseYVal, x, baseYVal + (skeletonCateogory * 5)); } else { g2.drawLine(x, baseYVal, x, baseYVal - (skeletonCateogory * 5)); } // Try and paint remark icons try { List<TridasRemark> remarks = g.graph.getTridasValues().get(i).getRemarks(); if (areBonesBelowLine) { Graph.drawRemarkIcons( g2, gInfo, remarks, g.graph.getTridasValues().get(i), x, baseYVal, false); } else { Graph.drawRemarkIcons( g2, gInfo, remarks, g.graph.getTridasValues().get(i), x, baseYVal, true); } } catch (Exception e) { log.error("Exception drawing icons to graph: " + e.getClass()); } } }