Sort Curves By Containment for CNC G-Code

Hi everyone,

I’m trying to prepare g-code for clay 3D printing machine.

and i’m stuck at this stage since one month pls guide me .

6 groups of curves in this image

machine will solve it’s black color first [outer curve of black group>inner>inner>inner>inner]

next it’ll pick any one from 4 groups
( Red, Green, Purple, Blue // I don’t know the logic of slicer software)

But once it picked ex: Red then It will run all curves inside “Red”

then same for “Purple”, “Blue”, “Green”

and in the last “Cyan” color.

/////////////////////////////////////////////////////////////////////////////////////////////////////////////

I genrate these curves from ‘Solid_Polysrf’ or ‘Solid Mesh’

then i have always same color curves

and it has multiplelayers also.

Like this.

May you guys help me pls to sort it like

layerheight = 0.0 ( then solve all curves as i explained machine working)

layer_height = 2.0 ( then solve all curves as i explained machine working)

layer_height = 4.0 ( then solve all curves as i explained machine working)

part_1_gcd_gh.gh (58.7 KB)

I have internalised this geometry,
just connet to run entire script.

:roll_eyes:

Sorry I forgot to mention used plugins.

I can try to prepare this script with clipper plugin only.

Hello

I have all plugins except curve plus but Bounding Rectangle could be replaced by that.

Whatever to my point of view you better use Clipper2 in a C# component (don’t know if python is possible)

Polytree class is very useful to make a tree with all your curves. It will sort them for you. There are some tools to make on the beginning but then it will be more easy to grow your gcode tool.

didn’t check your gh file because it has many plugins I’m not using, but speaking of clay printing, what I usually do is to leave a couple of outer contours “as they are”, in such a way the machine will print a neat outline for that layer

if for instance these are the toolpaths for a given layer, which are offsets of the external curve (done by hand so a bit uneven… but still) :slight_smile:

I would first print the first external outline, then the secons outline (will turn those red)

then, if you want to get a continuous closed path, you can bridge different curves, like this, in blue:

then delete the crossing parts:

this ensures you have a single curve as “third zone”

applied to your specific case, it could be something like this, first two external curves printed first to get a nice outer boundary, then third zone as a whole single closed curve:

there are a few components in the awesome Nautilus plugin that allow for infill calculation to be performed in different styles, like zig-zag, offset… I would give those a try!

Hello sir , I’ll explore PolyTree link ( it will take some days to understand properly)

and yes I learnt new method for curve bounding box.

You are right sir, there are many plugins in one script.

( Actually I installed lot’s of plugin to learn something new and some of them has many useful components, so I forgot that it can be long process to just open a .gh file)

But your idea gave me new way of thinking to,

Connect internal curves in one .

Or try some ways to infill area, it can solve infill steps,

Thanks

I don’t know what particular type of clay you are using, the water content, and how much experience you already have with 3D printing that material

for me, the main issue with printing many different closed lines in the very same layer usually comes with the printing head stop extruding, then raise, move to the next location, move down, and start extruding again

the stop extrusion + raise + move away is one of those things that doesn’t always work very well: the extruded material sometimes does not stick to the previous layer and preferes to be pulled away by the printing head to the new location, actually displacing the last few centimeters of snake

for that reason I generally tend to raise my printing head just the bare minimum needed times, and try to create one continuous shape anywhere else -when/if possible-

another approach I sometimes use, expecially when there will be a double external wall that will continue for the whole length of the print, is to apply the bridge thing also on the first two external curves, to merge those into one

something like this, in green:

this will reduce the amount of raise+move to just two per layer, instead of three

I’m working for Scara v4 from 3D potter.(Not much experience I’m new to 3D clay printing,

But old user of rhino.

And using simplify 3D slicer.

and using Porcelain clay & and some regional from Indian manufacturers.

But the slicer is not enough for clay printing,

It has very limited features and that’s why I decided to try in grasshopper.

it’s very difficult to find a slicer that gives you good results with clay (I was not able to find one :smiley: )
but I think you’ll be very happy of the results you can get with Grasshopper and 3D printing clay, by coding your own toolpaths :+1:

if I can suggest you a super useful reading, this book helped me so much at the beginning, it’s a very strong backbone that gives you LOTS of interesting and super useful hints: https://www.food4rhino.com/en/resource/advanced-3d-printing-grasshopper-clay-and-fdm?lang=it

There is 250 parameters total in g code file generated by simplify 3d,

I think I can be done in grasshopper :grinning_face:

This book is very nice, but currently unavailable in India ( hard copy)

I got some pages on scribe.

To answer the initial question.
You can control the sequence of curves by moving the slider.

sort_curves.gh (369.6 KB)

Hello sir @leopoldomonzani ,

I checked the script but it jumped to another layer without counting layer1’s all curves.

sort_curves_02.gh (355.9 KB)
(Only added list item component in the script)

I don’t see the error in the outline.
It seems correct to me.
But there is an error in the internal curves.

That should be correct.

sort_curves_02 a.gh (375.9 KB)

I was trying something like this
I written a component in C# .net (with help of chatgpt and some videos etc)

now it solved the 2D and single layer problem.

i’m still working to fix Z_Heights
may be this one component will fix it, or may be two.

Finally solved

I kept everything in one component.

C#? I ask because you didn’t post your code for your solution… :question:

:roll_eyes:

using System;

using System.Collections.Generic;

using Grasshopper.Kernel;

using Grasshopper.Kernel.Data;

using Grasshopper.Kernel.Types;

using Rhino.Geometry;

namespace ContainmentTopologyGH

{

public class ContainmentComponent : GH_Component

{

    public ContainmentComponent()

      : base(

          "Containment Groups",

          "Contain",

          "Groups nested offset curves by geometric containment (no booleans)",

          "Topology",

          "Containment")

    { }

    protected override void RegisterInputParams(GH_InputParamManager p)

    {

        p.AddCurveParameter(

            "Curves",

            "C",

            "Closed planar curves",

            GH_ParamAccess.list

        );

    }

    protected override void RegisterOutputParams(GH_OutputParamManager p)

    {

        p.AddCurveParameter(

            "Groups",

            "G",

            "Containment groups (one branch per lobe)",

            GH_ParamAccess.tree

        );

    }

    protected override void SolveInstance(IGH_DataAccess DA)

    {

        var curves = new List<Curve>();

        if (!DA.GetDataList(0, curves)) return;

        if (curves.Count == 0) return;

        // ---------- SORT BY AREA (LARGEST FIRST) ----------

        curves.Sort((a, b) =>

        {

            double areaA = AreaMassProperties.Compute(a).Area;

            double areaB = AreaMassProperties.Compute(b).Area;

            return Math.Abs(areaB).CompareTo(Math.Abs(areaA));

        });

        int n = curves.Count;

        int\[\] parent = new int\[n\];

        for (int i = 0; i < n; i++)

            parent\[i\] = -1;

        // ---------- FIND CONTAINMENT PARENT ----------

        for (int i = 0; i < n; i++)

        {

            Point3d testPt = curves\[i\].PointAtNormalizedLength(0.25);

            for (int j = 0; j < i; j++)

            {

                if (curves\[j\].Contains(

                        testPt,

                        Plane.WorldXY,

                        Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance

                    ) == PointContainment.Inside)

                {

                    parent\[i\] = j;

                    break; // nearest enclosing curve

                }

            }

        }

        // ---------- BUILD OUTPUT TREE ----------

        var tree = new GH_Structure<GH_Curve>();

        int groupIndex = 0;

        for (int i = 0; i < n; i++)

        {

            // root curves = one lobe per branch

            if (parent\[i\] != -1) continue;

            GH_Path path = new GH_Path(groupIndex);

            tree.Append(new GH_Curve(curves\[i\]), path);

            AppendChildren(i, curves, parent, tree, path);

            groupIndex++;

        }

        DA.SetDataTree(0, tree);

    }

    // ---------- ADD CHILDREN TO SAME BRANCH ----------

    private void AppendChildren(

        int parentIndex,

        List<Curve> curves,

        int\[\] parent,

        GH_Structure<GH_Curve> tree,

        GH_Path path)

    {

        for (int i = 0; i < parent.Length; i++)

        {

            if (parent\[i\] == parentIndex)

            {

                // SAME path → no grafting

                tree.Append(new GH_Curve(curves\[i\]), path);

                AppendChildren(i, curves, parent, tree, path);

            }

        }

    }

    protected override System.Drawing.Bitmap Icon => null;

    public override Guid ComponentGuid =>

        new Guid("9B9C1E2A-7D9E-4F5B-9F14-6E2B6D0B8A33");

}

}

It’s not the correct version, but I’ll correct version,

Next day.

With proper comments and final testing.