annotate src/samer/tools/Plotter.java @ 8:5e3cbbf173aa tip

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