/* * [Screws.java] * * Summary: Draws eight types of screw heads to teach the use of Canvas. * * Copyright: (c) 2002-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2002-03-09 * 1.1 2002-03-09 add Posi-Drive ake PoziDrive * simplify code with fillCentredRect * use of temp variables to clarify the code. * demonstrate use of AffineTransform. * 1.2 2008-01-01 add pad, ANT script, icon * 1.3 2009-03-25 use anti-aliasing to improve look. */ package com.mindprod.screws; import java.awt.Canvas; import java.awt.Color; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Polygon; import java.awt.RenderingHints; import java.awt.geom.AffineTransform; /** * Draws eight types of screw heads to teach the use of Canvas. *

* Demonstrate simple drawing, draws eight types of screw heads. A teaching * example for how to use Java Canvas, * fillRect, fillOval, fillPoly and AffineTransform to draw. * * @author Roedy Green, Canadian Mind Products * @version 1.3 2009-03-25 use anti-aliasing to improve look. * @since 2002-03-09 */ public class Screws { private static final int FIRST_COPYRIGHT_YEAR = 2002; /** * undisplayed copyright notice * * @noinspection UnusedDeclaration */ private static final String EMBEDDED_COPYRIGHT = "Copyright: (c) 2002-2017 Roedy Green, Canadian Mind Products, http://mindprod.com"; /** * date this version released. * * @noinspection UnusedDeclaration */ private static final String RELEASE_DATE = "2009-03-25"; /** * embedded version string. * * @noinspection UnusedDeclaration */ private static final String VERSION_STRING = "1.3"; /** * Draws five type of screw head. Just a demo of simple Java drawing. * * @param args not used */ public static void main( String[] args ) { Frame f = new Frame( "Screws" ); f.setSize( 600, 300 ); f.setLayout( new FlowLayout() ); f.setBackground( Color.white ); ScrewCanvas s = new ScrewCanvas(); s.setSize( 100, 100 ); s.setScrewType( 0 ); f.add( s ); ScrewCanvas p = new ScrewCanvas(); p.setSize( 100, 100 ); p.setScrewType( 1 ); f.add( p ); ScrewCanvas pd = new ScrewCanvas(); pd.setSize( 100, 100 ); pd.setScrewType( 2 ); f.add( pd ); ScrewCanvas r = new ScrewCanvas(); r.setSize( 100, 100 ); r.setScrewType( 3 ); f.add( r ); ScrewCanvas t5 = new ScrewCanvas(); t5.setSize( 100, 100 ); t5.setScrewType( 4 ); f.add( t5 ); ScrewCanvas t6 = new ScrewCanvas(); t6.setSize( 100, 100 ); t6.setScrewType( 5 ); f.add( t6 ); ScrewCanvas a = new ScrewCanvas(); a.setSize( 100, 100 ); a.setScrewType( 6 ); f.add( a ); ScrewCanvas w = new ScrewCanvas(); w.setSize( 100, 100 ); w.setScrewType( 7 ); f.add( w ); f.setVisible( true ); f.addWindowListener ( new java.awt.event.WindowAdapter() { /** * Handle request to shutdown. * @param e event giving details of closing. */ public void windowClosing( java.awt.event.WindowEvent e ) { System.exit( 0 ); } // end WindowClosing } // end anonymous class );// end addWindowListener line } } /** * Draws various types of screw heads */ class ScrewCanvas extends Canvas { /** * diameter of screw head in pixels. */ private static final int headDiameter = 100; /** * width of the slot on the screw head in pixels. */ private static final int slotWidth = 12; /** * x center of screw head, in pixels. */ private static final int xcenter = 50; /** * y center of screw head, in pixels. Y grows down. */ private static final int ycenter = 50; /** * Background colour of the images. */ private static final Color background = Color.white; /** * Colour to represent the colour of a nut driver, mid-green. */ private static final Color driverColor = new Color( 0x00c000 ); /** * colour of screw head. */ private static final Color headColor = Color.red; /** * colour of screw slot. */ private static final Color slotColor = Color.black; /** * type of screw to draw * * @see #setScrewType for a list of types */ private int screwType; /** * fill in a rectangle * * @param g Where to draw. * @param xcenter where rectangle in centred on x-axis, in pixels. * @param ycenter where rectangle is centred on y-axis, in pixels. * @param width width of rectangle. * @param height heigh of rectangle. */ private static void fillCentredRect( Graphics g, int xcenter, int ycenter, int width, int height ) { g.fillRect( xcenter - width / 2, ycenter - height / 2, width, height ); } /** * fill in a circle * * @param g Where to draw. * @param xcenter where circle in centred on x-axis, in pixels. * @param ycenter where circle is centred on y-axis, in pixels. * @param radius radius of circle on which all the vertices fall. */ private static void fillCircle( Graphics g, int xcenter, int ycenter, int radius ) { g.fillOval( xcenter - radius, ycenter - radius, radius * 2, radius * 2 ); } /** * Create a regular closed polygon, (all sides equal length, all interior angles equal). Vertices are generated in * counter clockwise order. * * @param xcenter where polygon in centred on x-axis in pixels * @param ycenter where polygon is centred on y-axis, in pixels. * @param radius radius of circle on which all the vertices fall. * @param sides n, the number of sides. * @param rotation angle in radians to the left of the vertical. If the rotation is zero, one vertex will fall at * the center top. * * @return Polygon containing n integer points. */ private static Polygon regularPolygon( int xcenter, int ycenter, int radius, int sides, double rotation ) { /* Polygon has no constructor to suggest how big the final polygon will eventually be. By building our own point arrays, we avoid most of the auto-growing overhead in Polygon. */ int[] xpoints = new int[ sides ]; int[] ypoints = new int[ sides ]; /* We define vertices in mathematically positive, counter-clockwise order. We could negate delta to define in clockwise order. drawPolygon and fillPolygon don't see to care. */ double delta = Math.PI * 2 / sides; for ( int i = 0; i < sides; i++ ) { double angle = delta * i + Math.PI / 2 + rotation; xpoints[ i ] = ( int ) ( radius * Math.cos( angle ) + .5 ) + xcenter; /* negative to compensate for Java.awt y axis reverse convention to math */ ypoints[ i ] = ycenter - ( int ) ( radius * Math.sin( angle ) + .5 ); } /* we don't bother to close the polygon since fillPolygon etc. does that automatically. */ return new Polygon( xpoints, ypoints, sides ); } /** * does drawing * * @param g where to paint */ void render( Graphics g ) { g.setColor( background ); g.fillRect( 0, 0, headDiameter, headDiameter ); g.setColor( headColor ); /* draw a solid circle to represent the screw head */ fillCircle( g, xcenter, ycenter, headDiameter / 2 ); g.setColor( slotColor ); switch ( screwType ) { case 0: { /* draw vertical slot flat blade screw. */ fillCentredRect( g, xcenter, xcenter, slotWidth, headDiameter ); break; } case 1: { /* draw cross for Phillips. Cross does not go all the way across the head. */ final int slotLength = headDiameter - slotWidth * 3; /* vertical slot */ fillCentredRect( g, xcenter, ycenter, slotWidth, slotLength ); /* horizontal slot. draw rotated slot. */ fillCentredRect( g, xcenter, ycenter, slotLength, slotWidth ); break; } case 2: { /* draw cross for with x whiskers for Posi-Drive aka PoziDrive. like Phillips. See photo at: http://www.xkms.org/Power-Tools-Power-DrillsDrivers/3-PoziDrive-Screwdriving-Bit-Tip.htm */ final int slotLength = headDiameter - slotWidth * 3; final int whiskerWidth = slotWidth / 4; final int whiskerLength = headDiameter * 3 / 10; /* vertical slot */ fillCentredRect( g, xcenter, ycenter, slotWidth, slotLength ); /* horizontal slot */ fillCentredRect( g, xcenter, ycenter, slotLength, slotWidth ); /* use 2D package */ Graphics2D g2 = ( Graphics2D ) g; AffineTransform at = new AffineTransform(); /* rotate 45 degrees counter-clockwise*/ at.rotate( Math.PI / 4, xcenter, ycenter ); g2.setTransform( at ); /* draw vertical whisker, which will rotate to \ */ fillCentredRect( g2, xcenter, ycenter, whiskerWidth, whiskerLength ); /* draw another vertical whisker, which will rotate to / */ /* rotate another 90 degrees counter clockwise*/ at.rotate( Math.PI / 2, xcenter, ycenter ); // Yes, the following setTransform is necessary. g2.setTransform( at ); fillCentredRect( g2, xcenter, ycenter, whiskerWidth, whiskerLength ); break; } case 3: { /* draw square for Robertson */ final int side = headDiameter * 15 / 35; fillCentredRect( g, xcenter, ycenter, side, side ); break; } case 4: { /* torx 5 lobe draw circle surrounted by five tiny circles roughly like gears. */ final int coreRadius = headDiameter / 5; final int lobeRadius = slotWidth * 3 / 4; final int lobes = 5; fillCircle( g, xcenter, ycenter, coreRadius ); Polygon vertices = regularPolygon( xcenter, ycenter, coreRadius, lobes, 0 ); for ( int i = 0; i < lobes; i++ ) { fillCircle( g, vertices.xpoints[ i ], vertices.ypoints[ i ], lobeRadius ); } break; } case 5: { /* torx 6 lobe draw circle surrounted by six tiny circles roughly like gears. */ final int coreRadius = headDiameter / 6; final int lobeRadius = slotWidth * 3 / 4; final int lobes = 6; fillCircle( g, xcenter, ycenter, coreRadius ); Polygon vertices = regularPolygon( xcenter, ycenter, coreRadius, lobes, 0 ); for ( int i = 0; i < lobes; i++ ) { fillCircle( g, vertices.xpoints[ i ], vertices.ypoints[ i ], lobeRadius ); } break; } case 6: { /* draw hexagon for Allen key, flat side up */ final int coreRadius = headDiameter * 10 / 35; final int sides = 6; g.fillPolygon( regularPolygon( xcenter, ycenter, coreRadius, sides, Math.PI / sides ) ); break; } case 7: { /* draw hexagon for socket wrench */ final int coreRadius = headDiameter * 7 / 16; final int sides = 6; g.setColor( driverColor ); /* redraw a solid circle to represent the driver */ fillCircle( g, xcenter, ycenter, headDiameter / 2 ); g.setColor( slotColor ); g.fillPolygon( regularPolygon( xcenter, ycenter, coreRadius, sides, 0 ) ); break; } default: throw new IllegalArgumentException(); } } // end paint /** * Draw a circle in outline * * @param g Graphics region where to paint. * @param xcenter where circle in centred on x-axis, in pixels. * @param ycenter where circle is centred on y-axis, in pixels. * @param radius radius of circle on which all the vertices fall. */ public static void drawCircle( Graphics g, int xcenter, int ycenter, int radius ) { g.drawOval( xcenter - radius, ycenter - radius, radius * 2, radius * 2 ); } /** * arrange for anti-alias, then do a custom render * * @param g where to paint */ public void paint( Graphics g ) { Graphics2D g2d = ( Graphics2D ) g; g2d.setRenderingHint( RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); g2d.setRenderingHint( RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY ); // smooth geometric shapes too g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON ); render( g2d ); } /** * Set type of screw to draw. * * @param screwType 0 = slot head 1 = Phillips 2 = Posi-Drive/PoziDrive 3 = Robertson 4 = Torx 5 lobe 5 = Torx 6 * lobe 6 = Allen key 7 = Socket wrench */ public void setScrewType( int screwType ) { this.screwType = screwType; } } // end class ScrewCanvas