/*
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.
*/
/*
* DrawSlope: draws the slope triangle for the slope of a line
*/
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.Kernel;
import org.geogebra.common.kernel.StringTemplate;
import org.geogebra.common.kernel.algos.AlgoSlope;
import org.geogebra.common.kernel.geos.GeoElement;
import org.geogebra.common.kernel.geos.GeoNumeric;
/**
*
* @author Markus Hohenwarter
*/
public class DrawSlope extends Drawable {
private GeoNumeric slope;
private AlgoSlope algo;
private boolean isVisible, labelVisible;
private int xLabelHor, yLabelHor;
private String horLabel; // horizontal label, i.e. triangleSize
private double[] coords = new double[2];
private GeneralPathClipped gp;
private Kernel kernel;
/**
* Creates new drawable for slope
*
* @param view
* view
* @param slope
* slope number
*/
public DrawSlope(EuclidianView view, GeoNumeric slope) {
this.view = view;
kernel = view.getKernel();
this.slope = slope;
geo = slope;
slope.setDrawable(true);
// get parent line
init();
update();
}
private void init() {
algo = ((AlgoSlope) slope.getDrawAlgorithm());
}
@Override
final public void update() {
isVisible = geo.isEuclidianVisible();
if (isVisible) {
if (!geo.getDrawAlgorithm().equals(geo.getParentAlgorithm())) {
init();
}
int slopeTriangleSize = slope.getSlopeTriangleSize();
double rwHeight = slope.getValue() * slopeTriangleSize;
double height = view.getYscale() * rwHeight;
if (Math.abs(height) > Float.MAX_VALUE) {
isVisible = false;
return;
}
// get point on line g
algo.getInhomPointOnLine(coords);
view.toScreenCoords(coords);
// draw slope triangle
double x = coords[0];
double y = coords[1];
double xright = x + view.getXscale() * slopeTriangleSize;
if (gp == null) {
gp = new GeneralPathClipped(view);
}
gp.reset();
gp.moveTo(x, y);
gp.lineTo(xright, y);
gp.lineTo(xright, y - height);
// closePath important for clipping: #4048
gp.closePath();
// 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
}
// label position
labelVisible = geo.isLabelVisible();
StringTemplate tpl = StringTemplate.defaultTemplate;
if (labelVisible) {
if (slopeTriangleSize > 1) {
StringBuilder sb = new StringBuilder();
switch (slope.getLabelMode()) {
case GeoElement.LABEL_NAME_VALUE:
sb.append(slopeTriangleSize);
sb.append(' ');
sb.append(geo.getLabel(tpl));
sb.append(" = ");
sb.append(kernel.format(rwHeight, tpl));
break;
case GeoElement.LABEL_VALUE:
sb.append(kernel.format(rwHeight, tpl));
break;
default: // case GeoElement.LABEL_NAME:
sb.append(slopeTriangleSize);
sb.append(' ');
sb.append(geo.getLabel(tpl));
break;
}
labelDesc = sb.toString();
} else {
labelDesc = geo.getLabelDescription();
}
yLabel = (int) (y - height / 2.0f + 6);
xLabel = (int) (xright) + 5;
addLabelOffset();
// position off horizontal label (i.e. slopeTriangleSize)
xLabelHor = (int) ((x + xright) / 2.0);
yLabelHor = (int) (y + view.getFontSize() + 2);
StringBuilder sb = new StringBuilder();
sb.append(slopeTriangleSize);
horLabel = sb.toString();
}
updateStrokes(slope);
}
}
@Override
final public void draw(GGraphics2D g2) {
if (isVisible) {
fill(g2, gp); // fill using default/hatching/image as
// appropriate
if (geo.doHighlighting()) {
g2.setPaint(geo.getSelColor());
g2.setStroke(selStroke);
g2.draw(gp);
}
if (geo.getLineThickness() > 0) {
g2.setPaint(getObjectColor());
g2.setStroke(objStroke);
g2.draw(gp);
}
if (labelVisible) {
g2.setPaint(slope.getLabelColor());
g2.setFont(view.getFontLine());
drawLabel(g2);
g2.drawString(horLabel, xLabelHor, yLabelHor);
}
}
}
@Override
final public boolean hit(int x, int y, int hitThreshold) {
return gp != null
&& (gp.contains(x, y) || gp.intersects(x, y, hitThreshold));
}
@Override
public boolean intersectsRectangle(GRectangle rect) {
return gp != null && (gp.intersects(rect));
}
@Override
final public boolean isInside(GRectangle rect) {
return false;
}
@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
}
}