SVG 路径似乎没有正确定位自己

SVG path doesn't seem to orientate itself correctly

我正在尝试围绕 2 个圆圈生成一条路径,当我四处移动它们时应该跟随它们。我以我发现的一个例子为基础,并构建了一个我期望实现的原型 example

我已经开始在我的应用程序中包含它,但出于某种原因,我似乎无法获得围绕正确位置绘制的绿色路径,而且我不明白为什么。

我整理了一个代码示例来说明:

function generatePath(planet, moon, join) {

    function distanceBetween(x1, y1, x2, y2) {
        var a = (x2 - x1) * (x2 - x1);
        var b = (y2 - y1) * (y2 - y1);
        return Math.sqrt(a + b);
    };
    
    function circleYFromX(circle, x) {
        return Math.sqrt(Math.pow(circle.r, 2) - Math.pow(x - circle.x, 2));
    };
    
     function calculateAngle(origin, point) {
        var tan = (point.y - origin.y) / (point.x - origin.x);
        var angle = Math.atan(tan) / Math.PI * 180 + 90;
        if (point.x < origin.x) angle += 180;
        return angle;
    };
    
    // Work out the distance between the moon and planet
    var distance = distanceBetween(planet.x, planet.y, moon.x, moon.y);
    var originDistance = planet.r - moon.r;
    var distanceDiff = distance - originDistance;
    if (distanceDiff < 1) {
        distanceDiff = 1;
    }

    console.log(distance);
    console.log(planet.r);
    console.log(moon.r);
    console.log(join.r);
    console.log(planet.r + moon.r + 2 * join.r);
    
    // Determine if the moon has moved out of the planet's gravitational pull
    if (distance > 2 * join.r + planet.r + moon.r) {
        return;
    }

    moon.h = 0;
    moon.k = 0 - planet.r + moon.r - distanceDiff;

    var triangleA = planet.r + join.r; // Side planet
    var triangleB = moon.r + join.r; // Side moon
    var triangleC = Math.abs(moon.k - 0); // Side c
    var triangleP = (triangleA + triangleB + triangleC) / 2; // Triangle half perimeter
    var triangleArea = Math.sqrt(triangleP * (triangleP - triangleA) * (triangleP - triangleB) * (triangleP - triangleC)); // Triangle area
    var triangleH;
    var triangleD;

    if (triangleC >= triangleA) {
        var triangleH = 2 * triangleArea / triangleC; // Triangle height
        var triangleD = Math.sqrt(Math.pow(triangleA, 2) - Math.pow(triangleH, 2)); // Big circle bisection of triangleC
    } else {
        var triangleH = 2 * triangleArea / triangleA; // Triangle height
        var triangleD = Math.sqrt(Math.pow(triangleC, 2) - Math.pow(triangleH, 2)); // Small circle bisection of triangleA
    }

    planet.tan = triangleH / triangleD;
    planet.angle = Math.atan(planet.tan);
    planet.sin = Math.sin(planet.angle);
    planet.intersectX = planet.sin * planet.r;
    planet.cos = Math.cos(planet.angle);
    planet.intersectY = planet.cos * planet.r;

    join.x = 0 + planet.sin * (planet.r + join.r);
    join.y = 0 - planet.cos * (planet.r + join.r);

    var coord1 = {
        x: -planet.intersectX,
        y: -planet.intersectY
    };
    var coord2 = {
        x: planet.intersectX,
        y: -planet.intersectY
    }
    moon.tan = (moon.k - join.y) / (moon.h - join.x);
    moon.angle = Math.atan(moon.tan);
    moon.intersectX = join.x - Math.cos(moon.angle) * (join.r);
    moon.intersectY = join.y - Math.sin(moon.angle) * (join.r);
    
    // If we have any bad values then just return no path
    if (isNaN(coord1.x) || isNaN(coord1.y) || isNaN(coord2.x) || isNaN(coord2.y)) {
        return;
    }

    var pathD = "M " + coord1.x + " " + coord1.y + " A " + planet.r + " " + planet.r + " 0 1 0 " + coord2.x + " " + coord2.y;
    if (join.x - join.r <= 0 && moon.k < join.y) {
        var crossOverY = circleYFromX(join, 0);
        pathD += "A " + join.r + " " + join.r + " 0 0 1 0 " + (join.y + crossOverY);
        pathD += "m 0 -" + (crossOverY * 2);
    }

    pathD += "A " + join.r + " " + join.r + " 0 0 1 " + moon.intersectX + " " + moon.intersectY;
    var largeArcFlag = 1;
    if (join.y < moon.k) {
        largeArcFlag = 0;
    }

    pathD += "a " + moon.r + " " + moon.r + " 0 " + largeArcFlag + " 0 " + (moon.intersectX * -2) + " 0";
    if (join.x - join.r <= 0 && moon.k < join.y) {
        pathD += "A " + join.r + " " + join.r + " 0 0 1 0 " + (join.y - crossOverY);
        pathD += "m 0 " + (crossOverY * 2);
    }

    pathD += "A " + join.r + " " + join.r + " 0 0 1 " + coord1.x + " " + coord1.y;
    pathD += "A " + join.r + " " + join.r + " 0 0 1 " + coord1.x + " " + coord1.y;
    return pathD;
};

var container = d3.select(".planet");
var moon = d3.select(".moon");
var tempPlanet = { x: -181.77581967381693, y: -144.9613789321555, r: 152 };
var tempMoon = { x: 0, y: 0, r: 32 };
var link = { r: 7.9 };

var pathD = generatePath(tempPlanet, tempMoon, { r: 31 });
if (pathD) {
                moon.append("path")
                        .attr("d", pathD)
                        .attr("transform", "translate(" + [-181.77581967381693, 144.9613789321555] + ")")
                        .attr("class", "gravity")
                        .style("fill", "none")
                        .style("stroke", "red")
                        .style("stroke-linecap", "round")
                        .style("stroke-width", 2);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg width="1680" height="523">
    <g width="1680" height="523">
        <g class="galaxy-main" width="1680" height="523">
            <g class="planet selected" transform="translate(341,300) scale(0.5,0.5)">
                <circle r="150" style="fill: rgb(72, 119, 159); stroke-dasharray: 944.477796076938px; stroke-dashoffset: 0px; stroke-width: 8px; stroke: rgb(255, 255, 255);"></circle>
                <g class="moon" transform="translate(181.77581967381693,-144.96137893215555)">
                    <circle r="30" class="moon-circle" id="3" style="fill: rgb(72, 119, 159);"></circle>
                </g>
            </g>
        </g>
    </g>
</svg>

我现在画的不是绿色填充,而是红色轮廓。您应该能够看到的是,红色轮廓正确地围绕着较大的圆圈(行星),但垂直向上而不是围绕着较小的圆圈(月亮)。

似乎我们只是缺少旋转,但我构建的原始原型 不知道 旋转,只知道每个圆的中心。在这种情况下,这应该非常简单:

月亮

var tempMoon = { x: 0, y: 0, r: 32 }; 

始终位于 (0, 0),因为此圆圈位于路径将附加到的组的中心

星球

var tempPlanet = { x: -181.77581967381693, y: -144.9613789321555, r: 152 }; 

行星位于组的中心,其中还包含月球组。因此,它的位置始终只是一个反向翻译,它定位包含月亮的组

我相信这些位置是正确的(我已经尝试在月球层上添加圆圈以确认它们在正确的位置 - 它们是正确的)。我觉得这一定是某种程度上取决于组,但我仍然无法确定为什么这没有以正确的方向呈现。

不幸的是,我似乎在代码的末尾遗漏了 translaterotate,而我之前出于某种原因遗漏了这些内容。将其包括在内使其按预期工作。