Wireframe "Lp" hypersphere

@param svgp SVG Plot
@param proj Visualization projection
@param mid mean vector
@param radius radius
@param p L_p value
@return path element
346879
public static Element drawLp(SVGPlot svgp, Projection2D proj, NumberVector mid, double radius, double p) {
    final double[] v_mid = mid.toArray();
    final long[] dims = proj.getVisibleDimensions2D();

    double kappax = p > 1 ? Math.min(1.3, 4. * (2 * FastMath.pow(0.5, 1. / p) - 1) / 3.) : 0;
    double kappay = p < 1 ? Math.min(1.3, 4. * (2 * (1 - FastMath.pow(0.5, 1. / p)) - 1) / 3.) : 0;

    SVGPath path = new SVGPath();
    for(int dim = BitsUtil.nextSetBit(dims, 0); dim >= 0; dim = BitsUtil.nextSetBit(dims, dim + 1)) {
      v_mid[dim] += radius;
      double[] pvp0 = proj.fastProjectDataToRenderSpace(v_mid);
      v_mid[dim] -= radius * 2;
      double[] pvm0 = proj.fastProjectDataToRenderSpace(v_mid);
      v_mid[dim] += radius;
      // delta vector
      double[] tvd0 = new double[v_mid.length];
      tvd0[dim] = radius;
      double[] vd0 = proj.fastProjectRelativeDataToRenderSpace(tvd0);
      for(int dim2 = BitsUtil.nextSetBit(dims, 0); dim2 >= 0; dim2 = BitsUtil.nextSetBit(dims, dim2 + 1)) {
        if(dim < dim2) {
          v_mid[dim2] += radius;
          double[] pv0p = proj.fastProjectDataToRenderSpace(v_mid);
          v_mid[dim2] -= radius * 2;
          double[] pv0m = proj.fastProjectDataToRenderSpace(v_mid);
          v_mid[dim2] += radius;
          // delta vector
          double[] tv0d = new double[v_mid.length];
          tv0d[dim2] = radius;
          double[] v0d = proj.fastProjectRelativeDataToRenderSpace(tv0d);

          if(p > 1) {
            // p > 1
            // support points, p0 to 0p
            final double s_pp1_x = pvp0[0] + v0d[0] * kappax;
            final double s_pp1_y = pvp0[1] + v0d[1] * kappax;
            final double s_pp2_x = pv0p[0] + vd0[0] * kappax;
            final double s_pp2_y = pv0p[1] + vd0[1] * kappax;
            // support points, 0p to m0
            final double s_mp1_x = pv0p[0] - vd0[0] * kappax;
            final double s_mp1_y = pv0p[1] - vd0[1] * kappax;
            final double s_mp2_x = pvm0[0] + v0d[0] * kappax;
            final double s_mp2_y = pvm0[1] + v0d[1] * kappax;
            // support points, m0 to 0m
            final double s_mm1_x = pvm0[0] - v0d[0] * kappax;
            final double s_mm1_y = pvm0[1] - v0d[1] * kappax;
            final double s_mm2_x = pv0m[0] - vd0[0] * kappax;
            final double s_mm2_y = pv0m[1] - vd0[1] * kappax;
            // support points, 0m to p0
            final double s_pm1_x = pv0m[0] + vd0[0] * kappax;
            final double s_pm1_y = pv0m[1] + vd0[1] * kappax;
            final double s_pm2_x = pvp0[0] - v0d[0] * kappax;
            final double s_pm2_y = pvp0[1] - v0d[1] * kappax;
            path.moveTo(pvp0[0], pvp0[1]) //
                .cubicTo(s_pp1_x, s_pp1_y, s_pp2_x, s_pp2_y, pv0p[0], pv0p[1]) //
                .cubicTo(s_mp1_x, s_mp1_y, s_mp2_x, s_mp2_y, pvm0[0], pvm0[1]) //
                .cubicTo(s_mm1_x, s_mm1_y, s_mm2_x, s_mm2_y, pv0m[0], pv0m[1]) //
                .cubicTo(s_pm1_x, s_pm1_y, s_pm2_x, s_pm2_y, pvp0[0], pvp0[1]) //
                .close();
          }
          else if(p < 1) {
            // p < 1
            // support points, p0 to 0p
            final double s_vp0_x = pvp0[0] - vd0[0] * kappay;
            final double s_vp0_y = pvp0[1] - vd0[1] * kappay;
            final double s_v0p_x = pv0p[0] - v0d[0] * kappay;
            final double s_v0p_y = pv0p[1] - v0d[1] * kappay;
            final double s_vm0_x = pvm0[0] + vd0[0] * kappay;
            final double s_vm0_y = pvm0[1] + vd0[1] * kappay;
            final double s_v0m_x = pv0m[0] + v0d[0] * kappay;
            final double s_v0m_y = pv0m[1] + v0d[1] * kappay;
            // Draw the star
            path.moveTo(pvp0[0], pvp0[1]) //
                .cubicTo(s_vp0_x, s_vp0_y, s_v0p_x, s_v0p_y, pv0p[0], pv0p[1]) //
                .cubicTo(s_v0p_x, s_v0p_y, s_vm0_x, s_vm0_y, pvm0[0], pvm0[1]) //
                .cubicTo(s_vm0_x, s_vm0_y, s_v0m_x, s_v0m_y, pv0m[0], pv0m[1]) //
                .cubicTo(s_v0m_x, s_v0m_y, s_vp0_x, s_vp0_y, pvp0[0], pvp0[1]) //
                .close();
          }
          else {
            // p == 1 - Manhattan
            path.moveTo(pvp0[0], pvp0[1]) //
                .lineTo(pv0p[0], pv0p[1]) //
                .lineTo(pvm0[0], pvm0[1]) //
                .lineTo(pv0m[0], pv0m[1]) //
                .lineTo(pvp0[0], pvp0[1]) //
                .close();
          }
        }
      }
    }
    return path.makeElement(svgp);
  }
500942
public Result<FindPolysAroundResult> findPolysAroundCircle(long startRef, float[] centerPos, float radius,
            QueryFilter filter) {

        // Validate input

        if (!m_nav.isValidPolyRef(startRef) || Objects.isNull(centerPos) || !vIsFinite(centerPos) || radius < 0
                || !Float.isFinite(radius) || Objects.isNull(filter)) {
            return Result.invalidParam();
        }

        List<Long> resultRef = new ArrayList<>();
        List<Long> resultParent = new ArrayList<>();
        List<Float> resultCost = new ArrayList<>();

        m_nodePool.clear();
        m_openList.clear();

        Node startNode = m_nodePool.getNode(startRef);
        vCopy(startNode.pos, centerPos);
        startNode.pidx = 0;
        startNode.cost = 0;
        startNode.total = 0;
        startNode.id = startRef;
        startNode.flags = Node.DT_NODE_OPEN;
        m_openList.push(startNode);

        float radiusSqr = sqr(radius);

        while (!m_openList.isEmpty()) {
            Node bestNode = m_openList.pop();
            bestNode.flags &= ~Node.DT_NODE_OPEN;
            bestNode.flags |= Node.DT_NODE_CLOSED;

            // Get poly and tile.
            // The API input has been cheked already, skip checking internal data.
            long bestRef = bestNode.id;
            Tupple2<MeshTile, Poly> tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(bestRef);
            MeshTile bestTile = tileAndPoly.first;
            Poly bestPoly = tileAndPoly.second;

            // Get parent poly and tile.
            long parentRef = 0;
            MeshTile parentTile = null;
            Poly parentPoly = null;
            if (bestNode.pidx != 0) {
                parentRef = m_nodePool.getNodeAtIdx(bestNode.pidx).id;
            }
            if (parentRef != 0) {
                tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(parentRef);
                parentTile = tileAndPoly.first;
                parentPoly = tileAndPoly.second;
            }

            resultRef.add(bestRef);
            resultParent.add(parentRef);
            resultCost.add(bestNode.total);

            for (int i = bestPoly.firstLink; i != NavMesh.DT_NULL_LINK; i = bestTile.links.get(i).next) {
                Link link = bestTile.links.get(i);
                long neighbourRef = link.ref;
                // Skip invalid neighbours and do not follow back to parent.
                if (neighbourRef == 0 || neighbourRef == parentRef) {
                    continue;
                }

                // Expand to neighbour
                tileAndPoly = m_nav.getTileAndPolyByRefUnsafe(neighbourRef);
                MeshTile neighbourTile = tileAndPoly.first;
                Poly neighbourPoly = tileAndPoly.second;

                // Do not advance if the polygon is excluded by the filter.
                if (!filter.passFilter(neighbourRef, neighbourTile, neighbourPoly)) {
                    continue;
                }

                // Find edge and calc distance to the edge.
                Result<PortalResult> pp = getPortalPoints(bestRef, bestPoly, bestTile, neighbourRef, neighbourPoly,
                        neighbourTile, 0, 0);
                if (pp.failed()) {
                    continue;
                }
                float[] va = pp.result.left;
                float[] vb = pp.result.right;

                // If the circle is not touching the next polygon, skip it.
                Tupple2<Float, Float> distseg = distancePtSegSqr2D(centerPos, va, vb);
                float distSqr = distseg.first;
                if (distSqr > radiusSqr) {
                    continue;
                }

                Node neighbourNode = m_nodePool.getNode(neighbourRef);

                if ((neighbourNode.flags & Node.DT_NODE_CLOSED) != 0) {
                    continue;
                }

                // Cost
                if (neighbourNode.flags == 0) {
                    neighbourNode.pos = vLerp(va, vb, 0.5f);
                }

                float cost = filter.getCost(bestNode.pos, neighbourNode.pos, parentRef, parentTile, parentPoly, bestRef,
                        bestTile, bestPoly, neighbourRef, neighbourTile, neighbourPoly);

                float total = bestNode.total + cost;
                // The node is already in open list and the new result is worse, skip.
                if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0 && total >= neighbourNode.total) {
                    continue;
                }

                neighbourNode.id = neighbourRef;
                neighbourNode.pidx = m_nodePool.getNodeIdx(bestNode);
                neighbourNode.total = total;

                if ((neighbourNode.flags & Node.DT_NODE_OPEN) != 0) {
                    m_openList.modify(neighbourNode);
                } else {
                    neighbourNode.flags = Node.DT_NODE_OPEN;
                    m_openList.push(neighbourNode);
                }
            }
        }

        return Result.success(new FindPolysAroundResult(resultRef, resultParent, resultCost));
    }
443054
function supportsSvgPathArgument(window) {
  const canvas = window.document.createElement('canvas');
  const g = canvas.getContext('2d');
  const p = new window.Path2D('M0 0 L1 1');
  g.strokeStyle = 'red';
  g.lineWidth = 1;
  g.stroke(p);
  const imgData = g.getImageData(0, 0, 1, 1);
  return imgData.data[0] === 255; // Check if pixel is red
}
118528
function SvgPath(path) {
  if (!(this instanceof SvgPath)) { return new SvgPath(path); }

  // Array of path segments.
  // Each segment is array [command, param1, param2, ...]
  try {
    this.segments = parse(path);
  } catch (e) {
    this.segments = [];
  }
}
848700
private static Polygon processPolygon(Polygon p, Geometry triangleLines, GeometryFactory factory) {
        Geometry diffExt = p.getExteriorRing().difference(triangleLines);
        final int nbOfHoles = p.getNumInteriorRing();
        final LinearRing[] holes = new LinearRing[nbOfHoles];
        for (int i = 0; i < nbOfHoles; i++) {
            holes[i] = factory.createLinearRing(lineMerge(p.getInteriorRingN(i).difference(triangleLines), factory).getCoordinates());
        }
        return factory.createPolygon(factory.createLinearRing(lineMerge(diffExt, factory).getCoordinates()), holes);

    }
819826
function(node, geometry, radius) {
        if(!isNaN(geometry.x)&& !isNaN(geometry.y)) {
            var resolution = this.getResolution();

            node.style.left = ((((geometry.x - this.featureDx) /resolution - this.offset.x) | 0) - radius) + "px";
            node.style.top = (((geometry.y /resolution - this.offset.y) | 0) - radius) + "px";
    
            var diameter = radius * 2;
            
            node.style.width = diameter + "px";
            node.style.height = diameter + "px";
            return node;
        }
        return false;
    }
762563
function SvgPath(path) {
  if (!(this instanceof SvgPath)) { return new SvgPath(path); }

  var pstate = pathParse(path);

  // Array of path segments.
  // Each segment is array [command, param1, param2, ...]
  this.segments = pstate.segments;

  // Error message on parse error.
  this.err      = pstate.err;

  // Transforms stack for lazy evaluation
  this.__stack    = [];
}
343845
public static Element drawFrame(SVGPlot svgp, Projection2D proj, double[] min, double[] max) {
    SVGPath path = new SVGPath();
    ArrayList<double[]> edges = getVisibleEdges(proj, min, max);
    double[] rv_min = proj.fastProjectDataToRenderSpace(min);
    recDrawEdges(path, rv_min[0], rv_min[1], edges, BitsUtil.zero(edges.size()));
    return path.makeElement(svgp);
  }
634751
function (x, y, rx, ry) {
    return new BVG('ellipse', x.constructor.name === 'Object' ? x : {
      x: x,
      y: y,
      rx: rx,
      ry: ry
    }, function (tag, data) {
      tag.setAttribute('cx', data.x);
      tag.setAttribute('cy', data.y);
      tag.setAttribute('rx', data.rx);
      tag.setAttribute('ry', data.ry);
    });
  }
1357566
function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {

	BufferGeometry.call( this );

	this.type = '';

	this.parameters = {
		radiusTop: radiusTop,
		radiusBottom: radiusBottom,
		height: height,
		radialSegments: radialSegments,
		heightSegments: heightSegments,
		openEnded: openEnded,
		thetaStart: thetaStart,
		thetaLength: thetaLength
	};

	var scope = this;

	radiusTop = radiusTop !== undefined ? radiusTop : 1;
	radiusBottom = radiusBottom !== undefined ? radiusBottom : 1;
	height = height || 1;

	radialSegments = Math.floor( radialSegments ) || 8;
	heightSegments = Math.floor( heightSegments ) || 1;

	openEnded = openEnded !== undefined ? openEnded : false;
	thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;

	// buffers

	var indices = [];
	var vertices = [];
	var normals = [];
	var uvs = [];

	// helper variables

	var index = 0;
	var indexArray = [];
	var halfHeight = height / 2;
	var groupStart = 0;

	// generate geometry

	generateTorso();

	if ( openEnded === false ) {

		if ( radiusTop > 0 ) generateCap( true );
		if ( radiusBottom > 0 ) generateCap( false );

	}

	// build geometry

	this.setIndex( indices );
	this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
	this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
	this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );

	function generateTorso() {

		var x, y;
		var normal = new Vector3();
		var vertex = new Vector3();

		var groupCount = 0;

		// this will be used to calculate the normal
		var slope = ( radiusBottom - radiusTop ) / height;

		// generate vertices, normals and uvs

		for ( y = 0; y <= heightSegments; y ++ ) {

			var indexRow = [];

			var v = y / heightSegments;

			// calculate the radius of the current row

			var radius = v * ( radiusBottom - radiusTop ) + radiusTop;

			for ( x = 0; x <= radialSegments; x ++ ) {

				var u = x / radialSegments;

				var theta = u * thetaLength + thetaStart;

				var sinTheta = Math.sin( theta );
				var cosTheta = Math.cos( theta );

				// vertex

				vertex.x = radius * sinTheta;
				vertex.y = - v * height + halfHeight;
				vertex.z = radius * cosTheta;
				vertices.push( vertex.x, vertex.y, vertex.z );

				// normal

				normal.set( sinTheta, slope, cosTheta ).normalize();
				normals.push( normal.x, normal.y, normal.z );

				// uv

				uvs.push( u, 1 - v );

				// save index of vertex in respective row

				indexRow.push( index ++ );

			}

			// now save vertices of the row in our index array

			indexArray.push( indexRow );

		}

		// generate indices

		for ( x = 0; x < radialSegments; x ++ ) {

			for ( y = 0; y < heightSegments; y ++ ) {

				// we use the index array to access the correct indices

				var a = indexArray[ y ][ x ];
				var b = indexArray[ y + 1 ][ x ];
				var c = indexArray[ y + 1 ][ x + 1 ];
				var d = indexArray[ y ][ x + 1 ];

				// faces

				indices.push( a, b, d );
				indices.push( b, c, d );

				// update group counter

				groupCount += 6;

			}

		}

		// add a group to the geometry. this will ensure multi material support

		scope.addGroup( groupStart, groupCount, 0 );

		// calculate new start value for groups

		groupStart += groupCount;

	}

	function generateCap( top ) {

		var x, centerIndexStart, centerIndexEnd;

		var uv = new Vector2();
		var vertex = new Vector3();

		var groupCount = 0;

		var radius = ( top === true ) ? radiusTop : radiusBottom;
		var sign = ( top === true ) ? 1 : - 1;

		// save the index of the first center vertex
		centerIndexStart = index;

		// first we generate the center vertex data of the cap.
		// because the geometry needs one set of uvs per face,
		// we must generate a center vertex per face/segment

		for ( x = 1; x <= radialSegments; x ++ ) {

			// vertex

			vertices.push( 0, halfHeight * sign, 0 );

			// normal

			normals.push( 0, sign, 0 );

			// uv

			uvs.push( 0.5, 0.5 );

			// increase index

			index ++;

		}

		// save the index of the last center vertex

		centerIndexEnd = index;

		// now we generate the surrounding vertices, normals and uvs

		for ( x = 0; x <= radialSegments; x ++ ) {

			var u = x / radialSegments;
			var theta = u * thetaLength + thetaStart;

			var cosTheta = Math.cos( theta );
			var sinTheta = Math.sin( theta );

			// vertex

			vertex.x = radius * sinTheta;
			vertex.y = halfHeight * sign;
			vertex.z = radius * cosTheta;
			vertices.push( vertex.x, vertex.y, vertex.z );

			// normal

			normals.push( 0, sign, 0 );

			// uv

			uv.x = ( cosTheta * 0.5 ) + 0.5;
			uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
			uvs.push( uv.x, uv.y );

			// increase index

			index ++;

		}

		// generate indices

		for ( x = 0; x < radialSegments; x ++ ) {

			var c = centerIndexStart + x;
			var i = centerIndexEnd + x;

			if ( top === true ) {

				// face top

				indices.push( i, i + 1, c );

			} else {

				// face bottom

				indices.push( i + 1, i, c );

			}

			groupCount += 3;

		}

		// add a group to the geometry. this will ensure multi material support

		scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );

		// calculate new start value for groups

		groupStart += groupCount;

	}

}
1191388
function(g, x, y, width, height, radius) {
        g.beginPath();
        // a
        g.moveTo(x + width / 2, y);
        // b
        g.bezierCurveTo(//
        x + width / 2 + radius / 2, y, //
        x + width / 2 + radius, y + radius / 2, //
        x + width / 2 + radius, y + radius);
        // c
        g.bezierCurveTo( //
        x + width / 2 + radius, y + radius * 2, //
        x + width / 2, y + height / 2 + radius / 3, //
        x + width / 2, y + height);
        // d
        g.bezierCurveTo(//
        x + width / 2, y + height / 2 + radius / 3, //
        x + width / 2 - radius, y + radius * 2, //
        x + width / 2 - radius, y + radius);
        // e (a)
        g.bezierCurveTo(//
        x + width / 2 - radius, y + radius / 2, //
        x + width / 2 - radius / 2, y + 0, //
        x + width / 2, y + 0);
        g.closePath();
    }
695171
static boolean pointInPolygon(float[] pt, float[] verts, int nverts) {
        // TODO: Replace pnpoly with triArea2D tests?
        int i, j;
        boolean c = false;
        for (i = 0, j = nverts - 1; i < nverts; j = i++) {
            int vi = i * 3;
            int vj = j * 3;
            if (((verts[vi + 2] > pt[2]) != (verts[vj + 2] > pt[2])) && (pt[0] < (verts[vj + 0] - verts[vi + 0])
                    * (pt[2] - verts[vi + 2]) / (verts[vj + 2] - verts[vi + 2]) + verts[vi + 0])) {
                c = !c;
            }
        }
        return c;
    }
476217
def call_graphviz_dot(src, fmt):
    
    try:
        svg = dot(src, T=fmt)
    except OSError as e:  # pragma: nocover
        if e.errno == 2:
            cli.error("""
               cannot find 'dot'

               pydeps calls dot (from graphviz) to create svg diagrams,
               please make sure that the dot executable is available
               on your path.
            """)
        raise
    return svg
251915
function(newRoot, p) {

            var self = this;

            if (document.documentElement.__transition__) return;

            // Rescale outside angles to match the new layout.
            var enterArc,
                exitArc,
                outsideAngle = d3.scale.linear().domain([0, 2 * Math.PI]);

            function insideArc(d) {
                return p.key > d.key
                    ? {depth: d.depth - 1, x: 0, dx: 0} : p.key < d.key
                    ? {depth: d.depth - 1, x: 2 * Math.PI, dx: 0}
                    : {depth: 0, x: 0, dx: 2 * Math.PI};
            }

            function outsideArc(d) {
                return {
                    depth: d.depth + 1, 
                    x: outsideAngle(d.x), 
                    dx: outsideAngle(d.x + d.dx) - outsideAngle(d.x)
                    };
            }

            function arcTween(b) {
                var i = d3.interpolate(this._current, b);
                this._current = i(0);
                return function(t) {
                    return self.arc(i(t));
                };
            }

            self.center.datum(newRoot);
            //console.log("newRoot");
            //console.log(newRoot);

            // When zooming in, 
            // arcs enter from the outside and exit to the inside.
            // Entering outside arcs start from the old layout.
            if (newRoot === p) {
                enterArc = outsideArc;
                exitArc = insideArc;
                outsideAngle.range([p.x, p.x + p.dx]);
            }

            self.path = self.path.data(self.partition.nodes(newRoot)
                                       .slice(1), function(d) { 
                                           return d.key; 
                                       });

            // When zooming out, 
            // arcs enter from the inside and exit to the outside.
            // Exiting outside arcs transition to the new layout.
            if (newRoot !== p) {
                enterArc = insideArc;
                exitArc = outsideArc;
                outsideAngle.range([p.x, p.x + p.dx]);
            }

            d3.transition()
              .duration(d3.event.altKey ? 7500 : 750)
              .each(function() {
                  self.path.exit().transition()
                      .style("fill-opacity", function(d) { 
                          return d.depth === 1 + (newRoot === p) ? 
                                 1 : 0;
                      })
                      .attrTween("d", function(d) { 
                          return arcTween.call(this, exitArc(d));
                      })
                      .remove();

                  self.path.enter().append("path")
                      .style("fill-opacity", function(d) { 
                          return d.depth === 2 - (newRoot === p) ? 
                                 1 : 0;
                      })
                      .style("fill", function(d) { 
                          return d.fill; 
                      })
                      .on("click", function(d, i) {
                          self.zoomIn(d);
                      })
                      .each(function(d) { 
                          this._current = enterArc(d);
                      });
                  // add the tooltip
                  self.path.append("title")
                      .text(function(d) {
                          return d.name + "\n" + 
                                 self.formatNumber(d.value) + 
                                 " Pageviews\n" +
                                 self.formatPercentage(d.value / self.totalValue) + 
                                 " of total pageviews";
                      });

                  self.path.transition()
                      .style("fill-opacity", 1)
                      .attrTween("d", function(d) { 
                          return arcTween.call(this, 
                                                self.updateArc(d)); 
                      });
              });
        }
1068388
function compare(pathData,opts={}) {
	var polys = svgPathToPolygons(pathData,opts);
	var minX=Infinity, maxX=-Infinity, minY=Infinity, maxY=-Infinity;
	polys.forEach(poly => {
		poly.forEach(pt => {
			if (pt[0]<minX) minX=pt[0];
			if (pt[1]<minY) minY=pt[1];
			if (pt[0]>maxX) maxX=pt[0];
			if (pt[1]>maxY) maxY=pt[1];
		});
	});
	let dx=maxX-minX, dy=maxY-minY;
	console.log(`
<svg xmlns="http://www.w3.org/2000/svg" width="${dx}px" height="${dy}px" viewBox="${minX} ${minY} ${dx*2} ${dy}">
<style>path,polygon,polyline { fill-opacity:0.2; stroke:black }</style>
<path d="${pathData}"/>
<g transform="translate(${dx},0)">
${polys.map(poly => `  <${poly.closed ? 'polygon' : 'polyline'} points="${poly.join(' ')}"/>`).join("\n")}
</g>
</svg>
	`.trim());
}
230124
function generateArcPath (x, y, radius, startAngle, endAngle) {
  var start = polarToCartesian(x, y, radius, startAngle);
  var end = polarToCartesian(x, y, radius, endAngle);
  var arcSweep = endAngle - startAngle <= 180 ? '0' : '1';
  return [
    'M', start.x, start.y,
    'A', radius, radius, 0, arcSweep, 0, end.x, end.y
  ].join(' ');
}
1344491
function svgPolygon($arguments)
	{
		$xbase = $arguments[0];
		$ybase = - $arguments[1];
		$path_cmd = sprintf('%.3F %.3F m ', $xbase * $this->kp, $ybase * $this->kp);
		for ($i = 2; $i < count($arguments); $i += 2) {
			$tmp_x = $arguments[$i];
			$tmp_y = - $arguments[($i + 1)];

			$path_cmd .= sprintf('%.3F %.3F l ', $tmp_x * $this->kp, $tmp_y * $this->kp);
		}
		$path_cmd .= sprintf('%.3F %.3F l ', $xbase * $this->kp, $ybase * $this->kp);
		$path_cmd .= 'h ';
		return $path_cmd;
	}