3

JavaFX 2.1 での線の正確な幅について疑問に思っています。

ポイント (10;10) で開始し、ポイント (20;10) で終了する直線を作成すると、予想される幅は 10px になります。線の幅を読み取ると、11px の値が返されます。添付の例を開始してスクリーンショットを作成すると、より高いズーム レベルで、線の幅が 12px、高さが 2px であることがわかります。

a を使用しLineBuilderても違いはありません。私は別のイベントを適用しようとしましたが、StrokeType成功しませんでした。

一辺の長さが 10 の正方形を作成すると、予想される幅 10px が返されます。

  1. line.getBoundsInLocal().getWidth()がレンダリング結果 (スクリーンショット) に表示される値と異なる値を返すのはなぜですか?
  2. ラインとポリゴンを作成するとき、幅に違いがあるのはなぜですか?

例:

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.shape.Line;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;

public class ShapeWidthDemo extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Group root = new Group();

        int startX = 10;
        int startY = 10;
        int length = 10;

        Line line = new Line(startX, startY, startX + length, startY);
        System.out.println("line width: " + line.getBoundsInLocal().getWidth());
        //->line width: 11.0
        System.out.println("line height: " + line.getBoundsInLocal().getHeight());
        //->line height: 1.0
        root.getChildren().add(line);

        int startY2 = startY + 2;

        Polygon polygon = new Polygon(
            startX, startY2,
            startX + 10, startY2, 
            startX + 10, startY2 + 10, 
            startX, startY2 + 10);
        System.out.println("polygon width: " + polygon.getBoundsInLocal().getWidth());
        //->polygon width: 10.0
        System.out.println("polygon height: " + polygon.getBoundsInLocal().getHeight());
        //->polygon height: 10.0
        root.getChildren().add(polygon);

        stage.setScene(new Scene(root, 100, 100));
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
4

2 に答える 2

2

1) 線の終点は によって制御されStrokeLineCapます。
したがって、デフォルトのストローク幅では、「望ましい」値を次のように取得できます

line.setStrokeType(StrokeType.CENTERED);
line.setStrokeLineCap(StrokeLineCap.BUTT);
... that the line has a width of 12px and a height of 2px.

StrokeType.OUTSIDE AND NOT StrokeLineCap.BUTTを適用すると、これらの値を取得できます。ただし、ストロークの属性を変更しても、高さは 2px のままです。それは奇妙だ..

2) ポリゴンのストローク値がデフォルトで NULL であるためです。polygon.setStroke(Color.RED);ストロークがレンダリングされるように設定することで。

于 2012-08-09T11:24:47.597 に答える
1

線自体は表面積がまったくないものと考えてください。無限に細い線です。線の寸法はストロークのみです。

StrokeTypeがCENTEREDで、StrokeLineCapがSQUARE(デフォルト値)の場合、線が占める面積は、線の周りのストローク幅の半分をすべての方向に均等に適用することで得られます。

あなたの例では、整数座標でストローク1の水平線を描画しています。JavaFX座標系は、整数のコーナーがピクセル間の線にマッピングされるようなものです。整数の座標で水平線を表示すると、線自体が線の両側の2つの垂直ピクセルの半分と交差し、1つの垂直ピクセルのみをシェーディングする黒い線ではなく、灰色のシェーディングされたアンチエイリアスラインになります。さらに、線の端に適用されるSQUAREのStrokeLineCapは、ストロークが線の端点を超えてストローク幅の半分だけ延びることを意味します。これにより、線の端の両側にある2組のピクセルの各ピクセルの4分の1がシェーディングされます。

線の座標を0.5ピクセルオフセットすることにより、線が各ピクセルの中央に沿って下降し、線のストロークが上まで伸びているため、垂直ピクセルの単一の行をシェーディングするように線を描画できます。各ピクセルの下端。さらに、ラインキャップを正方形ではなく突き合わせに設定すると、ラインの影付きの領域がラインの端を超えないようになります。

これを示すためのサンプルコードを次に示します。サンプルでは、​​最後の行だけが正確に10ピクセルを完全にシェーディングし、それ以上はシェーディングしません。また、境界ボックスに幅が10で、座標が整数である唯一の線です。

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.shape.Line;
import javafx.scene.shape.StrokeLineCap;
import javafx.stage.Stage;

public class LineBounds extends Application {
  public static void main(String[] args) { launch(args); }
  @Override public void start(Stage stage) throws Exception {
    double startX = 10;
    double startY = 10;
    double length = 10;

    Line lineSpanningPixelsSquareEnd = new Line(startX, startY, startX + length, startY);
    System.out.println("lineSpanningPixels (square) bounding box: " + lineSpanningPixelsSquareEnd.getBoundsInLocal());

    startX = 10;
    startY = 20;
    length = 10;

    Line lineSpanningPixelsButtEnd = new Line(startX, startY, startX + length, startY);
    lineSpanningPixelsButtEnd.setStrokeLineCap(StrokeLineCap.BUTT);
    System.out.println("lineSpanningPixels (butt) bounding box:   " + lineSpanningPixelsButtEnd.getBoundsInLocal());

    startX = 10;
    startY = 29.5;
    length = 10;

    Line lineOnPixelsSquareEnd = new Line(startX, startY, startX + length, startY);
    System.out.println("lineOnPixels (square) bounding box:       " + lineOnPixelsSquareEnd.getBoundsInLocal());

    startX = 10;
    startY = 39.5;
    length = 10;

    Line lineOnPixelsButtEnd = new Line(startX, startY, startX + length, startY);
    lineOnPixelsButtEnd.setStrokeLineCap(StrokeLineCap.BUTT);
    System.out.println("lineOnPixels (butt) bounding box:         " + lineOnPixelsButtEnd.getBoundsInLocal());

    stage.setScene(
      new Scene(
        new Group(
          lineSpanningPixelsSquareEnd, lineSpanningPixelsButtEnd, lineOnPixelsSquareEnd, lineOnPixelsButtEnd
        ), 100, 100
      )
    );
    stage.show();
  }
}

サンプルプログラムの出力は次のとおりです。

lineSpanningPixels (square) bounding box: BoundingBox [minX:9.5, minY:9.5, minZ:0.0, width:11.0, height:1.0, depth:0.0, maxX:20.5, maxY:10.5, maxZ:0.0]
lineSpanningPixels (butt) bounding box:   BoundingBox [minX:10.0, minY:19.5, minZ:0.0, width:10.0, height:1.0, depth:0.0, maxX:20.0, maxY:20.5, maxZ:0.0]
lineOnPixels (square) bounding box:       BoundingBox [minX:9.5, minY:29.0, minZ:0.0, width:11.0, height:1.0, depth:0.0, maxX:20.5, maxY:30.0, maxZ:0.0]
lineOnPixels (butt) bounding box:         BoundingBox [minX:10.0, minY:39.0, minZ:0.0, width:10.0, height:1.0, depth:0.0, maxX:20.0, maxY:40.0, maxZ:0.0]

ラインバウンドサンプルプログラム出力

于 2012-08-10T00:19:42.000 に答える