Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue converting different objects to a closed dxf #480

Closed
tabeaeggler opened this issue Jan 4, 2021 · 5 comments
Closed

Issue converting different objects to a closed dxf #480

tabeaeggler opened this issue Jan 4, 2021 · 5 comments

Comments

@tabeaeggler
Copy link

tabeaeggler commented Jan 4, 2021

Hi Maker.js developers!

I try to convert an SVG with lines, circles, arcs & ellipses to a DXF.

This approach is working as long as the objects are of the same type (only lines or only arcs...). As soon as the objects are mixed, they are not properly connected and are overlapping a tiny little bit or a small cap is created. Thus, it's not a chain any more.

    //case line
    let lines = svg.getElementsByClassName("line")
    for (let j = 0; j < lines.length; j++) {
      let child = lines[j]
      let childPath = "M" + child.getAttribute("x1") + " " + child.getAttribute("y1") + ", L" + child.getAttribute("x2") + " " + child.getAttribute("y1")
      let svgPathData = makerjs.importer.fromSVGPathData(childPath, { bezierAccuracy: 0.0 })
      let line = svgPathData.paths?.p_1
      makerjs.model.addPath(model, line, "line")
    }

    //case semi-circle (radius x == radius y)
    let semiCircles = svg.getElementsByClassName("arc")
    for (let j = 0; j < semiCircles.length; j++) {
      let childPath = semiCircles[j].getAttribute("d")
      let svgPathData = makerjs.importer.fromSVGPathData(childPath, { bezierAccuracy: 0.0 })
      let arc = svgPathData.paths?.p_1
      makerjs.model.addPath(model, arc, "arc")
    }

    //..same for circles and ellipses
    
    //export to dxf
    let chains = makerjs.model.findChains(model)
    let dxf = makerjs.exporter.toDXF(model, { usePOLYLINE: true })

If I zoom in very close it looks like this:
issue dxf export

Does anyone have an idea how to fix this issue so that all objects are merged properly?

@danmarshall
Copy link
Contributor

Hello, this looks like it might be a problem with "accuracy" settings. These can be fiddly. Accuracy settings depend on your application and units. For example, if you are outputting to a computer screen, the units would be pixels, and you can probably use accuracy of 0.5 (half a pixel) for good results.

In your example, you are importing SVG. Can you add your example SVG? Also, you should not use bezierAccuracy of 0.0, since this may cause endless calculation. It may be that your Bezier curves are being broken up into arcs that are too tiny and then being dismissed but the chain finding function.

@tabeaeggler
Copy link
Author

Thanks for your fast reply! An accuracy of 0.5 doesn't work either. It looks like the lines are a little bit shifted in direction of the y-axis.

Here is a sample svg containg two lines, a semi-circle (arc) and a semi-ellipse (bezier-seed):
<svg xmlns="http://www.w3.org/2000/svg" class="svg" width="880" height="772" preserveAspectRatio="none"><g/><g/><g/><g/><g/><g/><g><line class="line" id="2" x1="159.671875" y1="550.25" x2="149.671875" y2="294.25" fill="none" strokeWidth="5" stroke="black" strokeLinecap="round"/><text text-anchor="middle" x="179.671875" y="550.25">0</text></g><g><line class="line" id="7" x1="407.671875" y1="284.25" x2="420.671875" y2="544.25" fill="none" strokeWidth="5" stroke="black" strokeLinecap="round"/><text text-anchor="middle" x="427.671875" y="284.25">0</text></g><g><path d="M420.671875 544.25 A 130.5344782040362 71.23982803281127 178.68308759420674 0 1 159.671875 550.25" class="semi-circle bezier-seed" id="9" fill="none" strokeWidth="5" stroke="black" strokeLinecap="round"/></g><g><path d="M149.671875 294.25 A 146.88703491966612 146.88703491966612 0 0 1 407.671875 284.25" class="semi-circle arc" id="5" fill="none" strokeWidth="5" stroke="black" strokeLinecap="round"/></g></svg>

@tabeaeggler
Copy link
Author

Here you can find the code for the semi-ellipse if needed:

    //case semi-ellipse (radius x != radius y)

    let semiEllipses = svg.getElementsByClassName("bezier-seed")
    for (let j = 0; j < semiEllipses.length; j++) {
      let childPath = semiEllipses[j].getAttribute("d")
      let svgPathData = makerjs.importer.fromSVGPathData(childPath, { bezierAccuracy: 0.5 })
      model.models["bezier_seed_" + j + "_1"] = makerjs.travel(svgPathData, [
        "models",
        "p_1",
        "models",
        "Curve_1",
      ]).result
      model.models["bezier_seed_" + j + "_2"] = makerjs.travel(svgPathData, [
        "models",
        "p_1",
        "models",
        "Curve_2",
      ]).result
      model.models["bezier_seed_" + j + "_3"] = makerjs.travel(svgPathData, [
        "models",
        "p_1",
        "models",
        "Curve_3",
      ]).result
      model.models["bezier_seed_" + j + "_4"] = makerjs.travel(svgPathData, [
        "models",
        "p_1",
        "models",
        "Curve_4",
      ]).result
    }

@danmarshall
Copy link
Contributor

danmarshall commented Jan 4, 2021

Here's a demo converted for use in the Playground:

var makerjs = require('makerjs');

function demo() {

    var svgPath1 = makerjs.importer.fromSVGPathData("M420.671875 544.25 A 130.5344782040362 71.23982803281127 178.68308759420674 0 1 159.671875 550.25");
    var svgPath2 = makerjs.importer.fromSVGPathData("M149.671875 294.25 A 146.88703491966612 146.88703491966612 0 0 1 407.671875 284.25");

  	var line1 = new makerjs.paths.Line([159.671875, -550.25], [149.671875, -294.25]);
  	var line2 = new makerjs.paths.Line([407.671875, -284.25], [420.671875, -544.25]);
  
    this.paths = {
    	line1, line2
    };

    this.models = {
        svgPath1, svgPath2
    };

  var chains = makerjs.model.findChains(this);
  
  console.log(chains.length)
  console.log(chains[0].endless)
}

module.exports = demo;

It finds one endless chain. Does it export to DXF correctly?

@tabeaeggler
Copy link
Author

Thanks. Yes, your code exports a correct and closed DXF. This is my working code (based on your demo):

    //case line
    let lines = svg.getElementsByClassName("line")
    for (let j = 0; j < lines.length; j++) {
      let child = lines[j]
      let x1: number = parseFloat(child.getAttribute("x1")!)
      let y1: number = parseFloat(child.getAttribute("y1")!)
      let x2: number = parseFloat(child.getAttribute("x2")!)
      let y2: number = parseFloat(child.getAttribute("y2")!)
      let point1: IPoint = [x1, -y1]
      let point2: IPoint = [x2, -y2]
      let line = new makerjs.paths.Line(point1, point2)
      makerjs.model.addPath(model, line, "line")
    }

    //case semi-circle (radius x == radius y)
    let semiCircles = svg.getElementsByClassName("arc")
    for (let j = 0; j < semiCircles.length; j++) {
      let childPath = semiCircles[j].getAttribute("d")
      let svgPathData = makerjs.importer.fromSVGPathData(childPath)
      makerjs.model.addModel(model, svgPathData, "arc")
    }

    //case semi-ellipse (radius x != radius y)
    let semiEllipses = svg.getElementsByClassName("bezier-seed")
    for (let j = 0; j < semiEllipses.length; j++) {
      let childPath = semiEllipses[j].getAttribute("d")
      let svgPathData = makerjs.importer.fromSVGPathData(childPath)
      makerjs.model.addModel(model, svgPathData, "ellipticarc")
    }

    //var chains = makerjs.model.findChains(model)
    return makerjs.exporter.toDXF(model)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants