仿射变换图形,而不是文本和标签

这篇文章是我回答问题的答案: 改变形状

这是我想要的图像:

文字是横向的

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

文本被旋转

canvas被缩放,平移,旋转以进行绘制,因此文本不会水平显示,并且字体大小需要极大地减少(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(); } } 

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

如果我理解的话,这就是亚历山大基洛夫的建议:

 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代替canvas,调整文本的值是通过迭代尝试获得的(很多!); 我不知道如何计算它们

亚历山大,你可以编辑这篇文章或发表你自己的文章来完成它,在后面的例子中我将删除它。

结果如下,请注意光盘周围文字的近似位置:

亚历山大基洛夫回答

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