- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我开始构建一个使用 svg 资源(即足球场)的小部件。到目前为止,我正在使用常规的二维矩形,并且进展顺利。但是我想用这个 Assets 替换该 Assets :
我开始制作如何在这种 svg 中计算球位置的原型(prototype),但进展并不顺利。我想我需要的是从常规二维矩形模型到其他可以解释梯形图的模型的转换。
也许有人可以帮助理解它是如何完成的。假设我有以下坐标 {x: 0.2, y: 0.2}
这意味着我必须将球放在球场宽度的 20% 和高度的 20% 处。在这个例子中我该怎么做?
编辑#1
我读了 MBo 发布的答案,我努力将 delphi 代码重写为 JavaScript。我根本不了解 delphi,但我认为它进展顺利,但是在尝试代码后我遇到了几个问题:
梯形颠倒了(底部的水平线较短),我尝试修复它但没有成功,经过几次尝试后我得到了我想要的,但后来 0.2, 0.2
坐标出现在底部而不是靠近顶部。
我不确定计算总体上是否正确,中心坐标似乎奇怪地倾向于底部(至少这是我的视觉印象)
我尝试通过使用 YShift = Hg/4;
来解决反向梯形问题,但它会导致各种问题。想知道它到底是如何工作的
据我了解,该脚本的工作方式是您指定更长的水平线Wd
和高度Hg
,这会为您生成一个梯形,是正确吗?
编辑#2
我更新了演示片段,它似乎以某种方式工作,目前我遇到的唯一问题是如果我指定
Wd = 600; // width of source
Hg = 200; // height of source
实际的梯形较小(宽度和高度较小),
还以某种奇怪的方式操纵这一行:
YShift = Hg / 4;
改变梯子的实际高度。
它很难实现,就好像我已经获得了具有一定大小的 svg 法庭一样,我需要能够向函数提供实际大小,这样坐标计算才会准确。
假设我将获得一个我知道 4 个 Angular 的球场,并基于此我需要能够计算坐标。不幸的是,我的演示片段中的这个实现并没有实现。
任何人都可以帮助更改代码或提供更好的实现吗?
编辑 #3 - 解决方案
这是最终实现:
var math = {
inv: function (M){
if(M.length !== M[0].length){return;}
var i=0, ii=0, j=0, dim=M.length, e=0, t=0;
var I = [], C = [];
for(i=0; i<dim; i+=1){
I[I.length]=[];
C[C.length]=[];
for(j=0; j<dim; j+=1){
if(i==j){ I[i][j] = 1; }
else{ I[i][j] = 0; }
C[i][j] = M[i][j];
}
}
for(i=0; i<dim; i+=1){
e = C[i][i];
if(e==0){
for(ii=i+1; ii<dim; ii+=1){
if(C[ii][i] != 0){
for(j=0; j<dim; j++){
e = C[i][j];
C[i][j] = C[ii][j];
C[ii][j] = e;
e = I[i][j];
I[i][j] = I[ii][j];
I[ii][j] = e;
}
break;
}
}
e = C[i][i];
if(e==0){return}
}
for(j=0; j<dim; j++){
C[i][j] = C[i][j]/e;
I[i][j] = I[i][j]/e;
}
for(ii=0; ii<dim; ii++){
if(ii==i){continue;}
e = C[ii][i];
for(j=0; j<dim; j++){
C[ii][j] -= e*C[i][j];
I[ii][j] -= e*I[i][j];
}
}
}
return I;
},
multiply: function(m1, m2) {
var temp = [];
for(var p = 0; p < m2.length; p++) {
temp[p] = [m2[p]];
}
m2 = temp;
var result = [];
for (var i = 0; i < m1.length; i++) {
result[i] = [];
for (var j = 0; j < m2[0].length; j++) {
var sum = 0;
for (var k = 0; k < m1[0].length; k++) {
sum += m1[i][k] * m2[k][j];
}
result[i][j] = sum;
}
}
return result;
}
};
// standard soccer court dimensions
var soccerCourtLength = 105; // [m]
var soccerCourtWidth = 68; // [m]
// soccer court corners in clockwise order with center = (0,0)
var courtCorners = [
[-soccerCourtLength/2., soccerCourtWidth/2.],
[ soccerCourtLength/2., soccerCourtWidth/2.],
[ soccerCourtLength/2.,-soccerCourtWidth/2.],
[-soccerCourtLength/2.,-soccerCourtWidth/2.]];
// screen corners in clockwise order (unit: pixel)
var screenCorners = [
[50., 150.],
[450., 150.],
[350., 50.],
[ 150., 50.]
];
// compute projective mapping M from court to screen
// / a b c \
// M = ( d e f )
// \ g h 1 /
// set up system of linear equations A X = B for X = [a,b,c,d,e,f,g,h]
var A = [];
var B = [];
var i;
for (i=0; i<4; ++i)
{
var cc = courtCorners[i];
var sc = screenCorners[i];
A.push([cc[0], cc[1], 1., 0., 0., 0., -sc[0]*cc[0], -sc[0]*cc[1]]);
A.push([0., 0., 0., cc[0], cc[1], 1., -sc[1]*cc[0], -sc[1]*cc[1]]);
B.push(sc[0]);
B.push(sc[1]);
}
var AInv = math.inv(A);
var X = math.multiply(AInv, B); // [a,b,c,d,e,f,g,h]
// generate matrix M of projective mapping from computed values
X.push(1);
M = [];
for (i=0; i<3; ++i)
M.push([X[3*i], X[3*i+1], X[3*i+2]]);
// given court point (array [x,y] of court coordinates): compute corresponding screen point
function calcScreenCoords(pSoccer) {
var ch = [pSoccer[0],pSoccer[1],1]; // homogenous coordinates
var sh = math.multiply(M, ch); // projective mapping to screen
return [sh[0]/sh[2], sh[1]/sh[2]]; // dehomogenize
}
function courtPercToCoords(xPerc, yPerc) {
return [(xPerc-0.5)*soccerCourtLength, (yPerc-0.5)*soccerCourtWidth];
}
var pScreen = calcScreenCoords(courtPercToCoords(0.2,0.2));
var hScreen = calcScreenCoords(courtPercToCoords(0.5,0.5));
// Custom code
document.querySelector('.trapezoid').setAttribute('d', `
M ${screenCorners[0][0]} ${screenCorners[0][1]}
L ${screenCorners[1][0]} ${screenCorners[1][1]}
L ${screenCorners[2][0]} ${screenCorners[2][1]}
L ${screenCorners[3][0]} ${screenCorners[3][1]}
Z
`);
document.querySelector('.point').setAttribute('cx', pScreen[0]);
document.querySelector('.point').setAttribute('cy', pScreen[1]);
document.querySelector('.half').setAttribute('cx', hScreen[0]);
document.querySelector('.half').setAttribute('cy', hScreen[1]);
document.querySelector('.map-pointer').setAttribute('style', 'left:' + (pScreen[0] - 15) + 'px;top:' + (pScreen[1] - 25) + 'px;');
document.querySelector('.helper.NW-SE').setAttribute('d', `M ${screenCorners[3][0]} ${screenCorners[3][1]} L ${screenCorners[1][0]} ${screenCorners[1][1]}`);
document.querySelector('.helper.SW-NE').setAttribute('d', `M ${screenCorners[0][0]} ${screenCorners[0][1]} L ${screenCorners[2][0]} ${screenCorners[2][1]}`);
body {
margin:0;
}
.container {
width:500px;
height:200px;
position:relative;
border:solid 1px #000;
}
.view {
background:#ccc;
width:100%;
height:100%;
}
.trapezoid {
fill:none;
stroke:#000;
}
.point {
stroke:none;
fill:red;
}
.half {
stroke:none;
fill:blue;
}
.helper {
fill:none;
stroke:#000;
}
.map-pointer {
background-image:url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjxzdmcgaWQ9IkxheWVyXzEiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDUxMiA1MTI7IiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB4bWw6c3BhY2U9InByZXNlcnZlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj48Zz48cGF0aCBkPSJNMjU1LjksNmMtMjEuNywwLTQzLjQsNS4zLTYyLjMsMTZjLTMzLjksMTkuMi01Ny45LDU1LjMtNjEuOSw5NC4xYy0zLjcsMzYuMSw4LjksNzEuOCwyMiwxMDUuNyAgIGMxNS4xLDM4LjksMTAyLjEsMjI4LjksMTAyLjEsMjI4LjlzODcuNi0xOTEuNCwxMDIuOC0yMzAuOWMxMy4xLTM0LjIsMjUuNy03MC4yLDIxLjItMTA2LjVjLTUuMi00Mi4xLTM0LjctNzkuOS03My42LTk2LjggICBDMjkwLjUsOS41LDI3My4yLDYsMjU1LjksNnogTTI1NS45LDE4OS44Yy0zMywwLTU5LjgtMjYuOC01OS44LTU5LjhzMjYuOC01OS44LDU5LjgtNTkuOFMzMTUuNyw5NywzMTUuNywxMzAgICBTMjg5LDE4OS44LDI1NS45LDE4OS44eiIvPjxwYXRoIGQ9Ik0yOTIuMiwzOTcuMWMtNC4xLDguOS03LjksMTcuMi0xMS40LDI0LjdjMzYuOCwzLjYsNjMuNiwxNS4yLDYzLjYsMjguOGMwLDE2LjYtMzkuNiwzMC04OC40LDMwICAgYy00OC44LDAtODguNC0xMy40LTg4LjQtMzBjMC0xMy42LDI2LjgtMjUuMiw2My41LTI4LjhjLTMuNS03LjQtNy40LTE1LjgtMTEuNC0yNC43Yy02MC4yLDYuMy0xMDQuNSwyNy45LTEwNC41LDUzLjUgICBjMCwzMC42LDYzLjEsNTUuNCwxNDAuOCw1NS40czE0MC44LTI0LjgsMTQwLjgtNTUuNEMzOTYuOCw0MjUsMzUyLjQsNDAzLjQsMjkyLjIsMzk3LjF6IiBpZD0iWE1MSURfMV8iLz48L2c+PC9zdmc+');
display:block;
width:32px;
height:32px;
background-repeat:no-repeat;
background-size:32px 32px;
position:absolute;
opacity:.3;
}
<div class="container">
<svg class="view">
<path class="trapezoid"></path>
<circle class="point" r="3"></circle>
<circle class="half" r="3"></circle>
<path class="helper NW-SE"></path>
<path class="helper SW-NE"></path>
</svg>
<span class="map-pointer"></span>
</div>
最佳答案
您正在寻找从球场平面中的 (x,y)
到屏幕平面中的 (u,v)
的投影映射。投影映射的工作原理如下:
(x,y,1)
M
相乘,以获得屏幕像素的齐次坐标 (u',v',l)
(u,v) = (u'/l, v'/l)
适当的矩阵M
可以通过求解相应的方程来计算,例如 Angular 落。选择球场中心与原点重合,x
轴指向较长的一侧,并从图像中测量 Angular 坐标,我们得到标准 105x68 球场的以下相应坐标:
(-52.5, 34) -> (174, 57)
( 52.5, 34) -> (566, 57)
( 52.5,-34) -> (690,214)
(-52.5,-34) -> ( 50,214)
建立矩阵射影映射方程
/ a b c \
M = ( d e f )
\ g h 1 /
导致一个具有 8 个方程和 8 个未知数的线性系统,因为每个点对应 (x,y) -> (u,v)
贡献两个方程:
x*a + y*b + 1*c + 0*d + 0*e + 0*f - (u*x)*g - (u*y)*h = u
0*a + 0*b + 0*c + x*d + y*e + 1*f - (v*x)*g - (v*y)*h = v
(通过将 M (x y 1)^T = (l*u l*v l*1)^T
展开为三个方程并代入 l< 的值,可以得到这两个方程
从第三个方程变为前两个方程。)
将 8 个未知数 a,b,c,...,h
放入矩阵中的解给出:
/ 4.63 2.61 370 \
M = ( 0 -1.35 -116.64 )
\ 0 0.00707 1 /
因此,例如球场中心为 {x: 0.5, y: 0.5}
您必须首先将其转换为上述坐标系以获得 (x,y) = (0,0)
>。那么你必须计算
/ x \ / 4.63 2.61 370 \ / 0 \ / 370 \
M ( y ) = ( 0 -1.35 -116.64 ) ( 0 ) = ( 116.64 )
\ 1 / \ 0 0.00707 1 / \ 1 / \ 1 /
通过去均匀化,您可以得到中心的屏幕坐标
(u,v) = (370/1, 116.64/1) ~= (370,117)
JavaScript 实现可能如下所示:
// using library https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.2.1/math.js
// standard soccer court dimensions
var soccerCourtLength = 105; // [m]
var soccerCourtWidth = 68; // [m]
// soccer court corners in clockwise order with center = (0,0)
var courtCorners = [
[-soccerCourtLength/2., soccerCourtWidth/2.],
[ soccerCourtLength/2., soccerCourtWidth/2.],
[ soccerCourtLength/2.,-soccerCourtWidth/2.],
[-soccerCourtLength/2.,-soccerCourtWidth/2.]];
// screen corners in clockwise order (unit: pixel)
var screenCorners = [
[174., 57.],
[566., 57.],
[690.,214.],
[ 50.,214.]];
// compute projective mapping M from court to screen
// / a b c \
// M = ( d e f )
// \ g h 1 /
// set up system of linear equations A X = B for X = [a,b,c,d,e,f,g,h]
var A = [];
var B = [];
var i;
for (i=0; i<4; ++i)
{
var cc = courtCorners[i];
var sc = screenCorners[i];
A.push([cc[0], cc[1], 1., 0., 0., 0., -sc[0]*cc[0], -sc[0]*cc[1]]);
A.push([0., 0., 0., cc[0], cc[1], 1., -sc[1]*cc[0], -sc[1]*cc[1]]);
B.push(sc[0]);
B.push(sc[1]);
}
var AInv = math.inv(A);
var X = math.multiply(AInv, B); // [a,b,c,d,e,f,g,h]
// generate matrix M of projective mapping from computed values
X.push(1);
M = [];
for (i=0; i<3; ++i)
M.push([X[3*i], X[3*i+1], X[3*i+2]]);
// given court point (array [x,y] of court coordinates): compute corresponding screen point
function calcScreenCoords(pSoccer) {
var ch = [pSoccer[0],pSoccer[1],1]; // homogenous coordinates
var sh = math.multiply(M, ch); // projective mapping to screen
return [sh[0]/sh[2], sh[1]/sh[2]]; // dehomogenize
}
function courtPercToCoords(xPerc, yPerc) {
return [(xPerc-0.5)*soccerCourtLength, (yPerc-0.5)*soccerCourtWidth];
}
var pScreen = calcScreenCoords(courtPercToCoords(0.2,0.2))
关于javascript - 将常规二维矩形坐标转换为梯形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52314951/
当你进入页面http://m.google.com使用 Mobile Safari,您会在页面顶部看到漂亮的栏。 我想像那样画一些梯形(美国:梯形),但我不知道怎么画。我应该使用 css3 3d 转换
它基本上是一个 flex 的 div: 那么可以只使用 CSS 而不使用图像吗? 最佳答案 嗯...我是这个形状最大的怀疑者,但它似乎是可能的 O_o Demo HTML CSS .shape
我希望在 Java 中创建一个星号梯形,就像下面使用嵌套 for 循环的模式一样。 ** **** ******** 我知道如何打印两个、四个然后六个星号,如下面的代码所示。但是,我不知道如何创建两个
关于 Python 中实时数据的数值积分(梯形)的问题- 背景:实时测量一个平均速度为 100 米/分钟的移动物体,我每 100 毫秒采样一次,持续 60 秒 - 因此在一分钟结束时,我将获得 600
我很难解决这个问题: 我想用 css 做这个: 如图:两个圆 Angular 的飞人(重要!),一个带文字的飞人,一个带图片,或者图标的飞人,有图标的飞人尺寸可以细一些,但是两个飞人必须是大小相同。
我想创建一个响应式梯形形状,它可以是 CSS、SVG 或 Canvas。 我已经能够创建三 Angular 形,但不能创建响应式的梯形。 div { width: 0; height: 0;
这个问题在这里已经有了答案: css skew element and get inner rounded border top (1 个回答) 关闭 4 年前。 我想用 CSS 和 HTML 自定
这是 css 在 id 上的代码工作正常: border-bottom: 100px solid #0000ff80; border-right: 50px solid transparent; he
我在使用 CSS 时遇到了一个小问题。我需要一个梯形 div,它的左上角( Angular 大于 90 度的那个)是圆 Angular 的。我已经知道了: HTML: CSS: .tr
我在使用 CSS 时遇到了一个小问题。我需要一个梯形 div,它的左上角( Angular 大于 90 度的那个)是圆 Angular 的。我已经知道了: HTML: CSS: .tr
我有这个带有伪元素的形状: https://jsfiddle.net/6gf1m3j5/ body { margin: 0; background:#ccc; } #octagon-l
我在使用 CSS 时遇到了一个小问题。我需要一个梯形 div,它的左上角( Angular 大于 90 度的那个)是圆 Angular 的。我已经知道了: HTML: CSS: .tr
我怎样才能像这里的 Tidal 一样制作一个旋转的横幅 我试过制作梯形并根据 http://browniefed.com/blog/the-shapes-of-react-native/ 将其旋转 4
我正在使用 three.js 制作一个小动画,其中有一些基本的 3D 模型,其中一个我正在努力处理的是“梯形 ”。 到目前为止,我只能在 THREE.CylinderGeometry 的帮助下创建截顶
我正在使用 three.js 制作一个小动画,其中有一些基本的 3D 模型,其中一个我正在努力处理的是“梯形 ”。 到目前为止,我只能在 THREE.CylinderGeometry 的帮助下创建截顶
我是一名优秀的程序员,十分优秀!