Пример #1
0
void PluginDisplay::load() {
    int a = combobox_mono_stereo->get_model()->get_path(combobox_mono_stereo->get_active())[0];
    bool s = selected_only->get_active();
    bool c = changed_only->get_active();
    bool d = ladspa_only->get_active();
    bool e = lv2_only->get_active();
    plugin_liststore->clear();
    for (std::vector<PluginDesc*>::iterator v = pluginlist.begin(); v != pluginlist.end(); ++v) {
	if (s && !(*v)->active) {
	    continue;
	}
	else if (c && !(*v)->has_settings) {
	    continue;
	}
	else if (d && (*v)->is_lv2) {
	    continue;
	}
 	else if (e && !(*v)->is_lv2) {
	    continue;
	}
	if ((a == 1 && (*v)->tp != 0) || (a == 2 && (*v)->tp != 1)) {
	    continue;
	}

	Gtk::TreeIter it = plugin_liststore->append();
	it->set_value(plugin_liststore->col.name, ustring((*v)->Name));
	it->set_value(plugin_liststore->col.active, (*v)->active);
	it->set_value(plugin_liststore->col.pdesc, *v);
    }
}
Пример #2
0
void Surface::save_debug_image(string message)
{
    static unsigned int debug_image_index = 0;

    opacify(pixbuf);
    pixbuf->save( build_filename(outputdir,
                                 (boost::format("outp%1%_%2%.png") % debug_image_index % message).str() ),
                  "png");
    debug_image_index++;
}
Пример #3
0
void Surface_vectorial::save_debug_image(string message)
{
    const string filename = (boost::format("outp%d_%s.svg") % debug_image_index % message).str();
    svg_writer debug_image(build_filename(outputdir, filename), SVG_PIX_PER_IN, scale, bounding_box);

    srand(1);
    debug_image.add(*vectorial_surface, 1, true);

    ++debug_image_index;
}
Пример #4
0
void NGC_Exporter::export_all(boost::program_options::variables_map& options)
{

    bMetricinput = options["metric"].as<bool>();      //set flag for metric input
    bMetricoutput = options["metricoutput"].as<bool>();      //set flag for metric output
    bZchangeG53 = options["zchange-absolute"].as<bool>();
    bFrontAutoleveller = options["al-front"].as<bool>();
    bBackAutoleveller = options["al-back"].as<bool>();
    string outputdir = options["output-dir"].as<string>();
    
    //set imperial/metric conversion factor for output coordinates depending on metricoutput option
    cfactor = bMetricoutput ? 25.4 : 1;
    
    if( options["zero-start"].as<bool>() )
    {
        xoffset = board->get_min_x();
        yoffset = board->get_min_y();
    }
    else
    {
        xoffset = 0;
        yoffset = 0;
    }
    
    tileInfo = Tiling::generateTileInfo( options, ocodes, board->get_height(), board->get_width() );

    if( bFrontAutoleveller || bBackAutoleveller )
        leveller = new autoleveller ( options, &ocodes, &globalVars, quantization_error,
                                      xoffset, yoffset, tileInfo );

    if (options["bridges"].as<double>() > 0 && options["bridgesnum"].as<unsigned int>() > 0)
        bBridges = true;
    else
        bBridges = false;

    for ( string layername : board->list_layers() )
    {
        std::stringstream option_name;
        option_name << layername << "-output";
        string of_name = build_filename(outputdir, options[option_name.str()].as<string>());
        cout << "Exporting " << layername << "... " << flush;
        export_layer(board->get_layer(layername), of_name);
        cout << "DONE." << " (Height: " << board->get_height() * cfactor
             << (bMetricoutput ? "mm" : "in") << " Width: "
             << board->get_width() * cfactor << (bMetricoutput ? "mm" : "in")
             << ")";
        if (layername == "outline")
            cout << " The board should be cut from the " << ( workSide(options, "cut") ? "FRONT" : "BACK" ) << " side. ";
        cout << endl;
    }
}
Пример #5
0
void
GtkSDL::SetVideoMode (int width, int height)
{
    gchar SDL_WINDOWID[32];

    // As default, SDL check if environment variable
    // SDL_WINDOWID is defined, on true he diverts
    // the screen stream to the following XID (if it exists)
    // otherwises, just creates and display a new Xwindow.
    //FIXME: not portable to Win32.
    snprintf (SDL_WINDOWID, 32 * sizeof (gchar), "SDL_WINDOWID=%ld",
	      GDK_WINDOW_XWINDOW (unwrap (get_window ())));

    SDL_putenv (SDL_WINDOWID);

    HMI::Init ();

    HMI::GetRef ().SetVideoMode (width, height, true);

    Timer::GetRef ().Reset ();
}
Пример #6
0
    SilenceGtk (const char* plugin_uri)
    {
        /*  Required before creating widgets */
        Gtk::Main::init_gtkmm_internals();

        /*  Create the container with @c new because we don't
            know if the host is using Gtkmm or not */
        p_hbox = new Gtk::HBox();

        if (p_hbox) {
            Button *btn = manage (new Button(ustring("Silence")));

            btn->signal_pressed().connect(
                    mem_fun(*this, &SilenceGtk::send_note_on));
            btn->signal_released().connect(
                    mem_fun(*this, &SilenceGtk::send_note_off));

            p_hbox->pack_start (*btn);
        } else {
            p_hbox = 0;
        }
    }
Пример #7
0
int main(int argc, char* argv[])
{

    Glib::init();
    Gdk::wrap_init();

    options::parse(argc, argv);      //parse the command line parameters

    po::variables_map& vm = options::get_vm();      //get the cli parameters

    if (vm.count("version"))        //return version and quit
    {
        cout << PACKAGE_VERSION << endl;
        exit(EXIT_SUCCESS);
    }

    if (vm.count("help"))        //return help and quit
    {
        cout << options::help();
        exit(EXIT_SUCCESS);
    }

    options::check_parameters();      //check the cli parameters

    //---------------------------------------------------------------------------
    //deal with metric / imperial units for input parameters:

    double unit;      //factor for imperial/metric conversion

    unit = vm["metric"].as<bool>() ? (1. / 25.4) : 1;

    //---------------------------------------------------------------------------
    //prepare environment:

    const string outputdir = vm["output-dir"].as<string>();
    shared_ptr<Isolator> isolator;

    if (vm.count("front") || vm.count("back"))
    {
        isolator = shared_ptr<Isolator>(new Isolator());
        isolator->tool_diameter = vm["offset"].as<double>() * 2 * unit;
        isolator->zwork = vm["zwork"].as<double>() * unit;
        isolator->zsafe = vm["zsafe"].as<double>() * unit;
        isolator->feed = vm["mill-feed"].as<double>() * unit;
        if (vm.count("mill-vertfeed"))
            isolator->vertfeed = vm["mill-vertfeed"].as<double>() * unit;
        else
            isolator->vertfeed = isolator->feed / 2;
        isolator->speed = vm["mill-speed"].as<int>();
        isolator->zchange = vm["zchange"].as<double>() * unit;
        isolator->extra_passes = vm["extra-passes"].as<int>();
        isolator->optimise = vm["optimise"].as<bool>();
        isolator->internal_components = vm["internal-toolpaths"].as<bool>();
    }

    shared_ptr<Cutter> cutter;

    if (vm.count("outline") || (vm.count("drill") && vm["milldrill"].as<bool>()))
    {
        cutter = shared_ptr<Cutter>(new Cutter());
        cutter->tool_diameter = vm["cutter-diameter"].as<double>() * unit;
        cutter->zwork = vm["zcut"].as<double>() * unit;
        cutter->zsafe = vm["zsafe"].as<double>() * unit;
        cutter->feed = vm["cut-feed"].as<double>() * unit;
        if (vm.count("cut-vertfeed"))
            cutter->vertfeed = vm["cut-vertfeed"].as<double>() * unit;
        else
            cutter->vertfeed = cutter->feed / 2;
        cutter->speed = vm["cut-speed"].as<int>();
        cutter->zchange = vm["zchange"].as<double>() * unit;
        cutter->do_steps = true;
        cutter->stepsize = vm["cut-infeed"].as<double>() * unit;
        cutter->optimise = vm["optimise"].as<bool>();
        cutter->bridges_num = vm["bridgesnum"].as<unsigned int>();
        cutter->bridges_width = vm["bridges"].as<double>() * unit;
        if (vm.count("zbridges"))
            cutter->bridges_height = vm["zbridges"].as<double>() * unit;
        else
            cutter->bridges_height = cutter->zsafe;
        cutter->internal_components = vm["internal-toolpaths"].as<bool>();
    }

    shared_ptr<Driller> driller;

    if (vm.count("drill"))
    {
        driller = shared_ptr<Driller>(new Driller());
        driller->zwork = vm["zdrill"].as<double>() * unit;
        driller->zsafe = vm["zsafe"].as<double>() * unit;
        driller->feed = vm["drill-feed"].as<double>() * unit;
        driller->speed = vm["drill-speed"].as<int>();
        driller->zchange = vm["zchange"].as<double>() * unit;
    }

    //---------------------------------------------------------------------------
    //prepare custom preamble:

    string preamble, postamble;

    if (vm.count("preamble-text"))
    {
        cout << "Importing preamble text... ";
        string name = vm["preamble-text"].as<string>();
        fstream in(name.c_str(), fstream::in);

        if (!in.good())
        {
            cerr << "Cannot read preamble-text file \"" << name << "\"" << endl;
            exit(EXIT_FAILURE);
        }

        string line;
        string tmp;

        while (std::getline(in, line))
        {
            tmp = line;
            boost::erase_all(tmp, " ");
            boost::erase_all(tmp, "\t");

            if( tmp.empty() )		//If there's nothing but spaces and \t
                preamble += '\n';
            else
            {
                boost::replace_all ( line, "(", "<" );       //Substitute round parenthesis with angled parenthesis
                boost::replace_all ( line, ")", ">" );
                preamble += "( " + line + " )\n";
            }
        }

        cout << "DONE\n";
    }

    if (vm.count("preamble"))
    {
        cout << "Importing preamble... ";
        string name = vm["preamble"].as<string>();
        fstream in(name.c_str(), fstream::in);

        if (!in.good())
        {
            cerr << "Cannot read preamble file \"" << name << "\"" << endl;
            exit(EXIT_FAILURE);
        }

        string tmp((std::istreambuf_iterator<char>(in)),
                   std::istreambuf_iterator<char>());
        preamble += tmp + "\n";
        cout << "DONE\n";
    }

    //---------------------------------------------------------------------------
    //prepare custom postamble:

    if (vm.count("postamble"))
    {
        cout << "Importing postamble... ";
        string name = vm["postamble"].as<string>();
        fstream in(name.c_str(), fstream::in);

        if (!in.good())
        {
            cerr << "Cannot read postamble file \"" << name << "\"" << endl;
            exit(EXIT_FAILURE);
        }

        string tmp((std::istreambuf_iterator<char>(in)),
                   std::istreambuf_iterator<char>());
        postamble = tmp + "\n";
        cout << "DONE\n";
    }

    //---------------------------------------------------------------------------

    shared_ptr<Board> board(
        new Board(
            vm["dpi"].as<int>(),
            vm["fill-outline"].as<bool>(),
            vm["fill-outline"].as<bool>() ?
            vm["outline-width"].as<double>() * unit :
            INFINITY,
            outputdir));

    // this is currently disabled, use --outline instead
    if (vm.count("margins"))
    {
        board->set_margins(vm["margins"].as<double>());
    }

    //--------------------------------------------------------------------------
    //load files, import layer files, create surface:

    try
    {

        //-----------------------------------------------------------------------
        cout << "Importing front side... ";

        try
        {
            string frontfile = vm["front"].as<string>();
            boost::shared_ptr<LayerImporter> importer(
                new GerberImporter(frontfile));
            board->prepareLayer("front", importer, isolator, false,
                                vm["mirror-absolute"].as<bool>());
            cout << "DONE.\n";
        }
        catch (import_exception& i)
        {
            cout << "ERROR.\n";
        }
        catch (boost::exception& e)
        {
            cout << "not specified.\n";
        }

        //-----------------------------------------------------------------------
        cout << "Importing back side... ";

        try
        {
            string backfile = vm["back"].as<string>();
            boost::shared_ptr<LayerImporter> importer(
                new GerberImporter(backfile));
            board->prepareLayer("back", importer, isolator, true,
                                vm["mirror-absolute"].as<bool>());
            cout << "DONE.\n";
        }
        catch (import_exception& i)
        {
            cout << "ERROR.\n";
        }
        catch (boost::exception& e)
        {
            cout << "not specified.\n";
        }

        //-----------------------------------------------------------------------
        cout << "Importing outline... ";

        try
        {
            string outline = vm["outline"].as<string>();                               //Filename
            boost::shared_ptr<LayerImporter> importer(new GerberImporter(outline));
            board->prepareLayer("outline", importer, cutter, !workSide(vm, "cut"),
                                vm["mirror-absolute"].as<bool>());

            cout << "DONE.\n";
        }
        catch (import_exception& i)
        {
            cout << "ERROR.\n";
        }
        catch (boost::exception& e)
        {
            cout << "not specified.\n";
        }

    }
    catch (import_exception& ie)
    {
        if (ustring const* mes = boost::get_error_info<errorstring>(ie))
            std::cerr << "Import Error: " << *mes;
        else
            std::cerr << "Import Error: No reason given.";
    }

    //---------------------------------------------------------------------------
    //SVG EXPORTER

    shared_ptr<SVG_Exporter> svgexpo(new SVG_Exporter(board));
    Tiling::TileInfo *tileInfo = NULL;

    try
    {

        board->createLayers();      // throws std::logic_error

        if (vm.count("svg"))
        {
            cout << "Create SVG File ... " << vm["svg"].as<string>() << endl;
            svgexpo->create_svg( build_filename(outputdir, vm["svg"].as<string>()) );
        }

        shared_ptr<NGC_Exporter> exporter(new NGC_Exporter(board));
        exporter->add_header(PACKAGE_STRING);

        if (vm.count("preamble") || vm.count("preamble-text"))
        {
            exporter->set_preamble(preamble);
        }

        if (vm.count("postamble"))
        {
            exporter->set_postamble(postamble);
        }

        //SVG EXPORTER
        if (vm.count("svg"))
        {
            exporter->set_svg_exporter(svgexpo);
        }

        exporter->export_all(vm);

        tileInfo = new Tiling::TileInfo;
        *tileInfo = exporter->getTileInfo();
    }
    catch (std::logic_error& le)
    {
        cout << "Internal Error: " << le.what() << endl;
    }
    catch (std::runtime_error& re)
    {
        cout << "Runtime Error: " << re.what() << endl;
    }

    //---------------------------------------------------------------------------
    //load and process the drill file

    cout << "Importing drill... ";

    try
    {
        icoordpair min;
        icoordpair max;

        //Check if there are layers in "board"; if not, we have to compute
        //the size of the board now, based only on the size of the drill layer
        //(the resulting drill gcode will be probably misaligned, but this is the
        //best we can do)
        if(board->get_layersnum() == 0)
        {
            boost::shared_ptr<LayerImporter> importer(new GerberImporter(vm["drill"].as<string>()));
            min = std::make_pair( importer->get_min_x(), importer->get_min_y() );
            max = std::make_pair( importer->get_max_x(), importer->get_max_y() );
        }
        else
        {
            min = std::make_pair( board->get_min_x(), board->get_min_y() );
            max = std::make_pair( board->get_max_x(), board->get_max_y() );
        }

        ExcellonProcessor ep(vm, min, max);

        ep.add_header(PACKAGE_STRING);

        if (vm.count("preamble") || vm.count("preamble-text"))
        {
            ep.set_preamble(preamble);
        }

        if (vm.count("postamble"))
        {
            ep.set_postamble(postamble);
        }

        //SVG EXPORTER
        if (vm.count("svg"))
        {
            ep.set_svg_exporter(svgexpo);
        }

        cout << "DONE.\n";

        if (vm["milldrill"].as<bool>())
        {
            ep.export_ngc( build_filename(outputdir, vm["drill-output"].as<string>()), cutter);
        }
        else
        {
            ep.export_ngc( build_filename(outputdir, vm["drill-output"].as<string>()),
                           driller, vm["onedrill"].as<bool>(), vm["nog81"].as<bool>());
        }

        cout << "DONE. The board should be drilled from the " << ( workSide(vm, "drill") ? "FRONT" : "BACK" ) << " side.\n";

    }
    catch (drill_exception& e)
    {
        cout << "ERROR.\n";
    }
    catch (import_exception& i)
    {
        cout << "ERROR.\n";
    }
    catch (boost::exception& e)
    {
        cout << "not specified.\n";
    }

    cout << "END." << endl;

}
Пример #8
0
void PluginDisplay::selection_changed() {
    Gtk::TreeIter it = treeview1->get_selection()->get_selected();
    PluginDesc *p = 0;
    if (it) {
	p = it->get_value(plugin_liststore->col.pdesc);
	if (current_plugin == p) {
	    return;
	}
    }
    save_current();
    on_reordered_conn.block();
    port_liststore->clear();
    on_reordered_conn.unblock();
    ladspa_category->set_text("");
    ladspa_maker->set_text("");
    ladspa_uniqueid->set_text("");
    plugin_name->set_text("");
    plugin_category->set_active(-1);
    plugin_quirks->set_active(-1);
    if (!p) {
	return;
    }
    set_old_state(p);
    if (p->shortname != p->Name) {
	plugin_name->modify_text(Gtk::STATE_NORMAL, Gdk::Color("red"));
    } else {
	plugin_name->unset_text(Gtk::STATE_NORMAL);
    }
    plugin_name->set_text(p->shortname);
    Gtk::TreeNodeChildren ch = plugin_category->get_model()->children();
    int i = 0;
    for (it = ch.begin(); it != ch.end(); ++it, ++i) {
	ustring cat;
	it->get_value(1, cat);
	if (cat == p->category) {
	    plugin_category->set_active(i);
	    break;
	}
    }
    ch = plugin_quirks->get_model()->children();
    for (i = 0, it = ch.begin(); it != ch.end(); ++it, ++i) {
	int quirks;
	it->get_value(1, quirks);
	if (quirks == p->quirks) {
	    plugin_quirks->set_active(i);
	    break;
	}
    }
    Glib::RefPtr<Gtk::ListStore> ls_master = Glib::RefPtr<Gtk::ListStore>::cast_dynamic(master_slider_idx->get_model());
    ls_master->clear();
    it = ls_master->append();
    i = -1;
    it->set_value(0, i);
    ustring ml("");
    for (unsigned int i = 0; i < p->ctrl_ports.size(); ++i) {
	it = ls_master->append();
	it->set_value(0, int(i));
	if (p->ctrl_ports[i]->pos == p->MasterIdx) {
	    ml = p->ctrl_ports[i]->factory.get_name();
	}
    }
    master_slider_idx->set_active(p->MasterIdx+1);
    master_slider_name->unset_text(Gtk::STATE_NORMAL);
    if (!p->MasterLabel.empty()) {
	master_slider_name->set_text(p->MasterLabel);
	if (p->MasterLabel != ml) {
	    master_slider_name->modify_text(Gtk::STATE_NORMAL, Gdk::Color("red"));
	}
    }
    dry_wet_button->set_active(current_plugin->add_wet_dry);
    ladspa_category->set_text(p->ladspa_category);
    ladspa_maker->set_text(p->Maker);
    if (p->is_lv2) {
	ladspa_uniqueid->set_text(ustring::compose("LV2: %1", p->path));
    } else {
	ladspa_uniqueid->set_text(ustring::compose("%1: %2[%3]", p->UniqueID, p->path, p->index));
    }
    for (unsigned int i = 0; i < p->ctrl_ports.size(); ++i) {
	PortDesc *q = p->ctrl_ports[i];
	Glib::RefPtr<Gtk::ListStore> tls;
	if (q->is_output) {
	    tls = output_type_list;
	} else if (q->has_sr) {
	    tls = display_type_list_sr;
	} else {
	    tls = display_type_list;
	}
	float dflt = q->get_dflt();
	float low = q->get_low();
	float up = q->get_up();
	if (q->has_sr && !q->use_sr) {
	    if (q->factory.is_set(ChangeableValues::dflt_set)) {
		dflt *= q->SR;
	    }
	    if (q->factory.is_set(ChangeableValues::low_set)) {
		low *= q->SR;
	    }
	    if (q->factory.is_set(ChangeableValues::up_set)) {
		up *= q->SR;
	    }
	}
	it = port_liststore->append();
	it->set_value(port_liststore->col.pos, q->pos);
	it->set_value(port_liststore->col.name, q->get_name());
	it->set_value(port_liststore->col.dflt, ustring::format(dflt));
	it->set_value(port_liststore->col.low, ustring::format(low));
	it->set_value(port_liststore->col.up, ustring::format(up));
	it->set_value(port_liststore->col.step, ustring(step_type_names[q->step]));
	it->set_value(port_liststore->col.display, ustring(display_type_names[q->get_tp()]));
	it->set_value(port_liststore->col.display_types, tls);
	it->set_value(port_liststore->col.port, q);
	it->set_value(port_liststore->col.newrow, q->get_newrow());
	it->set_value(port_liststore->col.use_sr, q->has_sr && !q->use_sr);
	it->set_value(port_liststore->col.has_caption, q->has_caption);
    }
}
Пример #9
0
inline ustring sqlite3_column_ustring(sqlite3_stmt * stmt, unsigned int colnum)
{
	return ustring( (char *) sqlite3_column_text(stmt, colnum) );
}
Пример #10
0
vector<shared_ptr<icoords> > Surface_vectorial::get_toolpath(shared_ptr<RoutingMill> mill,
        bool mirror)
{
    multi_linestring_type toolpath;
    vector<shared_ptr<icoords> > toolpath_optimised;
    multi_polygon_type_fp voronoi;
    coordinate_type tolerance = mill->tolerance * scale;
    // This is by how much we will grow each trace if extra passes are needed.
    coordinate_type grow = mill->tool_diameter / 2 * scale;

    shared_ptr<Isolator> isolator = dynamic_pointer_cast<Isolator>(mill);
    // Extra passes are done on each trace if requested, each offset by half the tool diameter.
    const int extra_passes = isolator ? isolator->extra_passes : 0;
    const bool do_voronoi = isolator ? isolator->voronoi : false;

    if (tolerance <= 0)
        tolerance = 0.0001 * scale;

    bg::unique(*vectorial_surface);
    box_type voronoi_bounding_box;
    bg::convert(bounding_box, voronoi_bounding_box);
    voronoi = Voronoi::build_voronoi(*vectorial_surface, voronoi_bounding_box, tolerance);

    box_type svg_bounding_box;

    if (grow > 0)
        bg::buffer(bounding_box, svg_bounding_box, grow * (extra_passes + 1));
    else
        bg::assign(svg_bounding_box, bounding_box);

    const string traced_filename = (boost::format("outp%d_traced_%s.svg") % debug_image_index++ % name).str();
    svg_writer debug_image(build_filename(outputdir, "processed_" + name + ".svg"), SVG_PIX_PER_IN, scale, svg_bounding_box);
    svg_writer traced_debug_image(build_filename(outputdir, traced_filename), SVG_PIX_PER_IN, scale, svg_bounding_box);

    srand(1);
    debug_image.add(voronoi, 0.3, false);

    const coordinate_type mirror_axis = mill->mirror_absolute ?
        bounding_box.min_corner().x() :
        ((bounding_box.min_corner().x() + bounding_box.max_corner().x()) / 2);
    bool contentions = false;

    srand(1);

    for (unsigned int i = 0; i < vectorial_surface->size(); i++)
    {
        const unsigned int r = rand() % 256;
        const unsigned int g = rand() % 256;
        const unsigned int b = rand() % 256;

        unique_ptr<vector<polygon_type> > polygons;
    
        polygons = offset_polygon(*vectorial_surface, voronoi, toolpath, contentions,
                                  grow, i, extra_passes + 1, do_voronoi);

        debug_image.add(*polygons, 0.6, r, g, b);
        traced_debug_image.add(*polygons, 1, r, g, b);
    }

    srand(1);
    debug_image.add(*vectorial_surface, 1, true);

    if (contentions)
    {
        cerr << "\nWarning: pcb2gcode hasn't been able to fulfill all"
             << " clearance requirements and tried a best effort approach"
             << " instead. You may want to check the g-code output and"
             << " possibly use a smaller milling width.\n";
    }

    if (mill->eulerian_paths) {
        toolpath = eulerian_paths(toolpath);
    }
    if (tsp_2opt) {
        tsp_solver::tsp_2opt( toolpath, point_type(0, 0) );
    } else {
        tsp_solver::nearest_neighbour( toolpath, point_type(0, 0) );
    }
    auto scaled_toolpath = scale_and_mirror_toolpath(toolpath, mirror, mirror_axis);
    if (mill->optimise)
    {
        for (const shared_ptr<icoords>& ring : scaled_toolpath)
        {
            toolpath_optimised.push_back(make_shared<icoords>());
            bg::simplify(*ring, *(toolpath_optimised.back()), mill->tolerance);
        }

        return toolpath_optimised;
    }
    else
        return scaled_toolpath;
}