Grow Line

Download: jar file

A "grow line" is a line that is continually redrawn as the mouse is dragged from a fixed pivot point.

References

getGraphics()
setXORMode
drawLine

Demonstration

Contents

growline.java
Line2.java
Vec2.java

growline.java


001: import java.awt.*;
002: import java.awt.event.*;
003: import java.util.*;
004: import java.awt.geom.*;
005: import javax.swing.*;
006: 
007: 
008: class MousePanel extends JPanel implements MouseMotionListener
009: {
010:     ArrayList<Line2> lines;
011:     Point base, current;
012:     boolean isDragging;
013:     
014:     MousePanel()
015:     {
016:         isDragging = false;
017:         lines = new ArrayList<Line2>();
018:         addMouseListener(new MouseHandler());
019:         addMouseMotionListener(this);
020:     }
021: 
022:     public void paintComponent(Graphics g)
023:     {
024:         super.paintComponent(g);
025: 
026:         Graphics2D g2 = (Graphics2D) g;
027:         for (Line2 line: lines) line.draw(g);
028:     }
029: 
030:     private class MouseHandler extends MouseAdapter
031:     {
032: 
033:         public void mousePressed(MouseEvent event)
034:         {
035:             isDragging = true;
036:             current = event.getPoint();
037:             base = event.getPoint();
038:         }
039: 
040:         public void mouseReleased(MouseEvent event)
041:         {
042:             isDragging = false;
043:             current = event.getPoint();
044: 
045:             Graphics g = getGraphics();
046:             int bx = base.x;
047:             int by = base.y;
048:             g.setXORMode(Color.WHITE);
049:             g.drawLine(bx,by,current.x,current.y);
050:             g.setPaintMode();
051:             g.setColor(Color.BLACK);
052:             lines.add(new Line2(bx,by,current.x,current.y));
053:             repaint();
054:         }
055:     }
056: 
057:     public void mouseDragged(MouseEvent event)
058:     {
059:         Graphics g = getGraphics();
060:         int bx = base.x;
061:         int by = base.y;
062:         g.setXORMode(Color.WHITE);
063:         g.drawLine(bx,by,current.x,current.y);
064:         current = event.getPoint();
065:         g.drawLine(bx,by,current.x,current.y);
066:         g.setPaintMode();
067:         g.setColor(Color.BLACK);
068:     }
069: 
070:     public void mouseMoved(MouseEvent event)
071:     {
072:     }
073: }
074: 
075: public class growline extends JApplet
076: {
077:     public void init()
078:     {
079:         EventQueue.invokeLater(new Runnable() {
080:             public void run()
081:             {
082:                 MousePanel panel = new MousePanel();
083:                 add(panel);
084:             }
085:         });
086:     }
087:    public static void main(String[] args)
088:    {
089:        EventQueue.invokeLater(new Runnable() {
090:            public void run()
091:            {
092:                MousePanel panel = new MousePanel();
093:                JFrame frame = new JFrame("Grow Line");
094:                frame.add(panel);
095:                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
096:                frame.setSize(400,400);
097:                frame.setVisible(true);
098:            }
099:        });
100:    }
101: }


Line2.java


001: /* \file Line2.java
002:  *
003:  */
004: import java.awt.Graphics;
005: 
006: public class Line2
007: {
008:     public Vec2 [] pt;
009:     public Line2() { this(0.0,0.0,0.0,0.0);  } //!< default no-argument constructor
010:     public Line2(Vec2 to) { this(0.0,0.0,to.v[0],to.v[1]); }
011:         //! construct Line2 from origin to (x,y)
012:     public Line2(double x, double y) { this(0.0,0.0,x,y); }
013:         //! constructs Line2 from (x1,y1) to (x2,y2)
014:     public Line2(double x1, double y1, double x2, double y2)
015:     {
016:         pt = new Vec2[2];
017:         pt[0] = new Vec2(x1,y1);
018:         pt[1] = new Vec2(x2,y2);
019:     }
020:     //! construct Line2 from screen coordinates (integers)
021:     public Line2(int x1, int y1, int x2, int y2)
022:     {
023:         pt = new Vec2[2];
024:         pt[0] = new Vec2(x1,y1);
025:         pt[1] = new Vec2(x2,y2);
026:     }
027:     //! constructs Line2 from two points
028:     public Line2(Vec2 from, Vec2 to)
029:     {
030:         pt = new Vec2[2];
031:         pt[0] = new Vec2(from);
032:         pt[1] = new Vec2(to);
033:     }
034:     //! returns length of associated array
035:     public int rows()  { return 2; }
036:     public int cols()  { return 2; }
037:         //! return pointer to first element
038:     public Line2 set(double x1, double y1, double x2, double y2)
039:     {
040:         pt[0].v[0]=x1; pt[0].v[1]=y1;
041:         pt[1].v[0]=x2; pt[1].v[1]=y2;
042:         return this;
043:     }
044:     public Line2 from(double x, double y)
045:     {
046:         pt[0].v[0]=x; pt[0].v[1]=y;
047:         return this;
048:     }
049:     public Line2 from(Vec2 src)
050:     {
051:         pt[0]=src;
052:         return this;
053:     }
054:     public Line2 to(double x, double y)
055:     {
056:         pt[1].v[0]=x; pt[1].v[1]=y;
057:         return this;
058:     }
059: 
060:     public Line2 to(Vec2 src) {
061:         pt[1]=src;
062:         return this;
063:     }
064: 
065:     public Line2 away(double r, double theta)
066:     {
067:         Vec2 angl = new Vec2(theta);
068:         pt[1] = Vec2.sum(pt[0],angl.scale(r));
069:         return this;
070:     }
071: 
072:     public Line2 translate(double tx, double ty)
073:     {
074:         pt[0].translate(tx,ty); pt[1].translate(tx,ty);
075:         return this;
076:     }
077: 
078:     public Line2 translate(Vec2 b)
079:     {
080:         pt[0].translate(b); pt[1].translate(b);
081:         return this;
082:     }
083: 
084:     public Vec2 getDirection()
085:     {
086:         return Vec2.diff(pt[1],pt[0]);
087:     }
088: 
089:     public void draw(Graphics g)
090:     {
091:         int [] from = pt[0].convert();
092:         int [] to = pt[1].convert();
093:         g.drawLine(from[0],from[1],to[0],to[1]);
094:     }
095: 
096:     public String toString()
097:     {
098:         return (pt[0] + ":" + pt[1]);
099:     }
100: 
101:     //! return distance between two endpoints
102:     public double length()
103:     {
104:         return Vec2.distance(pt[0],pt[1]);
105:     }
106: 
107:     //! returns angle (in degrees) between two lines
108:     public static double angle(Line2 a, Line2 b)
109:     {
110:         Vec2 va = Vec2.diff(a.pt[1],a.pt[0]);
111:         Vec2 vb = Vec2.diff(b.pt[1],b.pt[0]);
112:         return Vec2.angle(va,vb);
113:     }
114:     public Vec2 lerp(double u)
115:     {
116:         double up = 1.0-u;
117:         double x = up*pt[0].v[0]+u*pt[1].v[0];
118:         double y = up*pt[0].v[1]+u*pt[1].v[1];
119:         return new Vec2(x,y);
120:     }
121: 
122:     public double getClosestPosition( Vec2 v)
123:     {
124:         Vec2 p = Vec2.diff(v,pt[0]);
125:         Vec2 k = getDirection();
126:         return Vec2.dot(p,k)/Vec2.dot(k,k);
127:     }
128: }


Vec2.java

Vec2.java


001: // Vec2.java
002: // Definition of class Vec2
003: import java.awt.Graphics; 
004: 
005: /**
006: *  <b>Vec2</b> describes a two-dimensional point.
007: */
008: 
009: public class Vec2
010: {
011:     static double Resolution = 96;
012:     static int xoffset = 120;
013:     static int yoffset = 120;
014:     public double [] v; // coordinates of the Point
015: 
016:         // No-argument constructor
017:         public Vec2() { this( 0, 0 ); }
018: 
019: 
020:         // Constructor
021:         public Vec2( double x, double y )
022:         {
023:             v = new double[2];
024:             set(x,y);
025:         }
026: 
027:         public Vec2( int x, int y)
028:         {
029:             v = new double[2];
030:             reconvert(x,y);
031:         }
032: 
033:         // copy constructor
034:         public Vec2( Vec2 src)
035:         {
036:             this(src.v[0],src.v[1]);
037:         }
038: 
039:         // Constructor (angle theta)
040:         public Vec2(double theta)
041:         {
042:             theta *= radg;
043:             v = new double[2];
044:             set(Math.cos(theta),Math.sin(theta));
045:         }
046:             
047: 
048:         public int length() { return v.length; }
049: 
050: 
051:         // Set x and y coordinates of Point
052:         public Vec2 set( double x, double y )
053:         {
054:                 v[0] = x;
055:                 v[1] = y;
056:                 return this;
057:         }
058: 
059:         public int [] convert()
060:         {
061:             int [] iv = new int[2];
062:             convert(iv);
063:             return iv;
064:         }
065: 
066:         public void convert(int [] iv)
067:         {
068:                 if (Resolution == 0)
069:                 {
070:                     iv[0] = (int) v[0];
071:                     iv[1] = (int) v[1];
072:                 }
073:                 else
074:                 {       
075:             iv[0] = (int) (xoffset + v[0]*Resolution);
076:             iv[1] = (int) (yoffset - v[1]*Resolution);
077:                 }
078:         }
079: 
080:         public void reconvert(int x, int y)
081:         {
082:             if (Resolution==0)
083:             {
084:                 v[0] = x;
085:                 v[1] = y;
086:             }
087:             else {
088:                 v[0] = (x-xoffset)/Resolution;
089:                 v[1] = (yoffset-y)/Resolution;
090:             }
091:         }
092: 
093:         static public Vec2 sum(Vec2 a, Vec2 b)
094:         {
095:             return new Vec2(a.v[0]+b.v[0],a.v[1]+b.v[1]);
096:         }
097: 
098:         static public Vec2 diff(Vec2 a, Vec2 b)
099:         {
100:             return new Vec2(a.v[0]-b.v[0],a.v[1]-b.v[1]);
101:         }
102: 
103:         /**
104:          * returns magnitude of 2D vector
105:          */
106:         public double magn()
107:         {
108:             return Math.sqrt(v[0]*v[0]+v[1]*v[1]);
109:         }
110: 
111:         // multiply point by a scalar
112:         public Vec2 scale(double s)
113:         {
114:             v[0] *= s;
115:             v[1] *= s;
116:             return this;
117:         }
118:            
119: 
120:         // offset (translate) point by the amount (tx, ty)
121:         public Vec2 translate(double tx, double ty)
122:         {
123:             v[0] += tx;
124:             v[1] += ty;
125:             return this;
126:         }
127: 
128:         // offset (translate) point by a Vec2
129:         public Vec2 translate(Vec2 b)
130:         {
131:             v[0] += b.v[0];
132:             v[1] += b.v[1];
133:             return this;
134:         }
135: 
136:         final static double radg = Math.atan(1)/45.0;
137: 
138:         // rotate point about the origin
139:         public Vec2 rotate(double theta)
140:         {
141:             double c, s, t;
142:             theta *= radg;
143:             c = Math.cos(theta);
144:             s = Math.sin(theta);
145:             t = v[1]*c+v[0]*s;
146:             v[0] = v[0]*c-v[1]*s;
147:             v[1] = t;
148:             return this;
149:         }
150: 
151:         public Vec2 perp()
152:         {
153:             double t = v[0];
154:             v[0] = -v[1];
155:             v[1] = t;
156:             return this;
157:         }
158: 
159:         static public Vec2 perp(Vec2 a)
160:         {
161:             return new Vec2(-a.v[1],a.v[0]);
162:         }
163: 
164:         static public double perpdot(Vec2 a, Vec2 b)
165:         {
166:             return (a.v[0]*b.v[1]-a.v[1]*b.v[0]);
167:         }
168: 
169:         static public double dot(Vec2 a, Vec2 b)
170:         {
171:             return (a.v[0]*b.v[0]+a.v[1]*b.v[1]);
172:         }
173: 
174:         static public double distance(Vec2 a, Vec2 b)
175:         {
176:             return Vec2.diff(a,b).magn();
177:         }
178:             
179:         //! returns angle (in degrees) between two vectors
180:         static public double angle(Vec2 a, Vec2 b)
181:         {
182:             double c, s;
183:             c = dot(a,b);
184:             s = perpdot(a,b);
185:             return Math.atan2(s,c)/radg;
186:         }
187: 
188:         public void setSize(double sz)
189:         {
190:             double vnorm = magn();
191:             if (vnorm==0.0) return;
192:             sz /= vnorm;
193:             v[0] *= sz;
194:             v[1] *= sz;
195:         }
196: 
197:         public void draw(Graphics g)
198:         {
199:             int [] iv = convert();
200:             g.fillOval(iv[0]-4,iv[1]-4,9,9);
201:         }   
202: 
203:    // convert the point into a String representation
204:    public String toString()
205:       { return String.format("[%.3g %.3g]",v[0],v[1]); }
206: 
207:    static public void  main(String args[])
208:    {
209:        Vec2 a, b, xaxis;
210:        a = new Vec2(0.2,0.5);
211:        System.out.println("a = " + a);
212:        int [] iv = a.convert();
213:        System.out.println("a.convert() = " + iv[0] + " " + iv[1]);
214:        System.out.println("perp(a) = " + perp(a) );
215:        b = new Vec2(1,0);
216:        b.scale(2).rotate(30);
217:        xaxis = new Vec2(1,0);
218:        System.out.println("b = " + b + String.format(" magn %.3g at %.3g deg.",b.magn(),angle(xaxis,b)));
219:    }
220: 
221: }


Maintained by John Loomis, updated Thu Mar 27 21:34:10 2008