/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.display; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.GeneralPath; /** * Draws a coil spring in a drawing panel. * @author F. Esquembre * @author W. Christian * @version 1.0 */ public class Spring implements Measurable { private GeneralPath springPath = new GeneralPath(); // Configuration variables protected boolean thinExtremes = true; protected boolean visible = true; protected int loops = -1, pointsPerLoop = -1; // -1 to make sure the arrays are allocated protected float x = 0.0f, y = 0.0f; protected float sizex = 0.1f, sizey = 0.0f; /** * The radius of the spring (normal to its direction) */ protected float radius = 0.1f; protected float solenoid = 0.0f; protected Color edgeColor = Color.BLACK; protected Stroke edgeStroke = new BasicStroke(1.0f); // Implementation variables protected boolean hasChanged = true, zeroLength = false; // Whether the element should recompute data that depends on position, size, scale, resolution, ... private int segments = 0; private float xPoints[] = null, yPoints[] = null; /** * Constructs a 0.1 radius Spring. */ public Spring() { this(0.1); } /** * Special constructor that allows to specify the radius of the spring * @param _radius the radius of the spring (normal to its direction) */ public Spring(double _radius) { setRadius(_radius); setResolution(8, 15); } // ------------------------------------- // Configuration methods // ------------------------------------- /** * Sets the X position of the origin of the spring * @param x double */ public void setX(double x) { this.x = (float) x; hasChanged = true; } /** * Gets the X position of the origin of the spring * @return double */ public double getX() { return this.x; } /** * Sets the Y position of the origin of the spring * @param y double */ public void setY(double y) { this.y = (float) y; hasChanged = true; } /** * Gets the Y position of the origin of the spring * @return double */ public double getY() { return this.y; } /** * Sets the position of the origin of the spring * @param x double * @param y double */ public void setXY(double x, double y) { this.x = (float) x; this.y = (float) y; hasChanged = true; } /** * Sets the X size of the spring * @param sizeX double */ public void setSizeX(double sizeX) { this.sizex = (float) sizeX; hasChanged = true; } /** * Gets the X size of the spring * @return double */ public double getSizeX() { return this.sizex; } /** * Sets the Y size of the spring * @param sizeY double */ public void setSizeY(double sizeY) { this.sizey = (float) sizeY; hasChanged = true; } /** * Gets the Y size of the spring * @return double */ public double getSizeY() { return this.sizey; } /** * Sets the size of the spring * @param sizeX double * @param sizeY double */ public void setSizeXY(double sizeX, double sizeY) { this.sizex = (float) sizeX; this.sizey = (float) sizeY; hasChanged = true; } /** * Set the radius of the spring. * @param _radius the radius of the spring (normal to its direction) */ public void setRadius(double radius) { this.radius = (float) radius; hasChanged = true; } /** * Get the radius of the spring. */ public double getRadius() { return this.radius; } /** * Sets the visibiliby of the spring * @param _visible boolean */ public void setVisible(boolean visible) { this.visible = visible; } public boolean isVisible() { return this.visible; } public void setEdgeColor(Color color) { this.edgeColor = color; } public Color getEdgeColor() { return this.edgeColor; } public void setEdgeStroke(Stroke stroke) { this.edgeStroke = stroke; } public Stroke getEdgeStroke() { return this.edgeStroke; } /** * Sets the number of spires and points per spire used to draw the spring * @param nLoops int * @param nPointsPerLoop int */ public void setResolution(int nLoops, int nPointsPerLoop) { if((nLoops==loops)&&(nPointsPerLoop==pointsPerLoop)) { return; // No need to reallocate arrays } this.loops = nLoops; this.pointsPerLoop = nPointsPerLoop; segments = loops*pointsPerLoop; int n = segments+1; xPoints = new float[n]; yPoints = new float[n]; hasChanged = true; } public int getLoops() { return this.loops; } public int getPointsPerLoop() { return this.pointsPerLoop; } /** * Sets a double factor that makes the spring look like a solenoid by * causing the spires to go back and forth * Default is 0, which makes a standard spring * @param factor double */ public void setSolenoid(double factor) { solenoid = (float) factor; hasChanged = true; } /** * Whether the spring should show thin extremes. Default is true * @param thin boolean */ public void setThinExtremes(boolean thin) { thinExtremes = thin; hasChanged = true; } /** * Implementation of Drawable. * @param panel DrawingPanel * @param g Graphics */ public void draw(DrawingPanel panel, Graphics g) { if(!visible) { return; } if(hasChanged) { computePoints(); } Graphics2D g2 = (Graphics2D) g; g2.setStroke(edgeStroke); g2.setColor(edgeColor); if(zeroLength) { int a = panel.xToPix(x), b = panel.yToPix(y); g2.drawLine(a, b, a, b); return; } Shape s = springPath.createTransformedShape(panel.getPixelTransform()); g2.draw(s); } // ------------------------------------- // Implementation of Measured3D // ------------------------------------- public boolean isMeasured() { return visible; } public double getXMin() { return(sizex>0) ? x : x+sizex; } public double getXMax() { return(sizex>0) ? x+sizex : x; } public double getYMin() { return(sizey>0) ? y : y+sizey; } public double getYMax() { return(sizey>0) ? y+sizey : y; } // ------------------------------------- // Private methods // ------------------------------------- private void computeGeneralPath() { if((xPoints==null)||(xPoints.length<2)) { return; } int n = xPoints.length; springPath = new GeneralPath(); springPath.moveTo(xPoints[0], yPoints[0]); for(int i = 1; i<n; i++) { springPath.lineTo(xPoints[i], yPoints[i]); } } private void computePoints() { float length = sizex*sizex+sizey*sizey; if(length==0) { zeroLength = true; return; } zeroLength = false; length = (float) Math.sqrt(length); float u2x = -sizey/length, u2y = sizex/length; float delta = (float) (2.0f*Math.PI/pointsPerLoop); if(radius<0) { delta *= -1; } int pre = pointsPerLoop/2; for(int i = 0; i<=segments; i++) { int k; if(thinExtremes) { if(i<pre) { k = 0; } else if(i<pointsPerLoop) { k = i-pre; } else if(i>(segments-pre)) { k = 0; } else if(i>(segments-pointsPerLoop)) { k = segments-i-pre; } else { k = pre; } } else { k = pre; } float angle = (float) (Math.PI/2+i*delta); float cos = (float) Math.cos(angle); //, sin = Math.sin(angle); xPoints[i] = (x+i*sizex/segments+k*radius*cos*u2x/pre); yPoints[i] = (y+i*sizey/segments+k*radius*cos*u2y/pre); if(solenoid!=0.0) { double cte = k*Math.cos(i*2*Math.PI/pointsPerLoop)/pre; xPoints[i] += solenoid*cte*sizex; yPoints[i] += solenoid*cte*sizey; } } computeGeneralPath(); hasChanged = false; } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */