图形的仿射变换,而不是文本和标签的仿射变换 [英] Affine transforms for graph, not for text and labels

查看:83
本文介绍了图形的仿射变换,而不是文本和标签的仿射变换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这篇文章是我对以下问题的回答的套件:转换形状

This post is a suite to an answer I made to question: Transforming a shape

这是我想要的图像:

这是一个简单程序生成的图像,如您所见,文本已旋转.我要横排文字:

Here is the image a simple program produces, as you can see the text is rotated. I want horizontal text:

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

The canvas is scaled, translated, rotated to do the drawing, so the text is not displayed horizontaly and the font size need to be extremely reduced (1.4). The program is wrote in Java (awt and JavaFX) but the problem is not language or technology relevant, so any suggestion is welcome.

这是简单的程序:

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计算坐标以匹配第一个画布中显示的项目.这两个画布都是重叠显示的,它们是透明的.

In the program used to display first image (the goal), I use two canvases, the first canvas is scaled, translated, rotated to do the drawing without any text and the second canvas is used only to draw labels horizontally, using java.awt.geom.AffineTransform to compute coordinates to match the item displayed in the first canvas. Both canvases are displayed superposed, they are transparent.

推荐答案

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

This is what suggest Alexander Kirov, if I understand well:

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代替画布,并且调整文本的值是通过反复尝试获得的(很多!); 我不知道该怎么计算.

It works but it use Node in place of canvas and the values to adjust texts are obtained by iterative tries (a lot!); I don't know how to calculate them.

亚历山大,您可以编辑此帖子或发表自己的帖子以完成它,在以后的情况下,我将其删除.

Alexander, you may edit this post or post your own to complete it, in the later case I'll delete this.

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

Here is the result, note the approximative placement of text around discs:

这篇关于图形的仿射变换,而不是文本和标签的仿射变换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆