/** Returns the bounding box of this Drawable in screen coordinates. */ @Override public final org.geogebra.common.awt.GRectangle getBounds() { if (!geo.isDefined() || !geo.isEuclidianVisible()) return null; org.geogebra.common.awt.GRectangle ret = null; if (lineVisible) ret = line.getBounds(); if (arrowheadVisible) ret = (ret == null) ? AwtFactory.prototype.newRectangle(gp.getBounds()) : AwtFactory.prototype.newRectangle(ret.union(gp.getBounds())); return ret; }
@Override public boolean intersectsRectangle(GRectangle rect) { return (lineVisible && line.intersects(rect)) || (arrowheadVisible && gp.intersects(rect)); }
@Override public final boolean hit(int x, int y, int hitThreshold) { return (lineVisible && line.intersects(x - 3, y - 3, 6, 6)) || (arrowheadVisible && gp.intersects(x - 3, y - 3, 6, 6)); }
@Override public final boolean isInside(org.geogebra.common.awt.GRectangle rect) { return (lineVisible && rect.contains(line.getBounds())) || (arrowheadVisible && rect.contains(gp.getBounds())); }
/** Sets the line and arrow of the vector. */ private void setArrow(float lineThickness) { // screen coords of start and end point of vector boolean onscreenA = view.toScreenCoords(coordsA); boolean onscreenB = view.toScreenCoords(coordsB); coordsV[0] = coordsB[0] - coordsA[0]; coordsV[1] = coordsB[1] - coordsA[1]; // calculate endpoint F at base of arrow double factor = getFactor(lineThickness); double length = MyMath.length(coordsV[0], coordsV[1]); // decrease arrowhead size if it's longer than the vector if (length < factor) { factor = length; } if (length > 0.0) { coordsV[0] = (coordsV[0] * factor) / length; coordsV[1] = (coordsV[1] * factor) / length; } double[] coordsF = new double[2]; coordsF[0] = coordsB[0] - coordsV[0]; coordsF[1] = coordsB[1] - coordsV[1]; // set clipped line if (line == null) line = AwtFactory.prototype.newLine2D(); lineVisible = true; if (onscreenA && onscreenB) { // A and B on screen line.setLine(coordsA[0], coordsA[1], coordsF[0], coordsF[1]); } else { // A or B off screen // clip at screen, that's important for huge coordinates // check if any of vector is on-screen org.geogebra.common.awt.GPoint2D[] clippedPoints = ClipLine.getClipped( coordsA[0], coordsA[1], coordsB[0], coordsB[1], -EuclidianStatic.CLIP_DISTANCE, view.getWidth() + EuclidianStatic.CLIP_DISTANCE, -EuclidianStatic.CLIP_DISTANCE, view.getHeight() + EuclidianStatic.CLIP_DISTANCE); if (clippedPoints == null) { isVisible = false; lineVisible = false; arrowheadVisible = false; } else { // now re-clip at A and F clippedPoints = ClipLine.getClipped( coordsA[0], coordsA[1], coordsF[0], coordsF[1], -EuclidianStatic.CLIP_DISTANCE, view.getWidth() + EuclidianStatic.CLIP_DISTANCE, -EuclidianStatic.CLIP_DISTANCE, view.getHeight() + EuclidianStatic.CLIP_DISTANCE); if (clippedPoints != null) line.setLine( clippedPoints[0].getX(), clippedPoints[0].getY(), clippedPoints[1].getX(), clippedPoints[1].getY()); else lineVisible = false; } } // add triangle if visible if (gp == null) gp = AwtFactory.prototype.newGeneralPath(); else gp.reset(); if (isVisible) { if (length > 0) { coordsV[0] /= 4.0; coordsV[1] /= 4.0; gp.moveTo((float) coordsB[0], (float) coordsB[1]); // end point gp.lineTo((float) (coordsF[0] - coordsV[1]), (float) (coordsF[1] + coordsV[0])); gp.lineTo((float) (coordsF[0] + coordsV[1]), (float) (coordsF[1] - coordsV[0])); gp.closePath(); } arrowheadVisible = onscreenB || gp.intersects(0, 0, view.getWidth(), view.getHeight()); } }