OOFEM 3.0
Loading...
Searching...
No Matches
Printer.h
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <iostream>
5#include <map>
6#include <functional>
7#include <cmath>
8#include <queue>
9
10#include "GCodeCommand.h"
11#include "CSG.h"
12#include "VoxelGrid.h"
13
18 double distance_moved = 0;
19 double filament_extruded = 0;
20 double time = 0;
22};
23
31
41
51
57
58 std::array<double, 3> steps = { 1.0, 1.0, 1.0 };
59 std::array<int, 3> sizes = { 1000, 1000, 1000 };
60
62 double layerHeight = 0.2;
63 double extrusionWidth = 0.4 * 1.2;
64 double depositionTemperature = 235.;
65 double heatBedTemperature = 60.; /* heat bed temperature */
66 double chamberTemperature = 30.; /* air temperature in printer chamber*/
67 double heatTransferFilmCoefficient= 10.; /* film coefficient for heat transfer between deposited material and air*/
68 double depositedMaterialHeatPower = 4200000.0; /* power = specificHeat * density */
69
70 double filamentDiameter = 1.75;
71};
72
77{
78public:
79 // Define a type for the callback function
80 using CommandCallback = std::function<void( const GCodeCommand & )>;
81
86 {
88 voxelGrid = { { options.steps[0], options.steps[1], options.steps[2] }, { options.sizes[0], options.sizes[1], options.sizes[2] } };
90 layer_height = options.layerHeight;
92
94
100
102 }
103
109 {
110 return statistics;
111 }
112
118 void registerCallback( const std::string &commandCode, CommandCallback callback )
119 {
120 commandCallbacks[commandCode] = callback;
121 }
122
127 void addCommandToQueue( const GCodeCommand &command )
128 {
129 commandQueue.push_back( command );
130 }
131
136 {
137 if ( !commandQueue.empty() )
138 commandQueue.erase( commandQueue.begin() );
139 }
140
145 void processCommand( const GCodeCommand &command )
146 {
147 auto it = commandCallbacks.find( command.getCode() );
148 if ( it != commandCallbacks.end() ) {
149 // Execute the callback associated with the command code
150 this->statistics.nunber_of_commands++;
151 it->second( command );
152 } else {
153 // Handle unknown command
154 // std::cout << "Unknown command: " << command.getCode() << std::endl;
155 }
156 }
157
159 {
160 return voxelGrid;
161 }
162
171 std::array<double, 4> calculatePosition( std::array<double, 4> position,
172 const std::optional<double> &xValue,
173 const std::optional<double> &yValue,
174 const std::optional<double> &zValue )
175 {
176 // If relative position, move by delta
178 if ( xValue.has_value() )
179 position[0] += *xValue;
180 if ( yValue.has_value() )
181 position[1] += *yValue;
182 if ( zValue.has_value() )
183 position[2] += *zValue;
184 }
185 // If absolute position, move to the position
186 else {
187 if ( xValue.has_value() )
188 position[0] = *xValue;
189 if ( yValue.has_value() )
190 position[1] = *yValue;
191 if ( zValue.has_value() )
192 position[2] = *zValue;
193 }
194
195 return position;
196 }
197
204 std::array<double, 3>
205 calculateDirectorVector( const std::array<double, 4> &position_prev,
206 const std::array<double, 4> &position_next )
207 {
208 std::array<double, 3> director_vector = { position_next[0] - position_prev[0],
209 position_next[1] - position_prev[1],
210 position_next[2] - position_prev[2] };
211
212 // Normalize
213 double norm = std::sqrt( director_vector[0] * director_vector[0] + director_vector[1] * director_vector[1] + director_vector[2] * director_vector[2] );
214
215 if ( std::abs( norm ) > 1e-16 ) {
216 director_vector[0] /= norm;
217 director_vector[1] /= norm;
218 director_vector[2] /= norm;
219 }
220
221 return director_vector;
222 }
223
232 double calculateMoveTime( double distance, double vs, double v, double ve )
233 {
234 double time_acc = ( v - vs ) / max_acceleration[0];
235 double distance_acc = time_acc * ( v - vs ) / 60 / 2;
236
237 double time_decc = ( v - ve ) / max_acceleration[0];
238 double distance_decc = time_decc * ( v - ve ) / 60 / 2;
239
240 return time_acc + time_decc + ( distance - distance_acc - distance_decc ) / v;
241 }
242
243 const Model get_model( std::array<double, 4> start, std::array<double, 4> end, double h, double w )
244 {
245 std::array<double, 3> dir = { end[0] - start[0], end[1] - start[1], 0 };
246 std::array<double, 3> n = { -dir[1], dir[0], dir[2] };
247
248 // Normalize dir
249 double norm_dir = std::sqrt( dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2] );
250 dir[0] /= norm_dir;
251 dir[1] /= norm_dir;
252 dir[2] /= norm_dir;
253
254 // Normalize n
255 double norm = std::sqrt( n[0] * n[0] + n[1] * n[1] + n[2] * n[2] );
256 n[0] *= w / 2 / norm;
257 n[1] *= w / 2 / norm;
258 n[2] *= w / 2 / norm;
259
260 Vertex v1( { { start[0] + n[0], start[1] + n[1], start[2] + n[2] - h }, { -dir[0] + n[0], -dir[1] + n[1], -1 } } );
261 Vertex v2( { { end[0] + n[0], end[1] + n[1], end[2] + n[2] - h }, { dir[0] + n[0], dir[1] + n[1], -1 } } );
262 Vertex v3( { { end[0] - n[0], end[1] - n[1], end[2] - n[2] - h }, { dir[0] - n[0], dir[1] - n[1], -1 } } );
263 Vertex v4( { { start[0] - n[0], start[1] - n[1], start[2] - n[2] - h }, { -dir[0] - n[0], -dir[1] - n[1], -1 } } );
264
265 Vertex v5( { { start[0] + n[0], start[1] + n[1], start[2] + n[2] }, { -dir[0] + n[0], -dir[1] + n[1], 1 } } );
266 Vertex v6( { { end[0] + n[0], end[1] + n[1], end[2] + n[2] }, { dir[0] + n[0], dir[1] + n[1], 1 } } );
267 Vertex v7( { { end[0] - n[0], end[1] - n[1], end[2] - n[2] }, { dir[0] - n[0], dir[1] - n[1], 1 } } );
268 Vertex v8( { { start[0] - n[0], start[1] - n[1], start[2] - n[2] }, { -dir[0] - n[0], -dir[1] - n[1], 1 } } );
269
270 // Polygon p1({v4, v3, v2, v1}); // bottom
271 // Polygon p2({v5, v6, v7, v8}); // top
272 // Polygon p3({v4, v8, v7, v3}); // left
273 // Polygon p4({v1, v2, v6, v5}); // right
274 // Polygon p5({v4, v1, v5, v8}); // front
275 // Polygon p6({v2, v3, v7, v6}); // back
276
277 Polygon p1( { v1, v2, v3, v4 } ); // bottom
278 Polygon p2( { v8, v7, v6, v5 } ); // top
279 Polygon p3( { v3, v7, v8, v4 } ); // left
280 Polygon p4( { v5, v6, v2, v1 } ); // right
281 Polygon p5( { v8, v5, v1, v4 } ); // front
282 Polygon p6( { v6, v7, v3, v2 } ); // back
283
284 return modelfrompolygons( { p1, p2, p3, p4, p5, p6 } );
285 }
286
291 void handleG1Command( const GCodeCommand &command )
292 {
293
294 // Retrieve move
295 auto xValue = command.param_double( 'X' );
296 auto yValue = command.param_double( 'Y' );
297 auto zValue = command.param_double( 'Z' );
298 auto fValue = command.param_double( 'F' );
299
300
301 // Handle new desired feedrate
302 if ( fValue.has_value() ) {
303 feedrate = *fValue;
304 }
305
306
307 // Previous position
308 std::array<double, 4> prev_position = { position[0], position[1], position[2], position[3] };
309 position = calculatePosition( position, xValue, yValue, zValue );
310
311
312 // Calculate distance moved
313 double dx = position[0] - prev_position[0];
314 double dy = position[1] - prev_position[1];
315 double dz = position[2] - prev_position[2];
316 double distance = std::sqrt( dx * dx + dy * dy + dz * dz );
317 double dxy = std::sqrt( dx * dx + dy * dy );
318 statistics.distance_moved += distance;
319
320 std::array<double, 4> tmp_position = position;
321 double lim_feedrate = feedrate / 60;
322
323
324 // Look into command queue to calculate target velocity at the end of the current move
325 for ( size_t i = 0; i < commandQueue.size(); i++ ) {
326 auto newPosition = calculatePosition( tmp_position, commandQueue[i].param_double( 'X' ), commandQueue.front().param_double( 'Y' ), commandQueue.front().param_double( 'Z' ) );
327 auto dirVector = calculateDirectorVector( tmp_position, newPosition );
328
329 std::array<double, 3> jerk = { dirVector[0] * feedrate / 60,
330 dirVector[1] * feedrate / 60,
331 dirVector[2] * feedrate / 60 };
332
333 if ( jerk[0] > max_jerk[0] ) {
334 lim_feedrate = std::min( lim_feedrate, jerk[0] );
335 }
336
337 if ( jerk[1] > max_jerk[1] ) {
338 lim_feedrate = std::min( lim_feedrate, jerk[1] );
339 }
340
341 if ( jerk[2] > max_jerk[2] ) {
342 lim_feedrate = std::min( lim_feedrate, jerk[2] );
343 }
344
345 tmp_position = newPosition;
346
347 if ( commandQueue[i].getCode() == "G1" )
348 break;
349 }
350
351
352 // Calculate print time of the current move
353 double move_time = calculateMoveTime( distance, real_feedrate / 60, feedrate / 60, lim_feedrate );
354 statistics.time += move_time;
355
356 // Set real velocity at the end of the current move
357 real_feedrate = lim_feedrate * 60;
358
359
360 // Handle extrusion
361 auto eValue = command.param_double( 'E' );
362 if ( eValue.has_value() ) {
363
364 // If relative extruder positioning, extrude by delta
366 position[3] += *eValue;
367 } else // If absolute extruder positioning, extrude to the position
368 {
369 position[3] = *eValue;
370 }
371
372 // Calculate filament extruded
373 double de = position[3] - prev_position[3];
374 statistics.filament_extruded += de;
375
376 // Activate elements if printing
377 if ( dxy > 0 && de > 0 && dz == 0 ) {
378 // Activate grid elements
380#if 0
381 double r = filament_diameter / 2;
382 double w = M_PI * r * r * de / ( dxy * h );
383#else
384 double w = extrusion_width;
385#endif
386
387 Model move = get_model( prev_position, position, h, w );
388
389 auto pt = voxelGrid.get_indices_from_point( { prev_position[0], prev_position[1], prev_position[2] } );
390 auto pt2 = voxelGrid.get_indices_from_point( { position[0], position[1], position[2] - h } );
391 int top = std::get<2>( pt ) + 1;
392 int bot = std::get<2>( pt2 ) - 1;
393
394 int minx = std::min( std::get<0>( pt ), std::get<0>( pt2 ) ) - 1;
395 int maxx = std::max( std::get<0>( pt ), std::get<0>( pt2 ) ) + 1;
396 int miny = std::min( std::get<1>( pt ), std::get<1>( pt2 ) ) - 1;
397 int maxy = std::max( std::get<1>( pt ), std::get<1>( pt2 ) ) + 1;
398
399 // Volume of single voxel
400 double elvol = getGrid().get_model( 0 ).volume();
401
402 std::vector<int> indicesToCheck;
403
404 for ( int z = bot; z <= top; z++ ) {
405 for ( int x = minx; x <= maxx; x++ ) {
406 for ( int y = miny; y <= maxy; y++ ) {
407 indicesToCheck.push_back( voxelGrid.get_index( x, y, z ) );
408 }
409 }
410 }
411
412
413 std::vector<std::tuple<int, double, double> > intersected_indices;
414#ifdef _OPENMP
415#pragma omp parallel
416#endif
417 {
418 std::vector<std::tuple<int, double, double> > intersected_indices_local;
419#ifdef _OPENMP
420#pragma omp for nowait
421#endif
422 for ( size_t ix = 0; ix < indicesToCheck.size(); ix++ ) {
423 int i = indicesToCheck[ix];
424 Model voxModel = voxelGrid.get_model( i );
425 Model is = csgintersection( move, voxModel );
426
427 if ( is.volume() > 0.0 ) {
428 double vofFrac = is.volume() / elvol;
429 intersected_indices_local.push_back( std::make_tuple( i, statistics.time, vofFrac ) );
430 }
431 }
432#ifdef _OPENMP
433#pragma omp critical
434#endif
435 intersected_indices.insert( intersected_indices.end(), intersected_indices_local.begin(), intersected_indices_local.end() );
436 }
437
438 for ( const auto &v : intersected_indices ) {
439 voxelGrid.activate( std::get<0>( v ), std::get<1>( v ), std::get<2>( v ) );
440 }
441 }
442 }
443 //printf("[%d] G1: Ts=%.2f, Te=%.2f, dist=%.2f, h=%.2f, E=%.2f\n", this->statistics.nunber_of_commands, statistics.time-move_time, statistics.time, distance, prev_position[2], eValue.value_or(0.0));
444 }
445
454
459 {
461 }
462
463private:
465 {
466 registerCallback( "G1", std::bind( &Printer::handleG1Command, this, std::placeholders::_1 ) );
467 registerCallback( "M83", std::bind( &Printer::handleM83Command, this, std::placeholders::_1 ) );
468 }
469
470 VoxelGrid voxelGrid = { { 0.5, 0.5, 0.5 }, { 1000, 1000, 1000 } };
471
472 std::map<std::string, CommandCallback> commandCallbacks;
473 std::vector<GCodeCommand> commandQueue;
475
476 // Machine positioning
477 std::array<double, 4> position = { 0.0, 0.0, 0.0, 0.0 };
480
481 // Machine velocity
483 double feedrate = 1000.0;
484 double real_feedrate = 0.0;
485
486 // Machine limits
487 double max_acceleration[4] = { 500.0, 500.0, 100.0, 5000.0 };
488 double max_jerk[4] = { 8.0, 8.0, 0.4, 5.0 };
489
490 // Dimensions
492 double layer_height = 0.2;
493 double nozzle_diameter = 0.4;
494 double filament_diameter = 1.75;
495 double extrusion_multiplier = 1.0;
497public:
498 double depositionTemperature = 235.;
499 double heatBedTemperature = 60.; /* heat bed temperature */
500 double chamberTemperature = 30.; /* air temperature in printer chamber*/
501 double heatTransferFilmCoefficient= 10.; /* film coefficient for heat transfer between deposited material and air*/
502 double depositedMaterialHeatPower = 4200000.0; /* power = specificHeat * density */
503};
Model modelfrompolygons(const std::vector< Polygon > &polygons)
Definition CSG.h:924
Model csgintersection(const Model &a, const Model &b)
Definition CSG.h:1081
LayerHeightModel
The LayerHeight enum class represents the layer height of the printer. The layer height can be consta...
Definition Printer.h:46
ExtruderPositioning
The ExtruderPositioning enum class represents the positioning mode of the extruder.
Definition Printer.h:27
VelocityModel
The VelocityModel enum class represents the velocity model of the printer. Acceleration and decelerat...
Definition Printer.h:36
The GCodeCommand class represents a single G-code command.
std::optional< double > param_double(char paramLetter) const
Get the value of a parameter as a double.
std::string getCode() const
Get the G-code command.
void handleM83Command(const GCodeCommand &command)
Handle the M83 command to set the extruder positioning mode to relative.
Definition Printer.h:450
void processCommand(const GCodeCommand &command)
Process a G-code command.
Definition Printer.h:145
void registerCallbacks()
Definition Printer.h:464
double real_feedrate
Definition Printer.h:484
Printer()
Constructor to register default callbacks.
Definition Printer.h:458
VoxelGrid & getGrid()
Definition Printer.h:158
double nozzle_diameter
Definition Printer.h:493
double filament_diameter
Definition Printer.h:494
double extrusion_width
Definition Printer.h:496
PrintStatistics getStatistics() const
Get the printer statistics.
Definition Printer.h:108
double extrusion_multiplier
Definition Printer.h:495
double chamberTemperature
Definition Printer.h:500
VelocityModel velocity_model
Definition Printer.h:482
double max_jerk[4]
Definition Printer.h:488
double heatBedTemperature
Definition Printer.h:499
void handleG1Command(const GCodeCommand &command)
Handle the G1 command to manage printer positions.
Definition Printer.h:291
std::vector< GCodeCommand > commandQueue
Definition Printer.h:473
PrintStatistics statistics
Definition Printer.h:474
std::array< double, 3 > calculateDirectorVector(const std::array< double, 4 > &position_prev, const std::array< double, 4 > &position_next)
Calculate the director vector between two positions.
Definition Printer.h:205
double feedrate
Definition Printer.h:483
std::array< double, 4 > position
Definition Printer.h:477
double depositionTemperature
Definition Printer.h:498
LayerHeightModel layer_height_model
Definition Printer.h:491
double max_acceleration[4]
Definition Printer.h:487
double layer_height
Definition Printer.h:492
double heatTransferFilmCoefficient
Definition Printer.h:501
const Model get_model(std::array< double, 4 > start, std::array< double, 4 > end, double h, double w)
Definition Printer.h:243
void addCommandToQueue(const GCodeCommand &command)
Add a G-code command to the command queue.
Definition Printer.h:127
Printer(PrinterOptions options)
Constructor for Printer using PrinterOptions.
Definition Printer.h:85
std::array< double, 4 > calculatePosition(std::array< double, 4 > position, const std::optional< double > &xValue, const std::optional< double > &yValue, const std::optional< double > &zValue)
Calculate the new position of the printer based on the given values.
Definition Printer.h:171
ExtruderPositioning positioning
Definition Printer.h:478
void registerCallback(const std::string &commandCode, CommandCallback callback)
Register a callback function for a specific G-code command.
Definition Printer.h:118
ExtruderPositioning extruder_positioning
Definition Printer.h:479
double depositedMaterialHeatPower
Definition Printer.h:502
VoxelGrid voxelGrid
Definition Printer.h:470
double calculateMoveTime(double distance, double vs, double v, double ve)
Calculate the time taken to move a certain distance with given velocities.
Definition Printer.h:232
void popCommandFromQueue()
Remove the first G-code command from the command queue.
Definition Printer.h:135
std::function< void(const GCodeCommand &)> CommandCallback
Definition Printer.h:80
std::map< std::string, CommandCallback > commandCallbacks
Definition Printer.h:472
A class to represent a 3D grid of voxels.
Definition VoxelGrid.h:65
Model get_model(int index)
Get the triangulated model of a voxel at a given index.
Definition VoxelGrid.h:380
#define M_PI
Definition mathfem.h:52
Definition CSG.h:202
double volume() const
Definition CSG.h:223
Definition CSG.h:186
The PrintStatistics struct is used to track statistics of the printer.
Definition Printer.h:17
double distance_moved
Definition Printer.h:18
int nunber_of_commands
Definition Printer.h:21
double time
Definition Printer.h:20
double filament_extruded
Definition Printer.h:19
The PrinterOptions struct is used to configure the Printer class.
Definition Printer.h:55
LayerHeightModel layerHeightModel
Definition Printer.h:61
double heatBedTemperature
Definition Printer.h:65
double filamentDiameter
Definition Printer.h:70
double depositedMaterialHeatPower
Definition Printer.h:68
double extrusionWidth
Definition Printer.h:63
double depositionTemperature
Definition Printer.h:64
VelocityModel velocityModel
Definition Printer.h:56
std::array< int, 3 > sizes
Definition Printer.h:59
std::array< double, 3 > steps
Definition Printer.h:58
double heatTransferFilmCoefficient
Definition Printer.h:67
double layerHeight
Definition Printer.h:62
double chamberTemperature
Definition Printer.h:66
Definition CSG.h:117

This page is part of the OOFEM-3.0 documentation. Copyright Copyright (C) 1994-2025 Borek Patzak Bořek Patzák
Project e-mail: oofem@fsv.cvut.cz
Generated at for OOFEM by doxygen 1.15.0 written by Dimitri van Heesch, © 1997-2011