package org.geogebra.common.euclidian.draw; import java.util.List; import org.geogebra.common.awt.GColor; 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.Matrix.Coords; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoTransferFunction; /** * @author Giuliano * * Draw a Nyquist diagram * */ public class DrawNyquist extends Drawable { private GeoTransferFunction gcf; private boolean isVisible; private GeneralPathClipped gpP; private List<Coords> coordsList; private Coords p; private double yP; private double xPN; private GeneralPathClipped gpN; private double yN; private static final double LEN = 6; private static final double ANGLE_L = Math.toRadians(135); private static final double ANGLE_R = -ANGLE_L; /** * @param view * Euclidian view * @param geo * Function */ public DrawNyquist(EuclidianView view, GeoTransferFunction geo) { gcf = geo; this.geo = geo; this.view = view; labelDesc = geo.getLabelSimple(); coordsList = gcf.getCoordsList(); update(); } @Override public void update() { isVisible = gcf.isEuclidianVisible(); if (!isVisible || !gcf.isDefined()) { return; } } @Override public void draw(GGraphics2D g2) { if (!isVisible || !gcf.isDefined()) { return; } boolean highlighting = geo.doHighlighting(); if (highlighting) { g2.setPaint(geo.getSelColor()); g2.setStroke(selStroke); } else { g2.setPaint(geo.getObjectColor()); g2.setStroke(objStroke); } gpP = new GeneralPathClipped(view); gpN = new GeneralPathClipped(view); for (int i = 0; i < coordsList.size(); i++) { p = coordsList.get(i); xPN = view.toScreenCoordXd(p.getX()); yP = view.toScreenCoordYd(p.getY()); yN = view.toScreenCoordYd(-p.getY()); gpP.lineTo(xPN, yP); gpN.lineTo(xPN, yN); } GColor geoColor = getObjectColor(); GColor color = GColor.newColor(geoColor.getRed(), geoColor.getGreen(), geoColor.getBlue(), 127); g2.setColor(color); g2.draw(gpN); g2.setColor(geoColor); g2.draw(gpP); drawArrow(g2); } private void drawArrow(GGraphics2D g2) { int i = (int) (coordsList.size() / 2.3); double x1 = view.toScreenCoordXd(coordsList.get(i).getX()); double y1 = view.toScreenCoordYd(coordsList.get(i).getY()); double y2 = view.toScreenCoordYd(coordsList.get(i - 1).getY()); double x2 = view.toScreenCoordXd(coordsList.get(i - 1).getX()); double angle = getAngle(x1, y1, x2, y2); GColor color = g2.getColor(); g2.setColor(GColor.BLUE); fill(g2, y2, x2, angle); y1 = view.toScreenCoordYd(-coordsList.get(i).getY()); y2 = view.toScreenCoordYd(-coordsList.get(i + 1).getY()); x2 = view.toScreenCoordXd(coordsList.get(i + 1).getX()); angle = getAngle(x1, y1, x2, y2); fill(g2, y2, x2, angle); g2.setColor(color); } private void fill(GGraphics2D g2, double y2, double x2, double angle) { GeneralPathClipped arrow = new GeneralPathClipped(view); arrow.moveTo(x2, y2); arrow.lineTo(x2 + LEN * Math.cos(angle + ANGLE_L), y2 + LEN * Math.sin(angle + ANGLE_L)); arrow.lineTo(x2 + LEN * Math.cos(angle + ANGLE_R), y2 + LEN * Math.sin(angle + ANGLE_R)); arrow.closePath(); g2.fill(arrow); } private static double getAngle(double x1, double y1, double x2, double y2) { double m = (y2 - y1) / (x2 - x1); if (x2 - x1 < 0 && y2 - y1 < 0) { return Math.atan(m) + Math.PI; } else if (x2 - x1 < 0 && y2 - y1 >= 0) { return Math.atan(m) + Math.PI; } else if (x2 - x1 >= 0 && y2 - y1 < 0) { return 2 * Math.PI + Math.atan(m); } else if (x2 - x1 >= 0 && y2 - y1 >= 0) { return Math.atan(m); } return 0; } @Override public boolean hit(int x, int y, int hitThreshold) { if (!isVisible || !gcf.isDefined()) { return false; } return gpP.contains(x, y) || gpN.contains(x, y); } @Override public boolean isInside(GRectangle rect) { if (!isVisible || !gcf.isDefined()) { return false; } return gpP.contains(rect) || gpN.contains(rect); } @Override public GeoElement getGeoElement() { return geo; } @Override public void setGeoElement(GeoElement geo) { this.geo = geo; } @Override public BoundingBox getBoundingBox() { // TODO Auto-generated method stub return null; } @Override public void updateBoundingBox() { // TODO Auto-generated method stub } }