如何在JavaSwing中绘制大小也不同的平滑连续线?

如何在JavaSwing中绘制大小也不同的平滑连续线?,java,swing,drawing,line,smooth,Java,Swing,Drawing,Line,Smooth,我正在使用swing和JPen用Java编写一个2D传统动画程序。该应用程序运行良好。然而,我不满意我画线时得到的结果 使用JPen API,swing面板侦听手写笔输入,其代码为: /** * This method is called whenever the stylus makes contact with the tablet while inside of the JPanel functioning * as the Drawing Canvas. * @param

我正在使用swing和JPen用Java编写一个2D传统动画程序。该应用程序运行良好。然而,我不满意我画线时得到的结果

使用JPen API,swing面板侦听手写笔输入,其代码为:

    /**
 * 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;

}
因此,调用上述方法后,jpaneldrawingCanvas通过获取图像的图形2D开始在BuffereImage上绘制。以下是代码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()  );
}

我对许多代码进行了注释,并提供了与问题相关的关键点。非常感谢您的帮助。同样,问题是如何绘制一条与下降绘图程序相当的平滑线。

任何绘图程序只能在响应鼠标事件时绘制。问题是,鼠标移动时不会为每个像素生成MouseEvents,因此在图形中会出现间隙。您需要跟踪当前/以前的点,并在两者之间绘制直线,以获得完整的实线。我一直在跟踪当前和以前的点。例如,我将上一点输出到控制台的当前点,对于一个冲程,得到以下读数:行259.0 416.0 258.0 416.0行258.0 416.0 259.0 416.0行259.0 416.0 260.0 417.0行260.0 417.0 262.0 417.0行267.0 417.0行267.0 417.0 276.0行276.0 415.0行290.0 413.0行290.0 413.0308.0 410.0行308.0 410.0 330.0 407.0