The 'l' formatting character in combination with 'd' was not allowed with MinGW on Windows. Simply formatting with 'd' is sufficient since our coordinates are allowed to be cast to integers at this stage: We won't need to square them any more or anything.
Contributes to issue CURA-3274.
Because this insertion requires dereferencing p1. If it has been removed from the list, dereferencing it would remove it from memory so that would be an invalid pointer reference.
Contributes to debugging issue CURA-3274.
Previously we had a crash only on windows because the long was not long enough. Perhaps this fixes something with the slicing loop.
Contributes to issue CURA-3274.
All support areas are now generated before generating the interface. They are stored in supportLayer.supportAreas right after generation of the areas.
generateSupportInterface then operates on the merged supportAreas.
Note that this has a performace impact: while evaluating support interface, the support of all models is considered, rather than only the support it introduced itself.
When you have a small feature above an outer layer (e.g. raised text), the
area under the feature will be infill rather than skin and so the skin is
composed of multiple segments around the feature. Better surface quality is
obtained if the area under the raised feature is treated as skin thus allowing
more of the outer layer to be printed as a single segment. This setting
specifies the minimum area (in mm^2) of a filled region. Areas smaller than
this will be filled with skin rather than infill.
those meshes didn't call createLayerParts and so their printZ was never set.
To determine the print height of a layer an arbitrary mesh was used to see the printZ.
According to the compiler, the path parameter of handleChildren was not unused, but that was only because it went recursively to subcalls to handleChildren, so it was actually also unused.
Contributes to issue CURA-3137.
This change was already made for CURA-2795, and upon this change was built by other commits for other issues. I had to revert CURA-2795, so that would undo the changes that the other commits depend on. Instead though, I un-reverted the change because it's nice and doesn't have anything inherently to do with CURA-2795.
Contributes to issue CURA-2795.
While parking the filament is essentially a retraction, it should not be called this way and therefore we should make an exception for park moves that they do not allow the printer to decide for itself how far to retract the filament.
Contributes to issue CURA-2795.
It doesn't need to know which extruder it came from. Just with which extruder to draw the lines. The new_extruder parameter was renamed because there is no need to disambiguate any more.
Contributes to issue CURA-2684.
The results are stored in the gcodeLayer parameter. Has been this way for a while. This was generating compiler warnings. The documentation was already updated, it seems.
Contributes to issue CURA-2684.
There is a circular dependency between prime tower height and support areas. Prime tower height is determined by the highest extruder switch. The highest extruder switch is dependent on the height of support if support is printed with a different exturder. The height of support is dependent on the support areas and the support areas are dependent on the prime tower height. Previously we resolved this by printing no support in the prime tower area and no prime tower, possibly violating the support horizontal expansion in an edge case. Now it is resolved by printing a prime tower there even if there are no extruder switches.
Contributes to issue CURA-2684.
It wasn't clear what retraction limit this function was not adhering to. It is not adhering to the only limit on retraction we currently have: The number of retractions.
Contributes to issue CURA-2795.
It should retract before the nozzle switch, of course, so it can't be retracting at the same time as when it's setting the extruder temperature to 0.
Contributes to issue CURA-2795.
It should be updated before we use it to write the retraction. Also we should subtract the retraction because it is the amount to retract, not the amount to prime.
Contributes to issue CURA-2795.
No X/Y offset is happening. This makes both support and prime tower sturdier, and prevents having to do an offset of the prime tower so it would make the support a bit faster in theory (but the difference is not noticable).
Contributes to issue CURA-2684.
If two polygons overlap, clipperlib can interpret them as one being the inside polygon with the even odd rule. If they overlap exactly, it produces no output. However if you union the polygons it will properly avoid all objects regardless of whether they overlap with other objects.
Contributes to issue CURA-3017.
At this point we don't know for certain if there will be a prime tower, but that is impossible since there is a circular dependency between prime tower and support then.
Contributes to issue CURA-2684.
We always generate a ground polygon now, so we can't rely on the ground polygon being empty if it is disabled due to there being no layer switches.
Contributes to issue CURA-2684.
This way we can always request the prime tower ground polygon throughout the entire process. The polygon will be empty if prime tower is disabled.
Contributes to issue CURA-2684.
I've verified that M203 Sxx is interpreted as mm/s in Marlin, Sprinter and Repetier-Firmware.
Other firmware types we support, like MakerBot, BFB and MACH weren't checked.
For skirt it does this union by taking the convex hull. For brim it did no such thing, so when polygons overlapped it would get complex polygons which didn't work out well.
Contributes to issue CURA-3017.
If the precooling command will precede the printing temeprature command to heat to the temp of the next layer, then don't use that temp;
we should already be cooling down, rather than heating toward the temp of the next layer.
It was a bad idea to change PolygonRef into PolygonPointer, because then we'd have to check whether it is a nullptr all over the engine...
cherry-picked from a2a8604c72
one public base class function, one private recursive function.
Instead of using a heap-allocated array of pointers to Polygons, just use a stack-allocated array of Polygons
The order of polygons is never important, except in PolygonsPart where the first polygon is the outer one, but there it should be impossible to remove the first element anyway.
before this we would get precool and preheat during a layer change even when the last extruder of the previous layer is the first extruder of the next...
with the initial and final printing temperature the old assumption didn't hold any more:
'Assumes from_temp is approximately the same as @p temp'
It uses the same logic as timeBeforeEndToInsertPreheatCommand_warmUpCoolDown(.)
insert heat command from initial_print_temp to print_temp at the first extrusion in a layer plan
insert cool command from print_temp to final_print_temp during the last extrusion moves in a layer plan
When printing dual color models with dual support (different support infill extruder than support skin extruder)
all support would either be printed before all models or after, leading to two extruder switches in one layer.
Now the extruder_order is calculated independently of the mesh_order and the support is added per extruder plan.
The support is always added first, so that:
- in single extrusion we never print in order support-support-model-model which would lead to model being printed on top of model which hasn't cooled enough
- in dual color, dual support we always print E1-support-model-support-model-E2-support-model-support-model so that oozle is automatically wiped on support
'I have to sort my books' she cried,
With self-indulgent glee;
With senseless, narcissistic pride:
'I'm just so OCD.'
'How random guys,' I smiled and said,
Then left without a peep -
And washed my hands until they bled,
And cried myself to sleep.
When printing dual color models with dual support (different support infill extruder than support skin extruder)
all support would either be printed before all models or after, leading to two extruder switches in one layer.
Now the extruder_order is calculated independently of the mesh_order and the support is added per extruder plan.
The support is always added first, so that:
- in single extrusion we never print in order support-support-model-model which would lead to model being printed on top of model which hasn't cooled enough
- in dual color, dual support we always print E1-support-model-support-model-E2-support-model-support-model so that oozle is automatically wiped on support
set bed temeprature to normal at first layer
set bed temp to initial layer bed temp the first layer of each next meshgroup (one-at-a-time mode)
wait for initial bed temp to be reached
don't wait for second layer bed temp
also fixed some problems:
- type of one setting was string rather than str
- there were some old unused settings in there (prime_tower_outward_dir, machine_prinbt_temp_wait)
A lot of (outdated) code depends on there being the same amount of layers in each mesh.
This was not the case for anti-overhang meshes and support meshes
Now each mesh starts out with the same amount of empty layers
Otherwise you will get something like:
In file included from /<<PKGBUILDDIR>>/src/FffPolygonGenerator.cpp:7:0:
/<<PKGBUILDDIR>>/src/utils/algorithm.h: In function ‘std::vector<long unsigned int> cura::order(const std::vector<_Tp>&)’:
/<<PKGBUILDDIR>>/src/utils/algorithm.h:30:5: error: ‘iota’ is not a member of ‘std’
std::iota(order.begin(), order.end(), 0); // fill vector with 1, 2, 3,.. etc
^~~
There used to be one global SubDivCube which would get reset for each mesh on the build plate.
Also resetting without deleting the object leads to memory loss.
Because the lines of tetrahedral infill sway toward and away from each other, we need to speak of an average line distance.
However, the line distance when you skip one line is constant; I call that the period.
This has the disadvantage that support meshes are re-evaluated for each normal mesh.
However, otherwise support meshes could overlap with each other mesh..
otherwise the move from the switch location to the wipe tower already wiped the nozzle on the prime tower, because it moved through the prime tower toward the wipe location
* feature_export_speedup:
lil writeInt2mm improvements (CURA-2472)
fix: output integers directly to stream rather than converting to double first (CURA-2472)
Sadly, stoui doesn't exist in C++11. We do have stoul though, which comes closer to what we intend and is still more powerful than we need.
Contributes to issue CURA-2314.
Because the line ended in a backslash, it would take the next line as a comment too. The next line was already a comment, so it didn't matter, but this period is now at the end to prevent the compiler warning.
Contributes to issue CURA-1966.
This is the only place where an outside offset is done and the inside polygons don't matter, so it is the only place where the union can safely be performed, since the union treats holes as normal polygons.
Contributes to issue CURA-2088.
We should really do this with all of these functions. In this case, I required this in order to be able to import SVG for a bit of debugging.
Contributes to issue CURA-2088.
In the case of stairs, there is no overlap either. The approximation now takes that into account at hardly any additional computational cost.
Contributes to issue CURA-1911.
The intermediary variable was supposed to make the variable name more clear. Instead, I just renamed the input parameter, removing the weird construct.
Contributes to issue CURA-1911.
the end point of the new line segment might still need to be projected onto the other line segment
short line segments might need linking from front to end when the previous and next line segment are parallel
also iterate over the newly introduced points again, because they might need links which don't get introduced when we already passed that point in the poly
also prevert newly introduced points to again introduce new points, cause otherwise we might introduce a lot of new points in a corner (visual explanation in code)
Make PolygONProximityLinker::Point2Link be a multimap, mapping points to multiple links
Change getLink(.) to getLinks(.)
Expose Point2Link so that outside classes can reason about which link is which
wallOverlap
Compute the actual overlapping area, since the ratio cannot easily be computed when multiple overlaps are involved
Compute the overlap area for segments for which both ends are linked to the same point
the [passed] attribute needs to be mutable: it doesn't change the hash of the object and needs to be changed after it's been in the set
fixed iterator invalidation issues by simply copying items from the set into the map, rather than referring to them
This new code was introduced by the brim-only-outside feature and gave no merge conflict, but was not up-to-date with the support roof rename to support skin.
Contributes to issue CURA-1413.
also cleaned up generateSkirtBrim a bit
also applied code conventions
inadvertently also causes support not to be removed by unprinted skirt
removed skirts_or_brims which didn't need to be a vector (only last elem was used)
This only applied to travel speeds, since raft print speeds are determined by other settings, support is not on the raft layers, and meshes are not on the raft layers.
Contributes to issue CURA-1507.
* feature_support_settings_from_support_extruder:
Remove debug statement
Set settingInheritBase on every mesh in the meshgroup
Be more robust against wrong input from Arcus
Distribute global_inherits_stack across meshgroups
Register SettingExtruder message type
Sync from frontend: global_inherits_stack message
feat: setting retrieval inheritance overrides (CURA-1953)
The front-end added the global_inherits_stack SettingExtruder message. We should add it too to be able to read the message. This is a copy from the same file in Cura's front-end.
Contributes to issue CURA-2011.
also cleaned up generateSkirtBrim a bit
also applied code conventions
inadvertently also causes support not to be removed by unprinted skirt
removed skirts_or_brims which didn't need to be a vector (only last elem was used)
Problem was that the draft shield height limit was measured in number of layers, but it was compared with the height of the first layer to determine if we should skip adding draft shield layers, and the first layer height was measured in microns.
Contributes to issue CURA-1295.
Renamed DraftShieldLimitation to DraftShieldHeightLimitation. Also applied the limit to FffGcodeWriter and made the draft shield function more logical and make it only check for the limit if the draft shield height is limited.
Contributes to issue CURA-1295.
The engine now listens to the draft shield limitation. If it's set to full, we use the full height of the print to limit the draft shield rather than the height limit setting.
Contributes to issue CURA-1295.
This moves them from the SlicerLayer::connectPolylinesImpl() function
to the SlicerLayer class. This results in the declaration movign to
the header file.
This hides the implementation of a polyline index and a flag as an
unsigned int. This also makes some of the uses more clear because
of the accessor function names.
This switches the storage for segments ending in a vertex to a vertex *
instead of copying the connected faces of the vertex into a copy
of the vector.
Because it is used not only for skirt but also for brim. This essentially means an API break, though Cura doesn't rely on this. Printers should not rely on this as per the g-code spec. The only things that rely on this are the postprocessing scripts, but it should be a trivial change for them.
Contributes to issue CURA-1678.
Support roof takes quite a lot of time to print, so only generate it below the actual mesh, not where the support area is X/Y expanded or where multiple pieces of support are joined and such.
Contributes to issue CURA-647.
Rather than taking the extruder of the current g-code, which is for an entire layer, take the retraction settings of the current extruder plan. This allows for different retraction settings on the same layer rather than just taking the retraction settings that layer begins with.
Contributes to issue CURA-1972.
Functions are now static and internally check in the command socket is instansiated to make the using code cleaner.
The sendLine function has been renamed to sendLineTo and only take the destination point to match how data is used and written to gcode.
CURA-1272
The names of these properties have changed a bit. Also, we're now getting the normal value first and defaulting back to default_value if there is no inheritance functions.
Contributes to issue CURA-1758.
If the line width is different per combined layer this would get the correct one, and it is also more robust if there are 0 layers in the vector.
Contributes to issue CURA-736.
Negative conical support angles are also allowed. Only when the support angle is exactly zero, it is nonsensical to generate conical support.
Contributes to issue CURA-736.
It's the only place where it's used. This makes the stack trace slimmer, potentially making the program faster. Also, it moves the dependency on the setting closer to where the setting is used.
Contributes to issue CURA-736.
This prime tower is long unused. The queue import also seems to be unused, since compiling gives no error and a CTRL+F has no results either.
Contributes to issue CURA-736.
This makes the line width with which we're extruding equal to the line width with which we did the insets for these lines.
Contributes to issue CURA-736.
We deemed that the inner wall line width is more akin to the line width you're seeking for the border line of skins, which attaches slin lines that end on the border with infill. More akin than skin line width anyway.
Contributes to issue CURA-736.
This makes the stack lighter, because the context switch to the functions doesn't need to copy the value over to the stack. Also removes the reference to old terminology: extrusion_width, and makes the variable const.
Contributes to issue CURA-736.
This makes the stack lighter, because the context switch to the functions doesn't need to copy the value over to the stack. The local variable can be an order of magnitude faster even though it needs to look-up the value from the mesh one additional time. Also removes the reference to old terminology: extrusion_width, and makes the variable const.
Contributes to issue CURA-736.
There are now distinct settings for speed_print_layer_0 (the extrusion moves) and speed_travel_layer_0 (the non-extrusion moves).
Contributes to issue CURA-1507.
The part.infill_area should remain the whole initial infill area for combing
During the generation of the part.infill_area_per_combine_per_density it refered to part.infill_area, rather than the infill-mesh-limited infill
I had to introduce an intermediate result - part.infill_area_own - which records the area where that mesh should print its infill pattern
In case there are no infill meshes the part.infill_area_own remains a nullptr, so that we don't waste resources.
After it's used and incorporated into infill_area_per_combine_per_density, its destroyed.
whenb computing gradual infill, we skip layersto compute which regions count as top. These skips are now such that
you end exactly one gradual infill step above.
Some of the comments had mentions of BucketGrid were the code had
already been updated to change BucketGrid2D uses to SparseGrid.
I didn't notice them before because of the different spelling.
The invansive version requires that the stored type being able to
provide a Point location on demand. This is a general version in
case the type being stored already has a location in it. The
non-invasive version is more convenient if the type to be stored
does not already contain a Point location.
It was calculating the angle to use for infill but then not using it.
This makes it use the calculated angle. This makes the bridge
generation go from basically completely non-functional to just mostly
non-functional.
From the slicing, we know which edge generated the end point of the
segment. We then know that the face that shares this edge is the only
candidate to have generated the next segment. This avoids checking
the other 2 segments.
Improved logic used in SlicerLayer::getNextSegmentIdx(). The previous
version only considered candidate faces for extending the current
polygon loop by looking at faces that shared an edge. This works for
many models, but if the slice height exactly intersects vertices of
the mesh, then the segment that would extend the loop is not typically
found. We know whether we hit a vertex with the slice from the
slicing calculation. There is a slight cost to checking for equality
to see if we hit a vertex. This can very slightly slow down normal
models but substantially increase speed on bad case models. This
extends the logic to use the faces connected to the vertex that the
segment ended on to try to extend the polygon loop. Theoretically,
this adds a slight performance penalty to makeBasicPolygonLoops when
vertices were hit by the slice. However, in very limited testing,
this extra time is not measurable. Adding this improved correctness
makes a big difference in the number of polygon loops successfully
constructed. In a bad case model, the number of polygons found
increased from 0 to 19 and the number of open polylines for the next
stage of processing went from 6357 to 0. This made the
connectOpenPolylines() go from taking .048 seconds to 0. The overall
effect on this model was to reduce the slicing time from 0.084 to 0.04
seconds (this is a small model for testing so total times are low).
Added use of spatial data structure in SlicerLayer::stitch(). Added
SparseGrid spatial data structure. This is similar to BucketGrid2D
but a bit more general and without the possibility of duplication in
returned points. SparseGrid does not offer a findNearestObject
function like BucketGrid2D does, although one could be added if
desired.
Sped up SlicerLayer::stit() further by only finding nearby points
once. The possible stitch points are calculated once and remembered.
They are put into a priority queue. A bidirectional map (via vectors)
is used to keep track of the transforms that happen to the polygons to
map from the original polyline ends to the new polyline ends.
Combined stitch and connectOpenPolylines implementations.
connectOpenPolylines basically does the same thing as stitch except
has a smaller search radius and doesn't allow for inverting edges. I
expressed these as parameters to the stitch implementation and then
reused the implementation. It is now much faster.
connectOpenPolylines has gone from O(n^2) to O(n) and stitch has gone
from O(n^3) to O(n). connectOpenPolylines has also gotten more
correct. With the original version,if polys 0 -> 10 -> 5 formed a
chain, then 0 -> 10 would be merged into 0 but the 10 -> 5 would never
be used. 0 -> 10 would be merged into 0, but this new 0 would not be
considered for merging with 5 since 10 > 5. It also wouldn't be
considered for merging 10 with 5 because 10 has already been cleared
out.
the frontend sends all known settings (and categories) via the command socket even though it should know which settings will be used by the engine.
This is because the json file is the interface ofthe engine and so the frontend sends everything in the interface.
snowballing: when we start cooling T0 before we require the temp of T1 to be reached, due to small discrepancy between the computed and actual heatup times, the time it takes to actually reach the required temp of T1 - while computed to be zero - causes T0 to drop in temperature in that time. This in turn will mean it will also take longer to heat up again, creating the same problem in the next extruder switch from T1 to T0, thereby snowballing into layer switches taking longer and longer.
sometimes it results in too small polygons which clipper itself and we cannot handle.
sometimes very small polygons are offsetted to polygons which lie outise the original polygon.
When accelerating the wrong way, the discriminant of this parabolic is negative. Instead of returning a time estimate of 0, return the extremum of the parabola.
Contributes to issue CURA-1717.
The only function using the last_retraction_config was the function which owuld convert a normal retraction into a nozzle switch retraction, instead of first performing the normal retraction and then the nozzle switch retraction. That functionality had to be removed anyway, because performing the nozzle switch retraction on the print can leave more scarring.
This was giving NaN values in the time estimates for the edge case where the discriminant of this quadratic was actually 0.0, but due to floating point rounding errors ended up below 0.
Contributes to issue CURA-1717.
These files are generated by CMake on Windows 10 64bit with Visual
Studio installed. They are not tracked by the project, so they can be
savely removed by git clean.
complex models with almost everywhere pieces smaller than twice the nozzle width could break the heuristic, when there are a lot of 3-way intersections of thin walls
Instead of keeping the defaults in the global settings registry, load the defaults immediately into a settings base, so that we can override the extruder train defaults.
Simplified the recursion of reading settings
Made the settings registry into a flat list, rather than a tree
Made each setting record a path instead (to keep the same information as the tree)
Moved extruder trains into a separate object, rather than it being a normal category
warn_duplicates strategy simplified: always after the first file
(rather than when applying overrides)
temporarily removed reading of machine_extruder_trains
made label attribute obligatory
Always add a setting to the global setting config (cause reading machine_extruder_trains is currently not implemented)
Thin walls may be unprintable, so getLayerOutlines returns pieces of polygons which aren't actually printed.
This caused an edge overhang to remove support due to the XY distance of unprinted parts of the edge overhang.
When two parts are connected via an unprintably thin wall, also combing would be affected, but not anymore.
Because of the LayerPlanBuffer the GCodePathConfig changed a couple of layers too early, resulting in spiralization in the first layers which include the bottom skin.
Given that having an G92 E0 at the start of the first use of a toolhead is no problem in any printer, we can just reset the E-value every start of a toolhead
this was done so that Jedi gcode also always includes a header
it also means that UMO gcode always gets a header, which is ok, as it is ignored by that firmware
Each layer is now sent individually, instead of grouped by object and grouping those objects in a sliced object list. The list was sometimes too large to send in one message. The objects weren't used by the front-end anyway.
Contributes to issue CURA-1210.
This test case now reduces to the normal test cases since there is only one option again. We can re-use the function that was made for normal test cases then.
Contributes to issue CURA-579.
These test what happens when two or more points are equal. There is nothing about this in the function specification, so it allows any output, but at least it shouldn't give like a divide by zero error.
Contributes to issue CURA-1170.
These test what happens when two or more points are equal. There is nothing about this in the function specification, so it allows any output, but at least it shouldn't give like a divide by zero error.
Contributes to issue CURA-1170.
The minimum value, maximum value, minimum warning value and maximum warning value of each setting is now evaluated as a function, preventing casting errors. Runtest.py runs without errors or even test failures again now.
Contributes to issue CURA-814.
The minimum value, maximum value, minimum warning value and maximum warning value of each setting is now evaluated as a function, preventing casting errors. Runtest.py runs without errors or even test failures again now.
Contributes to issue CURA-814.
The FinishedSlicing message was being sent after the mesh group is done slicing, but it should've been sent after all slicing is done (also other mesh groups and after sending the metadata). This indicates that the slicer is really really done.
Contributes to issue CURA-427.
factored computeBasicAndFullOverhang out of generateSupportAreas
keep overhang areas in a rolling deque so that they are available for the current layer and the layer supportZDistanceTop above
implemented some polygon magic to ensure that the distance of support to overhang areas is less than from non-overhang areas
sendPolygons was called for lines toward the starting point instead of the new point
also a line was sent for the coasted path, which is actually just a move path
removed code duplication by introducing another class called ActualZigzagConnectorProcessor.
explained the inheritance structure in the base class description.
made some things protected instead of public.
The ASCII file may contain whitespace at the start of the file. This causes the STL file to be flagged as binary (since it doesn't start with "solid"). This fix first skips all whitespace before trying to find "solid".
Contributes to issue CURA-605.
To determine the amount of memory allocated and the amount of faces to try to load, use the size of the file rather than the reported face count in the file. The reported face count may be missing or corrupt, in which case the engine would crash. If that happens now, it might miss one face. It will also give a warning if the reported face count does not match.
Contributes to issue CURA-605.
rewrote some for-if combinations which could be made simpler
small polygons which only cover a single scanline which are printed in total don't need the scanline...
MergeInfillLines already had a member nozzle_size, though still it had a line defining a local variable 'int nozzle_size = line_width; // TODO'
Also some minor code convention brackets...
This caused the command socket in LayerPlanBuffer to remain null, thus never flushing the g-code until the very end, thus causing the front-end to interpret the entire g-code as one layer, thus causing the post processing plugin to inject g-code at the wrong places.
Contributes to issue CURA-443.
Since comb_boundary_inside is now a field of gcodeplanner these utility functions were at an awkward place.
Conflicts:
src/gcodePlanner.cpp
src/gcodePlanner.h
The test currently fails due to a floating point rounding error. I'll give it some lenience, especially since both the ground truth and the supposed output are estimates.
The rest of this constructor was still using the input meshgroup, which might be nullptr. Make it use the field, which was checked for being nullptr and initialised if it was nullptr.
For this I moved the constructor properly to the cpp file. This prevents the constructor from having to be compiled a million times, and having to compile a million other files each time you modify this constructor, and prevents having to compile the FffProcessor header each time too. Also, since meshgroup must be defined before initializeRetractionConfigs and initializeSkirtConfigs, they are now in the body of the constructor to properly define the order.
It will set up a very basic g-code planner and let it estimate the time and material it needs. Currently it only tests with empty g-code, but I mean to add a test with retraction once this works. Currently the setup gives a segfault.
Contributes to issue CURA-415.
This variable is always initialised by LinearAlg2D::getDist2FromLineSegment before it is used. But the compiler can't detect that it is, because it noticed that the variable is not changed in some cases (namely if the pointer is null). So this just shuts up the compiler.
material_bed_temp_prepend - if true, prepend the bed temperature gcode
material_bed_temp_wait - if true, use the set and wait variant gcode
material_print_temp_prepend - if true, prepend the extruder temperature gcode
material_print_temp_wait - if true, also prepend the wait for temperature gcode
This variable is always initialised by LinearAlg2D::getDist2FromLineSegment before it is used. But the compiler can't detect that it is, because it noticed that the variable is not changed in some cases (namely if the pointer is null). So this just shuts up the compiler.
If an empty polygon was passed here in the outline, firstBoundarySegmentEndsInEven would be uninitialised. This initialises it by default to true so that the if statement after the loop exhibits predictably correct behaviour.
Some fields of Weaver were not properly initialised if the script was cut short. It now checks at several places where zero layers would be a problem and just continues as best as it can.
Contributes to issue CURA-349.
The retraction settings were not initialised and this caused wireframe printing to access uninitialised memory. This initialises it properly by loading them from settings. At one place the rest of the settings were still hardcoded with the todo that it should be loaded from settings, but I left that as-is for now.
Contributes to issue CURA-349.
This variable was possibly uninitialised by the time it is first used in an if statement. This causes undefined behaviour. This now initialises it to false, which is correct behaviour if the variable is not changed (zero outlines).
The polygons vector of the Polygons class was in some cases not initialised while the size of the vector was requested, causing Valgrind to report a conditional jump depending on uninitialised memory.
Contributes to issue CURA-349.
It should try to get as much information from the string as possible, regardless of whether the string is correctly formatted or not. At many places it used to iterate through the characters indefinitely until the next separator was reached. Now it stops at the end of string and returns the information it gathered up to then.
Contributes to issue CURA-349.
It can't request the height of the heighest layer if there are no layers. If there are no layers, the height is now 0. Fixes the wireframe printing issue.
Contributes to issue CURA-349.
If the mesh group is empty, the wireframe slicing crashed since it tried to access slicerList[0], which was filled with a slicer for each meshgroup.
Contributes to issue CURA-349.
It can't be named libCuraEngine, sadly, since that produces a naming conflict with the CuraEngine executable target itself. This is a better compromise than it was initially.
It is no longer necessary to build CuraEngine twice if building unit tests. It now simply builds all of CuraEngine (except main.cpp) as a library, then builds main.cpp as separate application and links the CuraEngine library to it. Then it does the same with the tests: Just build the test suite as application and link the already-built library to it.
At one place there was an accidental extra four spaces. At another place the alignment of a comment was off since it was aligned to a comment above it which had moved to the left.
If for some reason the opening of the file failed, an error is given that indicates where the file was opened. It still continues writing because the nature of this class requires it to fail fast rather than continue silently, but it should be easier to debug now. If silent fail behaviour is desired for this class then we could decide on that later. It involves checking for if(out) at every write function.
Rather than failing at the first assert, there are now only 2 asserts in these test cases. Also it allows for some leniency of 10 microns error in the distance, which was the actual reason I did this.
This is slightly more efficient to compute, though it allows for combing closer to the polygon than the specified combing distance if the edge approaches parallel with the desired combing path.
Contributes to issue CURA-286.
A point was being moved inside the polygon to obtain waypoints for combing through the inside of the polygon. Then it was being moved outside the polygon with a larger offset, but the second move used the inside point of the first move, causing the resulting offset to be a bit too small. This keeps a copy of the original waypoint before moving it inside, which it uses only for computing the outside waypoint.
Contributes to issue CURA-286.
Now that a collision is also triggered when the line crosses an endpoint of another line, the detection of collisions when the two lines are parallel is no longer needed.
Contributes to issue CURA-286.
Combining 1 layer has no effect. Combining 0 layers is invalid. Therefore, if this function is made to combine 1 or 0 layers, it doesn't combine anything, and immediately returns.
It's CuraEngineLibrary that uses these libraries, not the tests themselves. It's better to link it to CuraEngineLibrary itself rather than to the test executables.
If you add -DBUILD_TESTS=true to CMake, it will add a test target for each test file. These can be executed separately as executable file, or they can be ran all at once with 'make test'.
This script couldn't run because it couldn't convert the ints to strings. It shouldn't convert the ints to strings. It should convert the strings to ints (or floats).
If the infill density is 0 and it has to combine layers, it would try to access layers below the first layer that don't exist. Instead it will now not combine at all, saving some processing power too.
Contributes to issue Cura-285.
In the command socket, when slicing failed, it would just ignore the failure and continue. This is fine, but let's at least log an error when that happens.
A preprocessor definition is added if CMAKE_BUILD_TYPE == DEBUG. So for release builds, set CMAKE_BUILD_TYPE properly to RELEASE and CuraEngine will no longer stop at the assertion.
In discussion, we deemed infill_sparse_thickness more clear to the user and infill_sparse_combine superfluous, since it is really an intermediary value used by the engine to round the thickness up. So now it is actually computed in the engine. Accompanying this commit will be a commit to Cura to remove the setting from the .json file.
If there are no layers, the engine used to crash with an assertion error. Instead, it now returns an empty slice, which is correct behaviour. Fixes issue CURA-323.
If this setting is zero or negative, make it the minimum layer thickness: 1 micron. Also fixed a mistake in the comment of the similar check for the normal layer thickness setting.
In discussion, we deemed infill_sparse_thickness more clear to the user and infill_sparse_combine superfluous, since it is really an intermediary value used by the engine to round the thickness up. So now it is actually computed in the engine. Accompanying this commit will be a commit to Cura to remove the setting from the .json file.
If a line was parallel with an edge of the polygon, the line should be marked as intersecting that edge to properly register the scanline crossing. This handles that edge case for most cases by adding one intersection. In some cases it is plausible that two intersections should be registered. For those cases this procedure is still wrong, since it is computationally expensive to detect them.
When combing needs additional waypoints (middle_from and middle_to), these waypoints weren't offset away from the edge towards the inside of the mesh. This caused all sorts of mistakes with edge cases. This prevents these edge cases.
Rather than having to supply a polygon, you can now supply a vector of points too. This helps if you want to visualise a custom polygon. Rather than having to clone a polygon some way, clear it and fill it with your own points, you now don't have to create a polygon container at all.
If we're moving points inside, points on the edge also have their direction of motion altered. This effectively means that the corner case happens more often.
This functionality already existed for 3D axis aligned bounding boxes. It makes it easier to construct a bounding box when no explicit polygon is available. To facilitate this, the bounding box is properly constructed with high minimum value too.
If two consecutive points are exactly equal, a divide by zero would happen here. This check prevents the divide in that case and skips the second of the points then.
I just introduced a bug where if there were too few layers such that no infill is generated at all, the infill combining would take a practically infinite amount of time. The cause was an underflow. This fixes it.
Infill layers only need to be combined between <bottom_layers> and <N - 1 - top_layers>. This theoretically makes the code a bit faster. Also, the infill is now combined from 0 upwards rather than in reverse order, and renamed layer_index to layer_idx.
If a line doesn't intersect but does touch a polygon, a collision is now triggered. This is the desired behaviour in this case, since this method is only used by the combing code.
For instance, if the sparse_infill_combine setting is 3, it will only be computed for layers 0, 3, 6, etc. This prevents different parts of infill from landing on different layers, causing infill to break into multiple layers.
For instance, if the sparse_infill_combine setting is 3, it will only be computed for layers 0, 3, 6, etc. This prevents different parts of infill from landing on different layers, causing infill to break into multiple layers.
std::vector<>::size() returns a size_t. size_t is a long uint on 64-bit
but a normal uint on 32-bit. So compilation on 32-bit fails because
std::max cannot do template deduction correctly.
Commit 1070d36 broke the build by enabeling code that was not kept up to
date, this patch fixes it properly by adding the
writeLayerCountComment() method.
Signed-off-by: Olliver Schinagl <o.schinagl@ultimaker.com>
Commit 1070d36 broke the build by enabeling code that was not kept up to
date, this patch fixes it properly by adding the
writeLayerCountComment() method.
Signed-off-by: Olliver Schinagl <o.schinagl@ultimaker.com>
Since the enum values were changed to normalised values this check was
wrong. Additonally, now properly use an Enum for the values since that
is a cleaner approach.
FixesUltimaker/Cura#411
We now store options as (key => user visible string) in the json file.
The keys in the json file have been normalized. Now the engine also
reflects that change.
* 15.06: (21 commits)
bugfix: empty arcus messages
bugfix & feature: insets support smaller outer wall line width
Statically link libstdc++ on Linux to prevent issues with newer libstc++
bugfixes for raft problems: unregistered settings, printZ computed doubly, printZ didn't account for difference in initial slice Z and print Z, initial layer height should be appleid when using raft, wrong (negative) layer comments
bugfix: extrusion per mm to extrusion mm3 per mm is_volumetric set
bugfix: speed compensation for stable feedrate also changed the extrusion per mm
bugfix: speed compensation for stable feedrate also changed the extrusion per mm
bugfix+refactor: extrusion always per mm3
bugfix: no support for too low models
bugfix: no support for too low models
Also send infill polygon data to the UI, not just oultines
Also send line width to the UI along with the polygon's points
Add support for sending layer height and thickness to the UI
Properly reset the extrusion amount between slicing tasks.
Properly initialize extrusion_volume_per_mm variable
bugfix: reset filament at new print
Add missing <string> include so we can build on MacOSX
Install the created executable
bugfix gcode.writeMove(x,y,z) where z didn't get processed. = bug for wireprinting
Fix support generation by making sure "True" is also recognised as true
...
The CuraEngine is a C++ console application for 3D printing GCode generation. It has been made as a better and faster alternative to the old Skeinforge engine.
The CuraEngine is pure C++ and uses Clipper from http://www.angusj.com/delphi/clipper.php
There are no external dependences and Clipper is included in the source code without modifications.
Furthermore it depends on libArcus by Ultimaker, which can be found at http://github.com/Ultimaker/libArcus
This is just a console application for GCode generation. For a full graphical application look at https://github.com/daid/Cura which is the graphical frontend for CuraEngine.
This is just a console application for GCode generation. For a full graphical application look at https://github.com/Ultimaker/Cura which is the graphical frontend for CuraEngine.
The CuraEngine can be used seperately or in other applications. Feel free to add it to your application. But please take note of the License.
@@ -19,43 +19,52 @@ But in general it boils down to: You need to share the source of any CuraEngine
How to Install
==============
1. Clone the repository from https://github.com/Ultimaker/CuraEngine.git (the URL at the right hand side of this page).
2. Install Protobuf (see below)
2. Install Protobuf >= 3.0.0 (see below)
3. Install libArcus (see https://github.com/Ultimaker/libArcus)
In order to compile CuraEngine, either use CMake or start a project in your preferred IDE.
CMake compilation:
1. Navigate to the CuraEngine directory and execute the following commands
2. $ mkdir build && cd build
3. $ cmake ..
4. $ make
2.```$ mkdir build && cd build```
3.```$ cmake ..```
4.```$ make```
Project files generation:
1. Navigate to the CuraEngine directory and execute the following commands
2. cmake . -G "CodeBlocks - Unix Makefiles"
2.```cmake . -G "CodeBlocks - Unix Makefiles"```
3. (for a list of supported IDE's see http://www.cmake.org/Wiki/CMake_Generator_Specific_Information#Code::Blocks_Generator)
Installing Protobuf
-------------------
1. Be sure to have libtool installed.
2. Download protobuf from https://github.com/google/protobuf/ (download ZIP and unZIP at desired location, or clone the repo) The protocol buffer is used for communication between the CuraEngine and the GUI.
3.Before installing protobuf, change autogen.sh : comment line 18 to line 38 using '#'s. This removes the dependency on gtest-1.7.0.
4. Run autogen.sh from the protobuf directory:
$ ./autogen.sh
5. $ ./configure
6. $ make
7. $ make install # Requires superused priviliges.
8. (In case the shared library cannot be loaded, you can try "sudo ldconfig" on Linux systems)
2. Download protobuf from https://github.com/google/protobuf/releases (download ZIP and unZIP at desired location, or clone the repo). The protocol buffer is used for communication between the CuraEngine and the GUI.
3.Run ```autogen.sh``` from the protobuf directory:
```$ ./autogen.sh```
4. ```$ ./configure```
5. ```$ make```
6. ```# make install```
(Please note the ```#```. It indicates the need of superuser, as known as root, priviliges.)
7. (In case the shared library cannot be loaded, you can try ```sudo ldconfig``` on Linux systems)
Running
=======
Other than running CuraEngine from a frontend, such as PluggableCura, one can run CuraEngine from the command line.
Other than running CuraEngine from a frontend, such as Ultimaker/Cura, one can run CuraEngine from the command line.
For that one needs a settings JSON file, which can be found in the Ultimaker/Cura repository.
Note that the structure of the json files has changed since 2.1. In the corresponding branch of the Cura repository you can find how the json files used to be structured.
An example run for an UM2 machine looks as follows:
* Navigate to the CuraEngine directory and execute the following
Run `CuraEngine help` for a general description of how to use the CuraEngine tool.
[Set the environment variable](https://help.ubuntu.com/community/EnvironmentVariables) CURA_ENGINE_SEARCH_PATH to the appropriate paths, delimited by a colon e.g.
@@ -119,4 +128,4 @@ The GCode generation is quite a large bit of code. As a lot is going on here. Im
* PathOrderOptimizer: This piece of code needs to solve a TravelingSalesmanProblem. Given a list of polygons/lines it tries to find the best order in which to print them. It currently does this by finding the closest next polygon to print.
* Infill: This code generates a group of lines from an area. This is the code that generates the actuall infill pattern. There is also a concentric infill function, which is currently not used.
* Comb: The combing code is the code that tries to avoid holes when moving the head around without printing. This code also detects when it fails. The final GCode generator uses the combing code while generating the final GCode. So they interact closely.
* GCodeExport: The GCode export is a 2 step process. First it collects all the paths for a layer that it needs to print, this includes all moves, prints, extrusion widths. And then it generates the final GCode. This is the only piece of code that has knowledge about GCode keywords and syntax;meshmdhfdhfdhf to generate a different flavor of GCode it will be the only piece that needs adjustment. All volumatric calculations also happen here.
* GCodeExport: The GCode export is a 2 step process. First it collects all the paths for a layer that it needs to print, this includes all moves, prints, extrusion widths. And then it generates the final GCode. This is the only piece of code that has knowledge about GCode keywords and syntax to generate a different flavor of GCode it will be the only piece that needs adjustment. All volumatric calculations also happen here.
Tencent is pleased to support the open source community by making RapidJSON available.
Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.
If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON.
A copy of the MIT License is included in this file.
Other dependencies and licenses:
Open Source Software Licensed Under the BSD License:
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Open Source Software Licensed Under the JSON License:
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
friendclassFffProcessor;// cause WireFrame2Gcode uses the member [gcode] (TODO)
private:
intmax_object_height;//!< The maximal height of all previously sliced meshgroups, used to avoid collision when moving to the next meshgroup to print.
/*
* Buffer for all layer plans (of type GCodePlanner)
*
* The layer plans are buffered so that we can start heating up a nozzle several layers before it needs to be used.
* Another reason is to perform Auto Temperature.
*/
LayerPlanBufferlayer_plan_buffer;
/*!
* The class holding the current state of the gcode being written.
*
* It holds information such as the last written position etc.
*/
GCodeExportgcode;
/*!
* The gcode file to write to when using CuraEngine as command line tool.
*/
std::ofstreamoutput_file;
/*!
* Whether the skirt or brim polygons have been processed into planned paths
* for each extruder train.
*/
boolskirt_brim_is_processed[MAX_EXTRUDERS];
std::vector<std::vector<unsignedint>>mesh_order_per_extruder;//!< For each extruder, the cyclic order of the meshes (the first element is not the starting element per se)
/*!
* For each extruder whether priming has already been planned
*/
boolextruder_prime_is_planned[MAX_EXTRUDERS];
std::vector<FanSpeedLayerTimeSettings>fan_speed_layer_time_settings_per_extruder;//!< The settings used relating to minimal layer time and fan speeds. Configured for each extruder.
Pointlast_position_planned;//!< The position of the head before planning the next layer
intcurrent_extruder_planned;//!< The extruder train in use before planning the next layer
boolis_inside_mesh_layer_part;//!< Whether the last position was inside a layer part (used in combing)
public:
FffGcodeWriter(SettingsBase*settings_)
:SettingsMessenger(settings_)
,max_object_height(0)
,layer_plan_buffer(this,gcode)
,extruder_prime_is_planned{}// initialize all values in array with [false]
,last_position_planned(no_point)
,current_extruder_planned(0)// changed somewhere early in FffGcodeWriter::writeGCode
,is_inside_mesh_layer_part(false)
{
}
/*!
* Set the target to write gcode to: to a file.
*
* Used when CuraEngine is used as command line tool.
*
* \param filename The filename of the file to which to write the gcode.
*/
boolsetTargetFile(constchar*filename)
{
output_file.open(filename);
if(output_file.is_open())
{
gcode.setOutputStream(&output_file);
returntrue;
}
returnfalse;
}
/*!
* Set the target to write gcode to: an output stream.
*
* Used when CuraEngine is NOT used as command line tool.
*
* \param stream The stream to write gcode to.
*/
voidsetTargetStream(std::ostream*stream)
{
gcode.setOutputStream(stream);
}
/*!
* Get the total extruded volume for a specific extruder in mm^3
*
* Retractions and unretractions don't contribute to this.
*
* \param extruder_nr The extruder number for which to get the total netto extruded volume
* \return total filament printed in mm^3
*/
doublegetTotalFilamentUsed(intextruder_nr)
{
returngcode.getTotalFilamentUsed(extruder_nr);
}
/*!
* Get the total estimated print time in seconds
*
* \return total print time in seconds
*/
doublegetTotalPrintTime()
{
returngcode.getTotalPrintTime();
}
/*!
* Write all the gcode for the current meshgroup.
* This is the primary function of this class.
*
* \param[in] storage The data storage from which to get the polygons to print and the areas to fill.
* \param timeKeeper The stop watch to see how long it takes for each of the stages in the slicing process.
* Add the gcode of the top/bottom skin of the given part and of the perimeter gaps.
*
* Perimter gaps are generated for skin outlines and printed while the skin fill of the skin part is printed.
* Perimeter gaps between the walls are added to the gcode afterwards.
*
* \param gcodeLayer The initial planning of the gcode of the layer.
* \param mesh The mesh for which to add to the layer plan \p gcodeLayer.
* \param part The part for which to create gcode
* \param layer_nr The current layer number.
* \param skin_overlap The distance by which the skin overlaps with the wall insets and the distance by which the perimeter gaps overlap with adjacent print features.
* \param fillAngle The angle in the XY plane at which the infill is generated.
storage.meshes.reserve(slicerList.size());// causes there to be no resize in meshes so that the pointers in sliceMeshStorage._config to retraction_config don't get invalidated.
logDebug("Processing skins and infill layer %i of %i\n",layer_number,mesh_layer_count);
if(!mesh.getSettingBoolean("magic_spiralize")||static_cast<int>(layer_number)<mesh_max_bottom_layer_count)//Only generate up/downskin and infill for the first X layers when spiralize is choosen.
// note: don't change the part.infill_area, because we change the structure of that area, while the basic area in which infill is printed remains the same
unsignedintcombined_infill_layers=std::max(1U,round_divide(mesh.getSettingInMicrons("infill_sparse_thickness"),std::max(getSettingInMicrons("layer_height"),(coord_t)1)));//How many infill layers to combine to obtain the requested sparse thickness.
if(mesh.getSettingBoolean("magic_spiralize")&&static_cast<int>(layer_nr)<mesh.getSettingAsCount("bottom_layers")&&((layer_nr%2)+2)%2==1)//Add extra insets every 2 layers when spiralizing, this makes bottoms of cups watertight.
constunsignedintsupport_infill_extruder_nr=storage.getSettingAsIndex("support_infill_extruder_nr");// TODO: support extruder should be configurable per object
constunsignedintsupport_skin_extruder_nr=storage.getSettingAsIndex("support_interface_extruder_nr");// TODO: support skin extruder should be configurable per object
intallowed_angle_offset=tan(getSettingInAngleRadians("ooze_shield_angle"))*getSettingInMicrons("layer_height");// Allow for a 60deg angle in the oozeShield.
* Primary stage in Fused Filament Fabrication processing: Polygons are generated.
* The model is sliced and each slice consists of polygons representing the outlines: the boundaries between inside and outside the object.
* After slicing, the layers are processed; for example the wall insets are generated, and the areas which are to be filled with support and infill, which are all represented by polygons.
* In this stage nothing other than areas and circular paths are generated, which are both represented by polygons.
* No infill lines or support pattern etc. is generated.
*
* The main function of this class is FffPolygonGenerator::generateAreas().
* Slice the \p object and store the outlines in the \p storage.
*
* \param object The object to slice.
* \param timeKeeper Object which keeps track of timings of each stage.
* \param storage Output parameter: where the outlines are stored. See SliceLayerPart::outline.
*
* \return Whether the process succeeded (always true).
*/
boolsliceModel(MeshGroup*object,TimeKeeper&timeKeeper,SliceDataStorage&storage);/// slices the model
/*!
* Processes the outline information as stored in the \p storage: generates inset perimeter polygons, support area polygons, etc.
*
* \param storage Input and Output parameter: fetches the outline information (see SliceLayerPart::outline) and generates the other reachable field of the \p storage
* \param timeKeeper Object which keeps track of timings of each stage.
* Processes the outline information as stored in the \p storage: generates inset perimeter polygons, skin and infill
*
* \param storage Input and Output parameter: fetches the outline information (see SliceLayerPart::outline) and generates the other reachable field of the \p storage
* \param mesh_order_idx The index of the mesh_idx in \p mesh_order to process in the vector of meshes in \p storage
* \param mesh_order The order in which the meshes are processed (used for infill meshes)
* \param inset_skin_progress_estimate The progress stage estimate calculator
* Process the mesh to be an infill mesh: limit all outlines to within the infill of normal meshes and subtract their volume from the infill of those meshes
*
* \param storage Input and Output parameter: fetches the outline information (see SliceLayerPart::outline) and generates the other reachable field of the \p storage
* \param mesh_order_idx The index of the mesh_idx in \p mesh_order to process in the vector of meshes in \p storage
* \param mesh_order The order in which the meshes are processed
* Process features which are derived from the basic walls, skin, and infill:
* fuzzy skin, infill combine
*
* \param mesh Input and Output parameter: fetches the outline information (see SliceLayerPart::outline) and generates the other reachable field of the \p storage
* Set \ref SliceDataStorage::max_print_height_per_extruder and \ref SliceDataStorage::max_print_height_order and \ref SliceDataStorage::max_print_height_second_to_last_extruder
*
* \param[in,out] storage Where to retrieve mesh and support etc settings from and where the print height statistics are saved.
* Generate the inset polygons which form the walls.
* \param mesh Input and Output parameter: fetches the outline information (see SliceLayerPart::outline) and generates the other reachable field of the \p storage
* \param layer_nr The layer for which to generate the insets.
* \param storage Input and Output parameter: fetches the outline information (see SliceLayerPart::outline) and generates the other reachable field of the \p storage
*/
voidprocessOozeShield(SliceDataStorage&storage);
/*!
* Generate the skin areas.
* \param mesh Input and Output parameter: fetches the outline information (see SliceLayerPart::outline) and generates the other reachable field of the \p storage
* \param layer_nr The layer for which to generate the skin areas.
* Generate the polygons where the draft screen should be.
*
* \param storage Input and Output parameter: fetches the outline information (see SliceLayerPart::outline) and generates the other reachable field of the \p storage
*/
voidprocessDraftShield(SliceDataStorage&storage);
/*!
* Generate the skirt/brim/raft areas/insets.
* \param storage Input and Output parameter: fetches the outline information (see SliceLayerPart::outline) and generates the other reachable field of the \p storage
extruder_plan_before.insertCommand(path_idx,extruder,temp,wait);// insert at start of extruder plan if time_after_extruder_plan_start > extruder_plan.time
logWarning("Warning: Couldn't find previous extruder plan so as to set the standby temperature. Inserting temp command in earliest available layer.\n");
doubleheated_post_travel_time=0;// The time after the last extrude move toward the end of the extruder plan during which the nozzle is stable at the final print temperature
doubletime_window=0;// The time window within which the nozzle needs to heat from the initial print temp to the printing temperature and then back to the final print temp; i.e. from the first to the last extrusion move with this extruder
doubleweighted_average_print_temp=0;// The average of the normal printing temperatures of the extruder plans (which might be different due to flow dependent temp or due to initial layer temp) Weighted by time
doubleinitial_print_temp=-1;// The initial print temp of the first extruder plan with this extruder
{// compute time window and print temp statistics
doubleheated_pre_travel_time=-1;// The time before the first extrude move from the start of the extruder plan during which the nozzle is stable at the initial print temperature
// at this point cool_down_time is what time is left if cool down time of extruder plans after precool_extruder_plan (up until last_extruder_plan) are already taken into account
/** Copyright (C) 2016 Ultimaker - Released under terms of the AGPLv3 License */
#ifndef LAYER_PLAN_BUFFER_H
#define LAYER_PLAN_BUFFER_H
#include<list>
#include"settings/settings.h"
#include"commandSocket.h"
#include"gcodeExport.h"
#include"gcodePlanner.h"
#include"MeshGroup.h"
#include"Preheat.h"
namespacecura
{
/*!
* Class for buffering multiple layer plans (\ref GCodePlanner) / extruder plans within those layer plans, so that temperature commands can be inserted in earlier layer plans.
*
* This class handles where to insert temperature commands for:
* - initial layer temperature
* - flow dependent temperature
* - starting to heat up from the standby temperature
* - initial printing temperature | printing temperature | final printing temperature
*
* \image html assets/precool.png "Temperature Regulation" width=10cm
Preheatpreheat_config;//!< the nozzle and material temperature settings for each extruder train.
staticconstexprunsignedintbuffer_size=5;// should be as low as possible while still allowing enough time in the buffer to heat up from standby temp to printing temp // TODO: hardcoded value
// this value should be higher than 1, cause otherwise each layer is viewed as the first layer and no temp commands are inserted.
staticconstexprconstdoubleextra_preheat_time=1.0;//!< Time to start heating earlier than computed to avoid accummulative discrepancy between actual heating times and computed ones.
std::vector<bool>extruder_used_in_meshgroup;//!< For each extruder whether it has already been planned once in this meshgroup. This is used to see whether we should heat to the initial_print_temp or to the printing_temperature
public:
std::list<GCodePlanner>buffer;//!< The buffer containing several layer plans (GCodePlanner) before writing them to gcode.
returnfalse;// infill lines are too long; otherwise infill lines might be merged when the next infill line is coincidentally shorter like |, would become \ ...
}
// if the lines are in the same direction then abs( dot(ab,cd) / |ab| / |cd| ) == 1
int64_tprod=dot(ab,cd);
if(std::abs(prod)+400<ab_size*cd_size)// 400 = 20*20, where 20 micron is the allowed inaccuracy in the dot product, introduced by the inaccurate point locations of a,b,c,d
{
returnfalse;// extrusion moves not in the same or opposite diraction
}
// make lines in the same direction by flipping one
if(std::abs(std::abs(perp_proj)/infill_vector_perp_length-line_width)>20)// it should be the case that dot(ac, infill_vector_perp) / |infill_vector_perp| == line_width
{
returnfalse;// lines are too far apart or too close together
}
// check whether the two line segments are adjacent.
// full infill in a narrow area might result in line segments with arbitrary distance between them
// the more the narrow passage in the area gets aligned with the infill direction, the further apart the line segments will be
// however, distant line segments might also be due to different narrow passages, so we limit the distance between merged line segments.
GCodeExport&gcode;//!< Where to write the combined line to
intlayer_nr;//!< The current layer number
std::vector<GCodePath>&paths;//!< The paths currently under consideration
ExtruderPlan&extruder_plan;//!< The extruder plan of the paths currently under consideration
GCodePathConfig&travelConfig;//!< The travel settings used to see whether a path is a travel path or an extrusion path
int64_tnozzle_size;//!< The diameter of the hole in the nozzle
boolspeed_equalize_flow_enabled;//!< Should the speed be varied with extrusion width
doublespeed_equalize_flow_max;//!< Maximum speed when adjusting speed for flow
/*!
* Whether the next two extrusion paths are convertible to a single line segment, starting from the end point the of the last travel move at \p path_idx_first_move
* \param path_idx_first_move Index into MergeInfillLines::paths to the travel before the two extrusion moves udner consideration
* \param first_middle Output parameter: the middle of the first extrusion move
* \param second_middle Input/Output parameter: outputs the middle of the second extrusion move; inputs \p first_middle so we don't have to compute it
* \param resulting_line_width Output parameter: The width of the resulting combined line (the average length of the lines combined)
* \param use_second_middle_as_first Whether to use \p second_middle as input parameter for \p first_middle
* \return Whether the next two extrusion paths are convertible to a single line segment, starting from the end point the of the last travel move at \p path_idx_first_move
* Whether the two consecutive extrusion paths (ab and cd) are convitrible to a single line segment.
*
* Note: as an optimization the \p second_middle from the previous call to isConvertible can be used for \p first_middle, instead of recomputing it.
*
* \param a first from
* \param b first to
* \param c second from
* \param d second to
* \param line_width The line width of the moves
* \param first_middle Output parameter: the middle of the first extrusion move
* \param second_middle Input/Output parameter: outputs the middle of the second extrusion move; inputs \p first_middle so we don't have to compute it
* \param resulting_line_width Output parameter: The width of the resulting combined line (the average length of the lines combined)
* \param use_second_middle_as_first Whether to use \p second_middle as input parameter for \p first_middle
* \return Whether the next two extrusion paths are convertible to a single line segment, starting from the end point the of the last travel move at \p path_idx_first_move
* Check for lots of small moves and combine them into one large line.
* Updates \p path_idx to the next path which is not combined.
*
* \param gcode Where to write the combined line to
* \param paths The paths currently under consideration
* \param travelConfig The travel settings used to see whether a path is a travel path or an extrusion path
* \param nozzle_size The diameter of the hole in the nozzle
* \param path_idx Input/Output parameter: The current index in \p paths where to start combining and the current index after combining as output parameter.
* \return Whether lines have been merged and normal path-to-gcode generation can be skipped for the current resulting \p path_idx .
*/
boolmergeInfillLines(unsignedint&path_idx);
/*!
* send a line segment through the command socket from the previous point to the given point \p to
logWarning("Face count reported by file (%s) is not equal to actual face count (%s). File could be corrupt!\n",std::to_string(reported_face_count).c_str(),std::to_string(face_count).c_str());
Meshmesh=object_parent_settings?Mesh(object_parent_settings):Mesh(meshgroup);//If we have object_parent_settings, use them as parent settings. Otherwise, just use meshgroup.
if(loadMeshSTL(&mesh,filename,transformation))//Load it! If successful...
{
meshgroup->meshes.push_back(mesh);
log("loading '%s' took %.3f seconds\n",filename,load_timer.restart());
assert(material_extrusion_cool_down_speed<machine_nozzle_heat_up_speed&&"The extrusion cooldown speed must be smaller than the heat up speed; otherwise the printing temperature cannot be reached!");
* Class for computing heatup and cooldown times used for computing the time the printer needs to heat up to a printing temperature.
*/
classPreheat
{
/*!
* The nozzle and material temperature settings for an extruder train.
*/
classConfig
{
public:
doubletime_to_heatup_1_degree[2];//!< average time it takes to heat up one degree (in the range of normal print temperatures and standby temperature), while not-printing and while printing
doubletime_to_cooldown_1_degree[2];//!< average time it takes to cool down one degree (in the range of normal print temperatures and standby temperature), while not-printing and while printing
doublestandby_temp;//!< The temperature at which the nozzle rests when it is not printing.
doublemin_time_window;//!< Minimal time (in seconds) to allow an extruder to cool down and then warm up again.
doublematerial_initial_print_temperature;//!< print temp when first starting to extrude after a layer switch
doublematerial_final_print_temperature;//!< print temp at the end of all extrusion moves of an extruder to which it's cooled down just before - during the extrusion
boolflow_dependent_temperature;//!< Whether to make the temperature dependent on flow
FlowTempGraphflow_temp_graph;//!< The graph linking flows to corresponding temperatures
};
std::vector<Config>config_per_extruder;//!< the nozzle and material temperature settings for each extruder train.
public:
/*!
* The type of result when computing when to start heating up a nozzle before it's going to be used again.
*/
structWarmUpResult
{
doubletotal_time_window;//!< The total time in which cooling and heating takes place.
doubleheating_time;//!< The total time needed to heat to the required temperature.
doublelowest_temperature;//!< The lower temperature from which heating starts.
};
/*!
* The type of result when computing when to start cooling down a nozzle before it's not going to be used again.
*/
structCoolDownResult
{
doubletotal_time_window;//!< The total time in which heating and cooling takes place.
doublecooling_time;//!< The total time needed to cool down to the required temperature.
doublehighest_temperature;//!< The upper temperature from which cooling starts.
};
/*!
* Get the standby temperature of an extruder train
* \param extruder the extruder train for which to get the standby tmep
* \return the standby temp
*/
doublegetStandbyTemp(intextruder)
{
returnconfig_per_extruder[extruder].standby_temp;
}
/*!
* Get the time it takes to heat up one degree celsius
*
* \param extruder the extruder train for which to get time it takes to heat up one degree celsius
* \param during_printing whether the heating takes time during printing or when idle
* \return the time it takes to heat up one degree celsius
enabled&=storage.max_print_height_second_to_last_extruder>=0;//Maybe it turns out that we don't need a prime tower after all because there are no layer switches.
intn_patterns=2;// alternating patterns between layers
intinfill_overlap=60;// so that it can't be zero; EDIT: wtf?
intextra_infill_shift=0;
int64_tz=0;// (TODO) because the prime tower stores the paths for each extruder for once instead of generating each layer, we don't know the z position
floatflow=0.0001;// force this path being interpreted as an extrusion path, so that no Z hop will occur (TODO: really separately handle travel and extrusion moves)
first_layer_outline=first_layer_outline.unionPolygons();//To guard against overlapping outlines, which would produce holes according to the even-odd rule.
// || || ||[]|| > expand to fit an extra brim line
// |+-+| |+--+|
// +---+ +----+
Polygonsmodel_brim_covered_area=first_layer_outline.offset(primary_extruder_skirt_brim_line_width*(primary_line_count+primary_line_count%2),ClipperLib::jtRound);// always leave a gap of an even number of brim lines, so that it fits if it's generating brim from both sides
if(outside_only)
{// don't remove support within empty holes where no brim is generated.
if(skirt_brim_number+1>=primary_line_count&&length>0&&length<primary_extruder_minimal_length)//Make brim or skirt have more lines when total length is too small.
// generate areas where to make extra brim for the shields
// avoid gap in the middle
// V
// +---+ +----+
// |+-+| |+--+|
// || || ||[]|| > expand to fit an extra brim line
// |+-+| |+--+|
// +---+ +----+
constint64_tprimary_skirt_brim_width=(primary_line_count+primary_line_count%2)*primary_extruder_skirt_brim_line_width;// always use an even number, because we will fil the area from both sides
* Generates the insets / perimeters for all parts in a layer.
*
* Note that the second inset gets offsetted by WallsComputation::line_width_0 instead of the first,
* which leads to better results for a smaller WallsComputation::line_width_0 than WallsComputation::line_width_x and when printing the outer wall last.
*
* \param layer The layer for which to generate the insets.
*/
voidgenerateInsets(SliceLayer*layer);
private:
/*!
* Generates the insets / perimeters for a single layer part.
*
* \param part The part for which to generate the insets.
* This is the main function for Neith / Weaving / WirePrinting / Webbed printing.
* Creates a wireframe for the model consisting of horizontal 'flat' parts and connections between consecutive flat parts consisting of UP moves and diagonally DOWN moves.
*
* \param object The object for which to create a wireframe print
* \param commandSocket the commandSocket
* \param objects The objects for which to create a wireframe print
tmp<<"M227 S"<<(getSettingInMicrons("retraction_amount")*2560/1000)<<" P"<<(getSettingInMicrons("retraction_amount")*2560/1000);// TODO: put hard coded value in a variable with an explanatory name (and make var a parameter, and perhaps even a setting?)
//Optimize the pointList, skip each point we could already reach by not crossing a boundary. This smooths out the path and makes it skip any unneeded corners.
static_assert(sizeof(PrintFeatureType)==1,"To be compatible with the Cura frontend code PrintFeatureType needs to be of size 1");
//! Reference to the private data of the CommandSocket used to send the data to the front end.
CommandSocket::Private&_cs_private_data;
//! Keeps track of the current layer number being processed. If layer number is set to a different value, the current data is flushed to CommandSocket.
int_layer_nr;
intextruder;
PointTypedata_point_type;
std::vector<PrintFeatureType>line_types;//!< Line types for the line segments stored, the size of this vector is N.
std::vector<float>line_widths;//!< Line widths for the line segments stored, the size of this vector is N.
std::vector<float>points;//!< The points used to define the line segments, the size of this vector is D*(N+1) as each line segment is defined from one point to the next. D is the dimensionality of the point.
* Convert and add a point to the points buffer, each point being represented as two consecutive floats. All members adding a 2D point to the data should use this function.
*/
voidaddPoint2D(Pointpoint)
{
points.push_back(INT2MM(point.X));
points.push_back(INT2MM(point.Y));
last_point=point;
}
/*!
* Implements the functionality of adding a single 2D line segment to the path data. All member functions adding a 2D line segment should use this functions.
cura::proto::Slice*slice=dynamic_cast<cura::proto::Slice*>(message.get());// See if the message is of the message type Slice; returns nullptr otherwise
meshgroup->meshes.push_back(extruder_train);//Construct a new mesh (with the corresponding extruder train as settings parent object) and put it into MeshGroup's mesh list.
staticCommandSocket*instance;//!< May be a nullptr in case it hasn't been instantiated.
CommandSocket();//!< The single constructor is known only privately, since this class is similar to a singleton class (except the single object doesn't need to be instantiated)
public:
staticCommandSocket*getInstance();//!< Get the CommandSocket instance, or nullptr if it hasn't been instantiated.
staticvoidinstantiate();//!< Instantiate the CommandSocket.
staticboolisInstantiated();//!< Check whether the singleton is instantiated
/*!
* Connect with the GUI
* This creates and initialises the arcus socket and then continues listening for messages.
* \param ip string containing the ip to connect with
//The GCodeExport class writes the actual GCode. This is the only class that knows how GCode looks and feels.
// Any customizations on GCodes flavors are done in this class.
classGCodeExport
classGCodeExport:publicNoCopy
{
private:
structExtruderTrainAttributes
{
Point3prime_pos;//!< The location this nozzle is primed before printing
boolprime_pos_is_abs;//!< Whether the prime position is absolute, rather than relative to the last given position
boolis_primed;//!< Whether this extruder has currently already been primed in this print
boolis_used;//!< Whether this extruder train is actually used during the printing of all meshgroups
intnozzle_size;//!< The nozzle size label of the nozzle (e.g. 0.4mm; irrespective of tolerances)
Pointnozzle_offset;
charextruderCharacter;
std::stringmaterial_guid;//!< The GUID for the material used by this extruder
std::stringstart_code;
std::stringend_code;
doublefilament_area;//!< in mm^2 for non-volumetric, cylindrical filament
doubletotalFilament;//!< total filament used per extruder in mm^3
intcurrentTemperature;
intinitial_temp;//!< Temperature this nozzle needs to be at the start of the print.
doubleretraction_e_amount_current;//!< The current retracted amount (in mm or mm^3), or zero(i.e. false) if it is not currently retracted (positive values mean retracted amount, so negative impact on E values)
doubleretraction_e_amount_at_e_start;//!< The ExtruderTrainAttributes::retraction_amount_current value at E0, i.e. the offset (in mm or mm^3) from E0 to the situation where the filament is at the tip of the nozzle.
doubleprime_volume;//!< Amount of material (in mm^3) to be primed after an unretration (due to oozing and/or coasting)
doublelast_retraction_prime_speed;//!< The last prime speed (in mm/s) of the to-be-primed amount
std::deque<double>extruded_volume_at_previous_n_retractions;// in mm^3
* \note After GCodeExport::writeMove(Point, double, double) has been called currentPosition.z coincides with this value
*/
intcurrent_layer_z;
intisZHopped;//!< The amount by which the print head is currently z hopped, or zero if it is not z hopped. (A z hop is used during travel moves to avoid collision with other layer parts)
intcurrent_extruder;
intcurrentFanSpeed;
EGCodeFlavorflavor;
std::stringpreSwitchExtruderCode[MAX_EXTRUDERS];
std::stringpostSwitchExtruderCode[MAX_EXTRUDERS];
doubletotalFilament[MAX_EXTRUDERS];// in mm^3
doublefilament_diameter[MAX_EXTRUDERS];// in mm^3
doubletotalPrintTime;
doubletotalPrintTime;//!< The total estimated print time in seconds
TimeEstimateCalculatorestimateCalculator;
boolis_volumatric;
boolfirmware_retract;//!< whether retractions are done in the firmware, or hardcoded in E values.
unsignedintlayer_nr;//!< for sending travel data
intinitial_bed_temp;//!< bed temperature at the beginning of the print.
protected:
/*!
* Convert an E value to a value in mm (if it wasn't already in mm) for the current extruder.
*
* E values are either in mm or in mm^3
* The current extruder is used to determine the filament area to make the conversion.
*
* \param e the value to convert
* \return the value converted to mm
*/
doubleeToMm(doublee);
/*!
* Convert a volume value to an E value (which might be volumetric as well) for the current extruder.
*
* E values are either in mm or in mm^3
* The current extruder is used to determine the filament area to make the conversion.
*
* \param mm3 the value to convert
* \return the value converted to mm or mm3 depending on whether the E axis is volumetric
*/
doublemm3ToE(doublemm3);
/*!
* Convert a distance value to an E value (which might be linear/distance based as well) for the current extruder.
*
* E values are either in mm or in mm^3
* The current extruder is used to determine the filament area to make the conversion.
*
* \param mm the value to convert
* \return the value converted to mm or mm3 depending on whether the E axis is volumetric
*/
doublemmToE(doublemm);
public:
GCodeExport();
~GCodeExport();
/*!
* Get the gcode file header (e.g. ";FLAVOR:UltiGCode\n")
*
* \param print_time The total print time in seconds of the whole gcode (if known)
* \param filament_used The total mm^3 filament used for each extruder or a vector of the wrong size of unknown
* \param mat_ids The material GUIDs for each material.
std::vector<GCodePath>paths;//!< The paths planned for this extruder
std::list<NozzleTempInsert>inserts;//!< The nozzle temperature command inserts, to be inserted in between paths
intextruder;//!< The extruder used for this paths in the current plan.
doubleheated_pre_travel_time;//!< The time at the start of this ExtruderPlan during which the head travels and has a temperature of initial_print_temperature
doubleinitial_printing_temperature;//!< The required temperature at the start of this extruder plan.
doubleprinting_temperature;//!< The normal temperature for printing this extruder plan. That start and end of this extruder plan may deviate because of the initial and final print temp
std::optional<std::list<NozzleTempInsert>::iterator>printing_temperature_command;//!< The command to heat from the printing temperature of this extruder plan to the printing temperature of the next extruder plan (if it has the same extruder).
std::optional<double>prev_extruder_standby_temp;//!< The temperature to which to set the previous extruder. Not used if the previous extruder plan was the same extruder.
TimeMaterialEstimatesestimates;//!< Accumulated time and material estimates for all planned paths within this extruder plan.
public:
GCodePathConfig*config;
boolretract;
intextruder;
std::vector<Point>points;
booldone;//Path is finished, no more moves should be added, and a new path should be started instead of any appending done to this one.
/*!
* Simple contructor.
*
* \warning Doesn't set the required temperature yet.
*
* \param extruder The extruder number for which this object is a plan.
* \param start_position The position the head is when this extruder plan starts
* Compute naive time estimates (without accounting for slow down at corners etc.) and naive material estimates (without accounting for MergeInfillLines)
* and store them in each ExtruderPlan and each GCodePath.
*
* \return the total estimates of this layer
*/
TimeMaterialEstimatescomputeNaiveTimeEstimates();
};
//The GCodePlanner class stores multiple moves that are planned.
// It facilitates the combing to keep the head inside the print.
// It also keeps track of the print time estimate for this planning so speed adjustments can be made for the minimal-layer-time.
classGCodePlanner
{
private:
GCodeExport&gcode;
classLayerPlanBuffer;// forward declaration to prevent circular dependency
/*!
* The GCodePlanner class stores multiple moves that are planned.
*
*
* It facilitates the combing to keep the head inside the print.
* It also keeps track of the print time estimate for this planning so speed adjustments can be made for the minimal-layer-time.
*
* A GCodePlanner is also knows as a 'layer plan'.
*
*/
classGCodePlanner:publicNoCopy
{
friendclassLayerPlanBuffer;
friendclassGCodePlannerTest;
private:
SliceDataStorage&storage;//!< The polygon data obtained from FffPolygonProcessor
intlayer_nr;//!< The layer number of this layer plan
intis_initial_layer;//!< Whether this is the first layer (which might be raft)
intz;
intlayer_thickness;
Pointstart_position;
PointlastPosition;
std::vector<GCodePath>paths;
std::vector<ExtruderPlan>extruder_plans;//!< should always contain at least one ExtruderPlan
intlast_extruder_previous_layer;//!< The last id of the extruder with which was printed in the previous layer
SettingsBaseVirtual*last_planned_extruder_setting_base;//!< The setting base of the last planned extruder.
boolwas_inside;//!< Whether the last planned (extrusion) move was inside a layer part
boolis_inside;//!< Whether the destination of the next planned travel move is inside a layer part
Polygonscomb_boundary_inside;//!< The boundary within which to comb, or to move into when performing a retraction.
* Either create a new path with the given config or return the last path if it already had that config.
* If GCodePlanner::forceNewPathStart has been called a new path will always be returned.
*
* \param config The config used for the path returned
* \param space_fill_type The type of space filling which this path employs
* \param flow (optional) A ratio for the extrusion speed
* \param spiralize Whether to gradually increase the z while printing. (Note that this path may be part of a sequence of spiralized paths, forming one polygon)
* \return A path with the given config which is now the last path in GCodePlanner::paths
* \warning A nonretracted move is introduced so that the LayerPlanBuffer classifies this move as an extrusion move.
*/
voidplanPrime();
/*!
* Add an extrusion move to a certain point, optionally with a different flow than the one in the \p config.
*
* \param p The point to extrude to
* \param config The config with which to extrude
* \param space_fill_type Of what space filling type this extrusion move is a part
* \param flow A modifier of the extrusion width which would follow from the \p config
* \param spiralize Whether to gradually increase the z while printing. (Note that this path may be part of a sequence of spiralized paths, forming one polygon)
* Add polygon to the gcode starting at vertex \p startIdx
* \param polygon The polygon
* \param startIdx The index of the starting vertex of the \p polygon
* \param config The config with which to print the polygon lines
* \param wall_overlap_computation The wall overlap compensation calculator for each given segment (optionally nullptr)
* \param wall_0_wipe_dist The distance to travel along the polygon after it has been laid down, in order to wipe the start and end of the wall together
* \param spiralize Whether to gradually increase the z height from the normal layer height to the height of the next layer over this polygon
* When \p spiralize is true, each polygon will gradually increase from a z corresponding to this layer to the z corresponding to the next layer.
* Doing this for each polygon means there is a chance for the print head to crash into already printed parts,
* but doing it for the last polygon only would mean you are printing half of the layer in non-spiralize mode,
* while each layer starts with a different part.
* Two towers would result in alternating spiralize and non-spiralize layers.
*
* \param polygons The polygons
* \param config The config with which to print the polygon lines
* \param wall_overlap_computation The wall overlap compensation calculator for each given segment (optionally nullptr)
* \param z_seam_type The seam type / poly start optimizer
* \param z_seam_pos The location near where to start each part in case \p z_seam_type is 'back'
* \param wall_0_wipe_dist The distance to travel along each polygon after it has been laid down, in order to wipe the start and end of the wall together
* \param spiralize Whether to gradually increase the z height from the normal layer height to the height of the next layer over each polygon printed
* Compute naive time estimates (without accounting for slow down at corners etc.) and naive material estimates (without accounting for MergeInfillLines)
* and store them in each ExtruderPlan and each GCodePath.
*
* \warning This function recomputes values which are already computed if you've called processFanSpeedAndMinimalLayerTime
*
* \return the total estimates of this layer
*/
TimeMaterialEstimatescomputeNaiveTimeEstimates();
/*!
* Write the planned paths to gcode
*
* \param gcode The gcode to write the planned paths to
*/
voidwriteGCode(GCodeExport&gcode);
/*!
* Complete all GcodePathConfigs by
* - altering speeds to conform to speed_print_layer_0 and
* speed_travel_layer_0
* - setting the layer_height (and thereby computing the extrusionMM3perMM)
*/
voidcompleteConfigs();
/*!
* Interpolate between the initial layer speeds and the eventual speeds.
*/
voidprocessInitialLayersSpeedup();
/*!
* Whether the current retracted path is to be an extruder switch retraction.
* This function is used to avoid a G10 S1 after a G10.
*
* \param gcode The gcode to write the planned paths to
* \param extruder_plan_idx The index of the current extruder plan
* \param path_idx The index of the current retracted path
* \return Whether the path should be an extgruder switch retracted path
* Writes a path to GCode and performs coasting, or returns false if it did nothing.
*
* Coasting replaces the last piece of an extruded path by move commands and uses the oozed material to lay down lines.
*
* \param gcode The gcode to write the planned paths to
* \param extruder_plan_idx The index of the current extruder plan
* \param path_idx The index into GCodePlanner::paths for the next path to be written to GCode.
* \param layerThickness The height of the current layer.
* \param coasting_volume The volume otherwise leaked during a normal move.
* \param coasting_speed The speed at which to move during move-coasting.
* \param coasting_min_volume The minimal volume a path should have (before starting to coast) which builds up enough pressure to ooze as much as \p coasting_volume.
* \return Whether any GCode has been written for the path.
* Applying speed corrections for minimal layer times and determine the fanSpeed.
*/
voidprocessFanSpeedAndMinimalLayerTime();
/*!
* Add a travel move to the layer plan to move inside the current layer part by a given distance away from the outline.
* This is supposed to be called when the nozzle is around the boundary of a layer part, not when the nozzle is in the middle of support, or in the middle of the air.
*
* \param distance The distance to the comb boundary after we moved inside it.
Polygonsfirst_concentric_wall=in_outline.offset(outline_offset-line_distance+infill_line_width/2);// - infill_line_width / 2 cause generateConcentricInfill expects [outline] to be the outer most polygon instead of the outer outline
intscanline_idx0=(p0.X+((p0.X>0)?-1:-lineSpacing))/lineSpacing;// -1 cause a linesegment on scanline x counts as belonging to scansegment x-1 ...
intscanline_idx1=(p1.X+((p1.X>0)?-1:-lineSpacing))/lineSpacing;// -linespacing because a line between scanline -n and -n-1 belongs to scansegment -n-1 (for n=positive natural number)
intdirection=1;
if(p0.X>p1.X)
{
direction=-1;
scanline_idx1+=1;// only consider the scanlines in between the scansegments
}elsescanline_idx0+=1;// only consider the scanlines in between the scansegments
zigzag_connector_processor.registerVertex(p0);// always adds the first point to ZigzagConnectorProcessorEndPieces::first_zigzag_connector when using a zigzag infill type
// TODO: how to make sure it always adds the shortest line? (in order to prevent overlap with the zigzag connectors)
// note: this is already a problem for normal infill, but hasn't really cothered anyone so far.
p0=p1;
continue;
}
if(xMin>xMax){xMin=p0.X;xMax=p1.X;}
intscanline_idx0=(p0.X+((p0.X>0)?-1:-lineSpacing))/lineSpacing;// -1 cause a linesegment on scanline x counts as belonging to scansegment x-1 ...
intscanline_idx1=(p1.X+((p1.X>0)?-1:-lineSpacing))/lineSpacing;// -linespacing because a line between scanline -n and -n-1 belongs to scansegment -n-1 (for n=positive natural number)
intscanline_idx0;
intscanline_idx1;
// this way of handling the indices takes care of the case where a boundary line segment ends exactly on a scanline:
// in case the next segment moves back from that scanline either 2 or 0 scanline-boundary intersections are created
// otherwise only 1 will be created, counting as an actual intersection
intdirection=1;
if(p0.X>p1.X)
if(p0.X<p1.X)
{
scanline_idx0=computeScanSegmentIdx(p0.X-shift,line_distance)+1;// + 1 cause we don't cross the scanline of the first scan segment
scanline_idx1=computeScanSegmentIdx(p1.X-shift,line_distance);// -1 cause the vertex point is handled in the next segment (or not in the case which looks like >)
}
else
{
direction=-1;
scanline_idx1+=1;// only consider the scanlines in between the scansegments
}elsescanline_idx0+=1;// only consider the scanlines in between the scansegments
scanline_idx0=computeScanSegmentIdx(p0.X-shift,line_distance);// -1 cause the vertex point is handled in the previous segment (or not in the case which looks like >)
scanline_idx1=computeScanSegmentIdx(p1.X-shift,line_distance)+1;// + 1 cause we don't cross the scanline of the first scansegment
if(i<firstBoundarySegment.size()-1||!firstBoundarySegmentEndsInEven||connect_zigzags)// only add last element if connect_zigzags or boundary segment ends in uneven scanline
intscanline_idx0=(p0.X+((p0.X>0)?-1:-lineSpacing))/lineSpacing;// -1 cause a linesegment on scanline x counts as belonging to scansegment x-1 ...
intscanline_idx1=(p1.X+((p1.X>0)?-1:-lineSpacing))/lineSpacing;// -linespacing because a line between scanline -n and -n-1 belongs to scansegment -n-1 (for n=positive natural number)
intdirection=1;
if(p0.X>p1.X)
{
direction=-1;
scanline_idx1+=1;// only consider the scanlines in between the scansegments
}elsescanline_idx0+=1;// only consider the scanlines in between the scansegments
staticconstexprintperimeter_gaps_extra_offset=15;// extra offset so that the perimeter gaps aren't created everywhere due to rounding errors
EFillMethodpattern;//!< the space filling pattern of the infill to generate
constPolygons&in_outline;//!< a reference polygon for getting the actual area within which to generate infill (see outline_offset)
intoutline_offset;//!< Offset from Infill::in_outline to get the actual area within which to generate infill
intinfill_line_width;//!< The line width of the infill lines to generate
intline_distance;//!< The distance between two infill lines / polygons
intinfill_overlap;//!< the distance by which to overlap with the actual area within which to generate infill
doublefill_angle;//!< for linear infill types: the angle of the infill lines (or the angle of the grid)
int64_tz;//!< height of the layer for which we generate infill
int64_tshift;//!< shift of the scanlines in the direction perpendicular to the fill_angle
Polygons*perimeter_gaps;//!< (optional output) The areas in between consecutive insets when Concentric infill is used.
boolconnected_zigzags;//!< (ZigZag) Whether endpieces of zigzag infill should be connected to the nearest infill line on both sides of the zigzag connector
booluse_endpieces;//!< (ZigZag) Whether to include endpieces: zigzag connector segments from one infill line to itself
* Convert a mapping from scanline to line_segment-scanline-intersections (\p cut_list) into line segments, using the even-odd rule
* \param result (output) The resulting lines
* \param rotation_matrix The rotation matrix (un)applied to enforce the angle of the infill
* \param scanline_min_idx The lowest index of all scanlines crossing the polygon
* \param line_distance The distance between two lines which are in the same direction
* \param boundary The axis aligned boundary box within which the polygon is
* \param cut_list A mapping of each scanline to all y-coordinates (in the space transformed by rotation_matrix) where the polygons are crossing the scanline
* \param total_shift total shift of the scanlines in the direction perpendicular to the fill_angle.
* Generates the lines of subdivision of the specific cube at the specific layer. It recursively calls itself, so it ends up drawing all the subdivision lines of sub-cubes too.
* Generates the lines of subdivision of the specific cube at the specific layer. It recursively calls itself, so it ends up drawing all the subdivision lines of sub-cubes too.
* \param z the specified layer height
* \param result (output) The resulting lines
* \param directional_line_groups Array of 3 times a polylines. Used to keep track of line segments that are all pointing the same direction for line segment combining
* Adds the defined line to the specified polygons. It assumes that the specified polygons are all parallel lines. Combines line segments with touching ends closer than epsilon.
* \param[out] group the polygons to add the line to
unsignedintdepth;//!< the recursion depth of the cube (0 is most recursed)
Point3center;//!< center location of the cube in absolute coordinates
SubDivCube*children[8]={nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr};//!< pointers to this cube's eight octree children
staticstd::vector<CubeProperties>cube_properties_per_recursion_step;//!< precomputed array of basic properties of cubes based on recursion depth.
staticdoubleradius_multiplier;//!< multiplier for the bounding radius when determining if a cube should be subdivided
staticPoint3Matrixrotation_matrix;//!< The rotation matrix to get from axis aligned cubes to cubes standing on a corner point aligned with the infill_angle
staticPointMatrixinfill_rotation_matrix;//!< Horizontal rotation applied to infill
staticint32_tradius_addition;//!< addition to the bounding radius when determining if a cube should be subdivided
zigzag_connector.clear();// we're starting a new (odd) zigzag connector, so clear the old one
if(!this_scanline_is_even)// we are either in an end piece or an boundary segment starting in an odd scanline
{// only when a boundary segment starts in an odd scanline it depends on whether it ends in an odd scanline for whether this segment should be included or not
zigzag_connector.clear();// we're starting a new (odd) zigzag connector, so clear the old one
if(!this_scanline_is_even)// we are either in an end piece or an boundary segment starting in an odd scanline
{// only when a boundary segment starts in an odd scanline it depends on whether it ends in an odd scanline for whether this segment should be included or not
{// when a boundary segments starts in an even scanline it's either a normal zigzag connector or an endpiece to be included
// note that for ZigzagConnectorProcessorDisconnectedEndPieces only the last line segment from a boundary vertex to a scanline-boundary intersection is omitted
addLine(last_connector_point,vertex);
}
else
{// it's yet unclear whether the line segment should be included, so we store it until we know
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef INSET_H
#define INSET_H
#include"sliceDataStorage.h"
namespacecura
{
/*!
* Generates the insets / perimeters for a single layer part.
*
* \param part The part for which to generate the insets.
* \param line_width_0 Line width of the outer wall
* \param line_width_x Line width of other walls
* \param insetCount The number of insets to to generate
* \param avoidOverlappingPerimeters Whether to remove the parts of two consecutive perimeters where they have overlap (and store the gaps thus created in the \p part)
* Generates the insets / perimeters for all parts in a layer.
*
* \param layer The layer for which to generate the insets.
* \param line_width_0 Line width of the outer wall
* \param line_width_x Line width of other walls
* \param insetCount The number of insets to to generate
* \param avoidOverlappingPerimeters Whether to remove the parts of two consecutive perimeters where they have overlap (and store the gaps thus created in the \p part)
logAlways(" -v\n\tIncrease the verbose level (show log messages).\n");
logAlways(" -p\n\tLog progress information.\n");
logAlways(" -j\n\tLoad settings.def.json file to register all settings and their defaults.\n");
logAlways(" -s <setting>=<value>\n\tSet a setting to a value for the last supplied object, \n\textruder train, or general settings.\n");
logAlways(" -l <model_file>\n\tLoad an STL model. \n");
logAlways(" -g\n\tSwitch setting focus to the current mesh group only.\n\tUsed for one-at-a-time printing.\n");
logAlways(" -e<extruder_nr>\n\tSwitch setting focus to the extruder train with the given number.\n");
logAlways(" --next\n\tGenerate gcode for the previously supplied mesh group and append that to \n\tthe gcode of further models for one-at-a-time printing.\n");
logAlways(" -o <output_file>\n\tSpecify a file to which to write the generated gcode.\n");
logAlways("\n");
logAlways("The settings are appended to the last supplied object:\n");
logAlways("In order to load machine definitions from custom locations, you need to create the environment variable CURA_ENGINE_SEARCH_PATH, which should contain all search paths delimited by a (semi-)colon.\n");
logAlways("\n");
}
//Signal handler for a "floating point exception", which can also be integer division by zero errors.
std::vector<uint32_t>connected_faces;//!< list of the indices of connected faces
MeshVertex(Point3p):p(p){}//!< doesn't set connected_faces
MeshVertex(Point3p):p(p){connected_faces.reserve(8);}//!< doesn't set connected_faces
};
/*! A MeshFace is a 3 dimensional model triangle with 3 points. These points are already converted to integers
@@ -54,29 +57,52 @@ See MeshFace for the specifics of how/when faces are connected.
classMesh:publicSettingsBase// inherits settings
{
//! The vertex_hash_map stores a index reference of each vertex for the hash of that location. Allows for quick retrieval of points with the same location.
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef MODELFILE_H
#define MODELFILE_H
/**
modelFile contains the model loaders for the slicer. The model loader turns any format that it can read into a list of triangles with 3 X/Y/Z points.
The format returned is a Model class with an array of faces, which have integer points with a resolution of 1 micron. Giving a maximum object size of 4 meters.
**/
#include"../mesh.h"
//A PrintObject is a 3D model with 1 or more 3D meshes.
classPrintObject:publicSettingsBase
{
public:
std::vector<Mesh>meshes;
PrintObject(SettingsBase*settings_base)
:SettingsBase(settings_base)
{
}
Point3min()//! minimal corner of bounding box
{
if(meshes.size()<1)
returnPoint3(0,0,0);
Point3ret=meshes[0].min();
for(unsignedinti=1;i<meshes.size();i++)
{
Point3v=meshes[i].min();
ret.x=std::min(ret.x,v.x);
ret.y=std::min(ret.y,v.y);
ret.z=std::min(ret.z,v.z);
}
returnret;
}
Point3max()//! maximal corner of bounding box
{
if(meshes.size()<1)
returnPoint3(0,0,0);
Point3ret=meshes[0].max();
for(unsignedinti=1;i<meshes.size();i++)
{
Point3v=meshes[i].max();
ret.x=std::max(ret.x,v.x);
ret.y=std::max(ret.y,v.y);
ret.z=std::max(ret.z,v.z);
}
returnret;
}
voidclear()
{
for(Mesh&m:meshes)
m.clear();
}
voidoffset(Point3offset)
{
for(Mesh&m:meshes)
for(MeshVertex&v:m.vertices)
v.p+=offset;
}
voidfinalize()
{
// If a mesh position was given, put the mesh at this position in 3D space.
fullLayer=fullLayer.unionPolygons(layer1->parts[p1].outline.offset(20));// TODO: put hard coded value in a variable with an explanatory name (and make var a parameter, and perhaps even a setting?)
}
continue;
}
fullLayer=fullLayer.offset(-20);// TODO: put hard coded value in a variable with an explanatory name (and make var a parameter, and perhaps even a setting?)
memset(picked,false,sizeof(bool)*polygons.size());/// initialized as falses
for(unsignedinti_polygon=0;i_polygon<polygons.size();i_polygon++)/// find closest point to initial starting point within each polygon +initialize picked
for(PolygonRefpoly:polygons)/// find closest point to initial starting point within each polygon +initialize picked
memset(picked,false,sizeof(bool)*polygons.size());/// initialized as falses
for(unsignedinti_polygon=0;i_polygon<polygons.size();i_polygon++)/// find closest point to initial starting point within each polygon +initialize picked
for(unsignedintpoly_idx=0;poly_idx<polygons.size();poly_idx++)/// find closest point to initial starting point within each polygon +initialize picked
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff
Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.