How to Draw a Continuous Line on Java
I am writing a 2D traditional animation program in Java using swing and JPen. The application works well. However, i am dissatisfied with the results I am getting when I draw lines.
Using the JPen API, the swing panel listens for the stylus input and its code is:
/** * This method is called whenever the stylus makes contact with the tablet while inside of the JPanel functioning * as the Drawing Canvas. * @param evt */ public void penLevelEvent(PLevelEvent evt) { // Get kind of event: does it come from mouse (CURSOR), STYLUS or ERASER? PKind kind = evt.pen.getKind(); // Discard events from mouse if (kind == PKind.valueOf(PKind.Type.CURSOR)){ //System.out.println("returning since this is only a mouse cursor"); return; } // Get the current cursor location // position value is in with respect to entire application window // Get the tilt values (not with a Bamboo... so untested!) float curX = evt.pen.getLevelValue(PLevel.Type.X); float curY = evt.pen.getLevelValue(PLevel.Type.Y); float pressure = evt.pen.getLevelValue(PLevel.Type.PRESSURE);// 0.0 - 1.0 float xTilt = evt.pen.getLevelValue(PLevel.Type.TILT_X); float yTilt = evt.pen.getLevelValue(PLevel.Type.TILT_Y); // Set the brush's size, and darkness relative to the pressure float darkness = 255 * pressure; // Transform them to azimuthX and altitude, two angles with the projection of the pen against the X-Y plane // azimuthX is the angle (clockwise direction) between this projection and the X axis. Range: -pi/2 to 3*pi/2. // altitude is the angle between this projection and the pen itself. Range: 0 to pi/2. // Might be more pratical to use than raw x/y tilt values. double[] aa = { 0.0, 0.0 }; PLevel.Type.evalAzimuthXAndAltitude(aa, xTilt, yTilt); // or just PLevel.Type.evalAzimuthXAndAltitude(aa, evt.pen); double azimuthX = aa[0]; double altitude = aa[1]; //------------------------------------------------------------------------------------- // If the stylus is being pressed down, we want to draw a black // line onto the screen. If it's the eraser, we want to create // a white line, effectively "erasing" the black line //------------------------------------------------------------------------------------- if (kind == PKind.valueOf(PKind.Type.STYLUS)) { //System.out.println("Darkness "+darkness); int alpha = 255 - (int)darkness; color = new Color(0,0,255, 255 - alpha); } else if (kind == PKind.valueOf(PKind.Type.ERASER)) { System.out.println("Handle eraser"); } else { return; // IGNORE or CUSTOM... } //If movement of the stylus is occuring if (evt.isMovement()) { //and the buttonIsDown(boolean) if(buttonIsDown) { //drawingCanvas:JPanel -> instruct the jpanel to draw at the following coordinate using the specified pressure drawingCanvas.stylusMovementInput( prevXPos,prevYPos, curX,curY, pressure); } prevXPos = curX; prevYPos = curY; } prevXPos = curX; prevYPos = curY; }
So after the above method is invoked, the jpanel(drawingCanvas) starts to draw on a BufferedImage by obtaining the image's graphics2D. Here is the code stylusMovementInput->calls -> performDrawOnBufferImageGraphic2D :
/** * Draw on the active frame that is selected. Then call channel refresh, to refresh the the composite image derived * from call changes related to the current frame * @param cX current * @param cY current * @param oX previous * @param oY previous * @param pressure pressure 0 - 1f */ private void performDrawOnBufferImageGraphic2D(float oX, float oY, float cX, float cY, float pressure){ //Obtain the current layer that user wants to draw one //MyImageData is encapsulating a BufferedImage MyImageData $activeData = getActiveLayer(); //Exit if one is not valid if( $activeData == null) return; //if valid layer, get the, get the bufferedImage.getGraphics Graphics2D $activeDataGFX = $activeData.getImageGraphics(); // Customize the drawing brush (create a BasicStroke) Stroke thickness = Sys.makeStroke(getPencilSize(pressure), null); // Determine the tranparency with respect to the pressure int alpha = (int)(255 * pressure * getPencilOpacityPercentage()); // Get the current color found in the color wheel Color cwVal = Sys.getColorFromColorWheel(); Color drawingColor ; if(cwVal != null){ // add alpha value to it drawingColor = new Color(cwVal.getRed(), cwVal.getGreen(), cwVal.getBlue(), alpha); }else throw new RuntimeException("ColorWheel is null drawing stylus draw"); //set the brush and drawingColor $activeDataGFX.setStroke(thickness); // Save reference to the current bufferedImage graphic component Composite originalComposite =$activeDataGFX.getComposite(); if(getCurrentTool() == DrawingCanvasTool.ERASER){ //If eraser, set new composite information, to allow erasing to transparency $activeDataGFX.setPaint( new Color(255,255,255, 0)); $activeDataGFX.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, 0.0f)); }else { //set the drawing color $activeDataGFX.setPaint(drawingColor); } //--------------------------------------------------------------- // Rotate, Translate, Zoom the image according to the panning, zoom, and rotate // set by the user //--------------------------------------------------------------- //Figure out the canvas center, as it is used for rotating float theta = (float)Math.toRadians(canvasRotation); Dimension drawingAreaComponentSize = getSize(); float centerX = drawingAreaComponentSize.width/2; float centerY = drawingAreaComponentSize.height/2; AffineTransform transform = new AffineTransform(); transform.rotate(-theta, centerX, centerY); transform.scale(1.0f / canvasZoom, 1.0f / canvasZoom);//erase transform.translate(-canvasPan.x, -canvasPan.y);//erase $activeDataGFX.setTransform(transform); //Now Draw inside of the active data graphics object Shape line = new Line2D.Float(cX,cY, oX, oY); Path2D.Float t = new Path2D.Float(line); $activeDataGFX.draw(t); //drawing is complete if(getCurrentTool() ==DrawingCanvasTool.ERASER){ //Restore the old composite object $activeDataGFX.setComposite(originalComposite); } //Refresh basically merges frames along a frame column into a single preview buffered image //which will later be used to view the tool animation when user clicks "play" button channelPannel.refreshFrameOut( channelPannel.getCurrentFrame() ); }
I commented a lot of the code, and provided the critical points related to the question. Any help is much appreciated. And again, the problem is how do i draw a smooth line worthy of a descent drawing program.
Source: https://stackoverflow.com/questions/32924112/how-to-draw-smooth-continuous-line-in-java-swing-that-also-varies-in-size
0 Response to "How to Draw a Continuous Line on Java"
Enviar um comentário