comparison src/samer/tools/Plotter.java @ 0:bf79fb79ee13

Initial Mercurial check in.
author samer
date Tue, 17 Jan 2012 17:50:20 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:bf79fb79ee13
1 /*
2 * Copyright (c) 2000, Samer Abdallah, King's College London.
3 * All rights reserved.
4 *
5 * This software is provided AS iS and WITHOUT ANY WARRANTY;
6 * without even the implied warranty of MERCHANTABILITY or
7 * FITNESS FOR A PARTICULAR PURPOSE.
8 */
9
10 package samer.tools;
11 import samer.core.*;
12 import samer.core.util.*;
13 import java.awt.*;
14
15 /**
16 <p>
17 A Plotter object is a Canvas with its own Graphics
18 (ie a GCanvas) which has two LinearMaps
19 to map a portion of 2d space to the window.
20 It can optionally draw the X and Y axes.
21
22 <p>
23 The inner class Pen provides access to drawing
24 functions in the real-valued coordinate space.
25 */
26
27 public class Plotter extends samer.core.util.heavy.VCanvas
28 {
29 /** for passing to setAxes(int) */
30 public static final int NEITHER = 0;
31 public static final int YAXIS = 2;
32 public static final int XAXIS = 1;
33 public static final int BOTH = 3;
34 public IMap xmap, ymap;
35
36 int axesFlags=BOTH;
37 Color axesColor;
38
39 /**
40 Default constructor makes Plotter with both axes
41 drawn, in grey. LinearMaps take their default
42 setup.
43
44 @see samer.core.util.LinearMap
45 */
46
47 public Plotter()
48 {
49 xmap = new LinearMap();
50 ymap = new LinearMap();
51
52 axesColor=Shell.getColor("axesColor",Color.gray);
53 }
54
55 public void exposeMaps() {
56 exposeCommands(new VMap(xmap));
57 exposeCommands(new VMap(ymap));
58 }
59
60 protected void sized() {
61 // make sure maps map to whole window
62 xmap.setIntRange(width);
63 ymap.setIntRange(height);
64 }
65
66 public Dimension getPreferredSize() { return new Dimension(256,256); }
67
68 /** use one of NONE, XAXIS, YAXIS or BOTH */
69 public void setAxes(int f) { axesFlags=f; }
70 public void setAxesColor(Color c) { axesColor=c; }
71
72 /** not really for public use */
73 public void drawAxes(Graphics g)
74 {
75 if (axesFlags!=0) {
76 g.setColor(axesColor);
77
78 if ((axesFlags&XAXIS)!=0) {
79 int oy = height-ymap.toInt(0.0);
80 if (!ymap.wasClipped()) g.drawLine(0,oy,width-1,oy);
81 }
82
83 if ((axesFlags&YAXIS)!=0) {
84 int ox = xmap.toInt(0.0);
85 if (!xmap.wasClipped()) g.drawLine(ox,0,ox,height-1);
86 }
87
88 g.setColor(getForeground());
89 }
90 }
91
92 public void clear(Graphics g) { super.clear(g); drawAxes(g); }
93 public void paint(Graphics g) { Tools.initGraphics(g); drawAxes(g); }
94
95 /** return a new Pen for this Plotter */
96 public Pen getPen() { return new Pen(graphics); }
97 public Pen getPen(Graphics g) { return new Pen(g); }
98
99 // ----- drawing tools -------
100
101 /**
102 <p>
103 This class provides a state based plotting
104 environment (slightly inspired by Postscripts
105 crazy reverse polish). There is are <i>two</i>
106 current points: one for general use and another
107 which serves as the other point for lines,
108 rectangles and ellipses.
109
110 <p>
111 The primary current point can be set in absolute
112 coordinates using <code>abs(x,y)</code> or
113 moved relatively using <code>rel(dx,dy)</code>.
114 The folling functions use <i>only</i> the primary
115 current point:
116 <ul>
117 <li> <code>marker()</code>;
118 <li> <code>pixel()</code>;
119 <li> <code>blob()</code>.
120 </ul>
121 Calling <code>move()</code> copies the the location
122 of the primary current point to the secondary
123 current point. The following functions use both
124 the current points:
125 <ul>
126 <li> <code>line()</code>: line between both points;
127 <li> <code>rect()</code>: empty rectangle bounding both points
128 <li> <code>fillRect()</code>;
129 <li> <code>fill3DRect(boolean inOrOut)</code>;
130 <li> <code>ellipse()</code>;
131 <li> <code>fillEllipse()</code>.
132 </ul>
133 <p>
134 Some of the rectangle drawing commands
135 only work if the primary current point is below
136 and to the right (on the screen, that is) of the
137 secondary. The <code>rectify</code> function
138 swaps coordinates between the two points to make
139 it so. It will screw up any line drawing though.
140
141 */
142
143 public class Pen
144 {
145 Graphics graphics;
146 public Point p0=new Point(); // secondary
147 public Point p1=new Point(); // primary
148 vec2 r=new vec2(0,0);
149 int moff=3, msz=moff*2; // marker size
150 int ix, iy; // blob image hotspot
151 Color col=getForeground(); // current colour
152 Image blobImg; // drawn by blob()
153
154 /**
155 <p>
156 A program can have several Pens, each with different
157 colours, but the underlying Graphics has a
158 single current Color. So, if you have multiple Pens,
159 each pen must <code>activate()</code> its colour
160 before drawing anything.
161 */
162
163 public Pen(Graphics g) { graphics=g; }
164 final public Pen activate() { graphics.setColor(col); return this; }
165 final public Pen setColor(Color c) { col=c; graphics.setColor(c); return this; }
166 final public void setMarkerSize(int r) { moff=r; msz=2*r; }
167
168 /** returns true if the last primary current point was clipped */
169 public final boolean clipped() { return xmap.wasClipped() | ymap.wasClipped(); }
170 public final Pen abs( double x, double y) { r.x=x; r.y=y; map(); return this; }
171 public final Pen rel( double x, double y) { r.x+=x; r.y+=y; map(); return this; }
172
173 /** copies position of given pen to primary current point */
174 public final Pen set( Pen p) { r.x=p.r.x; r.y=p.r.y; p1.x=p.p1.x; p1.y=p.p1.y; return this; }
175 public final Pen move() { p0.x=p1.x; p0.y=p1.y; return this; }
176 public final Pen line() {
177 graphics.drawLine(p0.x,p0.y,p1.x,p1.y);
178 return this;
179 }
180
181 public Pen rect() {
182 graphics.drawRect(p0.x,p0.y,p1.x-p0.x,p1.y-p0.y);
183 return this;
184 }
185
186 public Pen fillRect() {
187 graphics.fillRect(p0.x,p0.y,p1.x-p0.x,p1.y-p0.y);
188 return this;
189 }
190
191 /** this swaps xs and ys to make sure rectangles work */
192 public Pen rectify() {
193 if (p1.y<p0.y) { int tmp=p0.y; p0.y=p1.y; p1.y=tmp; }
194 if (p1.x<p0.x) { int tmp=p0.x; p0.x=p1.x; p1.x=tmp; }
195 return this;
196 }
197
198 public Pen fill3DRect(boolean outin) {
199 if (p1.y!=p0.y) { // goes wrong otherwise
200 graphics.fill3DRect(p0.x,p0.y,p1.x-p0.x,p1.y-p0.y,outin);
201 }
202 return this;
203 }
204
205 public Pen ellipse() {
206 graphics.drawOval(p0.x,p0.y,p1.x-p0.x,p1.y-p0.y);
207 return this;
208 }
209
210 public Pen fillEllipse() {
211 graphics.fillOval(p0.x,p0.y,p1.x-p0.x,p1.y-p0.y);
212 return this;
213 }
214
215 public Pen marker() {
216 // graphics.drawOval(p1.x-moff,p1.y-moff,msz,msz);
217 graphics.fillRect(p1.x-moff,p1.y-moff,msz+1,msz+1);
218 // graphics.drawRect(p1.x-moff,p1.y-moff,msz,msz);
219 return this;
220 }
221
222 /** pixel drawn as 1x1 filled rectangle */
223 public Pen pixel() {
224 graphics.fillRect(p1.x,p1.y,1,1);
225 return this;
226 }
227
228 private Pen map() {
229 p1.x=xmap.toInt(r.x);
230 p1.y=ymap.toInt(r.y);
231 // if (xmap.wasClipped()) {
232 // if (p1.x<-16000) p1.x=-16000; else p1.x=16000;
233 // }
234 if (ymap.wasClipped()) {
235 if (p1.y<-32000) p1.y=32000;
236 else if (p1.y>32000) p1.y=-32000;
237 else p1.y=height-p1.y;
238 } else p1.y=height-p1.y;
239 return this;
240 }
241
242 /* These last three functions are here to speed up
243 two common operations:
244
245 moveto(x,y) is exactly equivalent to abs(x,y).map().move();
246 lineto(x,y) is exactly equivalent to abs(x,y).map().line().move();
247 lineto(x,y) is exactly equivalent to line().move() ;
248 */
249
250 public final Pen lineto()
251 {
252 graphics.drawLine(p0.x,p0.y,p1.x,p1.y);
253 p0.x=p1.x; p0.y=p1.y;
254 return this;
255 }
256
257 public final Pen lineto(double x, double y)
258 {
259 r.x=x; r.y=y; map();
260 graphics.drawLine(p0.x,p0.y,p1.x,p1.y);
261 p0.x=p1.x; p0.y=p1.y;
262 return this;
263 }
264
265 // this is exactly equivalent to abs(x,y).map().move();
266 public final Pen moveto(double x, double y)
267 {
268 r.x=x; r.y=y; map();
269 p0.x=p1.x; p0.y=p1.y;
270 return this;
271 }
272
273 /** draws the current blob image at the current point */
274 public Pen blob() {
275 graphics.drawImage(blobImg,ix+p1.x,iy+p1.y,null);
276 return this;
277 }
278
279 /** sets the blob image to be pixel of a given colour */
280 public void setBlobColor(Color col) {
281 blobImg=createPixel(col);
282 }
283
284 /** sets blob image to given image */
285 public void setBlobImage(Image i) { blobImg=i; ix=0; iy=0; }
286
287 /** sets blob image with given hotspot */
288 public void setBlobImage(Image i, int xhot, int yhot) { blobImg=i; ix=-xhot; iy=-yhot; }
289 }
290 }
291