如何垂直翻转整个awt.Canvas以适配左下角为原点的笛卡尔坐标系
解决方案
核心问题原因
- 直接调用
Graphics2D.setTransform()会覆盖系统默认的坐标变换(包括高DPI屏幕适配、容器偏移等参数),导致坐标计算和实际渲染位置不匹配,出现原点偏移、右侧空白问题 - AffineTransform的执行顺序与代码书写顺序相反,你当前的变换顺序错误,导致原点平移不到位
- 全局应用Y轴翻转后,文字渲染也会继承该变换,自然出现倒置
- 坐标轴绘制逻辑写死了
MINWIDTH/MINHEIGHT,没有适配Canvas实际宽高,也是右侧出现多余空白的原因之一
修正方案
1. 正确应用坐标变换
不要直接替换全局变换,改用transform()方法追加自定义变换,同时调整变换顺序,确保原点正确平移到画布左下角:
// 先保存原始的系统默认变换,后面绘制文字要用到 AffineTransform originalTransform = g2.getTransform(); // 自定义变换:代码书写顺序是先缩放再平移,实际执行顺序是先平移再Y轴翻转 AffineTransform cartesianTx = AffineTransform.getScaleInstance(1, -1); cartesianTx.translate(0, getHeight()); // 追加变换,不覆盖原有系统变换 g2.transform(cartesianTx);
2. 解决文字倒置问题
绘制文字前先临时恢复为原始系统变换,手动把文字的笛卡尔坐标转换为屏幕坐标后再绘制,绘制完成后恢复自定义变换即可:
// 绘制文字前保存当前变换,恢复原始变换 AffineTransform currentTx = g.getTransform(); g.setTransform(originalTransform); // 笛卡尔坐标(x,y)转屏幕坐标:x不变,y = 画布高度 - 笛卡尔y值 g.drawString("测试文字", x, getHeight() - y); // 恢复自定义变换,继续绘制图形 g.setTransform(currentTx);
完整修正后的代码
import java.awt.*; import java.awt.geom.AffineTransform; public class PlotterView extends Canvas { protected int MINWIDTH = 500; protected int MINHEIGHT = 400; Point[][] lines; public PlotterView() { Dimension dim = new Dimension(MINWIDTH, MINHEIGHT); setPreferredSize(dim); setBackground(Color.LIGHT_GRAY); } protected void plotAxes(Graphics2D g, AffineTransform originalTx) { Color defaultColor = g.getColor(); // save to restore defaults in the end int originX = 5; // x origin of both axes - shift right int originY = 5; // y origin of both axis - shift up // 绘制文字:临时恢复原始变换 AffineTransform customTx = g.getTransform(); g.setTransform(originalTx); g.setColor(Color.BLACK); // 坐标转换:笛卡尔y值originY转屏幕y为 getHeight() - originY g.drawString("X: " + originX + "; Y: " + originY, originX, getHeight() - originY); // 恢复自定义变换 g.setTransform(customTx); // X-Axis:用实际宽高代替固定MINWIDTH,适配窗口缩放 int canvasWidth = getWidth(); int canvasHeight = getHeight(); g.setColor(Color.RED); g.drawLine(originX, originY, canvasWidth-20, originY); g.drawLine(canvasWidth-20, originY, canvasWidth-30, originY-5); g.drawLine(canvasWidth-20, originY, canvasWidth-30, originY+5); // Y-Axis g.setColor(Color.BLUE); g.drawLine(originX, originY, originX, canvasHeight-20); g.drawLine(originX, canvasHeight-20, originX-5, canvasHeight-30); g.drawLine(originX, canvasHeight-20, originX+5, canvasHeight-30); // Restore defaults g.setColor(defaultColor); } public void paint(Graphics g) { super.paint(g); Graphics2D g2 = (Graphics2D) g; // 保存系统原始变换 AffineTransform originalTx = g2.getTransform(); // 正确的笛卡尔坐标变换 AffineTransform tx = AffineTransform.getScaleInstance(1, -1); tx.translate(0, getHeight()); g2.transform(tx); plotAxes(g2, originalTx); // 绘制完成后恢复原始变换,避免影响后续渲染 g2.setTransform(originalTx); } }
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

