数学转换世界转换为局部转换

时间:2014-03-21 13:31:54

标签: math svg box2d affinetransform

我有点头疼......我正在使用jsbox2d.js进行2D游戏,基于SVG图形。我想»将一个b2d-body连接到一个svg元素,这对于调试绘图已有效,但不适用于场景中的图形。

设置:

  • 有一个SVG,包括任意深度嵌套的组和形状结构。每一个我都有一些变换,所以每个元素都驻留在自己的坐标空间中。

  • 除了有一个box2d模拟,一些实体代表svg中的一个元素。

我想将b2body的变换应用于它所代表的svg-element,以便动画看起来正确。它已经在调试绘图中工作,我正在使用这段代码:

// links is an array like [[b2body, svgelement],…]

for (var i = 0; i < links.length; i++) {
    var t = links[i][0].GetTransform();

    //tiny helper function just taking the values and
    //setting it to the element
    // transform(element, a,b,c,d,e,f)
    //|a c e|
    //|b d f|
    svghelper.transform(links[i][1],
      t.q.c, t.q.s, -t.q.s,
      t.q.c, t.p.x, t.p.y);
}

主要区别在于,使用b2dShapes顶点的世界坐标,即时生成用于调试绘图的元素,无需任何变换。

但场景的图形取自使用inkscape和f.i创建的SVG图形。使用小组作为手臂或charackter的头部。

如何在元素上应用正文的变换?我想我需要改变变换矩阵的基础,但我不知道怎么做不起作用。

我试过这个:

var t = body.GetTransform(),
    mtr = svg,createSVGMatrix(
            t.q.c, t.q.s, -t.q.s,
            t.q.c, t.p.x, t.p.y),
    toElement = element.getTransformToElement(element.ownerSVGDocument),
    toElement_inv = toElement.invert();

    mtr = mtr.multiply(toElement);
    mtr = toElement_inv.multiply(mtr);

 //applying the result

但是通过反转矩阵导致了错误的结果和错误。

提前致谢!

1 个答案:

答案 0 :(得分:0)

我在下面有一个示例可能会有所帮助,希望不会增加您的头痛;)它解决了将元素放在不同的viewPorts中的问题

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <title>Find X,Y in Transforms &amp; ViewPorts</title>
<meta http-equiv="content-type" content="text/html;charset=UTF-8">
</head>
<body style='padding:10px;font-family:arial'>
<center>
<h4>Find X,Y in Transforms &amp; ViewPorts</h4>
<div style='width:90%;background-color:gainsboro;text-align:justify;padding:10px;border-radius:6px;'>
Elements are transformed and reside it different viewPorts. This example uses  <b>getScreenCTM</b> and <b>inverse</b> to access x,y values.
</div>
<table>
<tr><td align=left>
<b>Click on an element target.<br />
This will place the black circle<br />so it matches the target's transformations</b><br />
 Scenerio:<br />
1.) SVG image is inline, contained in a DIV.<br />
2.) The blue rect element is contained in a &lt;g&gt;.<br />
3.) The &lt;g&gt; element has been transformed.<br />
4.) The maroon rect resides in a different viewPort.<br />
5.) The orange circle has been transformed.<br />
6.) Move cursor over elements to get their x,y values<br />
6.) Click over element place black circle in its viewport or target's transform.<br />
</td>
<td align=left>
<div id="svgDiv" style='background-color:lightgreen;width:400px;height:400px;'>
<svg id="mySVG" width="400" height="400" onmousemove="svgCursor(evt)"  onclick="placeBlackCircle(evt)" >
<circle pointer-events="none" id="blackCircle" r="10" fill="black" />
<circle onmousemove=getXY(evt)  onmouseout=clearXY() id="redCircle" cx="120" cy="180" r="40" fill="red" stroke="black" stroke-width="2" />
<circle onmousemove=getXY(evt) onmouseout=clearXY()  id="orangeCircle" cx="200" cy="200" r="40" fill="orange" stroke="black" stroke-width="2" />
<svg viewBox="0 100 800 800">
<rect onmousemove=getXY(evt) onmouseout=clearXY()  id="maroonRect"  x="220" y="250" width="60" height="60" fill="maroon" stroke="black" stroke-width="2"  />
</svg>
<g id="myG" >
<rect onmousemove=getXY(evt)  onmouseout=clearXY() id="blueRect"  x="220" y="250" width="60" height="60" fill="blue" stroke="black" stroke-width="2"  />
</g>
</svg>
</div>
</td>
<td align=left>
<table style='font-family:lucida console'>
<tr><td colspan=4><b>HTML Page Values:</b></td></tr>
<tr style='font-size:110%'>
<td align=right>mouse X:</td><td><input style='font-size:120%' type=text id=htmlMouseXValue size=1 /></td>
<td><input style='font-size:120%'  type=text id=htmlMouseYValue size=1 /></td><td align=left>:mouse Y</td>
</tr>
<tr><td colspan=4><b>SVG Image Values:</b></td></tr>
<tr style='font-size:110%'>
<td align=right>svg X:</td> <td><input style='font-size:120%'  type=text id=svgXValue size=1 /></td>
<td><input style='font-size:120%'  type=text id=svgYValue size=1 /></td><td align=left>:svg Y</td>
</tr>
<tr><td colspan=4><b>Target:<input id=elemIdValue size=10 /></b></td></tr>
<tr style='font-size:110%'>
<td align=right>client X:</td> <td><input style='font-size:120%'  type=text id=clientXValue size=1 /></td>
<td><input style='font-size:120%'  type=text id=clientYValue size=1 /></td><td align=left>:client Y</td>
</tr>
<tr style='font-size:110%'>
<td align=right>screen X:</td>   <td><input style='font-size:120%'  type=text id=screenXValue size=1 /></td>
<td><input style='font-size:120%'  type=text id=screenYValue size=1 /></td><td align=left>:screen Y</td>
</tr>
</table>
</td>
</tr></table>
<br />SVG Source:<br />
<textarea id=svgSourceValue style='font-size:110%;font-family:lucida console;width:90%;height:200px'></textarea>
<br />Javascript:<br />
<textarea id=jsValue style='border-radius:26px;font-size:110%;font-weight:bold;color:midnightblue;padding:16px;background-color:beige;border-width:0px;font-size:100%;font-family:lucida console;width:90%;height:400px'></textarea>
</center>
<script id=myScript>
//---mouse move---
function getXY(evt)
{
    var target=evt.target
    elemIdValue.value=target.id

    var pnt = target.ownerSVGElement.createSVGPoint();
    pnt.x = evt.clientX;
    pnt.y = evt.clientY;
    clientXValue.value=pnt.x
    clientYValue.value=pnt.y

    //---element's x,y  screen transformed/inversevalues---
    var sCTM = target.getScreenCTM();
    var PNT = pnt.matrixTransform(sCTM.inverse());

    screenXValue.value=PNT.x
    screenYValue.value=PNT.y
}
function placeBlackCircle(evt)
{
    var target=evt.target;
    //---initialize a point in its respective viewport--
    if(target.nearestViewportElement) //--must click on an element not svg root--
    {
        var pnt = target.nearestViewportElement.createSVGPoint();
        //---client area click point---
        pnt.x = evt.clientX;
        pnt.y = evt.clientY;

        var sCTM = target.getScreenCTM();
        //---return viewport's Pnt.x, Pnt.y---
        PNT = pnt.matrixTransform(sCTM.inverse());
        //----place blackDot on top in viewport and locate it---
        target.nearestViewportElement.appendChild(blackCircle)
        blackCircle.setAttribute("cx",PNT.x)
        blackCircle.setAttribute("cy",PNT.y)

        if(target.parentNode.nodeName=="g")
        {
            target.parentNode.appendChild(blackCircle)
        }
        if(target.getAttribute("transform"))
        {
            var transform=target.getAttribute("transform")
            blackCircle.setAttribute("transform",transform)
        }
        else
            blackCircle.removeAttribute("transform")
    }
}

function clearXY()
{
    elemIdValue.value=""
    clientXValue.value=""
    clientYValue.value=""

    screenXValue.value=""
    screenYValue.value=""
}

//---onload---
function initTransforms()
{
//---place some transforms on the elements---

    //--- transform orange circle---
    var transformRequestObj=mySVG.createSVGTransform()
    var animTransformList=orangeCircle.transform
    var transformList=animTransformList.baseVal
    //---translate---
    transformRequestObj.setTranslate(180,-260)
    transformList.appendItem(transformRequestObj)
    transformList.consolidate()
    //----scale---
    transformRequestObj.setScale(.5,.9)
    transformList.appendItem(transformRequestObj)
    transformList.consolidate()
    //----skewY---
    transformRequestObj.setSkewY(52)
    transformList.appendItem(transformRequestObj)
    transformList.consolidate()

    //--init Transform on myG---
    var transformRequestObj=mySVG.createSVGTransform()
    var animTransformList=myG.transform
    var transformList=animTransformList.baseVal
    //---translate---
    transformRequestObj.setTranslate(-50,-80)
    transformList.appendItem(transformRequestObj)
    transformList.consolidate()
    //----skewX---
    transformRequestObj.setSkewX(15)
    transformList.appendItem(transformRequestObj)
    transformList.consolidate()
    //----skewY---
    transformRequestObj.setSkewY(20)
    transformList.appendItem(transformRequestObj)
    transformList.consolidate()
    //---rotate---
    transformRequestObj.setRotate(30,200,200)
    transformList.appendItem(transformRequestObj)
    transformList.consolidate()
}

document.onmousemove = htmCursor
//---'event' is the html event object---
function htmCursor(event)
{
    var event = event || window.event;
    myMouseX=event.clientX;
    myMouseY=event.clientY;
    myMouseX = myMouseX + document.documentElement.scrollLeft;
    myMouseY = myMouseY + document.documentElement.scrollTop;

    htmlMouseXValue.value=myMouseX
    htmlMouseYValue.value=myMouseY
}
//---'evt' is the svg event object--
function svgCursor(evt)
{
    var rect = svgDiv.getBoundingClientRect();
    svgXValue.value=evt.clientX-rect.left
    svgYValue.value=evt.clientY-rect.top
}
</script>
<script>
document.addEventListener("onload",init(),false)
function init()
{
    initTransforms()
    svgSourceValue.value=svgDiv.innerHTML
    jsValue.value=myScript.text
}
</script>

</body>

</html>