/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. */ package org.geogebra.common.euclidian.draw; import org.geogebra.common.awt.GGraphics2D; import org.geogebra.common.awt.GRectangle; import org.geogebra.common.euclidian.BoundingBox; import org.geogebra.common.euclidian.Drawable; import org.geogebra.common.euclidian.EuclidianView; import org.geogebra.common.euclidian.GeneralPathClipped; import org.geogebra.common.kernel.algos.AlgoFunctionAreaSums; import org.geogebra.common.kernel.algos.AlgoFunctionAreaSums.SumType; import org.geogebra.common.kernel.arithmetic.NumberValue; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoNumeric; import org.geogebra.common.util.debug.Log; /** * Draws upper / lower sum of a GeoFunction * * @author Markus Hohenwarter */ public class DrawUpperLowerSum extends Drawable { private GeoNumeric sum; private NumberValue a, b; // interval borders private boolean isVisible, labelVisible; private AlgoFunctionAreaSums algo; private GeneralPathClipped gp; private double[] coords = new double[2]; private boolean trapeziums; private boolean histogram; private boolean barchartFreqs, barchartFreqsWidth; /** * Creates graphical representation of the sum / barchart /... * * @param view * Euclidian view to be drawn into * @param n * The sum / barchart / boxplot / histogram to be drawn */ public DrawUpperLowerSum(EuclidianView view, GeoNumeric n) { this.view = view; sum = n; geo = n; n.setDrawable(true); init(); update(); } private void init() { algo = (AlgoFunctionAreaSums) geo.getDrawAlgorithm(); this.trapeziums = algo.useTrapeziums(); this.histogram = algo.isHistogram(); this.barchartFreqs = algo.getType() == SumType.BARCHART_FREQUENCY_TABLE; this.barchartFreqsWidth = algo .getType() == SumType.BARCHART_FREQUENCY_TABLE_WIDTH; a = algo.getA(); b = algo.getB(); } @Override final public void update() { isVisible = geo.isEuclidianVisible(); if (!isVisible) { return; } if (!geo.getDrawAlgorithm().equals(geo.getParentAlgorithm())) { init(); } labelVisible = geo.isLabelVisible(); updateStrokes(sum); if (gp == null) { gp = new GeneralPathClipped(view); } if (barchartFreqs || histogram) { updateBarChart(); return; } // init gp gp.reset(); double aRW = a.getDouble(); double bRW = b.getDouble(); double ax = view.toScreenCoordXd(aRW); double bx = view.toScreenCoordXd(bRW); double y0 = view.getYZero(); // plot upper/lower sum rectangles int N = algo.getIntervals(); double[] leftBorder = algo.getLeftBorder(); double[] yval = algo.getValues(); // first point double x = ax; double y = y0; gp.moveTo(x, y); for (int i = 0; i < N; i++) { coords[0] = leftBorder[i]; coords[1] = yval[i]; view.toScreenCoords(coords); /* * removed - so that getBounds() works // avoid too big y values if * (coords[1] < 0 && !trapeziums) { coords[1] = -1; } else if * (coords[1] > view.height && !trapeziums) { coords[1] = * view.height + 1; } */ x = coords[0]; if (trapeziums) { gp.lineTo(x, coords[1]); // top } else { gp.lineTo(x, y); // top } gp.lineTo(x, y0); // RHS gp.moveTo(x, y); y = coords[1]; gp.moveTo(x, y0); gp.lineTo(x, y); } if (trapeziums) { coords[0] = leftBorder[N]; coords[1] = yval[N]; view.toScreenCoords(coords); gp.lineTo(bx, coords[1]); // last bar: top } else if (!barchartFreqsWidth) { gp.lineTo(bx, y); // last bar: top } if (histogram) { gp.moveTo(bx, y0); } else if (!barchartFreqsWidth) { gp.lineTo(bx, y0);// last bar: right } gp.lineTo(ax, y0);// all bars, along bottom // gp on screen? if (!gp.intersects(0, 0, view.getWidth(), view.getHeight())) { isVisible = false; // don't return here to make sure that getBounds() works for // offscreen points too } if (labelVisible) { xLabel = (int) Math.round((ax + bx) / 2) - 6; yLabel = (int) view.getYZero() - view.getFontSize(); labelDesc = geo.getLabelDescription(); addLabelOffset(); } } private void updateBarChart() { gp.reset(); double base = view.getYZero(); int N = algo.getIntervals(); double[] leftBorder = algo.getLeftBorder(); double[] yval = algo.getValues(); gp.moveTo(view.toScreenCoordXd(leftBorder[0]), base); for (int i = 0; i < N - 1; i++) { double x0 = view.toScreenCoordXd(leftBorder[i]); double height = view.toScreenCoordYd(yval[i]); double x1 = view.toScreenCoordXd(leftBorder[i + 1]); gp.lineTo(x0, height); // up gp.lineTo(x1, height); // along gp.lineTo(x1, base); // down } gp.lineTo(view.toScreenCoordXd(leftBorder[0]), base); // gp on screen? if (!gp.intersects(0, 0, view.getWidth(), view.getHeight())) { isVisible = false; // don't return here to make sure that getBounds() works for // offscreen points too } if (labelVisible) { xLabel = (view.toScreenCoordX(leftBorder[0]) + view.toScreenCoordX(leftBorder[N - 1])) / 2 - 6; yLabel = (int) view.getYZero() - view.getFontSize(); labelDesc = geo.getLabelDescription(); addLabelOffset(); } } @Override final public void draw(GGraphics2D g2) { if (isVisible) { try { if (geo.doHighlighting()) { g2.setPaint(sum.getSelColor()); g2.setStroke(selStroke); g2.draw(gp); } } catch (Exception e) { Log.debug(e.getMessage()); } try { fill(g2, gp); // fill using default/hatching/image as // appropriate } catch (Exception e) { e.printStackTrace(); } try { if (geo.getLineThickness() > 0) { g2.setPaint(getObjectColor()); g2.setStroke(objStroke); g2.draw(gp); } } catch (Exception e) { Log.debug(e.getMessage()); } if (labelVisible) { g2.setFont(view.getFontConic()); g2.setPaint(geo.getLabelColor()); drawLabel(g2); } } } @Override final public boolean hit(int x, int y, int hitThreshold) { return gp != null && (gp.contains(x, y) || gp.intersects(x - 3, y - 3, 6, 6)); } @Override final public boolean isInside(GRectangle rect) { return false; } @Override public boolean intersectsRectangle(GRectangle rect) { return gp != null && gp.intersects(rect); } @Override public GeoElement getGeoElement() { return geo; } @Override public void setGeoElement(GeoElement geo) { this.geo = geo; } /** * Returns the bounding box of this Drawable in screen coordinates. */ @Override final public GRectangle getBounds() { if (!geo.isDefined() || !geo.isEuclidianVisible()) { return null; } return gp.getBounds(); } @Override public BoundingBox getBoundingBox() { // TODO Auto-generated method stub return null; } @Override public void updateBoundingBox() { // TODO Auto-generated method stub } }