1 /* 2 * 3 * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * - Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * - Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * - Neither the name of Oracle nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 34 package java2d.demos.Transforms; 35 36 import static java.awt.Color.BLACK; 37 import static java.awt.Color.BLUE; 38 import static java.awt.Color.CYAN; 39 import static java.awt.Color.GREEN; 40 import static java.awt.Color.LIGHT_GRAY; 41 import static java.awt.Color.MAGENTA; 42 import static java.awt.Color.ORANGE; 43 import static java.awt.Color.PINK; 44 import static java.awt.Color.RED; 45 import static java.awt.Color.WHITE; 46 import static java.awt.Color.YELLOW; 47 import static java.awt.Font.BOLD; 48 import static java.awt.Font.ITALIC; 49 import static java.awt.Font.PLAIN; 50 import java.awt.BasicStroke; 51 import java.awt.BorderLayout; 52 import java.awt.Color; 53 import java.awt.Component; 54 import java.awt.Dimension; 55 import java.awt.Font; 56 import java.awt.Graphics2D; 57 import java.awt.Image; 58 import java.awt.Paint; 59 import java.awt.Rectangle; 60 import java.awt.RenderingHints; 61 import java.awt.Shape; 62 import java.awt.TexturePaint; 63 import java.awt.event.ActionEvent; 64 import java.awt.event.ActionListener; 65 import java.awt.geom.AffineTransform; 66 import java.awt.geom.Arc2D; 67 import java.awt.geom.CubicCurve2D; 68 import java.awt.geom.Ellipse2D; 69 import java.awt.geom.GeneralPath; 70 import java.awt.geom.QuadCurve2D; 71 import java.awt.geom.Rectangle2D; 72 import java.awt.geom.RoundRectangle2D; 73 import java.awt.image.BufferedImage; 74 import java.util.ArrayList; 75 import java.util.List; 76 import java2d.AnimatingControlsSurface; 77 import java2d.CustomControls; 78 import javax.swing.AbstractButton; 79 import javax.swing.Box; 80 import javax.swing.BoxLayout; 81 import javax.swing.JSlider; 82 import javax.swing.JToggleButton; 83 import javax.swing.JToolBar; 84 import javax.swing.SwingConstants; 85 import javax.swing.border.EtchedBorder; 86 import javax.swing.border.TitledBorder; 87 import javax.swing.event.ChangeEvent; 88 import javax.swing.event.ChangeListener; 89 import javax.swing.plaf.metal.MetalBorders.ButtonBorder; 90 91 /** 92 * Animation of shapes, text and images rotating, scaling and translating 93 * around a canvas. 94 */ 95 @SuppressWarnings("serial") 96 public final class TransformAnim extends AnimatingControlsSurface { 97 98 private static final TexturePaint texturePaint; 99 static { 100 BufferedImage bi = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB); 101 Graphics2D gi = bi.createGraphics(); 102 gi.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 103 RenderingHints.VALUE_ANTIALIAS_ON); 104 gi.setColor(RED); 105 gi.fillOval(0,0,9,9); 106 texturePaint = new TexturePaint(bi,new Rectangle(0,0,10,10)); 107 } 108 109 private static BasicStroke bs = new BasicStroke(6); 110 private static Font[] fonts = { 111 new Font(Font.SERIF, PLAIN, 48), 112 new Font(Font.SERIF, BOLD|ITALIC, 24), 113 new Font(Font.MONOSPACED, BOLD, 36), 114 new Font(Font.SANS_SERIF, BOLD|ITALIC, 64), 115 new Font(Font.SANS_SERIF, PLAIN, 52)}; 116 private static String[] strings = { 117 "Transformation", "Rotate", "Translate", "Shear", "Scale" }; 118 private static String[] imgs = { "duke.png" }; 119 private static Paint[] paints = { 120 RED, BLUE, texturePaint, GREEN, MAGENTA, ORANGE, PINK, CYAN, 121 new Color(0, 255, 0, 128), new Color(0, 0, 255, 128), 122 YELLOW, LIGHT_GRAY, WHITE}; 123 private List<ObjData> objDatas = new ArrayList<ObjData>(13); 124 private int numShapes, numStrings, numImages; 125 protected boolean doRotate = true; 126 protected boolean doTranslate = true; 127 protected boolean doScale = true; 128 protected boolean doShear; 129 130 131 public TransformAnim() { 132 setBackground(BLACK); 133 setStrings(1); 134 setImages(2); 135 setShapes(10); 136 setControls(new Component[] { new DemoControls(this) }); 137 setConstraints(new String[] { BorderLayout.EAST }); 138 } 139 140 141 public void setImages(int num) { 142 if (num < numImages) { 143 List<ObjData> v = new ArrayList<ObjData>(objDatas.size()); 144 for (ObjData objData : objDatas) { 145 if (objData.object instanceof Image) { 146 v.add(objData); 147 } 148 } 149 objDatas.removeAll(v.subList(num, v.size())); 150 } else { 151 Dimension d = getSize(); 152 for (int i = numImages; i < num; i++) { 153 Object obj = getImage(imgs[i % imgs.length]); 154 ObjData objData = new ObjData(obj, BLACK); 155 objData.reset(d.width, d.height); 156 objDatas.add(objData); 157 } 158 } 159 numImages = num; 160 } 161 162 163 public void setStrings(int num) { 164 if (num < numStrings) { 165 List<ObjData> v = new ArrayList<ObjData>(objDatas.size()); 166 for (ObjData objData : objDatas) { 167 if (objData.object instanceof TextData) { 168 v.add(objData); 169 } 170 } 171 objDatas.removeAll(v.subList(num, v.size())); 172 } else { 173 Dimension d = getSize(); 174 for (int i = numStrings; i < num; i++) { 175 int j = i % fonts.length; 176 int k = i % strings.length; 177 Object obj = new TextData(strings[k], fonts[j]); 178 ObjData objData = new ObjData(obj, paints[i%paints.length]); 179 objData.reset(d.width, d.height); 180 objDatas.add(objData); 181 } 182 } 183 numStrings = num; 184 } 185 186 187 public void setShapes(int num) { 188 if (num < numShapes) { 189 List<ObjData> v = new ArrayList<ObjData>(objDatas.size()); 190 for (ObjData objData : objDatas) { 191 if (objData.object instanceof Shape) { 192 v.add(objData); 193 } 194 } 195 objDatas.removeAll(v.subList(num, v.size())); 196 } else { 197 Dimension d = getSize(); 198 for (int i = numShapes; i < num; i++) { 199 Object obj = null; 200 switch (i % 7) { 201 case 0 : obj = new GeneralPath(); break; 202 case 1 : obj = new Rectangle2D.Double(); break; 203 case 2 : obj = new Ellipse2D.Double(); break; 204 case 3 : obj = new Arc2D.Double(); break; 205 case 4 : obj = new RoundRectangle2D.Double(); break; 206 case 5 : obj = new CubicCurve2D.Double(); break; 207 case 6 : obj = new QuadCurve2D.Double(); break; 208 } 209 ObjData objData = new ObjData(obj, paints[i%paints.length]); 210 objData.reset(d.width, d.height); 211 objDatas.add(objData); 212 } 213 } 214 numShapes = num; 215 } 216 217 218 @Override 219 public void reset(int w, int h) { 220 for (ObjData objData : objDatas) { 221 objData.reset(w, h); 222 } 223 } 224 225 226 @Override 227 public void step(int w, int h) { 228 for (ObjData objData : objDatas) { 229 objData.step(w, h, this); 230 } 231 } 232 233 234 @Override 235 public void render(int w, int h, Graphics2D g2) { 236 for (ObjData objData : objDatas) { 237 g2.setTransform(objData.at); 238 g2.setPaint(objData.paint); 239 if (objData.object instanceof Image) { 240 g2.drawImage((Image) objData.object, 0, 0, this); 241 } else if (objData.object instanceof TextData) { 242 g2.setFont(((TextData) objData.object).font); 243 g2.drawString(((TextData) objData.object).string, 0, 0); 244 } else if (objData.object instanceof QuadCurve2D 245 || objData.object instanceof CubicCurve2D) 246 { 247 g2.setStroke(bs); 248 g2.draw((Shape) objData.object); 249 } else if (objData.object instanceof Shape) { 250 g2.fill((Shape) objData.object); 251 } 252 } 253 } 254 255 256 public static void main(String[] argv) { 257 createDemoFrame(new TransformAnim()); 258 } 259 260 261 static class TextData extends Object { 262 263 public String string; 264 public Font font; 265 266 public TextData(String str, Font font) { 267 string = str; 268 this.font = font; 269 } 270 } 271 272 273 static class ObjData extends Object { 274 Object object; 275 Paint paint; 276 static final int UP = 0; 277 static final int DOWN = 1; 278 double x, y; 279 double ix=5, iy=3; 280 int rotate; 281 double scale, shear; 282 int scaleDirection, shearDirection; 283 AffineTransform at = new AffineTransform(); 284 285 286 public ObjData(Object object, Paint paint) { 287 this.object = object; 288 this.paint = paint; 289 rotate = (int)(Math.random() * 360); 290 scale = Math.random() * 1.5; 291 scaleDirection = Math.random() > 0.5 ? UP : DOWN; 292 shear = Math.random() * 0.5; 293 shearDirection = Math.random() > 0.5 ? UP : DOWN; 294 } 295 296 297 public void reset(int w, int h) { 298 x = Math.random()*w; 299 y = Math.random()*h; 300 double ww = 20 + Math.random()*((w == 0 ? 400 : w)/4); 301 double hh = 20 + Math.random()*((h == 0 ? 300 : h)/4); 302 if (object instanceof Ellipse2D) { 303 ((Ellipse2D) object).setFrame(0, 0, ww, hh); 304 } else if (object instanceof Rectangle2D) { 305 ((Rectangle2D) object).setRect(0, 0, ww, ww); 306 } else if (object instanceof RoundRectangle2D) { 307 ((RoundRectangle2D) object).setRoundRect(0, 0, hh, hh, 20, 20); 308 } else if (object instanceof Arc2D) { 309 ((Arc2D) object).setArc(0, 0, hh, hh, 45, 270, Arc2D.PIE); 310 } else if (object instanceof QuadCurve2D) { 311 ((QuadCurve2D) object).setCurve(0, 0, w*.2, h*.4, w*.4, 0); 312 } else if (object instanceof CubicCurve2D) { 313 ((CubicCurve2D) object).setCurve(0,0,30,-60,60,60,90,0); 314 } else if (object instanceof GeneralPath) { 315 GeneralPath p = new GeneralPath(); 316 float size = (float) ww; 317 p.moveTo(- size / 2.0f, - size / 8.0f); 318 p.lineTo(+ size / 2.0f, - size / 8.0f); 319 p.lineTo(- size / 4.0f, + size / 2.0f); 320 p.lineTo(+ 0.0f, - size / 2.0f); 321 p.lineTo(+ size / 4.0f, + size / 2.0f); 322 p.closePath(); 323 object = p; 324 } 325 } 326 327 328 public void step(int w, int h, TransformAnim demo) { 329 at.setToIdentity(); 330 if (demo.doRotate) { 331 if ((rotate+=5) == 360) { 332 rotate = 0; 333 } 334 at.rotate(Math.toRadians(rotate), x, y); 335 } 336 at.translate(x, y); 337 if (demo.doTranslate) { 338 x += ix; 339 y += iy; 340 if (x > w) { 341 x = w - 1; 342 ix = Math.random() * -w/32 - 1; 343 } 344 if (x < 0) { 345 x = 2; 346 ix = Math.random() * w/32 + 1; 347 } 348 if (y > h ) { 349 y = h - 2; 350 iy = Math.random() * -h/32 - 1; 351 } 352 if (y < 0) { 353 y = 2; 354 iy = Math.random() * h/32 + 1; 355 } 356 } 357 if (demo.doScale && scaleDirection == UP) { 358 if ((scale += 0.05) > 1.5) { 359 scaleDirection = DOWN; 360 } 361 } else if (demo.doScale && scaleDirection == DOWN) { 362 if ((scale -= .05) < 0.5) { 363 scaleDirection = UP; 364 } 365 } 366 if (demo.doScale) { 367 at.scale(scale, scale); 368 } 369 if (demo.doShear && shearDirection == UP) { 370 if ((shear += 0.05) > 0.5) { 371 shearDirection = DOWN; 372 } 373 } else if (demo.doShear && shearDirection == DOWN) { 374 if ((shear -= .05) < -0.5) { 375 shearDirection = UP; 376 } 377 } 378 if (demo.doShear) { 379 at.shear(shear, shear); 380 } 381 } 382 } // End ObjData class 383 384 385 386 static final class DemoControls extends CustomControls implements ActionListener, ChangeListener { 387 388 TransformAnim demo; 389 JSlider shapeSlider, stringSlider, imageSlider; 390 Font font = new Font(Font.SERIF, Font.BOLD, 10); 391 JToolBar toolbar; 392 ButtonBorder buttonBorder = new ButtonBorder(); 393 394 @SuppressWarnings("LeakingThisInConstructor") 395 public DemoControls(TransformAnim demo) { 396 super(demo.name); 397 this.demo = demo; 398 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 399 add(Box.createVerticalStrut(5)); 400 401 JToolBar bar = new JToolBar(SwingConstants.VERTICAL); 402 bar.setFloatable(false); 403 shapeSlider = new JSlider(SwingConstants.HORIZONTAL,0,20,demo.numShapes); 404 shapeSlider.addChangeListener(this); 405 TitledBorder tb = new TitledBorder(new EtchedBorder()); 406 tb.setTitleFont(font); 407 tb.setTitle(String.valueOf(demo.numShapes) + " Shapes"); 408 shapeSlider.setBorder(tb); 409 shapeSlider.setOpaque(true); 410 shapeSlider.setPreferredSize(new Dimension(80,44)); 411 bar.add(shapeSlider); 412 bar.addSeparator(); 413 414 stringSlider = new JSlider(SwingConstants.HORIZONTAL,0,10,demo.numStrings); 415 stringSlider.addChangeListener(this); 416 tb = new TitledBorder(new EtchedBorder()); 417 tb.setTitleFont(font); 418 tb.setTitle(String.valueOf(demo.numStrings) + " Strings"); 419 stringSlider.setBorder(tb); 420 stringSlider.setOpaque(true); 421 stringSlider.setPreferredSize(new Dimension(80,44)); 422 bar.add(stringSlider); 423 bar.addSeparator(); 424 425 imageSlider = new JSlider(SwingConstants.HORIZONTAL,0,10,demo.numImages); 426 imageSlider.addChangeListener(this); 427 tb = new TitledBorder(new EtchedBorder()); 428 tb.setTitleFont(font); 429 tb.setTitle(String.valueOf(demo.numImages) + " Images"); 430 imageSlider.setBorder(tb); 431 imageSlider.setOpaque(true); 432 imageSlider.setPreferredSize(new Dimension(80,44)); 433 bar.add(imageSlider); 434 bar.addSeparator(); 435 add(bar); 436 437 toolbar = new JToolBar(); 438 toolbar.setFloatable(false); 439 addButton("T", "translate", demo.doTranslate); 440 addButton("R", "rotate", demo.doRotate); 441 addButton("SC", "scale", demo.doScale); 442 addButton("SH", "shear", demo.doShear); 443 add(toolbar); 444 } 445 446 447 public void addButton(String s, String tt, boolean state) { 448 JToggleButton b = (JToggleButton) toolbar.add(new JToggleButton(s)); 449 b.setFont(font); 450 b.setSelected(state); 451 b.setToolTipText(tt); 452 b.setFocusPainted(false); 453 b.setBorder(buttonBorder); 454 b.addActionListener(this); 455 } 456 457 458 @Override 459 public void actionPerformed(ActionEvent e) { 460 JToggleButton b = (JToggleButton) e.getSource(); 461 if (b.getText().equals("T")) { 462 demo.doTranslate = b.isSelected(); 463 } else if (b.getText().equals("R")) { 464 demo.doRotate = b.isSelected(); 465 } else if (b.getText().equals("SC")) { 466 demo.doScale = b.isSelected(); 467 } else if (b.getText().equals("SH")) { 468 demo.doShear = b.isSelected(); 469 } 470 if (!demo.animating.running()) { 471 demo.repaint(); 472 } 473 } 474 475 476 @Override 477 public void stateChanged(ChangeEvent e) { 478 JSlider slider = (JSlider) e.getSource(); 479 int value = slider.getValue(); 480 TitledBorder tb = (TitledBorder) slider.getBorder(); 481 if (slider.equals(shapeSlider)) { 482 tb.setTitle(String.valueOf(value) + " Shapes"); 483 demo.setShapes(value); 484 } else if (slider.equals(stringSlider)) { 485 tb.setTitle(String.valueOf(value) + " Strings"); 486 demo.setStrings(value); 487 } else if (slider.equals(imageSlider)) { 488 tb.setTitle(String.valueOf(value) + " Images"); 489 demo.setImages(value); 490 } 491 if (!demo.animating.running()) { 492 demo.repaint(); 493 } 494 slider.repaint(); 495 } 496 497 498 @Override 499 public Dimension getPreferredSize() { 500 return new Dimension(80,38); 501 } 502 503 504 @Override 505 @SuppressWarnings("SleepWhileHoldingLock") 506 public void run() { 507 Thread me = Thread.currentThread(); 508 while (thread == me) { 509 for (int i = 1; i < toolbar.getComponentCount(); i++) { 510 try { 511 Thread.sleep(4444); 512 } catch (InterruptedException e) { return; } 513 ((AbstractButton) toolbar.getComponentAtIndex(i)).doClick(); 514 } 515 } 516 thread = null; 517 } 518 } // End DemoControls 519 } // End TransformAnim