SSISO Community

시소당

Custom Strokes

import  java.awt.BasicStroke;
import  java.awt.Color;
import  java.awt.Font;
import  java.awt.Graphics;
import  java.awt.Graphics2D;
import  java.awt.RenderingHints;
import  java.awt.Shape;
import  java.awt.Stroke;
import  java.awt.font.GlyphVector;
import  java.awt.geom.GeneralPath;
import  java.awt.geom.PathIterator;
import  java.awt.event.WindowAdapter;
import  java.awt.event.WindowEvent;
import  javax.swing.JFrame;
import  javax.swing.JPanel;

/**  A  demonstration  of  writing  custom  Stroke  classes  */
public  class  CustomStrokes  extends  JPanel{
    static  final  int  WIDTH  =  750,  HEIGHT  =  200;  //  Size  of  our  example

    public  String  getName()  {
        return  "Custom  Strokes";
    }

    public  int  getWidth()  {
        return  WIDTH;
    }

    public  int  getHeight()  {
        return  HEIGHT;
    }

    //  These  are  the  various  stroke  objects  we'll  demonstrate
    Stroke[]  strokes  =  new  Stroke[]  {  new  BasicStroke(4.0f),  //  The  standard,
            //  predefined
            //  stroke
            new  NullStroke(),  //  A  Stroke  that  does  nothing
            new  DoubleStroke(8.0f,  2.0f),  //  A  Stroke  that  strokes  twice
            new  ControlPointsStroke(2.0f),  //  Shows  the  vertices  &  control
            //  points
            new  SloppyStroke(2.0f,  3.0f)  //  Perturbs  the  shape  before  stroking
    };

    /**  Draw  the  example  */
    public  void  paint(Graphics  g1)  {
        Graphics2D  g  =  (Graphics2D)g1;
        //  Get  a  shape  to  work  with.  Here  we'll  use  the  letter  B
        Font  f  =  new  Font("Serif",  Font.BOLD,  200);
        GlyphVector  gv  =  f.createGlyphVector(g.getFontRenderContext(),  "B");
        Shape  shape  =  gv.getOutline();

        //  Set  drawing  attributes  and  starting  position
        g.setColor(Color.black);
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                RenderingHints.VALUE_ANTIALIAS_ON);
        g.translate(10,  175);

        //  Draw  the  shape  once  with  each  stroke
        for  (int  i  =  0;  i  <  strokes.length;  i++)  {
            g.setStroke(strokes[i]);  //  set  the  stroke
            g.draw(shape);  //  draw  the  shape
            g.translate(140,  0);  //  move  to  the  right
        }
    }

    public  static  void  main(String[]  a)  {
        JFrame  f  =  new  JFrame();
        f.addWindowListener(new  WindowAdapter()  {
            public  void  windowClosing(WindowEvent  e)  {
                System.exit(0);
            }
        });
        f.setContentPane(new  CustomStrokes());
        f.setSize(750,200);
        f.setVisible(true);
    }

}

/**
  *  This  Stroke  implementation  does  nothing.  Its  createStrokedShape()  method
  *  returns  an  unmodified  shape.  Thus,  drawing  a  shape  with  this  Stroke  is  the
  *  same  as  filling  that  shape!
  */

class  NullStroke  implements  Stroke  {
    public  Shape  createStrokedShape(Shape  s)  {
        return  s;
    }
}

/**
  *  This  Stroke  implementation  applies  a  BasicStroke  to  a  shape  twice.  If  you
  *  draw  with  this  Stroke,  then  instead  of  outlining  the  shape,  you're  outlining
  *  the  outline  of  the  shape.
  */

class  DoubleStroke  implements  Stroke  {
    BasicStroke  stroke1,  stroke2;  //  the  two  strokes  to  use

    public  DoubleStroke(float  width1,  float  width2)  {
        stroke1  =  new  BasicStroke(width1);  //  Constructor  arguments  specify
        stroke2  =  new  BasicStroke(width2);  //  the  line  widths  for  the  strokes
    }

    public  Shape  createStrokedShape(Shape  s)  {
        //  Use  the  first  stroke  to  create  an  outline  of  the  shape
        Shape  outline  =  stroke1.createStrokedShape(s);
        //  Use  the  second  stroke  to  create  an  outline  of  that  outline.
        //  It  is  this  outline  of  the  outline  that  will  be  filled  in
        return  stroke2.createStrokedShape(outline);
    }
}

/**
  *  This  Stroke  implementation  strokes  the  shape  using  a  thin  line,  and  also
  *  displays  the  end  points  and  Bezier  curve  control  points  of  all  the  line  and
  *  curve  segments  that  make  up  the  shape.  The  radius  argument  to  the  constructor
  *  specifies  the  size  of  the  control  point  markers.  Note  the  use  of  PathIterator
  *  to  break  the  shape  down  into  its  segments,  and  of  GeneralPath  to  build  up  the
  *  stroked  shape.
  */

class  ControlPointsStroke  implements  Stroke  {
    float  radius;  //  how  big  the  control  point  markers  should  be

    public  ControlPointsStroke(float  radius)  {
        this.radius  =  radius;
    }

    public  Shape  createStrokedShape(Shape  shape)  {
        //  Start  off  by  stroking  the  shape  with  a  thin  line.  Store  the
        //  resulting  shape  in  a  GeneralPath  object  so  we  can  add  to  it.
        GeneralPath  strokedShape  =  new  GeneralPath(new  BasicStroke(1.0f)
                .createStrokedShape(shape));

        //  Use  a  PathIterator  object  to  iterate  through  each  of  the  line  and
        //  curve  segments  of  the  shape.  For  each  one,  mark  the  endpoint  and
        //  control  points  (if  any)  by  adding  a  rectangle  to  the  GeneralPath
        float[]  coords  =  new  float[6];
        for  (PathIterator  i  =  shape.getPathIterator(null);  !i.isDone();  i
                .next())  {
            int  type  =  i.currentSegment(coords);
            Shape  s  =  null,  s2  =  null,  s3  =  null;
            switch  (type)  {
            case  PathIterator.SEG_CUBICTO:
                markPoint(strokedShape,  coords[4],  coords[5]);  //  falls  through
            case  PathIterator.SEG_QUADTO:
                markPoint(strokedShape,  coords[2],  coords[3]);  //  falls  through
            case  PathIterator.SEG_MOVETO:
            case  PathIterator.SEG_LINETO:
                markPoint(strokedShape,  coords[0],  coords[1]);  //  falls  through
            case  PathIterator.SEG_CLOSE:
                break;
            }
        }

        return  strokedShape;
    }

    /**  Add  a  small  square  centered  at  (x,y)  to  the  specified  path  */
    void  markPoint(GeneralPath  path,  float  x,  float  y)  {
        path.moveTo(x  -  radius,  y  -  radius);  //  Begin  a  new  sub-path
        path.lineTo(x  +  radius,  y  -  radius);  //  Add  a  line  segment  to  it
        path.lineTo(x  +  radius,  y  +  radius);  //  Add  a  second  line  segment
        path.lineTo(x  -  radius,  y  +  radius);  //  And  a  third
        path.closePath();  //  Go  back  to  last  moveTo  position
    }
}

/**
  *  This  Stroke  implementation  randomly  perturbs  the  line  and  curve  segments  that
  *  make  up  a  Shape,  and  then  strokes  that  perturbed  shape.  It  uses  PathIterator
  *  to  loop  through  the  Shape  and  GeneralPath  to  build  up  the  modified  shape.
  *  Finally,  it  uses  a  BasicStroke  to  stroke  the  modified  shape.  The  result  is  a
  *  "sloppy"  looking  shape.
  */

class  SloppyStroke  implements  Stroke  {
    BasicStroke  stroke;

    float  sloppiness;

    public  SloppyStroke(float  width,  float  sloppiness)  {
        this.stroke  =  new  BasicStroke(width);  //  Used  to  stroke  modified  shape
        this.sloppiness  =  sloppiness;  //  How  sloppy  should  we  be?
    }

    public  Shape  createStrokedShape(Shape  shape)  {
        GeneralPath  newshape  =  new  GeneralPath();  //  Start  with  an  empty  shape

        //  Iterate  through  the  specified  shape,  perturb  its  coordinates,  and
        //  use  them  to  build  up  the  new  shape.
        float[]  coords  =  new  float[6];
        for  (PathIterator  i  =  shape.getPathIterator(null);  !i.isDone();  i
                .next())  {
            int  type  =  i.currentSegment(coords);
            switch  (type)  {
            case  PathIterator.SEG_MOVETO:
                perturb(coords,  2);
                newshape.moveTo(coords[0],  coords[1]);
                break;
            case  PathIterator.SEG_LINETO:
                perturb(coords,  2);
                newshape.lineTo(coords[0],  coords[1]);
                break;
            case  PathIterator.SEG_QUADTO:
                perturb(coords,  4);
                newshape.quadTo(coords[0],  coords[1],  coords[2],  coords[3]);
                break;
            case  PathIterator.SEG_CUBICTO:
                perturb(coords,  6);
                newshape.curveTo(coords[0],  coords[1],  coords[2],  coords[3],
                        coords[4],  coords[5]);
                break;
            case  PathIterator.SEG_CLOSE:
                newshape.closePath();
                break;
            }
        }

        //  Finally,  stroke  the  perturbed  shape  and  return  the  result
        return  stroke.createStrokedShape(newshape);
    }

    //  Randomly  modify  the  specified  number  of  coordinates,  by  an  amount
    //  specified  by  the  sloppiness  field.
    void  perturb(float[]  coords,  int  numCoords)  {
        for  (int  i  =  0;  i  <  numCoords;  i++)
            coords[i]  +=  (float)  ((Math.random()  *  2  -  1.0)  *  sloppiness);
    }
}

1241 view

4.0 stars