将 HTML Canvas 坐标系转换为笛卡尔坐标系

Posted

技术标签:

【中文标题】将 HTML Canvas 坐标系转换为笛卡尔坐标系【英文标题】:Convert HTML Canvas coordinate system to Cartesian system 【发布时间】:2019-06-23 23:47:02 【问题描述】:

html 画布的原点 (0,0) 是左上角(见下图),其中 x 正坐标向右,y 正坐标向下。

然而,数学的起源是“中心”,正 y 通过Cartesian coordinate system向上(见下文)。

我在KonvaJS 中使用了舞台的偏移和比例,以反映 X-max 为 10、Y-max 为 10、X-min 为 -10 和 Y-min 为 -10 的笛卡尔系统。但是,我当前的解决方案将象限倒置(见下文)。有什么建议吗?

当前的 javascript 方法:JSFiddle

var Width = 500;
var Height = 500;
var minX = -12; var maxX = 12;
var minY  = -12; var maxY  = 12;
var rangeX  = maxX - minX;
var rangeY  = maxY - minY;
var scaleX  = Width / rangeX;
var scaleY = Height  / rangeY;

var stage = new Konva.Stage(
container: 'container',
width: Width,
height: Height,
scaleX: scaleX,
scaleY: scaleY,
offset: 
	x: -12,
	y: -12
			
);		

var layer = new Konva.Layer();
stage.add(layer);

var rect = new Konva.Rect(
  x: -12,
  y: -12,
  width: 24,
  height: 24,		  

  stroke: 'black',
  strokeWidth: 0.1
);		
layer.add(rect);

var position = new Konva.Text(

	fontSize: 0.7,
	x: -11,
	y: -11			
);
 
layer.add(position);

var t0 = new Konva.Text(

fontSize: 1,
x: 0,
y: 0,
text: 'Center'

);		 
var t1 = new Konva.Text(

fontSize: 0.7,
x: 5,
y: 5,
text: 'Top\nRight',
fill: 'blue'
);		 
var t2 = new Konva.Text(

fontSize: 0.7,
x: -5,
y: 5,
text: 'Top\nLeft',
fill: 'blue'
);		 
var t3 = new Konva.Text(

fontSize: 0.7,
x: 5,
y: -5,
text: 'Bottom\nRight',
fill: 'blue'
);		 
var t4 = new Konva.Text(

fontSize: 0.7,
x: -5,
y: -5,
text: 'Bottom\nLeft',
fill: 'blue'			
);		 
layer.add(t0);	
layer.add(t1);
layer.add(t2);
layer.add(t3);
layer.add(t4);	

 var yaxis = new Konva.Arrow(
  points: [0, 11, 0, -11],
  pointerLength: 0.3,
  pointerWidth: 0.2,
  pointerAtBeginning: true,
  fill: 'green',
  stroke: 'green',
  strokeWidth: 0.1
);
layer.add(yaxis);

var xaxis = new Konva.Arrow(
  points: [11, 0, -11,0],
  pointerLength: 0.3,
  pointerWidth: 0.2,
  pointerAtBeginning: true,
  fill: 'green',
  stroke: 'green',
  strokeWidth: 0.1
);
layer.add(xaxis);

var circle = new Konva.Circle(
  x: 0,
  y: 5,
  radius: 0.5,
  fill: 'purple',
  stroke: 'purple',
  strokeWidth: 0,
  draggable: true
);		

layer.add(circle);

layer.draw();

function updateText(e) 
position.text('(' + Math.round(e.target.x()) + ', ' + Math.round(e.target.y()) + ')');
layer.batchDraw();


circle.on('dragmove', updateText);  
  
<script src="https://unpkg.com/konva@2.4.2/konva.min.js"></script>
<body>
 <div id="container"></div>
</body>

更新:

按照 Andrew Morton 的建议,设置:

scaleY = -Height / rangeY;

有正确的想法,但需要将阶段偏移更改为:

      offset: 
          x: -12,
          y: 12           
      

这导致了正确的象限,但所有文本都被反转了(见下文)。还有其他建议吗?

【问题讨论】:

Y 在画布元素上“增加”到“南”。看起来你可能忽略了这一点。 @RandyCasburn:我相信我说的没错。 @AndrewMorton:这并没有解决问题。 @lucidgold 好吧,这有点有趣,但很麻烦。也许 Text 构造函数中的 scaleY: -1, verticalAlign: 'top' 会纠正这个问题。 @AndrewMorton:你能发布一个答案让我接受吗! 【参考方案1】:

因为y是颠倒的,所以你需要

var scaleY = -Height / rangeY

但显然这也会导致文本倒置。您可以在 Text 构造函数中使用属性进行更正

scaleY: -1,
verticalAlign: 'top'

参考:Konva.Text

【讨论】:

【参考方案2】:

您可以将笛卡尔(正/负 x 和 y)点转换为对画布有意义的位置,只需计算画布中的中点并进行一些基本算术运算即可:

var getCanvasCartesianPoint = function (x, y) 
  var midWidth = width / 2;
  var midHeight = height / 2;
  var cartesianX = midWidth + x;
  var cartesianY = midHeight + y;

  return x: cartesianX, y: cartesianY;

因此,当您调用 getCanvasCartesianPoint(0,0) 并且您的宽度为 250 时,该函数将返回位于画布中间的 x: 125, y: 125

查看此代码笔进行演示 - https://codepen.io/joshdavenport/pen/NobERq

【讨论】:

非常好,差不多了。我还想通过比例考虑 X 和 Y 的最小值和最大值?

以上是关于将 HTML Canvas 坐标系转换为笛卡尔坐标系的主要内容,如果未能解决你的问题,请参考以下文章

个人笔记三维GIS开发-cesium坐标系统

将笛卡尔坐标系转换为多点极坐标系

将图像从笛卡尔坐标转换为极坐标 - 肢体变暗

如何将二维笛卡尔坐标数组转换为 OpenCV 输入数组?

Cesium坐标系及转换

Unity3D之笛卡尔坐标系转换——屏幕坐标转换世界坐标,世界坐标转换相机坐标工具