Mercurial > hg > jslab
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 |