... | ... | @@ -81,7 +81,8 @@ public: |
|
|
IPlugin() = default;
|
|
|
virtual ~IPlugin() = default;
|
|
|
|
|
|
// Initializes all resources (e.g., hardware handles, file assets, ports, etc) the plugin will use.
|
|
|
// Initializes all resources (e.g., hardware handles, file assets, ports, etc) the plugin will use.
|
|
|
// Returns `true` if successful
|
|
|
virtual bool initialize(
|
|
|
// `env` encapsulates the environment variables on which IceSL operates.
|
|
|
// The class `IPluginEnvironment` is subject to change as the environment of IceSL changes.
|
... | ... | @@ -728,14 +729,30 @@ class MyInfillerPlugin : public IceSLInterface::IInfillerPlugin |
|
|
...
|
|
|
};
|
|
|
```
|
|
|
3. Derive from the appropriate interface class and implement its methods:
|
|
|
- The `initialize` function usually goes like this:
|
|
|
```c++
|
|
|
bool initialize(IceSLInterface::IPluginEnvironment& env) override
|
|
|
{
|
|
|
IInfillerPlugin::initialize(env); // Save the environment variables
|
|
|
ImGui::SetCurrentContext(env.getImGuiContext()); // Set ImGui context (enables UI calls)
|
|
|
gluxInit(); // Init OpenGL (enables OpenGL calls)
|
|
|
return true; // Success!
|
|
|
}
|
|
|
```
|
|
|
4. Derive from the appropriate interface class and implement its methods:
|
|
|
```c++
|
|
|
class MyInfillerInterface: public IceSLInterface::IInfillerInterface
|
|
|
{
|
|
|
...
|
|
|
};
|
|
|
```
|
|
|
|
|
|
- Given the class above, the `createInfiller` function from `IInfillerPlugin` becomes straightforward:
|
|
|
```c++
|
|
|
std::unique_ptr<IInfillerInterface> createInfiller () override
|
|
|
{
|
|
|
return std::unique_ptr<IInfillerInterface>(new MyInfillerInterface());
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### The Shared Library Interface <a name="sharedlibrary"></a>
|
|
|
|
... | ... | @@ -764,10 +781,139 @@ void destroyPlugin(IceSLInterface::IPlugin* plugin) |
|
|
|
|
|
### Plugin Examples <a name="examples"></a>
|
|
|
|
|
|
In this section we explain the sample plugins that are include in the interface repository. We do not include all code but rather point to the crucial parts together with some explanation.
|
|
|
Sample plugins for each stage are include in the interface repository. We explain them here, however we do not include all code but rather point to the crucial parts together with some clarification.
|
|
|
|
|
|
#### `SampleInfillerPlugin`
|
|
|
|
|
|
In this sample infiller plugin we attempt to create an infill pattern that densely fills the area with trajectories that are concentric to the area's perimeter.
|
|
|
|
|
|
```c++
|
|
|
bool SampleInfillerPlugin::addPluginSettings(IceSLInterface::EnumerableSettingsInterface& enumerable_settings)
|
|
|
{
|
|
|
// Resizes vector to store all per-brush values of the setting
|
|
|
m_LineWidth_mm.resize(enumerable_settings.getNumberOfBrushes(),0.4f);
|
|
|
// Adds a 'Line Width' setting per-brush for this infiller
|
|
|
for (int i = 0; i < (int)m_LineWidth_mm.size(); i++) {
|
|
|
std::unique_ptr<IceSLInterface::EnumerableSettingsInterface::SettingInterface> s =
|
|
|
enumerable_settings.addSettingFromPlugin(
|
|
|
&m_LineWidth_mm[i], // Value storage
|
|
|
&m_LineWidth_min_mm, // Minimum value
|
|
|
&m_LineWidth_max_mm, // Maximum value
|
|
|
// Setting's internal name appended with an 'i' index to differentiate each per-brush value
|
|
|
"line_width_mm_" + std::to_string(i),
|
|
|
"Line width (mm)", // UI Name
|
|
|
"Brush_" + std::to_string(i), // Setting belongs to "Brush N" group
|
|
|
// Setting's tooltip
|
|
|
"Specifies the line width to be used during contouring. The flow is adjusted accordingly.",
|
|
|
1000, // Rank. It's high so it appears last after IceSL's native settings
|
|
|
// Show setting only when the sample infiller is selected on the 'Infill type' drown-down list
|
|
|
[this, &enumerable_settings, i]() -> bool {
|
|
|
std::string infiller;
|
|
|
enumerable_settings.getSettingByName("infill_type_" + std::to_string(i))->getValue(infiller);
|
|
|
return infiller == this->name();
|
|
|
}
|
|
|
);
|
|
|
if (s == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
The code above adds a _Line Width_ setting for each possible brush used in the geometry. This width refers to the deposition width of the concentric trajectories of the infill, thus the thicker it is, the less concentric trajectories the infill creates.
|
|
|
|
|
|
```c++
|
|
|
bool SampleInfiller::generateInfill(
|
|
|
int id, float height_mm, double thickness_mm, int brush,
|
|
|
const ClipperLib::Paths& surface,
|
|
|
std::vector<std::unique_ptr<IceSLInterface::IPath> >& fills,
|
|
|
bool& preserve_order, ClipperLib::Paths& _fallback_surface)
|
|
|
{
|
|
|
|
|
|
// Get extruder used for the infill by this brush
|
|
|
int extruder_id = 0;
|
|
|
{
|
|
|
auto s = m_EnumerableSettings->getSettingByName("infill_extruder_" + std::to_string(brush));
|
|
|
if (s == nullptr) {
|
|
|
throw Fatal("This plugin is only for FDM");
|
|
|
}
|
|
|
s->getValue(extruder_id);
|
|
|
}
|
|
|
// Get extruder nozzle diameter
|
|
|
float nozzle_diameter = 0.0f;
|
|
|
{
|
|
|
auto s = m_EnumerableSettings->getSettingByName("nozzle_diameter_mm_" + std::to_string(extruder_id));
|
|
|
if (s == nullptr) {
|
|
|
throw Fatal("This plugin is only for FDM");
|
|
|
}
|
|
|
s->getValue(nozzle_diameter);
|
|
|
}
|
|
|
// Get processing (i.e., slicing) scale factor
|
|
|
float xy_mm_per_int = 0.0f;
|
|
|
{
|
|
|
auto s = m_EnumerableSettings->getSettingByName("xy_mm_per_int");
|
|
|
if (s == nullptr) {
|
|
|
throw Fatal("Missing setting");
|
|
|
}
|
|
|
s->getValue(xy_mm_per_int);
|
|
|
}
|
|
|
// Get line width (plugin's setting)
|
|
|
float line_width_mm = 0.0f;
|
|
|
{
|
|
|
auto s = m_EnumerableSettings->getSettingByName("line_width_mm_" + std::to_string(brush));
|
|
|
if (s == nullptr) {
|
|
|
throw Fatal("Missing setting");
|
|
|
}
|
|
|
s->getValue(line_width_mm);
|
|
|
}
|
|
|
// Set fill percentage
|
|
|
{
|
|
|
auto s = m_EnumerableSettings->getSettingByName("infill_percentage_" + std::to_string(brush));
|
|
|
if (s == nullptr) {
|
|
|
throw Fatal("Missing setting");
|
|
|
}
|
|
|
s->setValue(100.0f);
|
|
|
}
|
|
|
// Generate infill
|
|
|
float radius = line_width_mm / 2.0f;
|
|
|
ClipperLib::Paths current = surface;
|
|
|
while (true) {
|
|
|
// Create concentric trajectory
|
|
|
ClipperLib::ClipperOffset offseter;
|
|
|
offseter.AddPaths(current, ClipperLib::jtMiter, ClipperLib::EndType::etClosedPolygon);
|
|
|
ClipperLib::Paths contours;
|
|
|
offseter.Execute(contours, - radius / xy_mm_per_int); // divided by `xy_mm_per_int` to be in processing space
|
|
|
// Use line width as spacing
|
|
|
radius = line_width_mm;
|
|
|
// If there isn't more space for another concentric deposition path, stop
|
|
|
if (contours.empty()) {
|
|
|
break;
|
|
|
}
|
|
|
// Add infill trajectory to output vector
|
|
|
ClipperLib::CleanPolygons(contours);
|
|
|
for (const auto &cnt : contours) { // for all the contours that make up the concentric trajectory
|
|
|
if (cnt.size() > 0) { // some paths may be empty after ClipperLib::CleanPolygons, these have to be skipped
|
|
|
// insert contour as infill
|
|
|
fills.push_back(std::unique_ptr<IceSLInterface::IPath>(new IceSLInterface::Path()));
|
|
|
fills.back()->createPath(cnt, true);
|
|
|
fills.back()->setPathType(PathType::e_Infill);
|
|
|
// Set flow to be able to have the line width as the deposition width
|
|
|
int flow_idx = fills.back()->addPathAttribute("flow_multiplier");
|
|
|
fills.back()->setPathAttributeValue(flow_idx, line_width_mm / nozzle_diameter);
|
|
|
}
|
|
|
}
|
|
|
// next
|
|
|
current = contours;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Our `generateInfill` function queries the necessary printing settings and then loops for each concentric trajectory (created using the Clipper library) going inwards and creates the appropriate deposition paths. The loop stops when there's isn't more space for another concentric trajectory.
|
|
|
|
|
|
#### `SamplePostProcessingPlugin`
|
|
|
|
|
|
|
|
|
|
|
|
#### `SampleMachineCodePlugin` |
|
|
\ No newline at end of file |