4

这篇文章是我对一个问题的回答的一个套件:Transforming a shape

这是我想要的图像:

文字是水平的

这是一个简单程序生成的图像,您可以看到文本已旋转。我想要水平文本:

文字旋转

画布被缩放、平移、旋转以进行绘图,因此文本不会水平显示并且字体大小需要大大减小(1.4)。该程序是用 Java(awt 和 JavaFX)编写的,但问题与语言或技术无关,因此欢迎提出任何建议。

这是一个简单的程序:

import javafx.application.Application;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;

public class TransRotScale extends Application {

   private static void drawGraph( GraphicsContext g ) {
      //---
      g.scale( 10.0, 10.0 );
      g.rotate( Math.toDegrees( Math.atan2( -15.0, 40.0 )));
      g.translate( -8, -10 );
      //---
      g.setStroke( Color.DARKRED );
      g.setLineWidth( LINE_WIDTH );
      g.strokeLine( 10, 20, 10, 30 );
      g.strokeLine( 10, 30, 50, 30 );
      g.strokeLine( 50, 30, 50, 35 );
      //---
      g.setFill( Color.BLACK );
      g.fillOval( 50-ENDPOINT_RADIUS, 35-ENDPOINT_RADIUS,
         ENDPOINT_DIAMETER, ENDPOINT_DIAMETER );
      g.fillOval( 10-ENDPOINT_RADIUS, 20-ENDPOINT_RADIUS,
         ENDPOINT_DIAMETER, ENDPOINT_DIAMETER );
      //---
      g.setFill( Color.LIGHTSALMON );
      g.fillOval( 10-ENDPOINT_RADIUS, 30-ENDPOINT_RADIUS,
         ENDPOINT_DIAMETER, ENDPOINT_DIAMETER );
      g.fillOval( 50-ENDPOINT_RADIUS, 30-ENDPOINT_RADIUS,
         ENDPOINT_DIAMETER, ENDPOINT_DIAMETER );
      //---
      g.setStroke( Color.DARKGRAY );
      g.setFont( Font.font( Font.getDefault().getFamily(), 1.4 ));
      g.setLineWidth( 0.1 );
      g.setTextAlign( TextAlignment.CENTER );
      g.setTextBaseline( VPos.BOTTOM );
      g.strokeText( "[10, 20]", 10, 20-ENDPOINT_RADIUS );
      g.setTextBaseline( VPos.TOP );
      g.strokeText( "[10, 30]", 10, 30+ENDPOINT_RADIUS );
      g.setTextBaseline( VPos.BOTTOM );
      g.strokeText( "[50, 30]", 50, 30-ENDPOINT_RADIUS );
      g.setTextBaseline( VPos.TOP );
      g.strokeText( "[50, 35]", 50, 35+ENDPOINT_RADIUS );
   }

   @Override
   public void start( Stage primaryStage ) throws Exception {
      BorderPane bp = new BorderPane();
      Canvas canvas = new Canvas( 540, 240 );
      bp.setCenter( canvas );
      drawGraph( canvas.getGraphicsContext2D());
      primaryStage.setScene( new Scene( bp ));
      primaryStage.centerOnScreen();
      primaryStage.show();
   }

   public static final double ENDPOINT_RADIUS   = 2.0;
   public static final double ENDPOINT_DIAMETER = 2.0*ENDPOINT_RADIUS;
   public static final double LINE_WIDTH        = 1.0;

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

在用于显示第一个图像(目标)的程序中,我使用了两个画布,第一个画布被缩放、平移、旋转以在没有任何文本的情况下进行绘图,第二个画布仅用于水平绘制标签,java.awt.geom.AffineTransform用于计算坐标以匹配第一个画布中显示的项目。两个画布叠加显示,它们是透明的。

4

2 回答 2

1

如果我理解得很好,这就是Alexander Kirov的建议:

import javafx.application.Application;
import javafx.geometry.VPos;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Polyline;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;

public class TransRotScal extends Application {

   @Override
   public void start( Stage primaryStage ) throws Exception {
      Pane pane = new Pane();
      pane.setScaleX( 10.0 );
      pane.setScaleY( 10.0 );
      pane.setRotate( theta );
      pane.setTranslateX( 468.0 );
      pane.setTranslateY( 152.0 );
      Polyline line = new Polyline( 10,20, 10,30, 50,30, 50,35 );
      line.setStroke( Color.DARKRED );
      Circle   c0   = new Circle( 10, 20, 2, Color.BLACK );
      Circle   c1   = new Circle( 10, 30, 2, Color.LIGHTSALMON );
      Circle   c2   = new Circle( 50, 30, 2, Color.LIGHTSALMON );
      Circle   c3   = new Circle( 50, 35, 2, Color.BLACK );
      Text     t0   = createText( 10, 20, "[10,20]", VPos.BOTTOM );
      Text     t1   = createText( 10, 30, "[10,30]", VPos.TOP );
      Text     t2   = createText( 50, 30, "[50,30]", VPos.BOTTOM );
      Text     t3   = createText( 50, 35, "[50,35]", VPos.TOP );
      pane.getChildren().addAll( line, c0, c1, c2, c3, t0, t1, t2, t3 );
      primaryStage.setScene( new Scene( pane ));
      primaryStage.centerOnScreen();
      primaryStage.setWidth ( 580 );
      primaryStage.setHeight( 280 );
      primaryStage.show();
   }

   private Text createText( int x, int y, String label, VPos vPos ) {
      Text text = new Text( x, y, label );
      text.setFill( Color.DARKGRAY );
      text.setFont( Font.font( Font.getDefault().getFamily(), 1.4 ));
      text.rotateProperty().set( -theta );
      text.textAlignmentProperty().setValue( TextAlignment.CENTER );
      text.setX( text.getX() - text.getBoundsInLocal().getWidth()/2.0);
      text.textOriginProperty().set( vPos );
      if( vPos == VPos.BOTTOM ) {
         text.setY( text.getY() - 2 );
      }
      else {
         text.setY( text.getY() + 2 );
      }
      return text;
   }

   private final double theta = Math.toDegrees( Math.atan2( -15.0, 40.0 ));

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

它可以工作,但它使用 Node 代替画布,并且调整文本的值是通过迭代尝试获得的(很多!);我不知道如何计算它们

Alexander,您可以编辑此帖子或发布您自己的帖子来完成它,在以后的情况下我会删除它。

这是结果,请注意光盘周围文本的近似位置:

亚历山大·基洛夫回答

于 2013-04-03T21:34:42.420 回答
0

您可以从字符串创建 GlyphVector 并将其绘制到 Graphics 对象,而不是直接将字符串绘制到 Graphics 对象上吗?这种方法的优点是 GlyphVector 可以有自己的变换,您可以使用它来有效地取消画布的旋转。我不记得创建字形的确切细节,但您需要一个 Font 和一个 FontRenderContext ......这两者都已可用于 Graphics 上下文。

于 2013-04-03T19:53:29.163 回答