mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 08:25:56 +08:00
First impl of the freecad script integration
with my own lib to allow easier scripting.
This commit is contained in:
parent
0a8be978d9
commit
b78a91bb06
3
resources/generation/freecad/Pyscad/Init.py
Normal file
3
resources/generation/freecad/Pyscad/Init.py
Normal file
@ -0,0 +1,3 @@
|
||||
# FreeCAD init script of the pyscad module
|
||||
|
||||
# print("Init from ", __name__)
|
136
resources/generation/freecad/Pyscad/README.md
Normal file
136
resources/generation/freecad/Pyscad/README.md
Normal file
@ -0,0 +1,136 @@
|
||||
|
||||
# FreePySCAD
|
||||
You like OpenSCAD but you hate it at the same time?
|
||||
You can't work in FreeCAD because don't like wasting your time moving the mouse and clicking?
|
||||
FreePySCAD is for you!
|
||||
|
||||
note: it's in an alpha stage right now. You can use it but some things may not work as advertised. Tested against 0.17.
|
||||
## How it work
|
||||
FreePySCAD is a python library for FreeCAD to let user write their code in a text editor and see the result after a "compilation" process, like OpenSCAD but in FreeCAD.
|
||||
To install the library, clone the github repository into the "FreeCAD X.xx/mod" directory
|
||||
To write your code, you can open the FreeCAD macro editor and beginning your macro with "from FreePySCAD.FreePySCAD import *"
|
||||
You can also type in the python console "execfile('path_to/my_pycad.py')", this has the advantage to show the errors.
|
||||
The geometry passed inside the scene().redraw(...) function will be added inside the current document, replacing everything.
|
||||
## what's different
|
||||
The braces are replaced with parenthesis
|
||||
The ';' are replaced with ',' and you also have to place it after ')' if no other ')' are directly after that to respect the python syntax.
|
||||
You can't let the modifiers like translate, rotate... be unattached: use the parenthesis or a dot (see below)
|
||||
|
||||
OpenSCAD: difference(){ translate([1,1,0]) cube(2); rotate([0,0,45]) cube(2); }
|
||||
FreePySCAD: difference()( translate([1,1,0]).cube(2), rotate([0,0,45])(cube(2)),)
|
||||
resize, minkowski and hull aren't implemented.
|
||||
|
||||
You can also wrote a more concise code with FreePySCAD if you want (i was tired of writing "translate([ ])" over an over)
|
||||
|
||||
cut()( move(1,1).cube(2), cube(2).rotate(0,0,60) , rotate(z=30)(cube(2)) )
|
||||
|
||||
You can now use functions with real variables that can be changed!
|
||||
Here is a working ugly example:
|
||||
|
||||
from Pyscad.pyscad import *
|
||||
def make_T(l,h):
|
||||
big = cube(l,w,h)
|
||||
l = l/3.0
|
||||
h = 2.0*h/3.0
|
||||
return cut("T")(
|
||||
big,
|
||||
cube(l,w,h),
|
||||
cube(l,w,h).move(l*2),
|
||||
)
|
||||
w=10
|
||||
T_10cube = make_T(10,10)
|
||||
w=3
|
||||
T_3cube = make_T(10,10)
|
||||
scene().redraw(
|
||||
T_10cube,
|
||||
T_3cube.move(12),
|
||||
)
|
||||
You also have to pass your objects inside the scene.redraw() function to put it into the FreeCAD environment.
|
||||
You can see and execute some complex exemples in the exemple directory
|
||||
## FreePySCAD cheatsheet:
|
||||
|
||||
#### 1D:
|
||||
* line([x1,y1,z1],[x2,y2,z2])
|
||||
* arc([x1,y1,z1],[x2,y2,z2],[x3,y3,z3])
|
||||
* helix(r,p,h) # p = pitch = height between the begin and the end of a single loop
|
||||
|
||||
#### 1D | 2D:
|
||||
* circle(r)
|
||||
* ellipse(r,l)
|
||||
* polygon([points],closed)
|
||||
* bspline([points],closed)
|
||||
* bezier([points],closed)
|
||||
|
||||
#### 2D:
|
||||
* square(size)
|
||||
* square([width,height]) | square(width,height) | rectangle([width,height])
|
||||
* poly_reg(r|d,nb,inscr)
|
||||
* text(text,size)
|
||||
* gear(nb, mod, angle, external, high_precision)
|
||||
|
||||
|
||||
#### transformation 1D to 2D to 3D:
|
||||
* create_wire(closed)(...1D) #create a new wire from many edges, can be extruded if they are connected, you can check that by putting closed to True
|
||||
* offset2D(length,fillet,fusion)(...2D)
|
||||
* linear_extrude(height,twist,taper)(obj_2D)
|
||||
* extrude(x,y,z,taper)(obj_2D)
|
||||
* rotate_extrude(angle)(obj_2D) #rotate over the Z axis
|
||||
* path_extrude(frenet,transition)(path_1D, patron_2D)
|
||||
|
||||
note: most of these transformations can only work on a single object, as these can't be unionized before.
|
||||
|
||||
#### 3D:
|
||||
* sphere(r|d,fn)
|
||||
* cube(size)
|
||||
* cube(x,y,z) | cube([width,depth,height]) | box(x,y,z)
|
||||
* triangle(x,y,z) | triangle([width,depth,height])
|
||||
* cylinder(r|d,h,fn,angle) #will call poly_ext if fn >0
|
||||
* cone(r1|d1,r2|d2,h,fn) | cylinder(r1|d1,r2|d2,h,fn)
|
||||
* torus(r1,r2,h)
|
||||
* poly_ext(r,nb,h) # r = radius, nb = nb vertex (min 3)
|
||||
* poly_int(a,nb,h) # a = apothem, nb = nb vertex (min 3)
|
||||
* polyhedron(points, faces) # for debugging use polyhedron_wip : it creates a group of points & faces instead of a 3D solid mesh
|
||||
* solid_slices(points, centers) #new way to create not-so complicated shells, see below. centers are optional. Much simpler than polyhedron. May not work with not-convex shapes.
|
||||
* thread(r,p,nb,r2, pattern,fn,center) # implementation of a way to create threads, with pattern (2D array of points). It creates a new 3D object from triangles (vertexes & faces).
|
||||
* iso_thread(d,p,h,internal,offset,fn) # usage of thread method with an iso pattern.
|
||||
|
||||
#### 3D Boolean operations:
|
||||
* union()(...3D) | union().add(...3D) # can work with 2D
|
||||
* intersection()(...3D)
|
||||
* difference()(...3D) | cut()(...3D)
|
||||
|
||||
#### Transformations:
|
||||
* mirror(x,y,z)(...) | mirror([x,y,z])(...)
|
||||
* offset(length,fillet,fusion)(...3D)
|
||||
|
||||
wip, don't work, use the gui for now:
|
||||
* chamfer().setEdges(radius,edge_id...)(...3D)
|
||||
* fillet().setEdges(radius,edge_id...)(...3D)
|
||||
|
||||
#### Modifiers:
|
||||
* .x/y/z() | .center()
|
||||
* translate/move(x,y,z)(...) | move([x,y,z])(...) | .move(x,y,z) | .move([x,y,z]) | move(x,y,z).stdfuncXXX(
|
||||
* rotate(x,y,z)(...) | rotate([x,y,z])(...) | .rotate(x,y,z) | .rotate([x,y,z]) | rotate(x,y,z).stdfuncXXX(
|
||||
* scale(x,y,z)(...) | scale([x,y,z])(...) | .scale(x,y,z) | .scale([x,y,z]) | scale(x,y,z).stdfuncXXX(
|
||||
* .color("colorname") | .color(r,g,b,a) | .color([r,g,b,a]) | color(something)(...) | color(something).stdfuncXXX(
|
||||
* .multmatrix(m)
|
||||
|
||||
#### Other:
|
||||
* scene().draw(...3D) | scene().redraw(...3D) #redraw() erase everything in the document before rebuilding the object tree. Draw() try to update when possible and don't erase everything, but sometimes it fail to detect a change.
|
||||
* importSvg(filepath,ids) #ids is an optional array of index to say which one have to be imported
|
||||
* importStl(filepath,ids)
|
||||
* group()(...) # a group of nodes (1D, 2D & 3D can be mixed), for viewing purpose only as it can't be used by anything, although you can use the modifiers.
|
||||
|
||||
All python syntax and standard library can be used
|
||||
|
||||
### notes:
|
||||
* ...3D represent a list (possibly empty) of 3D node
|
||||
* You can replace )(...) by ).add(...) for union, difference and
|
||||
* Center: on almost every object, you can set as parameter, center=True or center=center_x, center=center_yz, ...
|
||||
you can also use the transformation .center() or .x(), .yz(), .xyz() ....
|
||||
* Label: on almost everything, you can set the "name" parameter to whatever you want, it will be shown in the FreeCAD object hierarchy.
|
||||
* The notation move(2).box(1) should be used only when it's very convenient, it's here mainly to make conversion from OpenSCAD to FreePySCAD more easy, but it can led to strange behaviors, see the two points below.
|
||||
* Order of execution: move(6)(move(3).move(2).cube(1).move(4).move(5)) => it begin at the object then move away from it.
|
||||
* The move(2).box(1) work but you cannot do move(1).myfunc() because myfunc isn't in the list of functions that is available to the "move object". In this case, you have to use move(1)(myfunc()) or myfunc().move(1)
|
||||
* When a part fail to compile, it creates a sphere of size _default_size. you can change the variable _default_size, it's used as a default value when 0.0 will create an impossible object. Example: circle() == circle(_default_size).
|
||||
* solid_slices : need a double-array of points. Each array of points is a slice. It creates triangles to join one slice to the next. The last point of each slice have to be approximately aligned ( = don't put them 180° apart), because it's used as the first edge. The middle point (mean of all points if not given via the centers argument) is used to choose the next point to draw triangle and for closing the shell at the bottom layer and top layer. The line from the center of a slice to the center of the next one must be inside the slice and the next slice.
|
33
resources/generation/freecad/Pyscad/__init__.py
Normal file
33
resources/generation/freecad/Pyscad/__init__.py
Normal file
@ -0,0 +1,33 @@
|
||||
# ***************************************************************************
|
||||
# * *
|
||||
# * Copyright (c) 2016 - Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
|
||||
# * *
|
||||
# * This program is free software; you can redistribute it and/or modify *
|
||||
# * it under the terms of the GNU Lesser General Public License (LGPL) *
|
||||
# * as published by the Free Software Foundation; either version 2 of *
|
||||
# * the License, or (at your option) any later version. *
|
||||
# * for detail see the LICENCE text file. *
|
||||
# * *
|
||||
# * This program is distributed in the hope that it will be useful, *
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
# * GNU Library General Public License for more details. *
|
||||
# * *
|
||||
# * You should have received a copy of the GNU Library General Public *
|
||||
# * License along with this program; if not, write to the Free Software *
|
||||
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
|
||||
# * USA *
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "Pyscad"
|
||||
__author__ = "supermerill"
|
||||
__url__ = "http://www.freecadweb.org"
|
||||
__doc__ = "Dafuk"
|
||||
|
||||
## @package CompoundTools
|
||||
# \ingroup PART
|
||||
# \brief CompoundTools Package for Part workbench
|
||||
|
||||
# import pyscad
|
||||
|
2240
resources/generation/freecad/Pyscad/pyscad.py
Normal file
2240
resources/generation/freecad/Pyscad/pyscad.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -10,7 +10,7 @@ add_executable(opencsg_example WIN32
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../src/slic3r/GUI/I18N.cpp)
|
||||
|
||||
find_package(wxWidgets 3.1 REQUIRED COMPONENTS core base gl html)
|
||||
find_package(wxWidgets 3.1 REQUIRED COMPONENTS core base gl html stc scintilla aui)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GLEW REQUIRED)
|
||||
find_package(OpenCSG REQUIRED)
|
||||
|
@ -40,9 +40,9 @@ if (SLIC3R_GUI)
|
||||
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set (wxWidgets_CONFIG_OPTIONS "--toolkit=gtk${SLIC3R_GTK}")
|
||||
if (SLIC3R_WX_STABLE)
|
||||
find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl)
|
||||
find_package(wxWidgets 3.0 REQUIRED COMPONENTS base core adv html gl stc scintilla aui)
|
||||
else ()
|
||||
find_package(wxWidgets 3.1 QUIET COMPONENTS base core adv html gl)
|
||||
find_package(wxWidgets 3.1 QUIET COMPONENTS base core adv html gl stc scintilla aui)
|
||||
|
||||
if (NOT wxWidgets_FOUND)
|
||||
message(FATAL_ERROR "\nCould not find wxWidgets 3.1.\n"
|
||||
@ -50,7 +50,7 @@ if (SLIC3R_GUI)
|
||||
endif ()
|
||||
endif ()
|
||||
else ()
|
||||
find_package(wxWidgets 3.1 REQUIRED COMPONENTS html adv gl core base)
|
||||
find_package(wxWidgets 3.1 REQUIRED COMPONENTS html adv gl core base stc scintilla aui)
|
||||
endif ()
|
||||
|
||||
if(UNIX)
|
||||
|
@ -36,6 +36,8 @@ set(SLIC3R_GUI_SOURCES
|
||||
GUI/ConfigSnapshotDialog.hpp
|
||||
GUI/3DScene.cpp
|
||||
GUI/3DScene.hpp
|
||||
GUI/FreeCADDialog.cpp
|
||||
GUI/FreeCADDialog.hpp
|
||||
GUI/GLShader.cpp
|
||||
GUI/GLShader.hpp
|
||||
GUI/GLCanvas3D.hpp
|
||||
|
@ -56,6 +56,9 @@ void AppConfig::set_defaults()
|
||||
if (get("show_incompatible_presets").empty())
|
||||
set("show_incompatible_presets", "0");
|
||||
|
||||
if (get("freecad_path").empty())
|
||||
set("freecad_path", ".");
|
||||
|
||||
if (get("version_check").empty())
|
||||
set("version_check", "1");
|
||||
if (get("preset_update").empty())
|
||||
|
@ -66,6 +66,7 @@ void CalibrationAbstractDialog::create(std::string html_path, wxSize dialog_size
|
||||
}
|
||||
|
||||
void CalibrationAbstractDialog::closeMe(wxCommandEvent& event_args) {
|
||||
this->gui_app->change_calibration_dialog(this, nullptr);
|
||||
this->Destroy();
|
||||
}
|
||||
|
||||
|
305
src/slic3r/GUI/FreeCADDialog.cpp
Normal file
305
src/slic3r/GUI/FreeCADDialog.cpp
Normal file
@ -0,0 +1,305 @@
|
||||
#include "FreeCADDialog.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "AppConfig.hpp"
|
||||
#include "Tab.hpp"
|
||||
#include <wx/scrolwin.h>
|
||||
#include <wx/display.h>
|
||||
#include <wx/file.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include "wxExtensions.hpp"
|
||||
#include <iostream>
|
||||
|
||||
//C++11
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/iostreams/device/file_descriptor.hpp>
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <boost/iostreams/tee.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
|
||||
#if ENABLE_SCROLLABLE
|
||||
static wxSize get_screen_size(wxWindow* window)
|
||||
{
|
||||
const auto idx = wxDisplay::GetFromWindow(window);
|
||||
wxDisplay display(idx != wxNOT_FOUND ? idx : 0u);
|
||||
return display.GetClientArea().GetSize();
|
||||
}
|
||||
#endif // ENABLE_SCROLLABLE
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
std::string create_help_text() {
|
||||
std::stringstream ss;
|
||||
|
||||
ss << " == common 3D primitives ==\n";
|
||||
ss << "cube(x,y,z)\n";
|
||||
ss << "cylinder(r|d,h)\n";
|
||||
ss << "poly_int(a,nb)\n";
|
||||
ss << "poly_ext(r,nb)\n";
|
||||
ss << "cone(r1|d2,r2|d2,h)\n";
|
||||
ss << "iso_thread(d,p,h,internal,offset)\n";
|
||||
ss << "solid_slices(array_points, centers)\n";
|
||||
ss << "importStl(filepath)\n";
|
||||
ss << " == common 3D operation ==\n";
|
||||
ss << "cut()(...3D)\n";
|
||||
ss << "union()(...3D)\n";
|
||||
ss << "intersection()(...3D)\n";
|
||||
ss << " == common object modifier ==\n";
|
||||
ss << ".x/y/z() | .center()\n";
|
||||
ss << ".move(x,y,z)\n";
|
||||
ss << ".rotate(x,y,z)\n";
|
||||
ss << " == common 1D primitives ==\n";
|
||||
ss << "line([x1,y1,z1],[x2,y2,z2])\n";
|
||||
ss << "arc([x1,y1,z1],[x2,y2,z2],[x3,y3,z3])\n";
|
||||
ss << " == common 1D or 2D primitives ==\n";
|
||||
ss << "circle(r)\n";
|
||||
ss << "polygon([points],closed)\n";
|
||||
ss << "bezier([points],closed)\n";
|
||||
ss << "create_wire(closed)(...1D)\n";
|
||||
ss << " == common 2D primitives ==\n";
|
||||
ss << "square(width,height)\n";
|
||||
ss << "text(text,size)\n";
|
||||
ss << "gear(nb, mod, angle, isext, hprec)\n";
|
||||
ss << " === 2D to 3D (single object) ===\n";
|
||||
ss << "linear_extrude(height,twist,taper)(obj_2D)\n";
|
||||
ss << "extrude(x,y,z,taper)(obj_2D)\n";
|
||||
ss << "rotate_extrude(angle)(obj_2D)\n";
|
||||
ss << "path_extrude(frenet,transition)(path_1D, patron_2D)\n";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
FreeCADDialog::FreeCADDialog(GUI_App* app, MainFrame* mainframe)
|
||||
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("FreeCAD script engine")),
|
||||
#if ENABLE_SCROLLABLE
|
||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
#else
|
||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
|
||||
#endif // ENABLE_SCROLLABLE
|
||||
{
|
||||
|
||||
this->gui_app = app;
|
||||
this->main_frame = mainframe;
|
||||
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
|
||||
// fonts
|
||||
const wxFont& font = wxGetApp().normal_font();
|
||||
const wxFont& bold_font = wxGetApp().bold_font();
|
||||
SetFont(font);
|
||||
|
||||
|
||||
auto main_sizer = new wxGridBagSizer(5,5); //(int rows, int cols, int vgap, int hgap)
|
||||
|
||||
//main view
|
||||
createSTC();
|
||||
|
||||
m_errors = new wxTextCtrl(this, wxID_ANY, "",
|
||||
wxDefaultPosition, wxSize(600, 100), wxHW_SCROLLBAR_AUTO | wxTE_MULTILINE);
|
||||
m_errors->SetEditable(false);
|
||||
|
||||
m_help = new wxTextCtrl(this, wxID_ANY, create_help_text(),
|
||||
wxDefaultPosition, wxSize(200, 500), wxTE_MULTILINE);
|
||||
m_help->SetEditable(false);
|
||||
|
||||
//wxSizerItem* Add(wxSizer * sizer, const wxGBPosition & pos, const wxGBSpan & span = wxDefaultSpan, int flag = 0, int border = 0, wxObject * userData = NULL)
|
||||
//wxSizerItem* Add(wxSizer * sizer, int proportion = 0, int flag = 0, int border = 0, wxObject * userData = NULL)
|
||||
main_sizer->Add(m_text, wxGBPosition(1,1), wxGBSpan(1,1), wxEXPAND | wxALL, 5);
|
||||
main_sizer->Add(m_help, wxGBPosition(1, 2), wxGBSpan(2, 1), wxEXPAND | wxVERTICAL, 5);
|
||||
main_sizer->Add(m_errors, wxGBPosition(2, 1), wxGBSpan(1, 1), 0, 5);
|
||||
/*main_sizer->Add(m_text, 1, wxEXPAND | wxALL, 5);
|
||||
main_sizer->Add(m_errors, 1, wxALL, 5);
|
||||
main_sizer->Add(m_help, 1, wxALL, 5);*/
|
||||
|
||||
wxStdDialogButtonSizer* buttons = new wxStdDialogButtonSizer();
|
||||
|
||||
wxButton* bt = new wxButton(this, wxID_FILE1, _(L("Generate")));
|
||||
bt->Bind(wxEVT_BUTTON, &FreeCADDialog::create_geometry, this);
|
||||
buttons->Add(bt);
|
||||
|
||||
wxButton* close = new wxButton(this, wxID_CLOSE, _(L("Close")));
|
||||
close->Bind(wxEVT_BUTTON, &FreeCADDialog::closeMe, this);
|
||||
buttons->AddButton(close);
|
||||
close->SetDefault();
|
||||
close->SetFocus();
|
||||
SetAffirmativeId(wxID_CLOSE);
|
||||
buttons->Realize();
|
||||
main_sizer->Add(buttons, wxGBPosition(3, 1), wxGBSpan(1, 2), wxEXPAND | wxALL, 5);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
main_sizer->SetSizeHints(this);
|
||||
|
||||
}
|
||||
|
||||
void FreeCADDialog::closeMe(wxCommandEvent& event_args) {
|
||||
this->gui_app->change_calibration_dialog(this, nullptr);
|
||||
this->Destroy();
|
||||
}
|
||||
|
||||
|
||||
void FreeCADDialog::createSTC()
|
||||
{
|
||||
m_text = new wxStyledTextCtrl(this, wxID_ANY,
|
||||
wxDefaultPosition, wxSize(600,400), wxHW_SCROLLBAR_AUTO);
|
||||
|
||||
//m_text->SetMarginWidth(MARGIN_LINE_NUMBERS, 50);
|
||||
m_text->StyleSetForeground(wxSTC_STYLE_LINENUMBER, wxColour(75, 75, 75));
|
||||
m_text->StyleSetBackground(wxSTC_STYLE_LINENUMBER, wxColour(220, 220, 220));
|
||||
//m_text->SetMarginType(MARGIN_LINE_NUMBERS, wxSTC_MARGIN_NUMBER);
|
||||
|
||||
m_text->SetWrapMode(wxSTC_WRAP_WORD);
|
||||
|
||||
m_text->StyleClearAll();
|
||||
m_text->SetLexer(wxSTC_LEX_PYTHON);
|
||||
/*
|
||||
|
||||
|
||||
#define wxSTC_P_DEFAULT 0
|
||||
#define wxSTC_P_COMMENTLINE 1
|
||||
#define wxSTC_P_NUMBER 2
|
||||
#define wxSTC_P_STRING 3
|
||||
#define wxSTC_P_CHARACTER 4
|
||||
#define wxSTC_P_WORD 5
|
||||
#define wxSTC_P_TRIPLE 6
|
||||
#define wxSTC_P_TRIPLEDOUBLE 7
|
||||
#define wxSTC_P_CLASSNAME 8
|
||||
#define wxSTC_P_DEFNAME 9
|
||||
#define wxSTC_P_OPERATOR 10
|
||||
#define wxSTC_P_IDENTIFIER 11
|
||||
#define wxSTC_P_COMMENTBLOCK 12
|
||||
#define wxSTC_P_STRINGEOL 13
|
||||
#define wxSTC_P_WORD2 14
|
||||
#define wxSTC_P_DECORATOR 15
|
||||
*/
|
||||
m_text->StyleSetForeground(wxSTC_P_DEFAULT, wxColour(255, 0, 0));
|
||||
m_text->StyleSetForeground(wxSTC_P_COMMENTLINE, wxColour(255, 0, 0));
|
||||
m_text->StyleSetForeground(wxSTC_P_NUMBER, wxColour(255, 0, 0));
|
||||
m_text->StyleSetForeground(wxSTC_P_STRING, wxColour(0, 150, 0));
|
||||
m_text->StyleSetForeground(wxSTC_H_TAGUNKNOWN, wxColour(0, 150, 0));
|
||||
m_text->StyleSetForeground(wxSTC_H_ATTRIBUTE, wxColour(0, 0, 150));
|
||||
m_text->StyleSetForeground(wxSTC_H_ATTRIBUTEUNKNOWN, wxColour(0, 0, 150));
|
||||
m_text->StyleSetForeground(wxSTC_H_COMMENT, wxColour(150, 150, 150));
|
||||
m_text->StyleSetForeground(wxSTC_P_DEFAULT, wxColour(128, 128, 128));
|
||||
m_text->StyleSetForeground(wxSTC_P_COMMENTLINE, wxColour(0, 128, 0));
|
||||
m_text->StyleSetForeground(wxSTC_P_NUMBER, wxColour(0, 128, 128));
|
||||
m_text->StyleSetForeground(wxSTC_P_STRING, wxColour(128, 0, 128));
|
||||
m_text->StyleSetItalic(wxSTC_P_STRING,true),
|
||||
m_text->StyleSetForeground(wxSTC_P_CHARACTER, wxColour(128, 0, 128));
|
||||
m_text->StyleSetItalic(wxSTC_P_CHARACTER, true),
|
||||
m_text->StyleSetForeground(wxSTC_P_WORD, wxColour(0, 0, 128));
|
||||
m_text->StyleSetBold(wxSTC_P_WORD, true),
|
||||
m_text->StyleSetForeground(wxSTC_P_TRIPLE, wxColour(128, 0, 0));
|
||||
m_text->StyleSetForeground(wxSTC_P_TRIPLEDOUBLE, wxColour(128, 0, 0));
|
||||
m_text->StyleSetForeground(wxSTC_P_CLASSNAME, wxColour(0, 0, 255));
|
||||
m_text->StyleSetBold(wxSTC_P_CLASSNAME, true),
|
||||
m_text->StyleSetForeground(wxSTC_P_DEFNAME, wxColour(0, 128, 128));
|
||||
m_text->StyleSetBold(wxSTC_P_DEFNAME, true),
|
||||
m_text->StyleSetForeground(wxSTC_P_OPERATOR, wxColour(0, 0, 0));
|
||||
m_text->StyleSetBold(wxSTC_P_OPERATOR, true),
|
||||
m_text->StyleSetForeground(wxSTC_P_IDENTIFIER, wxColour(128, 128, 128));
|
||||
m_text->StyleSetForeground(wxSTC_P_COMMENTBLOCK, wxColour(128, 128, 128));
|
||||
m_text->StyleSetForeground(wxSTC_P_STRINGEOL, wxColour(0, 0, 0));
|
||||
m_text->StyleSetBackground(wxSTC_P_STRINGEOL, wxColour(224, 192, 224));
|
||||
|
||||
}
|
||||
|
||||
void FreeCADDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||
{
|
||||
msw_buttons_rescale(this, em_unit(), { wxID_OK });
|
||||
|
||||
Layout();
|
||||
Fit();
|
||||
Refresh();
|
||||
}
|
||||
void FreeCADDialog::create_geometry(wxCommandEvent& event_args) {
|
||||
//Create the script
|
||||
|
||||
std::string program = "C:/Program Files/FreeCAD 0.18/bin/python.exe";
|
||||
|
||||
// cleaning
|
||||
boost::filesystem::path object_path(Slic3r::resources_dir());
|
||||
object_path = object_path / "generation" / "freecad" / "temp.amf";
|
||||
m_errors->Clear();
|
||||
if (exists(object_path)) {
|
||||
remove(object_path);
|
||||
}
|
||||
|
||||
//create synchronous pipe streams
|
||||
boost::process::opstream pyin;
|
||||
//boost::process::ipstream pyout;
|
||||
//boost::process::ipstream pyerr;
|
||||
|
||||
boost::asio::io_service ios;
|
||||
std::future<std::string> dataOut;
|
||||
std::future<std::string> dataErr;
|
||||
|
||||
boost::filesystem::path pythonpath(gui_app->app_config->get("freecad_path"));
|
||||
pythonpath = pythonpath / "python.exe";
|
||||
if (!exists(pythonpath)) {
|
||||
m_errors->AppendText("Error, cannot find the freecad python at '"+ pythonpath.string()+"', please update your freecad bin directory in the preferences.");
|
||||
return;
|
||||
}
|
||||
boost::filesystem::path pyscad_path(Slic3r::resources_dir());
|
||||
pyscad_path = pyscad_path / "generation" / "freecad";
|
||||
|
||||
boost::process::child c(pythonpath.string() +" -u -i", boost::process::std_in < pyin, boost::process::std_out > dataOut, boost::process::std_err > dataErr, ios);
|
||||
pyin << "import FreeCAD" << std::endl;
|
||||
pyin << "import Part" << std::endl;
|
||||
pyin << "import Draft" << std::endl;
|
||||
pyin << "import sys" << std::endl;
|
||||
pyin << "sys.path.append('"<< pyscad_path.generic_string() <<"')"<<std::endl;
|
||||
pyin << "from Pyscad.pyscad import *" << std::endl;
|
||||
pyin << "App.newDocument(\"document\")" << std::endl;
|
||||
pyin << "scene().redraw("<< m_text->GetText() <<")" << std::endl;
|
||||
pyin << "Mesh.export(App.ActiveDocument.RootObjects, u\"" << object_path.generic_string() << "\")" << std::endl;
|
||||
pyin << "print('exported!')" << std::endl;
|
||||
pyin << "quit()" << std::endl;
|
||||
c.wait();
|
||||
ios.run();
|
||||
std::cout << "exit with code " << c.exit_code() << "\n";
|
||||
|
||||
std::string pyout_str_hello;
|
||||
std::cout << "==cout==\n";
|
||||
std::cout << dataOut.get();
|
||||
std::cout << "==cerr==\n";
|
||||
std::string errStr = dataErr.get();
|
||||
std::cout << errStr << "\n";
|
||||
std::string cleaned = boost::replace_all_copy(boost::replace_all_copy(errStr, ">>> ", ""),"\r","");
|
||||
m_errors->AppendText(cleaned);
|
||||
std::cout << std::count(cleaned.begin(), cleaned.end(), '\n') << "\n";
|
||||
std::cout << std::count(cleaned.begin(), cleaned.end(), '\r') << "\n";
|
||||
|
||||
if (!exists(object_path)) {
|
||||
m_errors->AppendText("\nError, no object generated.");
|
||||
return;
|
||||
}
|
||||
|
||||
Plater* plat = this->main_frame->plater();
|
||||
Model& model = plat->model();
|
||||
plat->reset();
|
||||
std::vector<size_t> objs_idx = plat->load_files(std::vector<std::string>{ object_path.generic_string() }, true, false);
|
||||
if (objs_idx.empty()) return;
|
||||
/// --- translate ---
|
||||
const DynamicPrintConfig* printerConfig = this->gui_app->get_tab(Preset::TYPE_PRINTER)->get_config();
|
||||
const ConfigOptionPoints* bed_shape = printerConfig->option<ConfigOptionPoints>("bed_shape");
|
||||
Vec2d bed_size = BoundingBoxf(bed_shape->values).size();
|
||||
Vec2d bed_min = BoundingBoxf(bed_shape->values).min;
|
||||
model.objects[objs_idx[0]]->translate({ bed_min.x() + bed_size.x() / 2, bed_min.y() + bed_size.y() / 2, 0 });
|
||||
|
||||
//update plater
|
||||
plat->changed_objects(objs_idx);
|
||||
//update everything, easier to code.
|
||||
ObjectList* obj = this->gui_app->obj_list();
|
||||
obj->update_after_undo_redo();
|
||||
|
||||
|
||||
//plat->reslice();
|
||||
plat->select_view_3D("3D");
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
42
src/slic3r/GUI/FreeCADDialog.hpp
Normal file
42
src/slic3r/GUI/FreeCADDialog.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef slic3r_GUI_FreeCADDialog_hpp_
|
||||
#define slic3r_GUI_FreeCADDialog_hpp_
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include <wx/wx.h>
|
||||
#include <wx/stc/stc.h>
|
||||
#include <wx/html/htmlwin.h>
|
||||
#include <wx/textctrl.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class FreeCADDialog : public DPIDialog
|
||||
{
|
||||
|
||||
public:
|
||||
FreeCADDialog(GUI_App* app, MainFrame* mainframe);
|
||||
virtual ~FreeCADDialog() { }
|
||||
|
||||
protected:
|
||||
void closeMe(wxCommandEvent& event_args);
|
||||
void createSTC();
|
||||
void create_geometry(wxCommandEvent& event_args);
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
|
||||
wxStyledTextCtrl* m_text;
|
||||
wxTextCtrl* m_errors;
|
||||
wxTextCtrl* m_help;
|
||||
MainFrame* main_frame;
|
||||
GUI_App* gui_app;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif
|
@ -47,6 +47,7 @@
|
||||
#include "CalibrationOverBridgeDialog.hpp"
|
||||
#include "CalibrationTempDialog.hpp"
|
||||
#include "ConfigSnapshotDialog.hpp"
|
||||
#include "FreeCADDialog.hpp"
|
||||
#include "FirmwareDialog.hpp"
|
||||
#include "Preferences.hpp"
|
||||
#include "Tab.hpp"
|
||||
@ -597,6 +598,10 @@ void GUI_App::calibration_cube_dialog()
|
||||
{
|
||||
change_calibration_dialog(nullptr, new CalibrationCubeDialog(this, mainframe));
|
||||
}
|
||||
void GUI_App::freecad_script_dialog()
|
||||
{
|
||||
change_calibration_dialog(nullptr, new FreeCADDialog(this, mainframe));
|
||||
}
|
||||
|
||||
// static method accepting a wxWindow object as first parameter
|
||||
bool GUI_App::catch_error(std::function<void()> cb,
|
||||
|
@ -138,6 +138,7 @@ public:
|
||||
void bridge_tuning_dialog();
|
||||
void over_bridge_dialog();
|
||||
void calibration_cube_dialog();
|
||||
void freecad_script_dialog();
|
||||
//void support_tuning(); //have to do multiple, in a submenu
|
||||
void load_project(wxWindow *parent, wxString& input_file) const;
|
||||
void import_model(wxWindow *parent, wxArrayString& input_files) const;
|
||||
|
@ -777,7 +777,14 @@ void MainFrame::init_menubar()
|
||||
[this](wxCommandEvent&) { wxGetApp().over_bridge_dialog(); });
|
||||
append_menu_item(objectsMenu, wxID_ANY, _(L("Calibration cube")), _(L("Print a calibration cube, for various calibration goals.")),
|
||||
[this](wxCommandEvent&) { wxGetApp().calibration_cube_dialog(); });
|
||||
|
||||
}
|
||||
|
||||
// objects menu
|
||||
auto generationMenu = new wxMenu();
|
||||
{
|
||||
append_menu_item(generationMenu, wxID_ANY, _(L("FreeCad python script")), _(L("Create an object by writing little easy script.")),
|
||||
[this](wxCommandEvent&) { wxGetApp().freecad_script_dialog(); });
|
||||
|
||||
}
|
||||
|
||||
// Help menu
|
||||
@ -831,6 +838,7 @@ void MainFrame::init_menubar()
|
||||
// Add additional menus from C++
|
||||
wxGetApp().add_config_menu(menubar);
|
||||
menubar->Append(objectsMenu, _(L("C&alibration")));
|
||||
menubar->Append(generationMenu, _(L("&Generate")));
|
||||
menubar->Append(helpMenu, _(L("&Help")));
|
||||
SetMenuBar(menubar);
|
||||
|
||||
|
@ -100,6 +100,19 @@ void PreferencesDialog::build()
|
||||
option = Option (def,"show_incompatible_presets");
|
||||
m_optgroup_general->append_single_option_line(option);
|
||||
|
||||
m_optgroup_paths = std::make_shared<ConfigOptionsGroup>(this, _(L("General")));
|
||||
m_optgroup_paths->title_width = 10;
|
||||
m_optgroup_paths->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||
m_values[opt_key] = boost::any_cast<std::string>(value);
|
||||
};
|
||||
def.label = L("FreeCAD path");
|
||||
def.type = coString;
|
||||
def.tooltip = L("If it pont to a valid freecad instance, you can use the built-in script to generate quickly things in a scripted python.");
|
||||
def.set_default_value(new ConfigOptionString{ app_config->get("freecad_path") });
|
||||
option = Option(def, "freecad_path");
|
||||
option.opt.full_width = true;
|
||||
m_optgroup_paths->append_single_option_line(option);
|
||||
|
||||
#if __APPLE__
|
||||
def.label = L("Use Retina resolution for the 3D scene");
|
||||
def.type = coBool;
|
||||
@ -152,7 +165,8 @@ void PreferencesDialog::build()
|
||||
|
||||
auto sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(m_optgroup_general->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
sizer->Add(m_optgroup_camera->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
sizer->Add(m_optgroup_paths->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
sizer->Add(m_optgroup_camera->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
sizer->Add(m_optgroup_gui->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10);
|
||||
|
||||
SetFont(wxGetApp().normal_font());
|
||||
|
@ -16,6 +16,7 @@ class PreferencesDialog : public DPIDialog
|
||||
{
|
||||
std::map<std::string, std::string> m_values;
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup_general;
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup_paths;
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup_camera;
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup_gui;
|
||||
wxSizer* m_icon_size_sizer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user