Author Topic: Run OpenSCAD .scad scripts with AngelCAD V1.5  (Read 1802 times)

Carsten Arnholm

  • Administrator
  • Jr. Member
  • *****
  • Posts: 65
    • View Profile
Run OpenSCAD .scad scripts with AngelCAD V1.5
« on: 2020-11-15, 21:31:29 »
In this post we will explain what it means to run OpenSCAD .scad scripts with AngelCAD and why it can be a good idea. Using this feature requires AngelCAD V1.5 or newer.

One criticism against OpenSCAD is that it can be very slow and requires a lot of memory to run its .scad scripts. Since the .scad scripts are widely used, it would be a good idea if there was a way to run them faster. That is where AngelCAD comes in. The reason why OpenSCAD is slow and memory hungry is because it is based on the CGAL library. AngelCAD on the other hand is using xcsg which is based on Carve, so it has the potential to be much faster.

How does running .scad scripts work in AngelCAD?

NOTE: OpenSCAD must be installed on the same computer as AngelCAD to use this feature, because OpenSCAD is used for parsing the .scad script into an easier to handle .csg file. This process is however very fast since it does not involve CGAL.

From a user point of view, running .scad scripts in AngelCAD is just as easy as in OpenSCAD, only faster. Drop an .scad script into the AngelCAD editor and press the build button, and the resulting STL or other 3d file format is produced in no time. Behind the scenes, several things will then happen:

First,  AngelCAD calls on OpenSCAD to convert the .scad script into a .scg file (fully automatic):

$ openscad myfile.scad --o myfile.csg

Second, the .csg file is automatically scanned by AngelCAD to see if it contains OpenSCAD import statements referring to STL or OFF files. If it does, these statements are replaced by suitable OpenSCAD polyhedron statements. If the import refers to an STL, AngelCADs polyfix is used to automatically compute the polyhedron. The result is a cleaned up .csg file that also OpenSCAD can read.

Third, the cleaned up .csg file is passed to AngelCADs xcsg application. Normally, xcsg requires the .xcsg file format, but version 1.5 has been enhanced to also accept OpenSCADs .csg files. The result is a 3d STL or other format file.

$ xcsg --stl myfile.csg

This may sound more complicated than running OpenSCAD, but in reality it is just as simple and faster from a user's point of view. All steps are fully automatic and it is much, much faster than running OpenSCAD itself, especially if the model is of some size. This is because the xcsg/carve boolean engine is quite lightweight, it uses native numerical representation and unlike OpenSCAD it is able to employ multi-threading, which means it can use more than one computer core at the same time.

The attached screenshots show AngelCAD running OpenSCAD's example12.scad. This example imports an STL file, so all the steps explained above are being carried out.

Mesh resolution
OpenSCAD has parameters like $fn and $fa to control mesh resolution, but these are not used by AngelCAD/xcsg. Instead, the resolution is controlled by the secant tolerance. This is also true for .scad scripts when run via AngelCAD. As can be seen from the first screenshot below, the command line argument sec_tol=0.01  (alternatively specified as the longer equivalent secant_tolerance=0.01) can be used to control the resulting mesh resolution. For this reason, running the same script through OpenSCAD may result in a slightly different result.

Limitations
The support for OpenSCAD modelling features is relatively complete, but not 100%. The following is a list of .scad language features that are not supported
  • import(file='somefile.dxf'): DXF or SVG file import is not supported. Import of STL and OFF is supported. Edit: DXF support is s available in V1.5-06
  • text(): text command is not supported. Edit: text() support is available in V1.5-06
  • surface(file='surface.dat'): surface command is not supported
  • resize(newsize=[30,60,10]): resize command is not supported
  • polygon without holes is supported, but a polygon with internal holes is not
« Last Edit: 2020-12-12, 19:33:16 by Carsten Arnholm »

Carsten Arnholm

  • Administrator
  • Jr. Member
  • *****
  • Posts: 65
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #1 on: 2020-11-19, 19:01:21 »
The latest V1.5-02 bugfix update linked to below greatly improves the number of OpenSCAD scripts that can successfully run in AngelCAD

https://forum.abmesh.com/index.php?topic=69.msg136#msg136
« Last Edit: 2020-11-19, 20:07:29 by Carsten Arnholm »

Carsten Arnholm

  • Administrator
  • Jr. Member
  • *****
  • Posts: 65
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #2 on: 2020-12-07, 14:53:55 »
We have some news relating to OpenSCAD scripts in AngelCAD, text() support is coming!


Carsten Arnholm

  • Administrator
  • Jr. Member
  • *****
  • Posts: 65
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #3 on: 2020-12-07, 15:07:29 »
And... some more news: DXF support is also coming! In some cases, AngelCAD will have more complete support for DXF than OpenSCAD.


Carsten Arnholm

  • Administrator
  • Jr. Member
  • *****
  • Posts: 65
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #4 on: 2020-12-12, 19:32:16 »
These new features  mentioned above, DXF import() and text() are now available in the latest release

https://forum.abmesh.com/index.php?topic=71.msg140;topicseen#msg140


raymw

  • Newbie
  • *
  • Posts: 32
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #5 on: 2021-05-04, 22:50:59 »
This runs considerably faster than rendering within openscad, seconds instead of many minutes in the few tests I've done. Would it be possible to parse the openscad script, and extract the $fn=80; (or similar values) and prefill the 'args' with a suitable value for secant_tolerance?

Carsten Arnholm

  • Administrator
  • Jr. Member
  • *****
  • Posts: 65
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #6 on: 2021-05-05, 16:41:42 »
Hi Ray,

Yes, it is supposed to run much faster, although we do not claim that all scripts will work, but most will work fine.

The question of $fn (OpenSCAD) and secant_tolerance (AngelCAD) is not directly straightforward to answer. $fn defines the number of straight segments in e.g. a circle, but it does not take the radius into account. secant_tolerance computes the number of segments using also the radius. So there is not a direct relation.

Overall, AngelCAD takes the position that it describes high level geometry and that the discretization is secondary, and therefore it ignores the $fa $fs and $fn values in OpenSCAD.

Maybe you have an example where this issue shows itself? I can understand that it can be a slight issue since the STL result will usually not be 100% identical, but then we are down to discretization. So maybe you can show a case where the difference is unacceptable?

raymw

  • Newbie
  • *
  • Posts: 32
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #7 on: 2021-05-06, 00:13:53 »
This is not what i wanted to show, since it does not work in angel cad, but does very slowly in openscad, but I had to comment out the fillet, I gave up waiting. There are a number of near misses with curves. If you've not got nophead'  library, then even if you comment out the 'male_metric_thread' line, it still won't work in angelcad, but it did more or less yesterday, iirc, because I experimented with the secant_tolerance values, smoothing out the curves.

Code: [Select]
//twist nut 8mm blank
include<NopSCADlib/utils/thread.scad>
include<rw/fillets3d.scad>

//module male_metric_thread(d, pitch, length, center = true, top = -1, bot = -1, solid = true, colour = undef) { //! Create male thread with metric profile example for variable names


//bottomFillet(b=0,r=1.5,s=8,e=enable)
translate([0,0,10])
difference(){
    union(){
      translate ([0,0, 5])  sphere( 12);
  scale([1.5,1,1])translate ([0,0,-5])  rotate ([90,0,0]) cylinder(h=3,d=15,center=true);
  cylinder (h=20,d=16,center=true);
  //  translate([0,0,10])cylinder (h=3,d=13);
    }
male_metric_thread(8,1.25,21);
 translate([0,0,-2])rotate([0,6,0])cylinder (h=21,d=8.2,center=true);   
   
  translate([0,0,-60])  cube([100,100,100],true); //chop off bottom
   
   
}


$fn=80;
//topBottomFillet(b = 0, t = 10, r = 1, s = 10, e = enable)

Carsten Arnholm

  • Administrator
  • Jr. Member
  • *****
  • Posts: 65
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #8 on: 2021-05-06, 12:39:47 »
I can't promise much, but I could at least try to reproduce your observations and see what that leads to, if anything. To do that I need to know where to find your 2 .scad includes

I am guessing NopSCADlib comes from https://github.com/nophead/NopSCADlib , please confirm

But where is include<rw/fillets3d.scad> to be found? If it is just a local file you have, please put it in a zip file and attach it to a reply.

--
I can't promise much, but I could at least try to reproduce your observations and see what that leads to, if anything. To do that I need to know where to find your 2 .scad includes

I am guessing NopSCADlib comes from https://github.com/nophead/NopSCADlib , please confirm

But where is include<rw/fillets3d.scad> to be found? If it is just a local file you have, please put it in a zip file and attach it to a reply.

EDIT: Your example as shown runs in 43 seconds using OpenSCAD nightly, with the filletting commented out. Please be exact wrt. what you are running to make it easier to reproduce
« Last Edit: 2021-05-06, 12:55:15 by Carsten Arnholm »

raymw

  • Newbie
  • *
  • Posts: 32
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #9 on: 2021-05-06, 17:34:56 »
The threading stuff is in  NopSCADlib and comes from https://github.com/nophead/NopSCADlib as you said.
The fillet was found on https://www.thingiverse.com/thing:2461392  there is a slight error in the code, I corrected it and reported it to the author, not sure if he fixed it, (I've attached that file*, but you can comment that out in my example). The problem is, that If I can't get things to work, then I try another way, and tend to forget the details of the original problem, which is probably not much help to you.

* for some reason, it couldn't get the path to the zip file for the attachment, so it's all below

Code: [Select]



/*
Created by Kevin Gravier
https://www.thingiverse.com/mrkmg/about

My take on a top and bottom fillet for a 3d shape.

Available Modules:

topBottomFillet(b, t, r, s, e)
b = z of bottom of 3d object
t = z of top of 3d object
r = radius of fillet
s = steps of filler (smaller is smoother)
e = enabled (pass e = 0 to disable fillet for faster preview)

topFillet(t, r, s, e)
t = z of top of 3d object
r = radius of fillet
s = steps of filler (smaller is smoother)
e = enabled (pass e = 0 to disable fillet for faster preview)

bottomFillet(b, r, s, e)
b = z of bottom of 3d object
r = radius of fillet
s = steps of filler (smaller is smoother)
e = enabled (pass e = 0 to disable fillet for faster preview)

*/

enable = 1;
/*
// Example, hard edges
translate([0, 20, 0])
topBottomFillet(b = 0, t = 10, r = 2, s = 20, e = enable)
linear_extrude(10, scale = 1.2)
difference() {
    union() {
        square([10, 10], true);
        translate([-15, 0]) circle(15);
    }
    translate([-15, 0]) circle(8);
    translate([-15, 0]) square([13, 13], center = true);
}

// Example, soft edges
use <fillets2d.scad>;
translate([0, -20, 0])
topBottomFillet(b = 0, t = 10, r = 1, s = 10, e = enable)
linear_extrude(10)
rounding2d(1)
fillet2d(1)
difference() {
    union() {
        square([10, 10], true);
        translate([-15, 0]) circle(15);
    }
    translate([-15, 0]) circle(8);
    translate([-15, 0]) square([13, 13], center = true);
}


// Example, text
translate([-60, 40])
rotate([0, 0, -90])
topBottomFillet(b = 0, t = 3, r = .5, s = 5, e = enable)
linear_extrude(3)
text("Fillets!", size = 20);

*/
// Library

function filletDepth(r, d, i) = r * cos(asin(d * i / r));

module topBottomFillet(b = 0, t = 2, r = 1, s = 4, e = 1) {
    if (e == 1) {       
        topFilletPeice(t = t, r = r, s = s) children(0);
        bottomFilletPeice(b = b, r = r, s = s) children(0);
       
        render()
        difference() {
            children(0);
           
            translate([0, 0, t - r])
            linear_extrude(r + 1)
            offset(delta = 1e5)
            projection()
            children(0);
           
            translate([0, 0, b - 1])
            linear_extrude(r + 1)
            offset(delta = 1e5)
            projection()
            children(0);
           
        }
    }
    if (e == 0) children(0);
}

module topFillet(t = 2, r = 1, s = 4, e = 1) {
    if (e == 1) {
        topFilletPeice(t = t, r = r, s = s) children(0);
       
        render()
        difference() {
            children(0);
            translate([0, 0, t-r])
            linear_extrude(r + 1)
            offset(delta = 1e5)
            projection()
            children(0);
        }
    }
    if (e == 0) children(0);
}

module bottomFillet(b = 0, r = 1, s = 4, e = 1) {
    if (e == 1) {
        bottomFilletPeice(b = b, r = r, s = s) children(0);
       
        render()
        difference() {
            children(0);
            translate([0, 0, b -  1])
            linear_extrude(r + 1)
            offset(delta = 1e5)
            projection()
            children(0);
        }
    }
    if (e == 0) children(0);
}

module topFilletPeice(t = 2, r = 1, s = 4) {
    d = r/s;
       
    for (i = [0:s]) {
        x = filletDepth(r, d, i);
        z = d * (s - i + 1);                 
        translate([0, 0, t - z])
        linear_extrude(d)
        offset(delta = -r + x)
        projection(true)
        translate([0, 0, -t + z])
        children(0);
    }
}

module bottomFilletPeice(b = 0, r =1, s = 4) {
    d = r/s;
       
    for (i = [0:s]) {
        x = filletDepth(r, d, i);
        z = d * (s - i);
        translate([0, 0, b + z])
        linear_extrude(d)
        offset(delta = -r + x)
        projection(true)
        translate([0, 0, b - z])
        children(0);
    }
}

Carsten Arnholm

  • Administrator
  • Jr. Member
  • *****
  • Posts: 65
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #10 on: 2021-05-06, 19:32:31 »
Thanks, there might still be an issue with attachments on the forum, sorry about that. Will see if it can be fixed.

However: When running the code you posted 2021-05-06, 00:13:53 unchanged, it now completes (F6) in less than a second in OpenSCAD, so this example is not reflecting the problem you described.

If you want me to look at this general issue further, please find a suitable example, test it and post the code exactly as tested in a new thread (do not continue this thread). I don't have time to guess at what you may or may not have done and I can't reproduce the problem.


raymw

  • Newbie
  • *
  • Posts: 32
    • View Profile
Re: Run OpenSCAD .scad scripts with AngelCAD V1.5
« Reply #11 on: 2021-05-06, 20:57:11 »
exactly as posted (without the fillet operational) it takes 1 minute and 27 seconds in openscad on my machine, and in angelcad, it produces a couple of lines -  UNEXPECTED face loop with size != 1.
UNEXPECTED face loop with size != 1. (and other messages as well), and a broken model. This is what I was getting at, what runs in openscad slowly, may not run at all in angelcad. I initially ran it in angelcad, with the fillet, since that took far to long in openscad. It did not run properly in angel cad, so I commented out the fillet code, and it still did not run in angel cad. I've just run this commented code, exactly as shown in the forum, and on my pc it takes 1 minute and 27 seconds in openscad. Your machine must be a bit faster, but it still does not run in Angel cad. It would be nice to know what causes the unexpected face loop, but I eventually got a result in openscad that was good enough.