沙盘坐标转换,
不同系转换功能改造,对比python 和js吧,
py就不说了 有numpy,
坐标系变换js库,
Math.js
https://mathjs.org/
Sylvester
http://sylvester.jcoglan.com/
gl-matrix
https://glmatrix.net/docs/v4/index.html
three.js
https://threejs.org/
测试 api对应情况js Sylvester python numpy
#!/usr/bin/env python
# coding=utf-8
import json
import time
import math
import numpy.matlib
import numpy as np
# cfg_data={
# "environment_width": 90.0,
# "environment_height": 61.0,
#
# "box_pixel_scale_size": [13,13],
#
# "world2field_sand_box_direction": [1,-1],
# "world2field_box_transfer_theta": 45,
# "world2field_box_deviation": [-69.5,25.5],
#
# "screen_select_field_corner": "A"
# }
class mtx():
@classmethod
def Rx(cls,r):
return np.array([
[1, 0, 0, 0],
[0, np.cos(r), -np.sin(r), 0],
[0, np.sin(r), np.cos(r), 0],
[0, 0, 0, 1],
])
@classmethod
def Ry(cls,r):
return np.array([
[np.cos(r), 0,np.sin(r), 0],
[0, 1, 0, 0],
[-np.sin(r), 0,np.cos(r), 0],
[0, 0, 0, 1],
])
@classmethod
def Rz(cls,r):
return np.array([
[np.cos(r), -np.sin(r), 0, 0],
[np.sin(r), np.cos(r), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
])
@classmethod
def T(cls,x,y,z):
return np.array([
[1, 0, 0, x],
[0, 1, 0, y],
[0, 0, 1, z],
[0, 0, 0, 1]
])
@classmethod
def F(cls,fx=1,fy=1,fz=1):
return np.array([
[fx, 0, 0, 0],
[0, fy, 0, 0],
[0, 0, fz, 0],
[0, 0, 0, 1]
])
@classmethod
def S(cls,sx,sy,sz):
return np.array([
[sx, 0, 0, 0],
[0, sy, 0, 0],
[0, 0, sz, 0],
[0, 0, 0, 1]
])
@classmethod
def P(cls,x,y,z):
return np.array([
[x],
[y],
[z],
[1]
])
class transData():
def __init__(self,mat_px2m,mat_m2px,theta_px2m,theta_m2px,scale_px2m,scale_m2px):
self.mat_px2m=mat_px2m
self.mat_m2px=mat_m2px
self.theta_px2m=theta_px2m
self.theta_m2px=theta_m2px
self.scale_px2m=scale_px2m
self.scale_m2px=scale_m2px
class point():
def __init__(self,x,y,z):
self.x=x
self.y=y
self.z=z
class trans():
def __init__(self):
# 读取外部参数文件
filename = "./config/env_params_config.json"
with open(filename, "r") as f:
cfg_data = json.load(f)
f.close()
self.trans_info=self.transinfo_field_to_world(cfg_data);
def transinfo_field_to_world(self,jdata):
w = float(jdata["environment_width"]) #// 90.0,
h = float(jdata["environment_height"]) #// 61.0,
d = 1000
tx = float(jdata["world2field_box_deviation"][0])
ty = float(jdata["world2field_box_deviation"][1])
tz = 0
ppmw = float(jdata["box_pixel_scale_size"][0])
ppmh = float(jdata["box_pixel_scale_size"][1])
ppmd = 1
rx = 0
ry = 0
rz = float(jdata["world2field_box_transfer_theta"])*math.pi/ 180.0
fx = jdata["world2field_sand_box_direction"][0]
fy = jdata["world2field_sand_box_direction"][1]
fz = 1
# //翻转
m = mtx.F(fx, fy, fz)
# //放缩
m2 = mtx.S(1.0 / ppmw, 1.0 / ppmh, 1.0 / ppmd)
# //位移
m3 = mtx.T(tx, ty, tz)
# //旋转矩阵
m4 = mtx.Rz(rz)
tm = np.dot(m2, m)
tm = np.dot(m4, tm)
tm = np.dot(m3, tm)
return transData(
tm,np.asarray(np.matrix(tm).I),
-rz,rz,
(1.0 / ppmw + 1.0 / ppmh) / 2,(ppmw + ppmh) / 2
)
# {
# "mat_px2m": tm,
# "mat_m2px": np.asarray(np.matrix(tm).I), # inverse(),
# "theta_px2m": -rz,
# "theta_m2px": rz,
# "scale_px2m": (1.0 / ppmw + 1.0 / ppmh) / 2,
# "scale_m2px": (ppmw + ppmh) / 2
# }
def px2m_point(self,x,y,z):
p=mtx.P(x,y,z)
v=np.dot(self.trans_info.mat_px2m,p)
return point(v[0][0],v[1][0],v[2][0])#{"x":v[0][0],"y":v[1][0],"z":v[2][0]}
def m2px_point(self,x,y,z):
p=mtx.P(x,y,z)
v=np.dot(self.trans_info.mat_m2px,p)
return point(v[0][0],v[1][0],v[2][0])#{"x":v[0][0],"y":v[1][0],"z":v[2][0]}
def m2px_lenth(self,m):
v=self.trans_info.scale_m2px*m
return v
def px2m_lenth(self,px):
v=self.trans_info.scale_px2m*px
return v
def px2m_theta(self,a):
v=self.trans_info.theta_px2m+a
return v
def m2px_theta(self,a):
v=self.trans_info.theta_m2px+a
return v
t=trans()
p= t.m2px_point(0,0,0)
p2=t.px2m_point(p.x,p.y,p.z)
print (p.x,p.y,p.z)
print (p2.x,p2.y,p2.z)
if __name__ == "__main__":
n=0
while 1:
print n
n=n+1
time.sleep(1)
对比js
/*
zzz 202403
cfg_data={
"environment_width": 90.0,
"environment_height": 61.0,
"box_pixel_scale_size": [13,13],
"world2field_sand_box_direction": [1,-1],
"world2field_box_transfer_theta":45,//
"world2field_box_deviation": [-69.5,25.5],
"screen_select_field_corner": "A"
}
*/
var np={
PI:3.14159265358,
sin: function(r){return Math.sin(r);},
cos: function(r){return Math.cos(r);},
sindeg: function(r){return Math.sin(this.PI*r/180.0);},
cosdeg: function(r){return Math.cos(this.PI*r/180.0);}
}
var mtx={
Rx:function (r){
return $M([
[1, 0, 0, 0],
[0, np.cos(r), -np.sin(r), 0],
[0, np.sin(r), np.cos(r), 0],
[0, 0, 0, 1],
])
},
Ry:function (r){
return $M([
[np.cos(r), 0,np.sin(r), 0],
[0, 1, 0, 0],
[-np.sin(r), 0,np.cos(r), 0],
[0, 0, 0, 1],
])
},
Rz:function (r){
return $M([
[np.cos(r), -np.sin(r), 0, 0],
[np.sin(r), np.cos(r), 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
])
},
T:function (x,y,z){
return $M([
[1, 0, 0, x],
[0, 1, 0, y],
[0, 0, 1, z],
[0, 0, 0, 1]
])
},
F:function (fx=1,fy=1,fz=1){
return $M([
[fx, 0, 0, 0],
[0, fy, 0, 0],
[0, 0, fz, 0],
[0, 0, 0, 1]
])
},
S:function (sx,sy,sz){
return $M([
[sx, 0, 0, 0],
[0, sy, 0, 0],
[0, 0, sz, 0],
[0, 0, 0, 1]
])
},
P:function (x,y,z){
return $M([
[x],
[y],
[z],
[1]
])
}
}
transClass=function (cfg_data){
this.transinfo_field_to_world=function (jdata){
w=jdata["environment_width"] //90.0,
h=jdata["environment_height"]//61.0,
d=1000
tx=jdata["world2field_box_deviation"][0]
ty=jdata["world2field_box_deviation"][1]
tz=0
ppmw=jdata["box_pixel_scale_size"][0]
ppmh=jdata["box_pixel_scale_size"][1]
ppmd=1
rx=0
ry=0
rz=jdata["world2field_box_transfer_theta"]/180*np.PI
fx=jdata["world2field_sand_box_direction"][0]
fy=jdata["world2field_sand_box_direction"][1]
fz=1
//翻转
const m = mtx.F(fx,fy,fz); //F(1,1,1); //
//放缩
const m2 = mtx.S(1.0/ppmw ,1.0/ppmh ,1.0/ppmd );
//位移
const m4 = mtx.T(tx,ty,tz);
//旋转矩阵
const m3 = mtx.Rz(rz);
//console.log ("m2---------");
//console.log (m2);
//console.log ("m3---------");
//console.log (m3);
//console.log ("m4---------");
//console.log (m4);
var tm=m2.x(m);
tm=m3.x(tm);
tm=m4.x(tm);
return {
mat_px2m:tm,
mat_m2px:tm.inverse(),
theta_px2m:-rz,
theta_m2px:rz,
scale_px2m:(1.0/ppmw +1.0/ppmh)/2,
scale_m2px:(ppmw +ppmh)/2
}
//console.log ("m4 .m3 .m2 . m");
}
this.trans_info=this.transinfo_field_to_world(cfg_data);
this.chk_min=function(v,m){
return v<m?m:v
}
this.chk_max=function (v,m){
return v>m?m:v
}
this.px2m_point=function(x,y,z){
p=mtx.P(x,y,z);
v=this.trans_info.mat_px2m.x(p).col(1);
console.log ("px2m v");
console.log (v);
return {x:v.e(1),y:v.e(2),z:v.e(3)}
}
this.m2px_point=function(x,y,z){
p=mtx.P(x,y,z)
v=this.trans_info.mat_m2px.x(p).col(1);
return {x:v.e(1),y:v.e(2),z:v.e(3)}
}
this.m2px_lenth=function(m){
v=this.trans_info.scale_m2px*m
return v
}
this.px2m_lenth=function(px){
v=this.trans_info.scale_px2m*px
return v
}
this.px2m_theta=function(a){
v=this.trans_info.theta_px2m+a
return v
}
this.m2px_theta=function(a){
v=this.trans_info.theta_m2px+a
return v
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>transClass</title>
</head>
<body>
<script type="text/javascript" src="sylvester.js"></script>
<script type="text/javascript" src="env_params_config.js"></script>
<script type="text/javascript" src="zzz_trans_class.js"></script>
<script>
//实例化转换对象
trans=new transClass(cfg_data);
//像素到米(点)
pm=trans.px2m_point( 0,0,0)
console.log (pm);
//米到像素(点)
pp=trans.m2px_point( pm.x,pm.y,pm.z)
console.log (pp);
//像素到米(长度)
lm=trans.px2m_lenth( 26)
console.log (lm);
//米到像素(长度)
lpx=trans.m2px_lenth( lm)
console.log (lpx);
//米到像素(弧度)
apx=trans.m2px_theta( 3.14)
console.log (apx);
//像素到米(弧度)
am=trans.px2m_theta( apx)
console.log (am);
//米到像素(点)
pp=trans.m2px_point( 0,0,0)
console.log (pp);
</script>
</body>
</html>