Comparar commits

..

599 Commits

Autor SHA1 Mensagem Data
Tim Kuipers d36934e35b bugfix: sliceDataStorage.meshes reallocation due to size change 2015-08-07 15:32:19 +02:00
Tim Kuipers 41f7258e25 bugfix: retraction count max 2015-08-05 14:30:57 +02:00
Tim Kuipers 24cb4fbb36 bugfix for combined infill lines 2015-07-28 14:00:51 +02:00
Tim Kuipers 6fa022013d bugfix: infill overlap for 100% infill 2015-07-22 15:30:45 +02:00
Tim Kuipers 9274846970 merge 2015-07-22 13:03:54 +02:00
Tim Kuipers 9050f8da53 cleanup debug shite last bugfix 2015-07-20 14:37:59 +02:00
Tim Kuipers f7039848c2 bugfix: remove degenerate verts: verts connected to overlapping line segments 2015-07-20 14:18:14 +02:00
Arjen Hiemstra d4e27d8bbb Force using clang libc++ on MacOSX to prevent issues with linking 2015-07-16 15:58:00 +02:00
Tim Kuipers 13f5ebe9d7 bugfix: empty arcus messages 2015-07-09 14:08:29 +02:00
Tim Kuipers db787c7cab Merge branch '15.06' of https://github.com/Ultimaker/CuraEngine into 15.06 2015-07-08 13:15:47 +02:00
Tim Kuipers 21a04beb25 bugfix & feature: insets support smaller outer wall line width 2015-07-08 13:15:35 +02:00
Arjen Hiemstra 1565e979ec Statically link libstdc++ on Linux to prevent issues with newer libstc++
Contributes to Ultimaker/Uranium#42
2015-07-07 12:14:24 +02:00
Tim Kuipers 927395630b 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 2015-07-02 16:13:32 +02:00
Tim Kuipers 79d164b2d4 bugfix: extrusion per mm to extrusion mm3 per mm is_volumetric set 2015-06-30 17:18:00 +02:00
Tim Kuipers 3cfbc20d75 bugfix: speed compensation for stable feedrate also changed the extrusion per mm 2015-06-30 14:48:59 +02:00
Tim Kuipers fcaa7d71b7 bugfix: speed compensation for stable feedrate also changed the extrusion per mm 2015-06-30 14:44:39 +02:00
Tim Kuipers 423516ddd9 bugfix+refactor: extrusion always per mm3 2015-06-30 14:34:29 +02:00
Tim Kuipers afc3088427 bugfix: no support for too low models 2015-06-24 14:28:10 +02:00
Tim Kuipers f1ac6c05b1 bugfix: no support for too low models 2015-06-24 14:27:49 +02:00
Arjen Hiemstra d965f1b7e5 Also send infill polygon data to the UI, not just oultines
Contributes to Ultimaker/Cura#52
2015-06-16 12:35:50 +02:00
Arjen Hiemstra 172722c63b Also send line width to the UI along with the polygon's points
Contributes to Ultimaker/Cura#52
2015-06-16 12:34:49 +02:00
Arjen Hiemstra 702564f5c6 Add support for sending layer height and thickness to the UI
Contributes to Ultimaker/Cura#52
2015-06-16 12:30:39 +02:00
Arjen Hiemstra 329d85a9aa Properly reset the extrusion amount between slicing tasks.
This fixes an issue where extrusion amount would be ridiculously high
since it used the old value for a new slicing task.
2015-06-15 13:36:40 +02:00
Arjen Hiemstra 0a31584760 Properly initialize extrusion_volume_per_mm variable
This fixes issues with volumetric mode.

Contributes to Asana issue 36101603778517
2015-06-09 11:13:53 +02:00
Tim Kuipers 01f1568dda bugfix: reset filament at new print 2015-05-26 12:33:13 +02:00
Arjen Hiemstra 883b0c2efc Add missing <string> include so we can build on MacOSX
Contributes to Ultimaker/Uranium#41
2015-05-18 13:55:34 +02:00
Arjen Hiemstra 57c91c35b0 Install the created executable
This makes it easier to build a combined setup of all things in
Cura.

Contributes to Ultimaker/Uranium#41
2015-05-18 13:54:02 +02:00
Tim Kuipers 00a2a2a107 bugfix gcode.writeMove(x,y,z) where z didn't get processed. = bug for wireprinting 2015-05-18 11:13:14 +02:00
Arjen Hiemstra eb164c8a0e Fix support generation by making sure "True" is also recognised as true 2015-05-15 17:48:43 +02:00
daid 61c4ffd982 test does not build on windows, remove it for now so we can build a release. 2015-05-07 16:39:57 +02:00
daid 6df992580a Fix #193 2015-05-06 09:24:14 +02:00
Arjen Hiemstra f4af9ec780 Fix merge issues 2015-04-30 11:01:45 +02:00
Arjen Hiemstra 81dc71a2de Merge branch 'PinkUnicorn'
* PinkUnicorn: (286 commits)
  some lil testing code for findSmallestConnection
  findClosestConnection between two polygons
  Account for volumatric extrusion.
  made the comb boundary larger, so that (barely) connected parts still use the comb boundary
  moved to polygonUtils: findClosest to polygon etc.
  setting fill_perimeter_gaps
  Do not write temperature commands for UltiGCode.
  bugfix: no abs(.) in centerOfMass!
  operator == already exported by Clipper!
  lil rewrite
  deleted my buggy polygon.inside() function
  debugged my polygon.inside a bit and added the one from gsmith-to https://github.com/Ultimaker/CuraEngine/pull/189
  better polygon.inside testing
  Fix the machine offset for PU.
  included BucketGrid3D in pathOrderOptimizer
  lil bugifxes for bucketGrid2D
  2D hash grid class for finding nearby items
  made zigzags the default suppoirt type
  Properly rename some dual extrusion settings.
  bugfix center of mass when center.x < 0 etc.
  ...
2015-04-30 10:45:33 +02:00
Tim Kuipers 9f36330fe6 some lil testing code for findSmallestConnection 2015-04-30 10:03:24 +02:00
Tim Kuipers f73094179e Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-30 09:26:11 +02:00
Tim Kuipers a430281b46 findClosestConnection between two polygons 2015-04-30 09:25:58 +02:00
daid 57820afdfa Account for volumatric extrusion. 2015-04-29 18:00:40 +02:00
Tim Kuipers 8ed7d6e4d5 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-29 16:05:23 +02:00
Tim Kuipers c23701d7f1 made the comb boundary larger, so that (barely) connected parts still use the comb boundary 2015-04-29 15:12:45 +02:00
Tim Kuipers 8964454bf4 moved to polygonUtils: findClosest to polygon etc. 2015-04-29 15:12:03 +02:00
Tim Kuipers 153370bbcb setting fill_perimeter_gaps 2015-04-29 15:10:46 +02:00
daid ff28da5bde Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-29 14:48:31 +02:00
daid 2ea7a8724a Do not write temperature commands for UltiGCode. 2015-04-29 14:48:21 +02:00
Tim Kuipers d073dda5c4 bugfix: no abs(.) in centerOfMass! 2015-04-29 12:56:06 +02:00
Tim Kuipers 93be1b8d63 operator == already exported by Clipper! 2015-04-29 12:54:02 +02:00
Tim Kuipers 0991624234 lil rewrite 2015-04-29 12:19:36 +02:00
Tim Kuipers bc28971f10 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-29 12:17:41 +02:00
Tim Kuipers c98b6ba8a8 deleted my buggy polygon.inside() function 2015-04-29 12:17:28 +02:00
Tim Kuipers 600eed61fc debugged my polygon.inside a bit and added the one from gsmith-to https://github.com/Ultimaker/CuraEngine/pull/189 2015-04-29 12:16:51 +02:00
Tim Kuipers 0088c2e6ca better polygon.inside testing 2015-04-29 12:15:23 +02:00
daid cdf7628287 Fix the machine offset for PU. 2015-04-29 12:11:27 +02:00
Tim Kuipers 7b7e9eec24 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-29 11:53:51 +02:00
Tim Kuipers 326ba11c87 included BucketGrid3D in pathOrderOptimizer 2015-04-28 17:30:31 +02:00
Tim Kuipers eee41a6aee lil bugifxes for bucketGrid2D 2015-04-28 15:46:35 +02:00
Tim Kuipers 20fa95def8 2D hash grid class for finding nearby items 2015-04-28 14:25:22 +02:00
Tim Kuipers 43c3b11253 made zigzags the default suppoirt type 2015-04-28 14:24:23 +02:00
daid 7c708c1072 Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-28 11:50:48 +02:00
daid 33b287000c Properly rename some dual extrusion settings. 2015-04-28 11:50:39 +02:00
Tim Kuipers 97ed92d785 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-28 11:39:46 +02:00
Tim Kuipers 218a028dd6 bugfix center of mass when center.x < 0 etc. 2015-04-28 11:33:40 +02:00
daid a53977e49c Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-28 11:15:24 +02:00
daid 3c718af85e Only offset the model if the called filled in the proper settings. 2015-04-28 11:13:56 +02:00
Tim Kuipers ae3c113ca0 corrected default top/bottom thickness to what should result from inherit function at defaults 2015-04-28 11:11:09 +02:00
Tim Kuipers b3f3135157 test file for quick n dirty tests 2015-04-28 10:48:17 +02:00
Tim Kuipers 3d8e1d39d7 test file for quick n dirty tests 2015-04-28 10:45:02 +02:00
Tim Kuipers a7335a5caa better checking of whether we are inside a polygon 2015-04-28 10:41:41 +02:00
daid a2f88584bf Link pthread on unix oses. (Should be handled better, as protobuf actually needs pthreads, not the CuraEngine. But this works for now) 2015-04-28 09:49:51 +02:00
Tim Kuipers 61c3de631e put cpp files in namespace (for consistency) 2015-04-28 09:47:50 +02:00
Tim Kuipers 2aa72aa0c4 changed default initial layer thickness to 0.2mm 2015-04-28 09:27:29 +02:00
Tim Kuipers c2c7e4dac3 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-24 17:24:26 +02:00
Tim Kuipers 626eed9ecb retraction limiting per extruded material 2015-04-24 17:24:14 +02:00
Tim Kuipers e1420f661d added setting alternate_extra_perimeter 2015-04-24 16:25:40 +02:00
Tim Kuipers e8faa99a46 better terminal run commands 2015-04-24 16:24:33 +02:00
daid 8f2fe55f54 Update code_conventions.md 2015-04-24 13:40:45 +02:00
daid e587cf0bee Make code bit clearer. 2015-04-24 12:32:22 +02:00
daid 1fb0ed5c5a Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn
Conflicts:
	src/skin.cpp
2015-04-24 12:14:15 +02:00
daid 5163caed25 Simplyfly the sparse infill generation code. 2015-04-24 12:10:39 +02:00
Tim Kuipers bd90859055 bugfix: perimeterGaps were also used when skinPart was bridged and didn't have perimeters! 2015-04-24 12:01:04 +02:00
Tim Kuipers 50cdb76249 split skins into parts as skin_parts in the sliceDataStorage.SliceLayerPart 2015-04-24 10:46:53 +02:00
daid 36e7e2c4f4 Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-24 10:06:04 +02:00
daid c66ca18e1f Temp fix for the skin multiple line export bug. 2015-04-24 10:05:54 +02:00
Tim Kuipers f68a82eca4 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-24 09:45:29 +02:00
Tim Kuipers 24f74a733b moved perimeterGap generation into skin.cpp; lil skirt change; commented out extra perimeter at uneven layers 2015-04-24 09:45:22 +02:00
daid ae545a9ee9 Allow json file from commandline. 2015-04-23 14:51:23 +02:00
daid 45a4f2f28f Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-23 13:54:43 +02:00
daid b533629835 Somehow the tower_roof size becomes 0 sometimes. 2015-04-23 13:54:35 +02:00
Tim Kuipers 282442c00c setting: support bottom stair distance; also some description enhancements to support-type 2015-04-23 12:33:31 +02:00
Tim Kuipers 1a014c9b36 example run from terminal in README 2015-04-23 12:20:39 +02:00
Tim Kuipers 66385ed4bd example run from terminal in README 2015-04-23 12:10:16 +02:00
Tim Kuipers f6013a8683 quick hack for added mesh_postion_x y z to setting registry 2015-04-23 11:58:58 +02:00
Tim Kuipers 3b798fb593 load settings JSON before parsing command line arguments! 2015-04-23 11:43:44 +02:00
daid ab36feefbe Fix flavor name parsing. 2015-04-23 11:27:11 +02:00
Tim Kuipers a509e6af7e added cool_min_layer_time_fan_speed_max, skin_outline_count, xy_offset to settings 2015-04-23 11:18:21 +02:00
Tim Kuipers 607989c28e bugfix: perimeter gaps filled didnt skip topmost layer 2015-04-23 10:44:18 +02:00
Tim Kuipers a31c855141 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-23 10:22:10 +02:00
daid 6a288763b1 travel and extrude time where uninitialized. 2015-04-23 10:22:00 +02:00
Tim Kuipers 16d960d5b7 set machine defaults to UM2 (temporarily) 2015-04-23 10:21:52 +02:00
Tim Kuipers ed659ea663 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-23 10:20:22 +02:00
Tim Kuipers 71af3e1548 machine settings added 2015-04-23 10:20:07 +02:00
Tim Kuipers 999f90cc00 remark on skin+sparse computation 2015-04-23 10:19:47 +02:00
daid 51214f9dfd Disable error catching in debug. 2015-04-23 09:52:57 +02:00
daid aaa871157b Stop slicing if there are no layers (prevents crashes and lots of checks later on) 2015-04-23 09:15:57 +02:00
Tim Kuipers 488d74c950 commenting skirt, skin, infill 2015-04-22 16:42:46 +02:00
Tim Kuipers bf23980e57 fixing maxRetractions setting 2015-04-22 16:13:48 +02:00
Tim Kuipers b175265385 commenting wireprinting 2015-04-22 16:13:19 +02:00
Tim Kuipers 8403514604 removed bug in perimeterGaps infill, implemented extra perimeter at uneven layers (is always on! for now); implemented max retractions per x amont of material (not tested) 2015-04-22 15:02:35 +02:00
Tim Kuipers 9e1a2c674e Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-22 14:16:57 +02:00
daid cbe36a41c3 Fix support selection handling. 2015-04-22 14:05:19 +02:00
Tim Kuipers 14e7397a53 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-22 14:02:02 +02:00
daid abbda6cd88 Add sparse infill line distance so sparse infill works again. 2015-04-22 13:52:33 +02:00
Tim Kuipers 44411a45c7 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-22 13:51:52 +02:00
Tim Kuipers 79b2b36ecf start of implementation of max n retractions over a given part of filament 2015-04-22 13:51:48 +02:00
daid 7a05419def Add a bunch of missing settings, improve brim/skirt/raft handling in engine. 2015-04-22 13:46:04 +02:00
daid 8423d2ab6c Converted most of the settings. Some still missing in json. some logic is still missing (when raft/brim. When support or not) 2015-04-22 12:41:12 +02:00
daid 44ab7dd0cd Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-22 12:17:49 +02:00
daid e6f4851d00 More setting renames. 2015-04-22 12:17:42 +02:00
daid e3d89e9fae Fix another bunch of settings. Split the retraction speed into 2 optional settings. 2015-04-22 12:12:42 +02:00
Tim Kuipers 4623962a11 There is no spoon 2015-04-22 12:02:57 +02:00
daid 3c37901918 More setting renames. 2015-04-22 11:48:41 +02:00
Tim Kuipers b763469114 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-22 11:35:01 +02:00
Tim Kuipers 33e68d7534 skirt convex hull approximation 2015-04-22 11:34:57 +02:00
daid 903d0b3260 Instead of crashing, report back that we failed to open the json file. 2015-04-22 11:34:41 +02:00
daid 52ca544328 Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-22 11:22:40 +02:00
daid 80ada66e91 Start with renaming settings for the new setting registry. 2015-04-22 11:22:34 +02:00
daid 4e9bc9c955 add fdmprinter.json. 2015-04-22 11:22:08 +02:00
Tim Kuipers d406cd3fd1 import got lost 2015-04-22 10:47:51 +02:00
Tim Kuipers 0e375ca376 import typo 2015-04-22 10:28:25 +02:00
Tim Kuipers 6c4d758cd9 file convention changes 2015-04-22 10:26:56 +02:00
Tim Kuipers 1cd7c82c03 import typo 2015-04-22 10:26:26 +02:00
Tim Kuipers 641dd33d74 fill perimeter gaps only on topmost or bottom most layers 2015-04-22 10:26:01 +02:00
daid e48e4dea7b Start with renaming settings for the new setting registry. 2015-04-22 10:21:21 +02:00
daid 0aa163d84d Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-21 16:48:05 +02:00
daid c2a233db51 add rapidjason. 2015-04-21 16:47:56 +02:00
Tim Kuipers e90d3008c2 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-21 16:44:57 +02:00
Tim Kuipers 59879ba38f whoops accidentally made global function into class function 2015-04-21 16:43:58 +02:00
daid 266e280860 Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-21 16:38:11 +02:00
daid 6c489217f5 Start of updating setting names. 2015-04-21 16:38:07 +02:00
daid d4bae3c377 Small fix for the setting registy, list should be used instead of vector, as list does not move the memory around causing pointers to be invalid. 2015-04-21 16:20:16 +02:00
Tim Kuipers 15cf1bffc8 some refactoring and extra commenting 2015-04-21 16:16:18 +02:00
Tim Kuipers bb7d6f4cdc some refactoring and extra commenting 2015-04-21 16:14:44 +02:00
Tim Kuipers 1936cbb781 code conventions 2015-04-21 16:13:55 +02:00
daid 55f4ad68a9 Refactor how the settings are read and stored with the registry. This will need the fdmprinter.json file from PluggableUnicorn. Note: Currently this will break intigration. 2015-04-21 15:57:51 +02:00
Tim Kuipers a45f936366 some refactoring and cleaning up of bad practices 2015-04-21 13:10:42 +02:00
Tim Kuipers dcef0205b2 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-21 11:42:54 +02:00
daid 61976be9c1 Fix compile issue. 2015-04-21 11:42:37 +02:00
Tim Kuipers fd5f33570d Bugfix: ancient header protection was missing 2015-04-21 11:10:52 +02:00
Tim Kuipers ff568d0be2 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-21 11:04:44 +02:00
daid b29d71b2cc Fix crash when IP with no port is given on connect. 2015-04-21 11:03:08 +02:00
Tim Kuipers 2ee21bf4d2 bugfix support: polygon.simplify(.) removed points 2015-04-21 10:51:36 +02:00
daid cfd5178d54 Let tim sort it out. 2015-04-21 10:42:25 +02:00
Tim Kuipers c1b6e5a8b3 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-21 09:58:36 +02:00
Tim Kuipers 02b32238d8 perimeterGaps problem fixed (bug that at any angle, perimeter gaps were created and they had infillOverlap) 2015-04-21 09:58:23 +02:00
Arjen Hiemstra 5f47023759 Add print material amount and simplify print time message 2015-04-20 17:54:07 +02:00
Tim Kuipers 68e3966257 Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-20 16:18:53 +02:00
Tim Kuipers 024fed3dc5 remove empty layers better (after insets are generated), fan speed based on setting 'minimalLayerTimeFanSpeedMin' 2015-04-20 16:18:29 +02:00
daid b2e5a290ce Print the wipetower with insetX settings for now (skirt is very slow) 2015-04-20 14:34:29 +02:00
daid 8f9fc7a7b1 Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-20 14:11:59 +02:00
daid 2bbd2a5cd8 Small fix for dual slicing (for now, we need to take a good look at the object message) 2015-04-20 14:11:47 +02:00
Tim Kuipers 18b476bc33 avoidOverlappingPerimeters refactor and skin perimeters implemented. Also perimeter gaps handled separately from skin. generateLineInfill(.) : added parameter offset_dist instead of always ofsetting with extrudsionWidth/2 2015-04-20 11:03:51 +02:00
Tim Kuipers 06aeff27df Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-17 10:16:08 +02:00
Tim Kuipers 683a1ea99b convex hull (NOT FINISHED) 2015-04-17 10:15:48 +02:00
Tim Kuipers dac08fa727 description of polygons 2015-04-17 09:49:01 +02:00
daid 22cffd2ac6 Reset the printing time when a new slice is done. 2015-04-17 08:47:37 +02:00
daid b2e00b042c Send the proper prefix for UltiGCode for the Ultimaker2. 2015-04-17 08:25:59 +02:00
daid d2240c7228 Bla. 2015-04-15 15:55:50 +02:00
daid 68d00d0d00 Have a different setting for the width of extrusion lines. 2015-04-15 15:26:06 +02:00
daid b37e864cee Add the wipe tower distance as setting. 2015-04-15 15:12:15 +02:00
daid acb58d0ac0 Improve the wipetower. 2015-04-15 15:11:04 +02:00
daid 2edfafb988 Write the Z position after a extruder switch, so we know we are on the proper height again. We know we will move the head in X/Y next, but Z could be moved without our knowledge. 2015-04-15 14:46:29 +02:00
daid 5ea46a44be Small fix for dual-extrusion. 2015-04-15 14:40:14 +02:00
daid a6ec820c1e Fix retraction prime speed. 2015-04-15 13:17:05 +02:00
daid 228b641b8d Also register the new pre/post extruder switch in the setting registry. 2015-04-14 16:31:00 +02:00
daid 22bf8b290a Set pre/post extruder switch code per extruder instead of global for all extruders. 2015-04-14 16:09:56 +02:00
daid c851427848 Allow setting of settings per mesh, useful for dual-extrusion. 2015-04-14 13:53:53 +02:00
daid 8d6d61b3aa Merge mistake. 2015-04-14 13:48:50 +02:00
daid 0787250aca Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn
Conflicts:
	src/Wireframe2gcode.cpp
2015-04-14 13:47:35 +02:00
daid 2c2492b6ea Fix uint to unsigned int, as uint is not an offical type. 2015-04-14 13:46:41 +02:00
Tim Kuipers 2d8ce2173a GCode_flavor instead of int 2015-04-14 11:42:19 +02:00
Tim Kuipers 35faa0c2ec writeTypeComment refactors 2015-04-14 11:23:44 +02:00
Tim Kuipers 7c5ea7cba4 better concentric infill 2015-04-13 17:29:52 +02:00
Tim Kuipers cace9448df concentric infill with avoidoverlappingPerimeters, lines/zigzag infill bugfix : lines parallel to scanlines resulted in missing points in in_outline polygon 2015-04-13 16:26:38 +02:00
Tim Kuipers 03a13199b4 little cleanup: unsigned int => uint ; removed some unused vars 2015-04-13 15:26:52 +02:00
daid 177d16015b Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-13 11:41:52 +02:00
daid 54080f7119 Fixed precision problems with commit a9db281 2015-04-13 11:41:42 +02:00
Tim Kuipers 66a0b0275d wireframe command socket stuff 2015-04-13 09:55:22 +02:00
Tim Kuipers 7602f3ccfb Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-04-08 13:59:36 +02:00
Tim Kuipers dcadf6668a renamed all variables names 'l' to 'layer_idx' etc. 2015-04-08 13:59:07 +02:00
daid 379fee78f4 Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2015-04-08 13:50:25 +02:00
daid d4f3d0c37b Update engine to no longer use temp files to communicate the gcode to the frontend. 2015-04-08 13:45:42 +02:00
Tim Kuipers 0954fef276 finishing wireprinting 2015-04-08 13:44:10 +02:00
Tim Kuipers eb947ef52c merge 2015-04-08 13:34:59 +02:00
Tim Kuipers 0c08bf6ce0 refractoring, cleaning, commenting 2015-04-08 13:31:49 +02:00
daid a9db2813a8 Change the gcode export to use a stream, for later use. Fix a bunch of warings. Add warning level to cmake. 2015-04-07 13:52:15 +02:00
Tim Kuipers 34682fc8a3 fixed better starting point chainify, removed some chainify bugs 2015-04-07 12:31:04 +02:00
Tim Kuipers 9b0b68c75e removed optimizedModel file 2015-04-07 12:17:25 +02:00
Tim Kuipers f9854aead9 removed default settings 2015-04-07 10:58:03 +02:00
Tim Kuipers 468abb641b removed default settings 2015-04-07 10:49:10 +02:00
Tim Kuipers c62774c572 simple back() function for polygons 2015-04-02 16:58:57 +02:00
Tim Kuipers 68f2824fd0 deleted superfluous empty files 2015-04-02 16:58:01 +02:00
Tim Kuipers 556dace457 wireframe refactoring and explanations, roofs still buggy, wireframe printing in debug state! 2015-03-31 15:56:36 +02:00
Tim Kuipers 6f80977b35 Triangles infill added 2015-03-31 13:25:43 +02:00
Tim Kuipers ef8c076a99 wireframe massive refactor; fixed roofs and floors 2015-03-31 11:32:18 +02:00
Tim Kuipers 31ea98a59d documentation overview and glossary 2015-03-27 17:01:16 +01:00
Tim Kuipers 6c05436a0e XYcompensation setting implemented (extra offset to all polygons) 2015-03-27 15:56:42 +01:00
Tim Kuipers 859f37b96c settings registry structuring 2015-03-27 15:24:03 +01:00
Tim Kuipers 05874bb9c4 lil fix 2015-03-27 13:33:49 +01:00
Tim Kuipers ca7353e4d4 remove first empty layers 2015-03-27 13:29:29 +01:00
Tim Kuipers b9d48c9580 bugfix last commit 2015-03-27 13:29:08 +01:00
Tim Kuipers f7edd64f9f imrovement to combined small moves: constant extrusion per second 2015-03-27 11:44:01 +01:00
Tim Kuipers 6fafc0ab29 in the process of correcting roofs and floors bugs, enhanced moves for roofs and floors 2015-03-27 11:37:47 +01:00
Tim Kuipers 93a45c4ed1 roofs fixed and better fill of roofs 2015-03-26 12:35:46 +01:00
Tim Kuipers 05263813f8 roofs fixed and better fill of roofs 2015-03-26 11:35:20 +01:00
Tim Kuipers bb3098e0bc removed very old Atals shite and a lil Weaver bugfix 2015-03-26 09:53:49 +01:00
Tim Kuipers 1288038edf refactorings and better roof handling 2015-03-26 09:46:00 +01:00
Tim Kuipers 33e0083cda starting intermediate roof creation 2015-03-24 17:11:41 +01:00
Tim Kuipers 7a01dbb08f weaver.cpp refactor: connecting separate from chainifying 2015-03-24 16:16:58 +01:00
Tim Kuipers 2cd3bc330c Oh dear I've forgotten to add a very important header file past couple of weeks! 2015-03-24 10:37:04 +01:00
Tim Kuipers eeeadb8221 refactored wireframe printing 2015-03-24 10:36:03 +01:00
Tim Kuipers 290c75669e bottom layer like a roof 2015-03-23 16:02:57 +01:00
Tim Kuipers 0a01ba47e5 neith settings extracted 2015-03-23 14:59:20 +01:00
Tim Kuipers 9b30d16a16 Neith weaver working first approximation; WARNING: gcode.writeMove(.) changed; move with Z component now extrudes more. 2015-03-19 09:45:32 +01:00
Tim Kuipers 01250390de reordering of settings listing 2015-03-19 09:43:08 +01:00
Tim Kuipers c22b1bef74 new intpoint functionality (double multiplication, addition of point and point3, vSizeMM for point3) 2015-03-19 09:42:01 +01:00
Tim Kuipers 4820fbc5ee polygons.remove(other_polygons) 2015-03-19 09:40:54 +01:00
Tim Kuipers 6285f1d1fd Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-03-16 14:23:23 +01:00
Tim Kuipers 1f77742a18 neith first approximation (no gcode generation yet), bedTemperature setting 2015-03-16 14:22:59 +01:00
Arjen Hiemstra f1a83c18db Generate a proper temp filename on windows 2015-03-13 15:22:52 +01:00
Arjen Hiemstra 8a2956334e Add an id to the GCode message so we can track the object on the ui side 2015-03-13 14:00:11 +01:00
Tim Kuipers ceacaa27b1 changed miter limit for EVERY polygon offset from 2.0 to 1.2 2015-03-13 10:31:34 +01:00
Tim Kuipers 8032c7bfec refactored support, more clarity + more explanations; refactored cupportEverywhere to supportOnBuildplateOnly (and negated appropriately) 2015-03-12 14:21:41 +01:00
Tim Kuipers b3c83ce5e1 removed old grid support./CuraEngine -v -s filamentFlow=100 -s layerThickness=100 -s initialLayerThickness=300 -s supportZDistanceBottom=150 -s supportZDistanceTop=150 -s supportBottomStairDistance=500 -s initialSpeedupLayers=4 -s minimalFeedrate=10 -s preSwitchExtruderCode= -s insetXSpeed=30 -s retractionZHop=0 -s extruderOffset3.X=0 -s extruderOffset3.Y=0 -s gcodeFlavor=GCODE_FLAVOR_ULTIGCODE -s postSwitchExtruderCode= -s retractionSpeed=40 -s infillOverlap=15 -s inset0Speed=20 -s coolHeadLift=0 -s extrusionWidth=400 -s upSkinCount=6 -s initialLayerSpeed=20 -s minimalLayerTime=120 -s infillSpeed=40 -s fanSpeedMax=100 -s enableCombing=1 -s fanSpeedMin=100 -s supportXYDistance=700 -s supportExtruder=-1 -s supportType=ZIGZAG -s supportZDistance=150 -s supportEverywhere=1 -s supportAngle=60 -s supportJoinDistance=600 -s supportBridgeBack=100 -s supportSpeed=20 -s supportConnectZigZags=1 -s supportAreaSmoothing=600 -s supportMinimalAreaSqrt=1000 -s supportTowerDiameter=2000 -s supportTowerRoofAngle=65 -s areaSupportPolyGenerator=1 -s filamentDiameter=1128 -s fanFullOnLayerNr=2 -s extruderOffset1.X=18000 -s extruderOffset1.Y=0 -s endCode=M25 -s minimalExtrusionBeforeRetraction=20 -s retractionMinimalDistance=1500 -s objectSink=5000 -s retractionAmount=4500 -s skinSpeed=25 -s skinPattern=SKIN_LINES -s startCode= 2015-03-12 12:57:07 +01:00
Tim Kuipers f278248402 generateGridInfill refactored ( * 2 outside of function call); removed supportBridgeBack; inBetween perimeters area moved to skin; better wall struts 2015-03-12 12:08:07 +01:00
Tim Kuipers 99f2950cb2 refactor of simplify and smooth 2015-03-11 14:03:29 +01:00
Tim Kuipers 712acb9639 support ON outline instead of within outline; better avoidOverlappingPerimeters insets; sparse areas between perimeters; struts for support walls; polygon smooth(.) and simplify(.) 2015-03-11 13:18:55 +01:00
Tim Kuipers 4b0189b1b6 bugfix: infill overlap was wronggit diff 2015-03-09 15:20:43 +01:00
Tim Kuipers eda8800636 added infill zigzag option 2015-03-09 13:49:24 +01:00
Tim Kuipers 9b95c2f506 refactored generateZigZagSupport to generateZigZagInfill in infill.h; adding zigzag as infill option 2015-03-09 11:41:02 +01:00
Tim Kuipers 6241ec2f5b bugfix : avoid overhang in top notch regions 2015-03-09 11:28:51 +01:00
Tim Kuipers 3d9f8bd740 fixed support bugs and implemented tower support for small overhang areas 2015-03-06 17:25:37 +01:00
Tim Kuipers 3c6f6832a9 new support settings 2015-03-06 17:24:02 +01:00
Tim Kuipers e0e009368d lil improvement of setting handling 2015-03-06 17:22:10 +01:00
Tim Kuipers df29292d8f added support settings for connect_zigzags and area smoothing, modified settings registry 2015-03-05 10:59:08 +01:00
Tim Kuipers 461b41b7e4 bugfix for infill and zigzag support: better iteration over scanlines 2015-03-04 11:10:31 +01:00
Tim Kuipers f02b197322 new option avoidOverlappingPerimetersgit status! 2015-03-04 11:10:04 +01:00
Tim Kuipers 2ef092a720 trying to get all possible settings in a setting registry 2015-03-03 16:18:26 +01:00
Tim Kuipers e305fd4823 lil commit 2015-03-03 16:17:17 +01:00
Tim Kuipers d1e4518961 bugfix when infill of polygons with size 0 2015-03-03 16:16:25 +01:00
Tim Kuipers 3948590ded bugfix crossing infill caused by not finding intersection between polygon and scanline 2015-03-03 11:38:35 +01:00
daid 7b2b9630c7 Merge pull request #161 from mosh1/infill_perimeter_ordering
Add option to change print order of infill vs perimeters. Default prints...
2015-03-03 11:37:04 +01:00
Tim Kuipers a1b0ffc1a7 use printTemp only when given! added settings functionality (hasSetting(.)). moved default settings from main to settings 2015-03-03 10:29:38 +01:00
Tim Kuipers fbbe908f35 zigzag support bugfix of pertruding boundary line piece 2015-03-02 17:06:43 +01:00
Tim Kuipers cdf3215ab3 fixed zigzag spport! some minot bugs exist.. added option to let the support rest on the model in the form of a stair => supportBottomStairDistance 2015-03-02 15:54:01 +01:00
Tim Kuipers faaf5737f2 first zigzag support infill approximation 2015-03-02 13:28:59 +01:00
Tim Kuipers e843d53ec0 removed support skip layer speedup which was buggy 2015-03-02 09:49:14 +01:00
Tim Kuipers cbb080f327 support skip layers additional shite ( support skip layers not working correctlygit diff! ) 2015-03-02 09:35:26 +01:00
Moshen Chan 4621d77a17 Add option to change print order of infill vs perimeters. Default prints infill first as was changed in v15, but this can lead to surface quality issues where infill would show on surface. This adds the option to change the order. 2015-02-27 00:50:50 -08:00
Tim Kuipers 77935a845c bugfix (XYdistance performed double in GCode generation) and speedup in which multiple layers get the same support polygon 2015-02-26 17:00:21 +01:00
Tim Kuipers 62c7c113ca Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-02-26 15:39:43 +01:00
Tim Kuipers 107aaf0c93 refactoring and removal of old area support computation 2015-02-26 15:39:30 +01:00
Tim Kuipers b90263b481 lil edit 2015-02-26 15:38:46 +01:00
Tim Kuipers d2f6a86e54 added new options and changed default options to arbitrary and bad numbers, but these defaults aren't used right? 2015-02-26 15:04:32 +01:00
Tim Kuipers e0c294238f new area support! new options for it and for toggling between old support and new 2015-02-26 15:03:10 +01:00
Tim Kuipers 487327256a optimized skirt calculations, changed outline smoothing 2015-02-26 15:01:49 +01:00
Arjen Hiemstra e4e0dff046 Send polygons only after we've had a chance to add all of them 2015-02-26 11:50:30 +01:00
Arjen Hiemstra 8e5881d7e4 Do not crash if we try to send polygons after we've already sent them 2015-02-26 11:50:30 +01:00
Arjen Hiemstra 780fe88fe7 Add a function to reset the file number 2015-02-26 11:50:30 +01:00
Tim Kuipers 9f73f59d2e fixed support touching buildplate only and gap between lower layers support structures introduced by XYdistance 2015-02-24 10:49:10 +01:00
Tim Kuipers 6e7cf77e3d Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn 2015-02-24 09:23:19 +01:00
Tim Kuipers 6207419948 bugfixes area support 2015-02-24 09:22:55 +01:00
Tim Kuipers 112cf55ea9 default setting changes in main (note that SOME settings are crappy! 2015-02-20 17:52:01 +01:00
Tim Kuipers b7587a1f1e bugfix: layer z instead of actual z 2015-02-20 17:08:44 +01:00
Tim Kuipers 01a430b052 area support generation 2015-02-20 16:40:29 +01:00
Tim Kuipers bdc12d0bd9 comments for clarification 2015-02-20 11:58:08 +01:00
Tim Kuipers 9b5b035e5e comments for clarification 2015-02-19 17:53:55 +01:00
Tim Kuipers d6f98f2db2 README install instructions 2015-02-19 12:06:14 +01:00
Arjen Hiemstra c0013a4329 Delay the actual processing of the print objects so the memory used for the message can be freed. 2015-02-12 17:49:33 +01:00
Arjen Hiemstra 46774fb1eb Add missing braces so slicing from command line works again 2015-02-12 17:48:38 +01:00
Arjen Hiemstra 327b38094a Properly close the file on a call to GCodeExport::close() 2015-02-12 17:48:13 +01:00
Arjen Hiemstra ffe50c6cb0 Add support for handling settings 2015-02-12 17:47:26 +01:00
Arjen Hiemstra 6b7d61d7db Add SettingList and Setting messages to the protocol 2015-02-12 17:41:39 +01:00
Arjen Hiemstra 6d8b5408bf Update CMakeLists to force c++11 2015-02-11 12:23:03 +01:00
Arjen Hiemstra 408bf5ef12 Update gitignore to exclude kdevelop project files 2015-01-29 11:20:33 +01:00
Arjen Hiemstra 0610c2193e Add a CMakeLists file that looks for libarcus and generates cpp/header files from the proto file 2015-01-29 11:20:10 +01:00
Arjen Hiemstra 866a1b4137 Add Cura protobug protocol file 2015-01-29 11:20:10 +01:00
Arjen Hiemstra 19c9c80c7d Send notifications to the command socket when starting slicing/gcode writing 2015-01-29 11:20:10 +01:00
Arjen Hiemstra 9aba19a738 Simplify command socket handling to a single --connect option 2015-01-29 11:20:10 +01:00
Arjen Hiemstra 616d2305cd Use libArcus for socket communication 2015-01-29 11:19:08 +01:00
Arjen Hiemstra 7be326ba1b Use 0,0 as default position 2015-01-29 11:19:08 +01:00
Arjen Hiemstra f6ec4f3700 Pass floatpoint as const ref in Matrix apply 2015-01-29 11:19:08 +01:00
Arjen Hiemstra ece2d4af18 Use an enum for Polygon type instead of magic strings 2015-01-29 11:18:16 +01:00
Arjen Hiemstra c22499bcc6 Add an assertion so we know what fails if the slicer is called with 0 or less layers 2015-01-29 11:18:16 +01:00
Arjen Hiemstra c12198ac25 Add a close() method to GCodeExport 2015-01-29 11:18:16 +01:00
daid 5a6ebd4156 Merge branch 'master' of github.com:Ultimaker/CuraEngine 2015-01-16 12:17:31 +01:00
daid 0fdec5246b CNC GCode needs P instead of S parameters. 2015-01-16 12:17:22 +01:00
daid bbed68e588 Merge pull request #153 from presslab-us/fixskintravel
Use retract on skins
2015-01-14 14:32:03 +01:00
daid 7ce7123dd9 Prevent uninitialized value. 2015-01-13 10:31:15 +01:00
daid 3ceff11112 Apply patch 2bef59e79b 2015-01-12 15:15:46 +01:00
daid 90c663c6cd Apply 3aa638ea42 2015-01-12 14:51:03 +01:00
daid 51314b765d Apply patch edf2f897d1 2015-01-12 14:45:31 +01:00
daid 445cc29ef0 Apply d7a26ab715 2015-01-12 14:31:27 +01:00
daid ae5aba694f Apply fix 65dc9fe64b 2015-01-12 14:27:01 +01:00
daid 8e570b8fc2 Fix BFB export. 2015-01-12 14:24:30 +01:00
daid 14482d2cf5 Apply commit e72aee5558 2015-01-12 14:17:39 +01:00
Ryan Press 49d5a81d02 Add option to disable combing on skin surfaces
The existing enableCombing options 0, 1 work as before.  A new
option 2 disables combing on the skin surfaces.  This forces a
retract to reduce the unsightly scarring on flat surfaces.
2015-01-09 14:20:52 -08:00
Ryan Press 3e980a84fd slab-us presslab-us authored 5 days ago evert "Use retract on skins"
This reverts commit af14f82a7f.
Because this option should be configurable, change the implementation.
2015-01-09 10:06:39 -08:00
Ryan Press af14f82a7f Use retract on skins
Using combing on skins causes unsightly scarring on flat surfaces.
By forcing a retract between travel moves we can lift the head
above the surface to avoid this.
2015-01-04 14:19:50 -08:00
daid ff4fa3581e Fix the raft printing speed. 2014-12-18 11:02:18 +01:00
daid 2bef59e79b Seperate the skin and infill to give them different speeds. Also change the printing order of this to handle pressure differences better. Which should increase print quality on advanced profiles. 2014-12-16 15:54:55 +01:00
daid 2e5b72cfef Merge pull request #150 from presslab-us/fixpathstart
Reset start position for new layers
2014-12-15 09:59:11 +01:00
Ryan Press 3aa638ea42 Reset start position for new layers
Reset the start position of the path optimizer for each new layer
so that it doesn't double up on the layers, causing problems for
cooling.
2014-12-14 09:08:17 -08:00
daid edf2f897d1 Change how open polygons are saved. As std::vector never clears memory and the old implementation could mean a lot of memory was never freed. 2014-12-12 11:00:33 +01:00
daid cacffadc61 It looks like removing duplicate faces actually has a negative effect on "bad" model. 2014-12-10 08:54:38 +01:00
daid d7a26ab715 Improve skirt handling with support material 2014-12-03 15:39:30 +01:00
daid 65dc9fe64b Fix #144 for dos format files. 2014-11-26 15:08:09 +01:00
daid 951f8f4e4b Added some documentation to the sliceDataStorage. 2014-11-26 14:52:11 +01:00
daid f459c91631 Add some comments to the header of support. 2014-11-26 14:21:11 +01:00
daid db6c9a05e0 Merge branch 'master' of github.com:Ultimaker/CuraEngine 2014-11-26 12:14:08 +01:00
daid 93e2cda988 Fix BFB support. 2014-11-26 12:12:57 +01:00
Tim Kuipers b1bf1ccbdc small edge case warning generation 2014-11-24 15:48:45 +01:00
Tim Kuipers 47b75368af mesh doc 2014-11-24 14:15:23 +01:00
Tim Kuipers aa7b1f5c76 bug fixing in mesh 2014-11-24 13:36:37 +01:00
daid d49257d30c Merge pull request #141 from qbit/master
Add flags for OpenBSD
2014-11-24 07:25:31 +01:00
Aaron Bieber e53408dc52 Flags for OpenBSD 2014-11-20 18:06:06 -07:00
Tim Kuipers ecb365f275 halfedg emesh bugfixing and supportpoint bugfixing 2014-11-19 15:28:23 +01:00
Tim Kuipers 4be5999770 support point generation finished, some bug fixes, made Point3::cross deprecated 2014-11-18 14:51:15 +01:00
Tim Kuipers f4e1a7b1f7 no more forced colorgcc, fix your own linking to colorgcc 2014-11-12 15:25:38 +01:00
Tim Kuipers c771da74d4 colorsgit add colorgcc git add colorgcc git add colorgcc git add colorgcc git add colorgcc git add colorgcc git add colorgcc 2014-11-12 15:08:09 +01:00
Tim Kuipers 914417ee3e added half-edge mesh 2014-11-12 14:51:34 +01:00
Tim Kuipers a4f3656093 removed testing code and hide debugging output 2014-11-12 14:36:31 +01:00
Tim Kuipers 763b9e4827 m
Merge branch 'PinkUnicorn' of https://github.com/Ultimaker/CuraEngine into PinkUnicorn
2014-11-12 14:21:22 +01:00
Tim Kuipers 1231bf6ce0 half-edge meshes and overhang classification of faces, edges and vertices 2014-11-12 14:21:15 +01:00
daid ed8c6cd5ce Remove build clipper on clean. 2014-10-30 10:08:14 +01:00
daid f76510ce26 Fix compile problems for mingw compiler. 2014-10-28 11:09:05 +01:00
daid fa4eafa8e3 Do not change the default build type. 2014-10-28 11:03:38 +01:00
daid 685991cd98 Small fix to the dot score calculation 2014-10-28 11:02:46 +01:00
daid 9a3d0c7099 Fix in the dot_score calculation, was causing wrong start points to be selected. 2014-10-28 11:00:40 +01:00
Tim Kuipers 67771564be refactoring, renaming and commenting 2014-10-23 16:16:43 +02:00
Tim Kuipers 5b67ca1a00 refactoring, renaming, commenting. Splitting pathOrderOptimizer for polygons and edges 2014-10-22 14:53:14 +02:00
daid 5d3d436105 Fix include. 2014-10-22 11:07:26 +02:00
TimKuipers 40ff880ef0 Update README.md
removed typos, improved syntax and changed some expressions
2014-10-20 16:15:34 +02:00
daid ead90e6862 Make the skirt&brim use rounded offsets so they fit better. 2014-10-17 15:59:46 +02:00
daid 92937617f5 Add very basic temperature settings. 2014-10-17 11:26:15 +02:00
daid 4cf43fca20 Merge pull request #134 from zwbrush/master
Update optimizedModel.h
2014-10-16 16:00:47 +02:00
zwbrush 525c8a6966 Update optimizedModel.h
fix position calculate error when autoCenter!=1
2014-10-15 21:18:11 +08:00
daid 68473ad811 Fix problems with path order generating more travel on infill then it should. See: http://umforum.ultimaker.com/index.php?/topic/7727-1409-creates-insane-amounts-of-travel/ 2014-10-13 09:50:57 +02:00
daid 90ca7b8658 Make the hashPoint function use a const to fix compile issues. 2014-10-01 15:22:19 +02:00
daid 0871cd7492 Make the hashPoint function use a const to fix compile issues. 2014-10-01 15:21:56 +02:00
daid b3b79f42d5 Speed up the path-order-optimizer by using a hashmap to look for nearby points. This greatly speeds up the order optimizer when used on infill lines. 2014-09-26 14:56:57 +02:00
daid 42b6f365c5 Speed up the path-order-optimizer by using a hashmap to look for nearby points. This greatly speeds up the order optimizer when used on infill lines. 2014-09-26 14:55:59 +02:00
daid 7b042b2b7d Merge pull request #128 from foosel/fix/fileExtension
"*.STL" files might be STL files too
2014-09-25 10:57:55 +02:00
Gina Häußge b5e4928780 "*.STL" files might be STL files too
Makes STL file detection based on extension work case insensitive. Without
that patch, files named like "FILE.STL" or "file.StL" or ... couldn't be
sliced. CuraEngine quit attempts to do so with "Could not load file"
instead.
2014-09-25 10:39:14 +02:00
daid d1f9e80b5d More additions to the polygon class. 2014-09-25 10:24:48 +02:00
daid 175a3243a5 Small update on polygon and debug functions for more future features. 2014-09-25 09:10:44 +02:00
daid e089c82781 Merge pull request #127 from repetier/master
Fix problems in settings parser
2014-09-24 15:05:00 +02:00
repetier cf5008bec3 Fixed problems with settings 2014-09-23 17:50:01 +02:00
repetier ceae269ff1 Merge branch 'master' of https://github.com/Ultimaker/CuraEngine 2014-09-23 16:19:26 +02:00
repetier fac9b89f81 Merge branch 'master' of https://github.com/Ultimaker/CuraEngine 2014-09-23 16:17:44 +02:00
daid 613c2af385 Fix build on linux. 2014-09-19 13:35:13 +02:00
daid 0c60a087f3 Cross hatch the first layer of line grids so you get better bed adheasion. Also expand these lines a bit more so they attach to a brim better, if there is a brim. 2014-09-19 11:41:37 +02:00
daid 0f7f58aab4 Some better parameters for the corner finding routine. 2014-09-19 11:39:57 +02:00
daid dd1612c763 Try to put the Z seam in internal corners instead of anywhere on the external face. 2014-09-19 11:39:44 +02:00
daid 4c42b16059 Some better parameters for the corner finding routine. 2014-08-29 14:58:32 +02:00
daid 5a4548d426 Try to put the Z seam in internal corners instead of anywhere on the external face. 2014-08-29 14:14:36 +02:00
daid bb587d17d9 Cross-hatch the first support line layer when line support is done. 2014-08-29 12:34:34 +02:00
daid c004124f85 Update support type code to use simple names. 2014-08-29 12:05:10 +02:00
daid 9fd36d8820 Merge pull request #124 from foosel/fix/tooMuchRounding
Fix rounding issue on generated GCODE
2014-08-28 12:01:05 +02:00
Gina Häußge e72aee5558 Fix rounding issue on generated GCODE
We store the X, Y, Z coordinates in microns, let's try to
keep as much precision and do not round to 2 digits after
the decimal point but 3 in generated GCODEs when converting
into mm.
2014-08-28 10:40:24 +02:00
daid 63e81e33d3 Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2014-08-22 15:37:46 +02:00
daid 8b8c385441 Allow setting of settings on object settings as well as mesh level. 2014-08-22 14:59:51 +02:00
daid cad96e24dd Merge pull request #122 from martinxyz/PinkUnicorn
fix build on Linux
2014-08-14 09:14:27 +02:00
Martin Renold c688fc67ef fix build on Linux 2014-08-14 00:01:35 +02:00
daid 68c34fad86 Fix retraction issues after refactoring. 2014-08-13 13:39:10 +02:00
daid 96af51afce Have filament settings per mesh (and thus per extruder) 2014-08-12 13:43:36 +02:00
daid f20fb1aec5 Make speed and retraction settings per mesh. 2014-08-12 10:57:39 +02:00
daid f6d7b77e8e Call mesh->finish so the mesh gets properly optimized and slicing is a lot faster. 2014-08-07 15:44:08 +02:00
daid ce6f78dd89 Fix setting custom build_dir 2014-08-06 10:57:28 +02:00
daid 61ace00ab3 Remove clipperlib.a on clean. 2014-08-06 10:38:20 +02:00
daid 19800c66b8 Update makefile for building windows binary on linux. 2014-08-06 10:34:40 +02:00
daid 69f931b298 Update makefile for building windows binary on linux. 2014-08-06 10:34:05 +02:00
daid 2a15672b98 Merge branch 'PinkUnicorn' of github.com:Ultimaker/CuraEngine into PinkUnicorn 2014-08-05 14:57:39 +02:00
daid 7e788e64b2 Fix extruder offset settings. 2014-08-05 14:57:29 +02:00
Daid 7e59e3b23f Add missing sources. 2014-08-05 14:14:49 +02:00
daid 5f361846bb Some code cleanup. 2014-08-05 14:06:04 +02:00
daid c1c676d892 Remove debug print. 2014-08-05 12:21:24 +02:00
daid 7240dc6ffe move around the ooze shield code, and have the mesh order set by the extruderNr 2014-08-05 11:44:01 +02:00
daid 848a08f4b7 Do not make the extruder number depended on the mesh index, so we can have multiple meshes with the same extruder. 2014-08-05 10:55:33 +02:00
daid 93c2ceae8c Improvements for new settings method 2014-08-05 09:39:15 +02:00
daid 778c26e90c Lots of changes to get to a point where we can define settings per mesh instead of for the whole slice. 2014-08-04 13:36:07 +02:00
daid 9e1d180e81 Remove the ugly UltiGCode hacky code and let the frontend handle this. 2014-07-30 08:39:22 +02:00
daid 4c671418ee Modify UltiGCode flow with the flow setting. Fix problems with the combineSparseLayers generting lots of small areas 2014-07-30 08:26:05 +02:00
daid 95bd012bbe Change the skirt speed handling, as it did not do anything like this. 2014-07-22 10:21:20 +02:00
daid 4c1043f69a Merge pull request #118 from electrocbd/use_gdb
No -flto compiler option in debug mode under Linux
2014-07-19 23:11:23 +02:00
electrocbd 7df7da788b No -flto compiler option in debug mode under Linux 2014-07-19 15:10:14 +02:00
daid beb781ac68 Merge pull request #115 from electrocbd/raftskirt
Print skirt before raft
2014-07-16 17:17:57 +02:00
electrocbd b5e94f93b7 Print skirt before raft 2014-07-15 10:34:53 +02:00
daid d721ae7daf Merge branch 'master' into PinkUnicorn 2014-07-14 16:46:56 +02:00
daid 21494ffc6c Combine multiple sparse infill layers into a single sparse infill with more extrusion to save printing time. 2014-07-14 16:46:30 +02:00
daid e1a11d0741 Remove the automatic infill pattern (let the caller decide) Add skin fill pattern option. 2014-07-14 13:50:11 +02:00
daid 64faaca516 Do not send raft polygons right now. 2014-07-14 11:52:11 +02:00
repetier 2451df3f1e Do not add CodeBlocks config 2014-07-10 15:46:37 +02:00
daid 54f9620fc5 Slight change how the layers are send towards the frontend. 2014-07-01 11:50:26 +02:00
daid e4e2c0428d Merge pull request #111 from cyberjoac/master
Handling correctly both the Ascii models and Binary models.
2014-06-28 21:33:14 +02:00
Joachim Hagege 074d4cea00 Bug correction in the logic for loading an Ascii model 2014-06-28 18:13:11 +03:00
Joachim Hagege b17a3f2a92 Corrected a bug with loading an ASCII model 2014-06-28 18:03:08 +03:00
daid 5c327b7100 Send print information per object. 2014-06-25 11:48:55 +02:00
daid e9e0457238 Merge fix 2014-06-25 09:29:27 +02:00
daid 481df6ddcd On -- process the current file, which allows for one-at-a-time printing from the commandline. 2014-06-25 09:28:19 +02:00
daid febbdcaf27 Remove old hacky processing. 2014-06-25 09:26:20 +02:00
daid b0e962d37f Track the current object number to send the proper progress update. 2014-06-25 09:23:20 +02:00
daid d0af23d7c8 Merge branch 'master' into PinkUnicorn 2014-06-24 10:31:20 +02:00
daid 0f85c400d3 Fix loading of solidworks files, which start with "solid" but are binary files... 2014-06-24 10:21:11 +02:00
daid 548d58cf8e More proper protocol implementation. 2014-06-23 14:56:10 +02:00
daid 35beec7104 Merge branch 'master' into PinkUnicorn 2014-06-23 13:36:40 +02:00
daid 63c6a6e4f4 Implemented new protocol as defined internally with Ultimaker software development team. 2014-06-23 13:33:14 +02:00
daid e5f42cb1f7 Fixed #107 - Good catch! 2014-06-17 09:09:21 +02:00
daid 4a2f76503c Fix settings from socket, allow sending multiple volumes with different offsets. 2014-06-06 11:28:09 +02:00
daid 0d65ef9ccc Merge branch 'master' into PinkUnicorn 2014-06-05 11:31:32 +02:00
daid 1a21409220 Fix problems with dual-extrusion retraction. Make sure retraction on head-lift happens. 2014-06-05 09:37:07 +02:00
daid 881db618ca Merge fix. 2014-06-05 09:14:16 +02:00
daid 08b16b3c4e Merge pull request #104 from cederom/master
Fixed abs() -> fabs() typo that blocked build on FreeBSD.
2014-06-04 11:56:51 +02:00
Tomek CEDRO 8b94f8d886 Fixed abs() -> fabs() typo that blocked build on FreeBSD.
BUILD SYSTEM:
% uname -a
FreeBSD hexagon 10.0-RELEASE-p2 FreeBSD 10.0-RELEASE-p2 #0: Tue Apr 29 17:06:01 UTC 2014     root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC  amd64

BUILD LOG BEFORE FIX:
% gmake CXX="c++"
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/bridge.cpp -o build/bridge.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/comb.cpp -o build/comb.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/gcodeExport.cpp -o build/gcodeExport.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/infill.cpp -o build/infill.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/inset.cpp -o build/inset.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/layerPart.cpp -o build/layerPart.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/main.cpp -o build/main.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/optimizedModel.cpp -o build/optimizedModel.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/pathOrderOptimizer.cpp -o build/pathOrderOptimizer.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/polygonOptimizer.cpp -o build/polygonOptimizer.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/raft.cpp -o build/raft.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/settings.cpp -o build/settings.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/skin.cpp -o build/skin.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/skirt.cpp -o build/skirt.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/slicer.cpp -o build/slicer.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/support.cpp -o build/support.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/timeEstimate.cpp -o build/timeEstimate.o
src/timeEstimate.cpp:119:35: error: use of undeclared identifier 'abs'; did you mean 'fabs'?
        current_abs_feedrate[n] = abs(current_feedrate[n]);
                                  ^~~
                                  fabs
/usr/include/math.h:259:8: note: 'fabs' declared here
double  fabs(double) __pure2;
        ^
1 error generated.
gmake: *** [build/timeEstimate.o] Error 1

BUILD LOG AFTER FIX:
% gmake CXX="c++"
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/bridge.cpp -o build/bridge.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/comb.cpp -o build/comb.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/gcodeExport.cpp -o build/gcodeExport.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/infill.cpp -o build/infill.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/inset.cpp -o build/inset.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/layerPart.cpp -o build/layerPart.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/main.cpp -o build/main.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/optimizedModel.cpp -o build/optimizedModel.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/pathOrderOptimizer.cpp -o build/pathOrderOptimizer.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/polygonOptimizer.cpp -o build/polygonOptimizer.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/raft.cpp -o build/raft.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/settings.cpp -o build/settings.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/skin.cpp -o build/skin.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/skirt.cpp -o build/skirt.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/slicer.cpp -o build/slicer.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/support.cpp -o build/support.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/timeEstimate.cpp -o build/timeEstimate.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/modelFile/modelFile.cpp -o build/modelFile/modelFile.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/utils/gettime.cpp -o build/utils/gettime.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/utils/logoutput.cpp -o build/utils/logoutput.o
c++ -c -Wall -Wextra -Wold-style-cast -Woverloaded-virtual -std=c++11 -DVERSION=\"DEV\" -isystem libs -O3 -fomit-frame-pointer src/utils/socket.cpp -o build/utils/socket.o
c++ build/bridge.o build/comb.o build/gcodeExport.o build/infill.o build/inset.o build/layerPart.o build/main.o build/optimizedModel.o build/pathOrderOptimizer.o build/polygonOptimizer.o build/raft.o build/settings.o build/skin.o build/skirt.o build/slicer.o build/support.o build/timeEstimate.o build/modelFile/modelFile.o build/utils/gettime.o build/utils/logoutput.o build/utils/socket.o -o build/CuraEngine -Lbuild/ -lclipper
2014-06-02 21:59:48 +02:00
daid 1f64315092 Fix merge 2014-05-27 11:40:17 +02:00
daid b27a51e031 Add missing code for the pre/post extruder swap codes. 2014-05-27 09:53:06 +02:00
daid ae7f359f23 Add pre/post extruder switch gcode templates. Add ZHop to extruder switch retraction. Fixed #99 2014-05-26 09:46:55 +02:00
daid 2cb777bfdc Fix slicing for PinkUnicorn. 2014-05-23 13:58:50 +02:00
daid 4b4c71c537 Fix multi-object slicing in cura. 2014-05-23 10:31:53 +02:00
nallath dd3be7d4c9 Updated makefile 2014-05-21 15:24:37 +02:00
daid 3c3a24ff92 Optimize line segment order a bit so it favors going more in a straight line. 2014-05-21 09:05:02 +02:00
daid b993e93a68 Some fixes for the SimpleMode. 2014-05-21 08:55:30 +02:00
daid 17fe09fff9 Merge branch 'master' into PinkUnicorn 2014-05-20 16:14:03 +02:00
daid cc4a65de19 Fix the bug introduced into the concentric infill in #90 2014-05-20 16:13:51 +02:00
daid 47a996cf15 Merge fix. 2014-05-20 13:01:14 +02:00
daid e71ea1f3a9 Merge pull request #96 from oliv3r/master
Carriage return cleanups from CuraEngine
2014-05-20 09:59:56 +02:00
Olliver Schinagl a4957c52fd Remove \r from CuraEngine
CuraEngine uses newline's, not carriage return's. This patch strips \r's
from the source files. No code changes where performed.

Signed-off-by: Olliver Schinagl <o.schinagl@ultimaker.com>
2014-05-19 13:50:53 +02:00
Olliver Schinagl 848e395b72 Add missing stdio.h for usage of filestream functions
Signed-off-by: Olliver Schinagl <o.schinagl@ultimaker.com>
2014-05-19 13:11:32 +02:00
daid b3d79e675b Add simple mode which does hardly anything, but has nice use for some artists. 2014-05-17 07:18:38 +02:00
daid 8c6f42cbb8 Some minor cleanup after #95 2014-05-17 06:40:53 +02:00
daid 40fb8896d8 Some minor cleanup after #95 2014-05-17 06:40:11 +02:00
daid fe6bc0499e Merge pull request #95 from repetier/master
Multi-Stl-load, codeblocks support, autocenter, bug fixes
2014-05-17 06:31:38 +02:00
repetier b8a91bb06f Merge branch 'master' of https://github.com/Ultimaker/CuraEngine
Fixed raft air gap bug
2014-05-15 18:48:26 +02:00
daid 1de9da4558 Merge branch 'master' into PinkUnicorn 2014-05-15 13:00:12 +02:00
daid aa46967d79 Fix problem with G11 added at the first skirt line. 2014-05-15 12:58:07 +02:00
daid 85fe231dcc Update to working new command socket implementation. 2014-05-08 21:24:53 +02:00
daid 06e9f576b2 Add commandsocket for PinkUnicorn engine communication. 2014-05-08 13:54:30 +02:00
daid d0ce9523d3 Merge pull request #90 from znib/patch-1
removed an unnecessary if()
2014-05-05 10:58:23 +02:00
znib 05657bbe6c removed an unnecessary if()
Nothing too important, but I think it makes the code cleaner :-)
2014-05-03 12:56:10 +02:00
repetier 7b0e835168 Merge branch 'master' of https://github.com/Ultimaker/CuraEngine 2014-04-29 17:25:19 +02:00
daid ad28c7707c The lto flag does not work on MacOS with multi-arch builds. 2014-04-23 15:19:54 +02:00
daid 4fc877afd0 Cross-hatch the surface layers of the raft. 2014-04-23 14:26:02 +02:00
daid ea10ec7c44 Do not retract during raft, that is unneeded. 2014-04-23 12:42:34 +02:00
daid c4a127fcd6 Fix makefile, crashed on msys windows. 2014-04-23 10:54:56 +02:00
daid 129f502f28 Fix makefile, crashed on msys windows. 2014-04-23 10:53:59 +02:00
daid cd0ef93813 Add volumatric RepRap GCode for https://github.com/daid/Cura/issues/825 2014-04-23 09:55:49 +02:00
daid 1ceac5ab0e Merge pull request #84 from Skeen/modern_casts
Modern casting
2014-04-23 09:52:28 +02:00
daid b5769093c4 Merge pull request #86 from Skeen/enums
Change defines into enums
2014-04-23 09:51:44 +02:00
daid 73157f49d1 Merge pull request #87 from Skeen/origin
Link time optimization
2014-04-23 09:51:26 +02:00
repetier 16a51edc2d Load multiple stl files at once to allow multi-extruder slicing from command line 2014-04-21 19:59:59 +02:00
Skeen cd8cb7733a Merge remote-tracking branch 'upstream/master' into HEAD
Conflicts:
	Makefile
2014-04-18 23:56:00 +02:00
Skeen 884b9100d1 Merge remote-tracking branch 'upstream/master' into enums
Conflicts:
	src/settings.cpp
2014-04-18 23:49:20 +02:00
Skeen 4999c1d6ea Merge remote-tracking branch 'upstream/master' into modern_casts
Conflicts:
	Makefile
2014-04-18 23:47:38 +02:00
daid 981d956766 Merge branch 'master' of github.com:Ultimaker/CuraEngine 2014-04-18 06:44:55 +02:00
daid 98c7fc1ee3 Fixing https://github.com/daid/Cura/issues/820 2014-04-18 06:44:46 +02:00
daid 9434abfcf6 Merge pull request #85 from Skeen/multi_infill
Prepare for supporting multiple different infills.
2014-04-18 06:41:29 +02:00
daid f1acd11ffd Merge pull request #83 from Skeen/nullptr
Change NULL into nullptr
2014-04-18 06:38:11 +02:00
daid 3c252ff91e Merge pull request #82 from Skeen/build_profiles
Add support for multiple build profiles
2014-04-18 06:37:24 +02:00
Skeen 55cd07cf58 We should do link type optimization, in order to get a faster executable. 2014-04-16 17:18:11 +02:00
Skeen 7051907cd5 Integer constructors are really casts too. 2014-04-16 17:15:48 +02:00
Skeen be02553c46 Changed a few defines into weak type enums.
These should eventually be changed into strong type enums,
in order to provide type safety!
2014-04-16 17:11:36 +02:00
Skeen 3a1f0ca2e1 Applied the quickfix from the working branch. 2014-04-16 17:05:59 +02:00
Skeen c5f3fe2b9c Removing a wierd unwanted space. 2014-04-16 17:02:26 +02:00
Skeen 094ed5b4c7 Prepare for supporting multiple different infills. 2014-04-16 17:01:17 +02:00
Skeen c7eb07468d Added a flag to warn on C style casts.
Removed all C style flags, and replaced with C++ casts.
2014-04-16 16:50:16 +02:00
Skeen 7623c51e41 Changed NULL to nullptr 2014-04-16 16:43:03 +02:00
Skeen 2c8ddc3295 Added support for multiple build profiles. Defaulting to release. 2014-04-16 16:38:59 +02:00
Skeen 7c2606287e Removed invalid hint about how to easily build project 2014-04-16 16:31:45 +02:00
repetier 82028756da Add auto center option, Codeblocks compilation support 2014-04-13 10:45:59 +02:00
daid 8bd2bcacbc _Polygon define is no longer needed due to namespaces. 2014-04-11 16:09:25 +02:00
daid dc74a09092 Merge branch 'master' of github.com:Ultimaker/CuraEngine 2014-04-11 10:15:22 +02:00
daid 8f049641d7 Fix crash bug. 2014-04-11 09:04:54 +02:00
daid 2ee44238ec Fix crash bug. 2014-04-11 09:04:15 +02:00
daid 74b1b67b0d Merge pull request #80 from martinxyz/master
fix compilation on Linux
2014-04-10 11:45:49 +02:00
Martin Renold 0e6f4abe27 fix compilation on Linux
src/gcodeExport.cpp:63:23: error: cannot convert ‘fpos_t {aka _G_fpos_t}’ to ‘long int’ for argument ‘2’ to ‘int fseek(FILE*, long int, int)’
     fseek(f, oldPos, SEEK_SET);
2014-04-09 15:30:43 +02:00
daid 10b6a4788f Make bridges per fill area instead of per layer. 2014-04-08 13:58:00 +02:00
daid 6430e67ddd Merge branch 'master' of github.com:Ultimaker/CuraEngine 2014-04-08 12:09:53 +02:00
daid 6d38063e34 Some cleanup, moved the inside function into the polygon class instead of the comb class. Made all the lineends unix style. Added namespaces. 2014-04-08 12:09:42 +02:00
Daid ab08b89496 Fix MacOS build. 2014-04-07 14:45:28 +02:00
daid 4f8caa85ec Add missing util/string.h 2014-04-07 14:41:32 +02:00
daid 8b4d4743e9 Strange shit is happening... how the hell did this happen?. 2014-04-07 13:30:24 +02:00
daid c2348ef17c Fix c++11 compiling. 2014-04-07 13:26:41 +02:00
daid 78853237e0 Do not force lineends. 2014-04-07 12:15:57 +02:00
daid 87eacf161b Fix building libclipper.a all the time after #76 2014-04-07 11:32:33 +02:00
daid 24db283088 Merge pull request #76 from Skeen/master
out-of-source building + more
2014-04-07 10:52:56 +02:00
Skeen d7d9b5b9a4 Moved clipper to a libraries folder.
Added a DO_NOT_CHANGE_THESE files, nothing developers that the sources in this
folder, is not to be changed directly in this repository, but should rather be
modified in their respective repositories.
Updated the Makefile to build this library.
Updated the Makefile to include the libs folder, as a isystem include
    I.e. do not throw errors, warnings, ect. from these headers.
Updated intpoint, and polygon to include clipper via. compiler lookup.
2014-04-06 22:24:19 +02:00
Skeen d00682c56f We want crlf endings 2014-04-06 21:45:38 +02:00
Skeen 0888e50219 We want uniform line endings!
The gitattributes file, should ensure that files always have the same
line endings at checkout.
2014-04-06 21:36:47 +02:00
Skeen 4abd629e2f Cross platform makefile
The mkdir step, should now work on all platforms.
2014-04-06 19:11:11 +02:00
Skeen c454b7881c Fixed gitignore, made makefile cross platform.
Fixed gitignore to actually ignore vim swap files.
2014-04-06 19:10:43 +02:00
Skeen f0d7e830f5 Removed vim swap file
This was an accidental upload.
2014-04-06 19:03:32 +02:00
Skeen b539f0d2b0 Updated gitignore
Ignore vim comment files, and the build folder (for out of source
builds)
2014-04-06 19:00:13 +02:00
daid 6aa27e0271 Merge branch 'master' of github.com:Ultimaker/CuraEngine 2014-03-31 12:09:29 +02:00
daid c4f0f354ae M103 is stop all extruders. 2014-03-31 10:13:51 +02:00
daid 6cc0cca7a6 Merge pull request #73 from Ryoko/Raft_interface_generation_angle
Change the angle on which raft interface layer's infill generated.
2014-03-31 10:01:55 +02:00
Ryoko e41ebcb3ae In case of no surface layers in raft - generate interface layer infill on 90 degree angle. 2014-03-30 22:11:24 +03:00
daid 943ae5901f Add AGPL notice to engine. 2014-03-28 16:21:32 +01:00
daid de8661da31 Change extruder swaps for BFB. 2014-03-28 10:21:14 +01:00
daid 93dfc8b2d6 Do not use the G92 Exxx for BFB code. 2014-03-28 09:48:53 +01:00
daid 1cea56cdd3 Fix RPM and multiple extruders for BFB style GCode. 2014-03-28 09:31:52 +01:00
daid 483f18ed96 Merge branch 'master' of github.com:Ultimaker/CuraEngine 2014-03-25 14:10:29 +01:00
daid c4fa1ba55a Fix the problem where very high polygon circles generate a lot of very small segments 2014-03-25 14:09:34 +01:00
daid 0ef0ae3ca0 Merge pull request #71 from Ryoko/AddToPrime
Added setting 'retractionAmountPrime'
2014-03-24 10:01:14 +01:00
daid a9376b50e6 Merge pull request #72 from Gregwar/raft_parameters
Introducing raftFanSpeed and raftSurfaceSpeed
2014-03-24 10:00:14 +01:00
Gregwar 8d57f871aa Introducing raftFanSpeed and raftSurfaceSpeed 2014-03-23 22:33:32 +01:00
Ryoko bb4ff5a2ca Added setting 'retractionAmountPrime' specifying the amount of filament added to the prime after the retraction. 2014-03-23 19:45:03 +03:00
daid 62667ff2e7 Merge pull request #68 from Gregwar/first_layer_gap
Shifting raft surface only for first layer
2014-03-19 17:22:58 +01:00
daid ea767b8615 Merge pull request #66 from Gregwar/fixing_speed_smoothing
Fixing speed smoothing
2014-03-18 13:40:08 +01:00
daid e2c33e576e Set default raftSurface layers to 0. 2014-03-18 08:33:46 +01:00
Gregwar 80cea5e104 Fixing speed smoothing 2014-03-18 00:05:46 +01:00
Gregwar 052c79b8eb Shifting raft surface only for first layer 2014-03-17 23:41:24 +01:00
daid 218067b650 Merge branch 'BFB' 2014-03-17 15:59:53 +01:00
daid a77a4549b8 Merge pull request #64 from Gregwar/master
Adding raft surface support
2014-03-17 15:24:12 +01:00
Gregwar c7f18f21a4 Defaulting raftBaseSpeed to 0 2014-03-15 15:56:36 +01:00
Gregwar 8403b3d238 Removing testing config 2014-03-15 15:54:27 +01:00
Gregwar e9ce954141 Renaming raftFull to raftSurface 2014-03-15 13:42:07 +01:00
Gregwar 3467e1f1a5 Fixes 2014-03-14 11:16:52 +01:00
Gregwar b67f18a64a Introducing raftFull layers 2014-03-14 10:53:47 +01:00
daid 9f46abc2b0 Reduce the default layer0extrusionwidth a bit. 2014-03-14 09:02:47 +01:00
Gregwar 704492360d Introducing new parameters (for solid raft) 2014-03-13 23:58:25 +01:00
daid 338b4d374d Fix retraction for RepRap. 2014-03-13 17:23:19 +01:00
daid 142739a24b Merge branch 'master' into BFB 2014-03-13 15:55:22 +01:00
daid 4d0dd255b4 Better fix for clipper. 2014-03-12 11:58:19 +01:00
daid 190bf34ac2 Now that clipper is fixed, disable the removal of near linear points. Fixing a long standing quality problem. 2014-03-12 11:53:03 +01:00
daid 856e82dd95 Patch up clipper to solve the nipples on offsets. 2014-03-12 11:45:23 +01:00
daid 3943b2863d Merge branch 'master' into BFB 2014-03-12 08:33:36 +01:00
daid 4ab210cb4e Fix include case. 2014-03-11 18:35:12 +01:00
daid 8febcc40f8 Remove unused include. 2014-03-11 09:07:44 +01:00
daid f05a75a15d Remove unused include. 2014-03-10 23:41:02 +01:00
daid 1667e19910 Fix the wierd 500 milion bug. 2014-03-10 23:34:43 +01:00
daid 1665c38e3a Some more hard coded micron fixes. 2014-03-10 15:53:26 +01:00
daid a69de22d31 Merge fix. 2014-03-10 14:40:19 +01:00
daid b2f4c197ca Fix version number define. 2014-03-10 10:36:03 +01:00
daid 8afaa83a4b Add version number from commandline. 2014-03-10 10:28:25 +01:00
daid 3cbaae3695 Add some more debug logging to catch that annoying bug. 2014-03-10 10:23:21 +01:00
daid 1b20d83b82 Crash instead of slice in case of the strange huge object bug. 2014-03-10 10:19:42 +01:00
daid 4b85f8fdec Fix multi-object Z move: https://github.com/daid/Cura/issues/777 2014-03-10 09:38:09 +01:00
daid ed299916c5 Prepare code for resolution change. 2014-03-09 11:03:30 +01:00
daid 0b2171d1dd update to newer clipper. 2014-03-04 14:39:21 +01:00
daid 46f376ba8b Update some BFB comments. 2014-02-26 10:39:56 +01:00
daid bccf807b1c Fix usage message. 2014-02-25 19:54:47 +01:00
daid fc000dae7a Merge branch 'master' into BFB 2014-02-25 14:52:07 +01:00
daid f32e292764 Force the skirt to printed outside in. 2014-02-25 11:01:26 +01:00
daid ca0de8162d Expand the raft around the support and wipe tower. 2014-02-24 08:04:41 +01:00
daid 11e2c98c64 Fix https://github.com/daid/Cura/issues/738 2014-02-22 17:25:42 +01:00
daid e8e5773005 Only make inner skirt lines when the skirt is attached to the object. 2014-02-22 11:30:29 +01:00
daid 74672f27da Fix huge offset moves in dual-extrusion print. 2014-02-20 21:10:02 +01:00
daid 94c74ca22d Add obj finish command trough gui socket. 2014-02-19 10:32:09 +01:00
daid 445498eba1 Add MACH3 GCode flavor. 2014-02-19 09:41:09 +01:00
daid d790cfd3c0 Retract during printing of the raft. As requested. 2014-02-19 08:58:59 +01:00
daid f94a77bf94 Adds initial bits from bytes support. 2014-02-17 16:54:08 +01:00
daid bb8056c31a Fix the visual Z offset in the polygon view for the GUI. 2014-02-17 11:54:59 +01:00
daid 726b7c8055 Do not use G92 E0 for makerbot flavor code, as the makerbot firmware does not handle this very well. 2014-02-14 15:08:08 +01:00
daid dd0bac4371 Add support for line based support material. 2014-02-13 08:50:35 +01:00
daid b4cf57214f Merge pull request #56 from sshirokov/multiline-config
Multiline configuration values
2014-02-12 13:11:32 +01:00
daid 3d6552e3ce Merge branch 'master' of github.com:Ultimaker/CuraEngine 2014-02-12 13:07:05 +01:00
daid 260128e2b8 Add raft for wipe tower. https://github.com/daid/Cura/issues/725 2014-02-12 13:06:34 +01:00
Yaroslav Shirokov fa5776d4e3 No need for iostream, I guess. 2014-02-11 15:17:11 -08:00
Yaroslav Shirokov 9df845e5d7 Config support for multiline strings.
Multiline strings are started with """
and continue until a line contains only """ at the beginning

For example:

```
# Start and End gcode
startCode = """
; This is coming from the config
"""

endCode = """
;     such end code
;

; very wow
"""
```
2014-02-11 15:01:41 -08:00
Yaroslav Shirokov 4dec5b2b6e ConfigSettings::[start|end]Code are now std::string 2014-02-11 15:00:26 -08:00
Yaroslav Shirokov b6ef32dbbc Whitespace trim before I start hacking. 2014-02-11 14:29:03 -08:00
Yaroslav Shirokov 4501319c83 Split TRIM_STRING into LTRIMS_STRING and RTRIM_STRING 2014-02-11 02:18:48 -08:00
Yaroslav Shirokov bf712a8d1e WIP: Bunch out output around a multiline parser 2014-02-11 02:13:01 -08:00
Yaroslav Shirokov b881d552c0 Define a multiline separator 2014-02-11 02:12:08 -08:00
daid 8110bdd91e Merge pull request #55 from sshirokov/config-file
Support for loading Configuration Files
2014-02-09 09:31:42 +01:00
Yaroslav Shirokov 28703096cd Actually fail the read if a key is unknown 2014-02-08 03:50:19 -08:00
Yaroslav Shirokov b5210f8c3f Add -c <config> option to read a non-default config 2014-02-08 03:09:04 -08:00
Yaroslav Shirokov 02e4264c0e Fail a config read if we can't read it instead of setting 0 settings 2014-02-08 03:08:50 -08:00
Yaroslav Shirokov 35b8d124d0 Centralize settings concerns in settings.cpp/h 2014-02-08 02:42:43 -08:00
Yaroslav Shirokov 1c559cf497 _trim_string() is now TRIM_STRING() the macro 2014-02-08 02:26:19 -08:00
Yaroslav Shirokov 0547a83700 Whitespace. 2014-02-08 02:19:17 -08:00
Yaroslav Shirokov c40d5d7203 A simple key=value config parser
With comments
2014-02-08 02:08:02 -08:00
Yaroslav Shirokov 95880f8d0a Add a DEFAULT_CONFIG_PATH and ConfigSettings::readSetting(char*) scaffold
This will serve as the API to populate the settings from
a file on disk before evaulating command line arguments.
2014-02-08 02:08:02 -08:00
daid 9f5e1de888 Add ZHop and change where the default settings are stored. 2014-02-05 13:15:53 +01:00
daid 9c6f7eeca9 Refactoring thanks to Jaime. 2014-01-30 17:08:50 +01:00
daid 63be107768 Add missing newline. 2014-01-29 17:18:53 +01:00
daid 1ebe4315c3 Fix replaceTagInStart when using stdout as GCode output. 2014-01-29 16:36:24 +01:00
daid a9e6bb012a Fix new[] delete mismatch. 2014-01-29 15:55:49 +01:00
daid c6c8efd671 Fix the order in which support islands are printed. 2014-01-29 14:51:39 +01:00
daid fd59ee4b68 Fix the LDFLAGS order so building on windows works. 2014-01-29 14:13:58 +01:00
daid 52ee77f6b5 Add wsock32 library for windows. 2014-01-29 14:10:17 +01:00
daid 0707629846 Add missing include and proper close call for linux. 2014-01-29 13:05:00 +01:00
daid da7636580c Fix build with socket. 2014-01-29 11:22:21 +01:00
daid 5c91e890ac Add inset speed. 2014-01-29 10:02:05 +01:00
daid 2000edf105 Do not send infill lines to GUI, as this adds some significant slicing time. 2014-01-29 08:43:54 +01:00
daid ba3d2f26ce Add includes for linux/mac build of sockets. 2014-01-29 08:27:59 +01:00
daid 0f8bc5de19 Remove -I. as requested by debian maintainer. 2014-01-29 08:20:54 +01:00
daid ee622059d5 Add socket communication for polygon data and model data. 2014-01-28 17:46:59 +01:00
daid f97236a5aa Allow output of polygons towards the GUI. Change the Engine->GUI interface 2014-01-24 10:20:11 +01:00
daid 6ced5eb5d1 Fix the problem when type-A fix horrible generate filled areas due to flipping of line order. 2014-01-16 10:42:31 +01:00
daid 0debc14906 Set the makerbot toolchanges as by https://groups.google.com/forum/#!topic/ultimaker/h6i2ZjoSLTc 2014-01-14 09:54:48 +01:00
daid a2daa9b918 Fixed #49 2014-01-10 14:55:31 +01:00
143 arquivos alterados com 29824 adições e 10685 exclusões
+9
Ver Arquivo
@@ -13,4 +13,13 @@ _obj
.*.swp
*.gcode
CuraEngine
build/*
*~
NUL
CuraEngine.layout
CuraEngine.cbp
documentation/html/*
documentation/latex/*
*kdev*
*.kate-swp
+71
Ver Arquivo
@@ -0,0 +1,71 @@
project(CuraEngine)
cmake_minimum_required(VERSION 2.8.12)
find_package(Arcus REQUIRED)
if(NOT ${CMAKE_VERSION} VERSION_LESS 3.1)
set(CMAKE_CXX_STANDARD 11)
else()
set(CMAKE_CXX_FLAGS "-std=c++11")
endif()
# Add warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
if(NOT APPLE AND NOT WIN32)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++")
elseif(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
endif()
include_directories(${CMAKE_CURRENT_BINARY_DIR} libs)
add_library(clipper STATIC libs/clipper/clipper.cpp)
set(engine_SRCS
src/bridge.cpp
src/comb.cpp
src/commandSocket.cpp
src/gcodeExport.cpp
src/gcodePlanner.cpp
src/infill.cpp
src/inset.cpp
src/layerPart.cpp
src/main.cpp
src/mesh.cpp
src/multiVolumes.cpp
src/pathOrderOptimizer.cpp
src/polygonOptimizer.cpp
src/raft.cpp
src/settingRegistry.cpp
src/settings.cpp
src/skin.cpp
src/skirt.cpp
src/slicer.cpp
src/support.cpp
src/timeEstimate.cpp
src/Weaver.cpp
src/Wireframe2gcode.cpp
src/modelFile/modelFile.cpp
src/utils/gettime.cpp
src/utils/logoutput.cpp
src/utils/polygonUtils.cpp
)
protobuf_generate_cpp(engine_PB_SRCS engine_PB_HEADERS Cura.proto)
add_executable(CuraEngine ${engine_SRCS} ${engine_PB_SRCS})
target_link_libraries(CuraEngine clipper Arcus)
add_executable(Test src/test.cpp)
target_link_libraries(Test clipper)
if (UNIX)
target_link_libraries(CuraEngine pthread)
endif()
include(GNUInstallDirs)
install(TARGETS CuraEngine DESTINATION ${CMAKE_INSTALL_BINDIR})
+86
Ver Arquivo
@@ -0,0 +1,86 @@
syntax = "proto3";
package Cura;
// typeid 1
message ObjectList {
repeated Object objects = 1;
}
message Object {
int64 id = 1;
bytes vertices = 2; //An array of 3 floats.
bytes normals = 3; //An array of 3 floats.
bytes indices = 4; //An array of ints.
repeated Setting settings = 5; // Setting override per object, overruling the global settings.
}
// typeid 3
message Progress {
float amount = 1;
}
// typeid 2
message SlicedObjectList {
repeated SlicedObject objects = 1;
}
message SlicedObject {
int64 id = 1;
repeated Layer layers = 2;
}
message Layer {
int32 id = 1;
float height = 2;
float thickness = 3;
repeated Polygon polygons = 4;
}
message Polygon {
enum Type {
NoneType = 0;
Inset0Type = 1;
InsetXType = 2;
SkinType = 3;
SupportType = 4;
SkirtType = 5;
InfillType = 6;
SupportInfillType = 7;
}
Type type = 1;
bytes points = 2;
float line_width = 3;
}
// typeid 4
message GCodeLayer {
int64 id = 1;
bytes data = 2;
}
// typeid 5
message ObjectPrintTime {
int64 id = 1;
float time = 2;
float material_amount = 3;
}
// typeid 6
message SettingList {
repeated Setting settings = 1;
}
message Setting {
string name = 1;
bytes value = 2;
}
// typeid 7
message GCodePrefix {
bytes data = 2;
}
+2303
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
-52
Ver Arquivo
@@ -1,52 +0,0 @@
#
# Makefile for CuraEngine
#
# simplest working invocation to compile it
#g++ main.cpp modelFile/modelFile.cpp clipper/clipper.cpp -I. -o CuraEngine
CXX ?= g++
CFLAGS += -I. -c -Wall -Wextra -O3 -fomit-frame-pointer
# also include debug symbols
#CFLAGS+=-ggdb
LDFLAGS +=
SOURCES = bridge.cpp comb.cpp gcodeExport.cpp infill.cpp inset.cpp layerPart.cpp main.cpp optimizedModel.cpp pathOrderOptimizer.cpp polygonOptimizer.cpp raft.cpp settings.cpp skin.cpp skirt.cpp slicer.cpp support.cpp timeEstimate.cpp
SOURCES += clipper/clipper.cpp modelFile/modelFile.cpp utils/gettime.cpp utils/logoutput.cpp
OBJECTS = $(SOURCES:.cpp=.o)
EXECUTABLE = ./CuraEngine
UNAME := $(shell uname)
ifeq ($(UNAME), Linux)
OPEN_HTML=firefox
LDFLAGS += --static
endif
ifeq ($(UNAME), Darwin)
OPEN_HTML=open
#For MacOS force to build
CFLAGS += -force_cpusubtype_ALL -mmacosx-version-min=10.6 -arch x86_64 -arch i386
LDFLAGS += -force_cpusubtype_ALL -mmacosx-version-min=10.6 -arch x86_64 -arch i386
endif
ifeq ($(UNAME), MINGW32_NT-6.1)
#For windows make it large address aware, which allows the process to use more then 2GB of memory.
EXECUTABLE := $(EXECUTABLE).exe
CFLAGS += -march=pentium4
LDFLAGS += -Wl,--large-address-aware -lm
endif
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CXX) $(LDFLAGS) $(OBJECTS) -o $@
.cpp.o:
$(CXX) $(CFLAGS) $< -o $@
test: $(EXECUTABLE)
python _tests/runtest.py $(abspath $(EXECUTABLE))
## clean stuff
clean:
rm -f $(EXECUTABLE) $(OBJECTS)
help:
@cat Makefile |grep \#\#| grep \: |cut -d\# -f3
+52 -11
Ver Arquivo
@@ -5,9 +5,9 @@ The CuraEngine is a C++ console application for 3D printing GCode generation. It
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.
This is just a console application for GCode generation. For a full graphical application look at https://github.com/daid/Cura with 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/daid/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 to take note of the License.
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.
License
=======
@@ -16,11 +16,52 @@ Terms of the license can be found in the LICENSE file. Or at http://www.gnu.org/
But in general it boils down to: You need to share the source of any CuraEngine modifications if you make an application with the CuraEngine. (Even if you make a web-based slicer, you still need to share the source!)
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)
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
Project files generation:
1. Navigate to the CuraEngine directory and execute the following commands
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)
Running
=======
Other than running CuraEngine from a frontend, such as PluggableCura, one can run CuraEngine from the command line.
An example run for an UM2 machine looks as follows:
* Navigate to the CuraEngine directory and execute the following
```
./build/CuraEngine -v -j fdmprinter.json -s machine_start_gcode=";FLAVOR:UltiGCode
;TIME:10000000
;MATERIAL:2000
;MATERIAL2:0" -s mesh_position_x=115.0 -s mesh_position_y=112.5 -s mesh_position_z=0 -s material_diameter=1.128 -o "output/test.gcode" "/path/to/model.stl"
```
Internals
=========
The Cura Engine is structured as mainly .h files. This is not standard for an C++ project. However, using less cpp files makes the optimizer work harder and removes linking error issues. It's partialy a result of lazyness but also for optimalizations.
The Cura Engine is structured as mainly .h files. This is not standard for a C++ project. However, using less cpp files makes the optimizer work harder and removes linking error issues. It's partialy a result of lazyness but comes in handy for optimalizations.
The .h files contain different steps called from the main.cpp file. The main.cpp file contains the global slicing logic.
@@ -45,20 +86,20 @@ The OptimizedModel is a 3D model stored with vertex<->face relations. This gives
Slicer
======
While usually the whole GCode generation process is called Slicing. The slicer in the CuraEngine is the piece of code that generates layers. Each layer has closed 2D polygons.
While usually the whole GCode generation process is called 'slicing', the Slicer in the CuraEngine is the piece of code that generates layers. Each layer contains closed 2D polygons.
These polygons are generated in a 2 step process. First all triangles are cut into lines per layer, for each layer a "line segment" is added to that layer.
Next all these line-segments are connected to eachother to make Polygons. The vertex<->face relations of the OptimizedModel help to make this process fast, as there is a huge chance that 2 connecting faces also make 2 connecting line-segments.
This code also fixes up small holes in the 3D model, so your model doesn't need to be perfect Manifold. It also accounts for incorrect normals, so it can flip around line-segments to fit end-to-end.
This code also patches up small holes in the 3D model, so your model doesn't need to be a perfect Manifold. It also deals with incorrect normals, so it can flip around line-segments to fit end-to-end.
After the Slicer we have closed Polygons which can be used in Clipper, as Clipper can only opperate on closed 2D polygons.
LayerParts
==========
An important concept to grasp is the LayerParts. LayerParts are seperate parts inside a single layer. For example, if you have a cube. Then each layer has a single LayerPart. However, if you have a table, then the layers which build the legs have a LayerPart per leg, and thus there will be 4 LayerParts.
A LayerPart is a seperated area inside a single layer which does not touch any other LayerParts. Most operations run on LayerParts as it reduces the amount of data to process. During GCode generation handling each LayerPart as an own step makes sure you never travel between LayerParts and thus reducing the amount of external travel.
An important concept to grasp is the idea of LayerParts. LayerParts are seperate parts inside a single layer. For example, in a solid cube each layer has a single LayerPart. However, in a table the layers which cover the legs have a LayerPart per leg, and thus there will be 4 LayerParts.
A LayerPart is a seperated area inside a single layer which does not touch any other LayerParts. Most operations run on LayerParts as it reduces the amount of data to be processed. During GCode generation handling each LayerPart as a separate step makes sure you never travel between LayerParts which reduces the amount of external travel.
LayerParts are generated after the Slicer step.
To generate the LayerParts Clipper is used. A Clipper union with extended results gives a list of Polygons with holes in them. Each polygon is a LayerPart, and the holes are added to this LayerPart.
In order to generate the LayerParts, Clipper is used. A Clipper union with extended results gives a list of Polygons with holes in them. Each polygon is a LayerPart, and the holes are added to this LayerPart.
Insets
@@ -70,12 +111,12 @@ Up/Down skin
The skin code generates the fully filled areas, it does this with some heavy boolean Clipper action. The skin step uses data from different layers to get the job done. Check the code for details.
The sparse infill area code is almost the same as the skin code. With the difference that it keeps the other areas and uses different offsets.
Note that these steps generate the areas, not the actual infill lines. The infill line paths are generated later on. So the result of this step are list of Polygons which are the areas that need to be filled.
Note that these steps generate the areas, not the actual infill lines. The infill line paths are generated later on. So the result of this step are lists of Polygons which are the areas that need to be filled.
GCode generation
================
The GCode generation is quite a large bit of code. As a lot is going on here. Important bits here are:
* 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 around the head 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, and to generate a different flavor of GCode it will be the only piece that needs adjustment. All volumatric calculations also happen here.
* 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.
-14
Ver Arquivo
@@ -1,14 +0,0 @@
#!/usr/bin/python
import sys
import subprocess
def main(engine):
p = subprocess.Popen([engine, '-c', 'supportAngle=60', '-c', 'supportEverywhere=1', '_tests/testModel.stl'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
p.communicate()
if p.wait() != 0:
print "Engine failed to report success on test object slice..."
sys.exit(1)
if __name__ == '__main__':
main(sys.argv[1])
+1
Ver Arquivo
@@ -0,0 +1 @@
html/index.html
Arquivo binário não exibido.

Depois

Largura:  |  Altura:  |  Tamanho: 18 KiB

+126
Ver Arquivo
@@ -0,0 +1,126 @@
Code Conventions
=======
Note that the code convention described here have not all yet been fully implemented.
Bracketing and indenting
-----
~~~~~~~~~~~~~~~{.cpp}
if (condition) // brackets always on new lines
{ // allways a bracket after an if, for, while, etc.
// indent always with 4 spaces, never with tabs
}
else // else on new line
{
// more code
}
~~~~~~~~~~~~~~~
Naming conventions
------
* variables: lower_case_with_underscores
* functions: loweCamelCase
* classes: UpperCamelCase
* macros: UPPER_CASE_WITH_UNDERSCORES
~~~~~~~~~~~~~~~{.cpp}
#define UPPER_CASE_MACRO 1
class UpperCamelCase
{
private:
MemberVariableObject with_underscores;
public:
MemberVariableObject with_underscores;
public:
UpperCamelCase();
~UpperCamelCase();
// start with input variable(s) and end with output variable(s)
void lowerCamelCaseFunctions(ParamObject& also_with_underscores)
{
LocalObject under_scores;
}
private:
void putFunctionsAndVariablesInSeperatePublicPrivateBlocks();
};
~~~~~~~~~~~~~~~
Ordering
----
~~~~~~~~~~~~~~~{.cpp}
class Example
{
// start with input variable(s) and end with output parameter(s)
void function1(ParamObject& input_variable, int setting_parameter, ParamObject2& return_parameter)
{
function2();
function3();
}
// place functions called solely by one other function below it chronologically
void function2();
void function3();
};
~~~~~~~~~~~~~~~
Documentation
----
We use [Doxygen](www.doxygen.org/) to generate documentation. Try to keep your documentation in doxygen style.
Here's a small example:
~~~~~~~~~~~~~~~{.cpp}
/ *!
* Doxygen style comments!
*
* \param param1 explanation may refer to another \p param2
* /
void function(int param1, int param2)
{
// non-doxygen style comments on implementation details
}
int member; //!< inline doxygen comment on the entry to the left
~~~~~~~~~~~~~~~
Files
--------
For a file Foo.h (UpperCamelCase):
~~~~~~~~~~~~~~~{.cpp}
#ifndef FOO_H
#define FOO_H
// [content]
#endif//FOO_H
~~~~~~~~~~~~~~~
Other
----
~~~~~~~~~~~~~~~{.cpp}
#include <all>
#include <includes>
#include <on>
#include <top>
#include <first_system_includes>
#include <then_library_includes>
#include "finally_local_includes"
enum class EnumExample
{
ELEM0 = 0,
ELEM1 = 1
}
~~~~~~~~~~~~~~~
Illegal syntax
----
~~~~~~~~~~~~~~~{.cpp}
void function()
{
if (condition)
single_line_outside_code_block(); // always use braces!
}; // unneccesary semicolon after function definition is not allowed
~~~~~~~~~~~~~~~
+11
Ver Arquivo
@@ -0,0 +1,11 @@
Glossary
========
Term/Synonyms | Meaning
--- | ---
Island/Part | isolated/unconnected part in 2D slice
Inset | perimeter, the perimeters which are laid down around the infill
Slicing | The act of extracting the contours of the object at a certain height (not the whole process which would also include gcode generation etc.)
Tower (support) | A strut to reinforce parts of the support which would otherwise be unstable.
Weaver / Neith / WirePrint | A non-layer-wise form of printing 'in thin air'
+10
Ver Arquivo
@@ -0,0 +1,10 @@
CuraEngine {#mainpage}
=======
This is the documentation for CuraEngine, the back-end slicer of Cura.
[Overview](documentation/overview.md)
[Glossary](documentation/glossary.md)
[Code Conventions](documentation/code_conventions.md)
+68
Ver Arquivo
@@ -0,0 +1,68 @@
Overview
========
Internals
---------
The Cura Engine is structured as mainly .h files. This is not standard for an C++ project. However, using less cpp files makes the optimizer work harder and removes linking error issues. It's partialy a result of lazyness but also for optimalizations.
The .h files contain different steps called from the main.cpp file. The main.cpp file contains the global slicing logic.
The slicing process follows the following global steps:
* Load 3D model
* Analize and fix 3D model
* Slice 3D model into 2D layers
* Build LayerParts from sliced layers
* Generate Insets
* Generate up/down skins areas
* Generate sparse infill areas
* Generate GCode for each layer
Each step has more logic in it. But this is a general overview.
All data for the engine is stored in the "SliceDataStorage". It's important to remember that only the data from the previous step is valid.
Coordinates are stored in 64bit integers as microns in the code. So if you see a value of 1000 then this mean 1mm of distance. This is because Clipper works on 64bit integers and microns give a high enough resolution without limiting the size too much. Note that there are some bits and pieces of code that need to be careful about 64bit overflows, especially calculating lengths sqrt(x*x+y*y) can cause overflows.
OptimizedModel
--------------
The OptimizedModel is a 3D model stored with vertex<->face relations. This gives touching face relations which are used later on to slice into layers faster.
Slicer
------
While usually the whole GCode generation process is called Slicing. The slicer in the CuraEngine is the piece of code that generates layers. Each layer has closed 2D polygons.
These polygons are generated in a 2 step process. First all triangles are cut into lines per layer, for each layer a "line segment" is added to that layer.
Next all these line-segments are connected to eachother to make Polygons. The vertex<->face relations of the OptimizedModel help to make this process fast, as there is a huge chance that 2 connecting faces also make 2 connecting line-segments.
This code also fixes up small holes in the 3D model, so your model doesn't need to be perfect Manifold. It also accounts for incorrect normals, so it can flip around line-segments to fit end-to-end.
After the Slicer we have closed Polygons which can be used in Clipper, as Clipper can only opperate on closed 2D polygons.
LayerParts
----------
An important concept to grasp is the LayerParts. LayerParts are seperate parts inside a single layer. For example, if you have a cube. Then each layer has a single LayerPart. However, if you have a table, then the layers which build the legs have a LayerPart per leg, and thus there will be 4 LayerParts.
A LayerPart is a seperated area inside a single layer which does not touch any other LayerParts. Most operations run on LayerParts as it reduces the amount of data to process. During GCode generation handling each LayerPart as an own step makes sure you never travel between LayerParts and thus reducing the amount of external travel.
LayerParts are generated after the Slicer step.
To generate the LayerParts Clipper is used. A Clipper union with extended results gives a list of Polygons with holes in them. Each polygon is a LayerPart, and the holes are added to this LayerPart.
Polygons
--------
Holes are polygons in counter-clockwise (or at-least, in the other direction) and the polygons are guaranteed to be "even-odd", so every crossing of polygon lines will switch from "fill" to "empty".
Insets
------
Insets are also called "Perimeters" or "Loops" sometimes. Generating the insets is only a small bit of code, as Clipper does most of the heavy lifting.
Up/Down skin
------------
The skin code generates the fully filled areas, it does this with some heavy boolean Clipper action. The skin step uses data from different layers to get the job done. Check the code for details.
The sparse infill area code is almost the same as the skin code. With the difference that it keeps the other areas and uses different offsets.
Note that these steps generate the areas, not the actual infill lines. The infill line paths are generated later on. So the result of this step are list of Polygons which are the areas that need to be filled.
GCode generation
----------------
The GCode generation is quite a large bit of code. As a lot is going on here. Important bits here are:
* 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 around the head 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, and to generate a different flavor of GCode it will be the only piece that needs adjustment. All volumatric calculations also happen here.
+1325
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
-525
Ver Arquivo
@@ -1,525 +0,0 @@
#ifndef FFF_PROCESSOR_H
#define FFF_PROCESSOR_H
//FusedFilamentFabrication processor.
class fffProcessor
{
private:
int maxObjectHeight;
int fileNr;
GCodeExport gcode;
ConfigSettings& config;
TimeKeeper timeKeeper;
GCodePathConfig skirtConfig;
GCodePathConfig inset0Config;
GCodePathConfig inset1Config;
GCodePathConfig fillConfig;
GCodePathConfig supportConfig;
public:
fffProcessor(ConfigSettings& config)
: config(config)
{
fileNr = 1;
maxObjectHeight = 0;
}
bool setTargetFile(const char* filename)
{
gcode.setFilename(filename);
if (gcode.isValid())
gcode.addComment("Generated with Cura_SteamEngine %s", VERSION);
return gcode.isValid();
}
bool processFile(const char* input_filename)
{
if (!gcode.isValid())
return false;
TimeKeeper timeKeeperTotal;
SliceDataStorage storage;
preSetup();
if (!prepareModel(storage, input_filename))
return false;
processSliceData(storage);
writeGCode(storage);
logProgress("process", 1, 1);
log("Total time elapsed %5.2fs.\n", timeKeeperTotal.restart());
return true;
}
void finalize()
{
if (!gcode.isValid())
return;
gcode.addFanCommand(0);
gcode.addRetraction();
gcode.setZ(maxObjectHeight + 5000);
gcode.addMove(gcode.getPositionXY(), config.moveSpeed, 0);
gcode.addCode(config.endCode);
log("Print time: %d\n", int(gcode.getTotalPrintTime()));
log("Filament: %d\n", int(gcode.getTotalFilamentUsed(0)));
log("Filament2: %d\n", int(gcode.getTotalFilamentUsed(1)));
if (gcode.getFlavor() == GCODE_FLAVOR_ULTIGCODE)
{
char numberString[16];
sprintf(numberString, "%d", int(gcode.getTotalPrintTime()));
gcode.replaceTagInStart("<__TIME__>", numberString);
sprintf(numberString, "%d", int(gcode.getTotalFilamentUsed(0)));
gcode.replaceTagInStart("<FILAMENT>", numberString);
sprintf(numberString, "%d", int(gcode.getTotalFilamentUsed(1)));
gcode.replaceTagInStart("<FILAMEN2>", numberString);
}
}
private:
void preSetup()
{
skirtConfig.setData(config.printSpeed, config.extrusionWidth, "SKIRT");
inset0Config.setData(config.printSpeed, config.extrusionWidth, "WALL-OUTER");
inset1Config.setData(config.printSpeed, config.extrusionWidth, "WALL-INNER");
fillConfig.setData(config.infillSpeed, config.extrusionWidth, "FILL");
supportConfig.setData(config.printSpeed, config.extrusionWidth, "SUPPORT");
for(unsigned int n=1; n<MAX_EXTRUDERS;n++)
gcode.setExtruderOffset(n, config.extruderOffset[n].p());
gcode.setFlavor(config.gcodeFlavor);
gcode.setRetractionSettings(config.retractionAmount, config.retractionSpeed, config.retractionAmountExtruderSwitch, config.minimalExtrusionBeforeRetraction);
}
bool prepareModel(SliceDataStorage& storage, const char* input_filename)
{
timeKeeper.restart();
log("Loading %s from disk...\n", input_filename);
SimpleModel* m = loadModel(input_filename, config.matrix);
if (!m)
{
log("Failed to load model: %s\n", input_filename);
return false;
}
log("Loaded from disk in %5.3fs\n", timeKeeper.restart());
log("Analyzing and optimizing model...\n");
OptimizedModel* om = new OptimizedModel(m, Point3(config.objectPosition.X, config.objectPosition.Y, -config.objectSink));
for(unsigned int v = 0; v < m->volumes.size(); v++)
{
log(" Face counts: %i -> %i %0.1f%%\n", (int)m->volumes[v].faces.size(), (int)om->volumes[v].faces.size(), float(om->volumes[v].faces.size()) / float(m->volumes[v].faces.size()) * 100);
log(" Vertex counts: %i -> %i %0.1f%%\n", (int)m->volumes[v].faces.size() * 3, (int)om->volumes[v].points.size(), float(om->volumes[v].points.size()) / float(m->volumes[v].faces.size() * 3) * 100);
}
delete m;
log("Optimize model %5.3fs \n", timeKeeper.restart());
//om->saveDebugSTL("c:\\models\\output.stl");
log("Slicing model...\n");
vector<Slicer*> slicerList;
for(unsigned int volumeIdx=0; volumeIdx < om->volumes.size(); volumeIdx++)
{
slicerList.push_back(new Slicer(&om->volumes[volumeIdx], config.initialLayerThickness / 2, config.layerThickness, config.fixHorrible & FIX_HORRIBLE_KEEP_NONE_CLOSED, config.fixHorrible & FIX_HORRIBLE_EXTENSIVE_STITCHING));
//slicerList[volumeIdx]->dumpSegmentsToHTML("C:\\models\\output.html");
}
log("Sliced model in %5.3fs\n", timeKeeper.restart());
fprintf(stdout,"Generating support map...\n");
generateSupportGrid(storage.support, om, config.supportAngle, config.supportEverywhere > 0, config.supportXYDistance, config.supportZDistance);
storage.modelSize = om->modelSize;
storage.modelMin = om->vMin;
storage.modelMax = om->vMax;
delete om;
log("Generating layer parts...\n");
for(unsigned int volumeIdx=0; volumeIdx < slicerList.size(); volumeIdx++)
{
storage.volumes.push_back(SliceVolumeStorage());
createLayerParts(storage.volumes[volumeIdx], slicerList[volumeIdx], config.fixHorrible & (FIX_HORRIBLE_UNION_ALL_TYPE_A | FIX_HORRIBLE_UNION_ALL_TYPE_B | FIX_HORRIBLE_UNION_ALL_TYPE_C));
delete slicerList[volumeIdx];
}
log("Generated layer parts in %5.3fs\n", timeKeeper.restart());
return true;
}
void processSliceData(SliceDataStorage& storage)
{
//carveMultipleVolumes(storage.volumes);
generateMultipleVolumesOverlap(storage.volumes, config.multiVolumeOverlap);
//dumpLayerparts(storage, "c:/models/output.html");
const unsigned int totalLayers = storage.volumes[0].layers.size();
for(unsigned int layerNr=0; layerNr<totalLayers; layerNr++)
{
for(unsigned int volumeIdx=0; volumeIdx<storage.volumes.size(); volumeIdx++)
{
int insetCount = config.insetCount;
if (config.spiralizeMode && int(layerNr) < config.downSkinCount && layerNr % 2 == 1)//Add extra insets every 2 layers when spiralizing, this makes bottoms of cups watertight.
insetCount += 5;
generateInsets(&storage.volumes[volumeIdx].layers[layerNr], config.extrusionWidth, insetCount);
}
logProgress("inset",layerNr+1,totalLayers);
}
if (config.enableOozeShield)
{
for(unsigned int layerNr=0; layerNr<totalLayers; layerNr++)
{
Polygons oozeShield;
for(unsigned int volumeIdx=0; volumeIdx<storage.volumes.size(); volumeIdx++)
{
for(unsigned int partNr=0; partNr<storage.volumes[volumeIdx].layers[layerNr].parts.size(); partNr++)
{
oozeShield = oozeShield.unionPolygons(storage.volumes[volumeIdx].layers[layerNr].parts[partNr].outline.offset(2000));
}
}
storage.oozeShield.push_back(oozeShield);
}
for(unsigned int layerNr=0; layerNr<totalLayers; layerNr++)
storage.oozeShield[layerNr] = storage.oozeShield[layerNr].offset(-1000).offset(1000);
int offsetAngle = tan(60.0*M_PI/180) * config.layerThickness;//Allow for a 60deg angle in the oozeShield.
for(unsigned int layerNr=1; layerNr<totalLayers; layerNr++)
storage.oozeShield[layerNr] = storage.oozeShield[layerNr].unionPolygons(storage.oozeShield[layerNr-1].offset(-offsetAngle));
for(unsigned int layerNr=totalLayers-1; layerNr>0; layerNr--)
storage.oozeShield[layerNr-1] = storage.oozeShield[layerNr-1].unionPolygons(storage.oozeShield[layerNr].offset(-offsetAngle));
}
log("Generated inset in %5.3fs\n", timeKeeper.restart());
for(unsigned int layerNr=0; layerNr<totalLayers; layerNr++)
{
if (!config.spiralizeMode || int(layerNr) < config.downSkinCount) //Only generate up/downskin and infill for the first X layers when spiralize is choosen.
{
for(unsigned int volumeIdx=0; volumeIdx<storage.volumes.size(); volumeIdx++)
{
generateSkins(layerNr, storage.volumes[volumeIdx], config.extrusionWidth, config.downSkinCount, config.upSkinCount, config.infillOverlap);
generateSparse(layerNr, storage.volumes[volumeIdx], config.extrusionWidth, config.downSkinCount, config.upSkinCount);
}
}
logProgress("skin",layerNr+1,totalLayers);
}
log("Generated up/down skin in %5.3fs\n", timeKeeper.restart());
if (config.wipeTowerSize > 0)
{
PolygonRef p = storage.wipeTower.newPoly();
p.add(Point(storage.modelMin.x - 3000, storage.modelMax.y + 3000));
p.add(Point(storage.modelMin.x - 3000, storage.modelMax.y + 3000 + config.wipeTowerSize));
p.add(Point(storage.modelMin.x - 3000 - config.wipeTowerSize, storage.modelMax.y + 3000 + config.wipeTowerSize));
p.add(Point(storage.modelMin.x - 3000 - config.wipeTowerSize, storage.modelMax.y + 3000));
storage.wipePoint = Point(storage.modelMin.x - 3000 - config.wipeTowerSize / 2, storage.modelMax.y + 3000 + config.wipeTowerSize / 2);
}
generateSkirt(storage, config.skirtDistance, config.extrusionWidth, config.skirtLineCount, config.skirtMinLength, config.initialLayerThickness);
generateRaft(storage, config.raftMargin);
for(unsigned int volumeIdx=0; volumeIdx<storage.volumes.size(); volumeIdx++)
{
for(unsigned int layerNr=0; layerNr<totalLayers; layerNr++)
{
for(unsigned int partNr=0; partNr<storage.volumes[volumeIdx].layers[layerNr].parts.size(); partNr++)
{
if (layerNr > 0)
storage.volumes[volumeIdx].layers[layerNr].parts[partNr].bridgeAngle = bridgeAngle(&storage.volumes[volumeIdx].layers[layerNr].parts[partNr], &storage.volumes[volumeIdx].layers[layerNr-1]);
else
storage.volumes[volumeIdx].layers[layerNr].parts[partNr].bridgeAngle = -1;
}
}
}
}
void writeGCode(SliceDataStorage& storage)
{
if (fileNr == 1)
{
if (gcode.getFlavor() == GCODE_FLAVOR_ULTIGCODE)
{
gcode.addCode(";FLAVOR:UltiGCode");
gcode.addCode(";TIME:<__TIME__>");
gcode.addCode(";MATERIAL:<FILAMENT>");
gcode.addCode(";MATERIAL2:<FILAMEN2>");
}
gcode.addCode(config.startCode);
}else{
gcode.addFanCommand(0);
gcode.resetExtrusionValue();
gcode.addRetraction();
gcode.setZ(maxObjectHeight + 5000);
gcode.addMove(Point(storage.modelMin.x, storage.modelMin.y), config.moveSpeed, 0);
}
fileNr++;
unsigned int totalLayers = storage.volumes[0].layers.size();
gcode.addComment("Layer count: %d", totalLayers);
if (config.raftBaseThickness > 0 && config.raftInterfaceThickness > 0)
{
GCodePathConfig raftBaseConfig(config.initialLayerSpeed, config.raftBaseLinewidth, "SUPPORT");
GCodePathConfig raftInterfaceConfig(config.initialLayerSpeed, config.raftInterfaceLinewidth, "SUPPORT");
{
gcode.addComment("LAYER:-2");
gcode.addComment("RAFT");
GCodePlanner gcodeLayer(gcode, config.moveSpeed, config.retractionMinimalDistance);
gcode.setZ(config.raftBaseThickness);
gcode.setExtrusion(config.raftBaseThickness, config.filamentDiameter, config.filamentFlow);
gcodeLayer.addPolygonsByOptimizer(storage.raftOutline, &raftBaseConfig);
Polygons raftLines;
generateLineInfill(storage.raftOutline, raftLines, config.raftBaseLinewidth, config.raftLineSpacing, config.infillOverlap, 0);
gcodeLayer.addPolygonsByOptimizer(raftLines, &raftBaseConfig);
gcodeLayer.writeGCode(false, config.raftBaseThickness);
}
{
gcode.addComment("LAYER:-1");
gcode.addComment("RAFT");
GCodePlanner gcodeLayer(gcode, config.moveSpeed, config.retractionMinimalDistance);
gcode.setZ(config.raftBaseThickness + config.raftInterfaceThickness);
gcode.setExtrusion(config.raftInterfaceThickness, config.filamentDiameter, config.filamentFlow);
Polygons raftLines;
generateLineInfill(storage.raftOutline, raftLines, config.raftInterfaceLinewidth, config.raftLineSpacing, config.infillOverlap, 90);
gcodeLayer.addPolygonsByOptimizer(raftLines, &raftInterfaceConfig);
gcodeLayer.writeGCode(false, config.raftInterfaceThickness);
}
}
int volumeIdx = 0;
for(unsigned int layerNr=0; layerNr<totalLayers; layerNr++)
{
logProgress("export", layerNr+1, totalLayers);
gcode.addComment("LAYER:%d", layerNr);
if (layerNr == 0)
gcode.setExtrusion(config.initialLayerThickness, config.filamentDiameter, config.filamentFlow);
else
gcode.setExtrusion(config.layerThickness, config.filamentDiameter, config.filamentFlow);
GCodePlanner gcodeLayer(gcode, config.moveSpeed, config.retractionMinimalDistance);
int32_t z = config.initialLayerThickness + layerNr * config.layerThickness;
z += config.raftBaseThickness + config.raftInterfaceThickness;
gcode.setZ(z);
bool printSupportFirst = (storage.support.generated && config.supportExtruder > 0 && config.supportExtruder == gcodeLayer.getExtruder());
if (printSupportFirst)
addSupportToGCode(storage, gcodeLayer, layerNr);
for(unsigned int volumeCnt = 0; volumeCnt < storage.volumes.size(); volumeCnt++)
{
if (volumeCnt > 0)
volumeIdx = (volumeIdx + 1) % storage.volumes.size();
addVolumeLayerToGCode(storage, gcodeLayer, volumeIdx, layerNr);
}
if (!printSupportFirst)
addSupportToGCode(storage, gcodeLayer, layerNr);
//Finish the layer by applying speed corrections for minimal layer times and slowdown for the initial layer.
if (int(layerNr) < config.initialSpeedupLayers)
{
int n = config.initialSpeedupLayers;
int layer0Factor = config.initialLayerSpeed * 100 / config.printSpeed;
gcodeLayer.setExtrudeSpeedFactor((layer0Factor * (n - layerNr) + 100 * (layerNr)) / n);
if (layerNr == 0)//On the first layer, also slow down the travel
gcodeLayer.setTravelSpeedFactor(layer0Factor);
}
gcodeLayer.forceMinimalLayerTime(config.minimalLayerTime, config.minimalFeedrate);
int fanSpeed = config.fanSpeedMin;
if (gcodeLayer.getExtrudeSpeedFactor() <= 50)
{
fanSpeed = config.fanSpeedMax;
}else{
int n = gcodeLayer.getExtrudeSpeedFactor() - 50;
fanSpeed = config.fanSpeedMin * n / 50 + config.fanSpeedMax * (50 - n) / 50;
}
if (int(layerNr) < config.fanFullOnLayerNr)
{
//Slow down the fan on the layers below the [fanFullOnLayerNr], where layer 0 is speed 0.
fanSpeed = fanSpeed * layerNr / config.fanFullOnLayerNr;
}
gcode.addFanCommand(fanSpeed);
gcodeLayer.writeGCode(config.coolHeadLift > 0, int(layerNr) > 0 ? config.layerThickness : config.initialLayerThickness);
}
/* support debug
for(int32_t y=0; y<storage.support.gridHeight; y++)
{
for(int32_t x=0; x<storage.support.gridWidth; x++)
{
unsigned int n = x+y*storage.support.gridWidth;
if (storage.support.grid[n].size() < 1) continue;
int32_t z = storage.support.grid[n][0].z;
gcode.addMove(Point3(x * storage.support.gridScale + storage.support.gridOffset.X, y * storage.support.gridScale + storage.support.gridOffset.Y, 0), 0);
gcode.addMove(Point3(x * storage.support.gridScale + storage.support.gridOffset.X, y * storage.support.gridScale + storage.support.gridOffset.Y, z), z);
gcode.addMove(Point3(x * storage.support.gridScale + storage.support.gridOffset.X, y * storage.support.gridScale + storage.support.gridOffset.Y, 0), 0);
}
}
//*/
log("Wrote layers in %5.2fs.\n", timeKeeper.restart());
gcode.tellFileSize();
gcode.addFanCommand(0);
//Store the object height for when we are printing multiple objects, as we need to clear every one of them when moving to the next position.
maxObjectHeight = std::max(maxObjectHeight, storage.modelSize.z);
}
//Add a single layer from a single mesh-volume to the GCode
void addVolumeLayerToGCode(SliceDataStorage& storage, GCodePlanner& gcodeLayer, int volumeIdx, int layerNr)
{
int prevExtruder = gcodeLayer.getExtruder();
bool extruderChanged = gcodeLayer.setExtruder(volumeIdx);
if (layerNr == 0 && volumeIdx == 0)
gcodeLayer.addPolygonsByOptimizer(storage.skirt, &skirtConfig);
SliceLayer* layer = &storage.volumes[volumeIdx].layers[layerNr];
if (extruderChanged)
addWipeTower(storage, gcodeLayer, layerNr, prevExtruder);
if (storage.oozeShield.size() > 0 && storage.volumes.size() > 1)
{
gcodeLayer.setAlwaysRetract(true);
gcodeLayer.addPolygonsByOptimizer(storage.oozeShield[layerNr], &skirtConfig);
gcodeLayer.setAlwaysRetract(!config.enableCombing);
}
PathOrderOptimizer partOrderOptimizer(gcode.getPositionXY());
for(unsigned int partNr=0; partNr<layer->parts.size(); partNr++)
{
partOrderOptimizer.addPolygon(layer->parts[partNr].insets[0][0]);
}
partOrderOptimizer.optimize();
for(unsigned int partCounter=0; partCounter<partOrderOptimizer.polyOrder.size(); partCounter++)
{
SliceLayerPart* part = &layer->parts[partOrderOptimizer.polyOrder[partCounter]];
if (config.enableCombing)
gcodeLayer.setCombBoundary(&part->combBoundery);
else
gcodeLayer.setAlwaysRetract(true);
if (config.insetCount > 0)
{
if (config.spiralizeMode)
{
if (int(layerNr) >= config.downSkinCount)
inset0Config.spiralize = true;
if (int(layerNr) == config.downSkinCount && part->insets.size() > 0)
gcodeLayer.addPolygonsByOptimizer(part->insets[0], &inset1Config);
}
for(int insetNr=part->insets.size()-1; insetNr>-1; insetNr--)
{
if (insetNr == 0)
gcodeLayer.addPolygonsByOptimizer(part->insets[insetNr], &inset0Config);
else
gcodeLayer.addPolygonsByOptimizer(part->insets[insetNr], &inset1Config);
}
}
Polygons fillPolygons;
int fillAngle = 45;
if (layerNr & 1)
fillAngle += 90;
//int sparseSteps[1] = {config.extrusionWidth};
//generateConcentricInfill(part->skinOutline, fillPolygons, sparseSteps, 1);
generateLineInfill(part->skinOutline, fillPolygons, config.extrusionWidth, config.extrusionWidth, config.infillOverlap, (part->bridgeAngle > -1) ? part->bridgeAngle : fillAngle);
//int sparseSteps[2] = {config.extrusionWidth*5, config.extrusionWidth * 0.8};
//generateConcentricInfill(part->sparseOutline, fillPolygons, sparseSteps, 2);
if (config.sparseInfillLineDistance > 0)
{
if (config.sparseInfillLineDistance > config.extrusionWidth * 4)
{
generateLineInfill(part->sparseOutline, fillPolygons, config.extrusionWidth, config.sparseInfillLineDistance * 2, config.infillOverlap, 45);
generateLineInfill(part->sparseOutline, fillPolygons, config.extrusionWidth, config.sparseInfillLineDistance * 2, config.infillOverlap, 45 + 90);
}
else
{
generateLineInfill(part->sparseOutline, fillPolygons, config.extrusionWidth, config.sparseInfillLineDistance, config.infillOverlap, fillAngle);
}
}
gcodeLayer.addPolygonsByOptimizer(fillPolygons, &fillConfig);
//After a layer part, make sure the nozzle is inside the comb boundary, so we do not retract on the perimeter.
if (!config.spiralizeMode || int(layerNr) < config.downSkinCount)
gcodeLayer.moveInsideCombBoundary(config.extrusionWidth * 2);
}
gcodeLayer.setCombBoundary(NULL);
}
void addSupportToGCode(SliceDataStorage& storage, GCodePlanner& gcodeLayer, int layerNr)
{
if (!storage.support.generated)
return;
if (config.supportExtruder > -1)
{
int prevExtruder = gcodeLayer.getExtruder();
if (gcodeLayer.setExtruder(config.supportExtruder))
addWipeTower(storage, gcodeLayer, layerNr, prevExtruder);
if (storage.oozeShield.size() > 0 && storage.volumes.size() == 1)
{
gcodeLayer.setAlwaysRetract(true);
gcodeLayer.addPolygonsByOptimizer(storage.oozeShield[layerNr], &skirtConfig);
gcodeLayer.setAlwaysRetract(!config.enableCombing);
}
}
int32_t z = config.initialLayerThickness + layerNr * config.layerThickness;
SupportPolyGenerator supportGenerator(storage.support, z);
for(unsigned int volumeCnt = 0; volumeCnt < storage.volumes.size(); volumeCnt++)
{
SliceLayer* layer = &storage.volumes[volumeCnt].layers[layerNr];
for(unsigned int n=0; n<layer->parts.size(); n++)
supportGenerator.polygons = supportGenerator.polygons.difference(layer->parts[n].outline.offset(config.supportXYDistance));
}
//Contract and expand the suppory polygons so small sections are removed and the final polygon is smoothed a bit.
supportGenerator.polygons = supportGenerator.polygons.offset(-config.extrusionWidth * 3);
supportGenerator.polygons = supportGenerator.polygons.offset(config.extrusionWidth * 3);
vector<Polygons> supportIslands = supportGenerator.polygons.splitIntoParts();
for(unsigned int n=0; n<supportIslands.size(); n++)
{
Polygons supportLines;
if (config.supportLineDistance > 0)
{
if (config.supportLineDistance > config.extrusionWidth * 4)
{
generateLineInfill(supportIslands[n], supportLines, config.extrusionWidth, config.supportLineDistance*2, config.infillOverlap, 0);
generateLineInfill(supportIslands[n], supportLines, config.extrusionWidth, config.supportLineDistance*2, config.infillOverlap, 90);
}else{
generateLineInfill(supportIslands[n], supportLines, config.extrusionWidth, config.supportLineDistance, config.infillOverlap, (layerNr & 1) ? 0 : 90);
}
}
gcodeLayer.forceRetract();
if (config.enableCombing)
gcodeLayer.setCombBoundary(&supportIslands[n]);
gcodeLayer.addPolygonsByOptimizer(supportIslands[n], &supportConfig);
gcodeLayer.addPolygonsByOptimizer(supportLines, &supportConfig);
gcodeLayer.setCombBoundary(NULL);
}
}
void addWipeTower(SliceDataStorage& storage, GCodePlanner& gcodeLayer, int layerNr, int prevExtruder)
{
if (config.wipeTowerSize < 1)
return;
//If we changed extruder, print the wipe/prime tower for this nozzle;
gcodeLayer.addPolygonsByOptimizer(storage.wipeTower, &supportConfig);
Polygons fillPolygons;
generateLineInfill(storage.wipeTower, fillPolygons, config.extrusionWidth, config.extrusionWidth, config.infillOverlap, 45 + 90 * (layerNr % 2));
gcodeLayer.addPolygonsByOptimizer(fillPolygons, &supportConfig);
//Make sure we wipe the old extruder on the wipe tower.
gcodeLayer.addTravel(storage.wipePoint - config.extruderOffset[prevExtruder].p() + config.extruderOffset[gcodeLayer.getExtruder()].p());
}
};
#endif//FFF_PROCESSOR_H
-578
Ver Arquivo
@@ -1,578 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdarg.h>
#include "gcodeExport.h"
#include "pathOrderOptimizer.h"
#include "timeEstimate.h"
#include "settings.h"
#if defined(__APPLE__) && defined(__MACH__)
//On MacOS the file offset functions are always 64bit.
#define off64_t off_t
#define ftello64 ftello
#define fseeko64 fseeko
#endif
GCodeExport::GCodeExport()
: currentPosition(0,0,0)
{
extrusionAmount = 0;
extrusionPerMM = 0;
retractionAmount = 4.5;
minimalExtrusionBeforeRetraction = 0.0;
extrusionAmountAtPreviousRetraction = -10000;
extruderSwitchRetraction = 14.5;
extruderNr = 0;
currentFanSpeed = -1;
totalPrintTime = 0.0;
for(unsigned int e=0; e<MAX_EXTRUDERS; e++)
totalFilament[e] = 0.0;
currentSpeed = 0;
retractionSpeed = 45;
isRetracted = true;
memset(extruderOffset, 0, sizeof(extruderOffset));
f = stdout;
}
GCodeExport::~GCodeExport()
{
if (f)
fclose(f);
}
void GCodeExport::replaceTagInStart(const char* tag, const char* replaceValue)
{
off64_t oldPos = ftello64(f);
char buffer[1024];
fseeko64(f, 0, SEEK_SET);
fread(buffer, 1024, 1, f);
char* c = strstr(buffer, tag);
memset(c, ' ', strlen(tag));
if (c) memcpy(c, replaceValue, strlen(replaceValue));
fseeko64(f, 0, SEEK_SET);
fwrite(buffer, 1024, 1, f);
fseeko64(f, oldPos, SEEK_SET);
}
void GCodeExport::setExtruderOffset(int id, Point p)
{
extruderOffset[id] = p;
}
void GCodeExport::setFlavor(int flavor)
{
this->flavor = flavor;
}
int GCodeExport::getFlavor()
{
return this->flavor;
}
void GCodeExport::setFilename(const char* filename)
{
f = fopen(filename, "w+");
}
bool GCodeExport::isValid()
{
return f != NULL;
}
void GCodeExport::setExtrusion(int layerThickness, int filamentDiameter, int flow)
{
double filamentArea = M_PI * (double(filamentDiameter) / 1000.0 / 2.0) * (double(filamentDiameter) / 1000.0 / 2.0);
if (flavor == GCODE_FLAVOR_ULTIGCODE)//UltiGCode uses volume extrusion as E value, and thus does not need the filamentArea in the mix.
extrusionPerMM = double(layerThickness) / 1000.0;
else
extrusionPerMM = double(layerThickness) / 1000.0 / filamentArea * double(flow) / 100.0;
}
void GCodeExport::setRetractionSettings(int retractionAmount, int retractionSpeed, int extruderSwitchRetraction, int minimalExtrusionBeforeRetraction)
{
this->retractionAmount = double(retractionAmount) / 1000.0;
this->retractionSpeed = retractionSpeed;
this->extruderSwitchRetraction = double(extruderSwitchRetraction) / 1000.0;
this->minimalExtrusionBeforeRetraction = double(minimalExtrusionBeforeRetraction) / 1000.0;
}
void GCodeExport::setZ(int z)
{
this->zPos = z;
}
Point GCodeExport::getPositionXY()
{
return Point(currentPosition.x, currentPosition.y);
}
int GCodeExport::getPositionZ()
{
return currentPosition.z;
}
int GCodeExport::getExtruderNr()
{
return extruderNr;
}
double GCodeExport::getTotalFilamentUsed(int e)
{
if (e == extruderNr)
return totalFilament[e] + extrusionAmount;
return totalFilament[e];
}
double GCodeExport::getTotalPrintTime()
{
return totalPrintTime;
}
void GCodeExport::updateTotalPrintTime()
{
totalPrintTime += estimateCalculator.calculate();
estimateCalculator.reset();
}
void GCodeExport::addComment(const char* comment, ...)
{
va_list args;
va_start(args, comment);
fprintf(f, ";");
vfprintf(f, comment, args);
fprintf(f, "\n");
va_end(args);
}
void GCodeExport::addLine(const char* line, ...)
{
va_list args;
va_start(args, line);
vfprintf(f, line, args);
fprintf(f, "\n");
va_end(args);
}
void GCodeExport::resetExtrusionValue()
{
if (extrusionAmount != 0.0)
{
fprintf(f, "G92 E0\n");
totalFilament[extruderNr] += extrusionAmount;
extrusionAmountAtPreviousRetraction -= extrusionAmount;
extrusionAmount = 0.0;
}
}
void GCodeExport::addDelay(double timeAmount)
{
fprintf(f, "G4 P%d\n", int(timeAmount * 1000));
totalPrintTime += timeAmount;
}
void GCodeExport::addMove(Point p, int speed, int lineWidth)
{
if (lineWidth != 0)
{
Point diff = p - getPositionXY();
if (isRetracted)
{
if (flavor == GCODE_FLAVOR_ULTIGCODE)
{
fprintf(f, "G11\n");
}else{
fprintf(f, "G1 F%i E%0.5lf\n", retractionSpeed * 60, extrusionAmount);
currentSpeed = retractionSpeed;
estimateCalculator.plan(TimeEstimateCalculator::Position(double(p.X) / 1000.0, (p.Y) / 1000.0, double(zPos) / 1000.0, extrusionAmount), currentSpeed);
}
if (extrusionAmount > 10000.0) //According to https://github.com/Ultimaker/CuraEngine/issues/14 having more then 21m of extrusion causes inaccuracies. So reset it every 10m, just to be sure.
resetExtrusionValue();
isRetracted = false;
}
extrusionAmount += extrusionPerMM * double(lineWidth) / 1000.0 * vSizeMM(diff);
fprintf(f, "G1");
}else{
fprintf(f, "G0");
}
if (currentSpeed != speed)
{
fprintf(f, " F%i", speed * 60);
currentSpeed = speed;
}
fprintf(f, " X%0.2f Y%0.2f", float(p.X - extruderOffset[extruderNr].X)/1000, float(p.Y - extruderOffset[extruderNr].Y)/1000);
if (zPos != currentPosition.z)
fprintf(f, " Z%0.2f", float(zPos)/1000);
if (lineWidth != 0)
fprintf(f, " E%0.5lf", extrusionAmount);
fprintf(f, "\n");
currentPosition = Point3(p.X, p.Y, zPos);
estimateCalculator.plan(TimeEstimateCalculator::Position(double(currentPosition.x) / 1000.0, (currentPosition.y) / 1000.0, double(currentPosition.z) / 1000.0, extrusionAmount), currentSpeed);
}
void GCodeExport::addRetraction()
{
if (retractionAmount > 0 && !isRetracted && extrusionAmountAtPreviousRetraction + minimalExtrusionBeforeRetraction < extrusionAmount)
{
if (flavor == GCODE_FLAVOR_ULTIGCODE)
{
fprintf(f, "G10\n");
}else{
fprintf(f, "G1 F%i E%0.5lf\n", retractionSpeed * 60, extrusionAmount - retractionAmount);
estimateCalculator.plan(TimeEstimateCalculator::Position(double(currentPosition.x) / 1000.0, (currentPosition.y) / 1000.0, double(currentPosition.z) / 1000.0, extrusionAmount - retractionAmount), currentSpeed);
currentSpeed = retractionSpeed;
}
extrusionAmountAtPreviousRetraction = extrusionAmount;
isRetracted = true;
}
}
void GCodeExport::switchExtruder(int newExtruder)
{
if (extruderNr == newExtruder)
return;
resetExtrusionValue();
extruderNr = newExtruder;
if (flavor == GCODE_FLAVOR_ULTIGCODE)
{
fprintf(f, "G10 S1\n");
}else{
fprintf(f, "G1 F%i E%0.4lf\n", retractionSpeed * 60, extrusionAmount - extruderSwitchRetraction);
currentSpeed = retractionSpeed;
}
isRetracted = true;
fprintf(f, "T%i\n", extruderNr);
}
void GCodeExport::addCode(const char* str)
{
fprintf(f, "%s\n", str);
}
void GCodeExport::addFanCommand(int speed)
{
if (currentFanSpeed == speed)
return;
if (speed > 0)
{
if (flavor == GCODE_FLAVOR_MAKERBOT)
fprintf(f, "M126 T0 ; value = %d\n", speed * 255 / 100);
else
fprintf(f, "M106 S%d\n", speed * 255 / 100);
}
else
{
if (flavor == GCODE_FLAVOR_MAKERBOT)
fprintf(f, "M127 T0\n");
else
fprintf(f, "M107\n");
}
currentFanSpeed = speed;
}
int GCodeExport::getFileSize(){
return ftell(f);
}
void GCodeExport::tellFileSize() {
float fsize = (float) ftell(f);
if(fsize > 1024*1024) {
fsize /= 1024.0*1024.0;
fprintf(stdout, "Wrote %5.1f MB.\n",fsize);
}
if(fsize > 1024) {
fsize /= 1024.0;
fprintf(stdout, "Wrote %5.1f kilobytes.\n",fsize);
}
}
GCodePath* GCodePlanner::getLatestPathWithConfig(GCodePathConfig* config)
{
if (paths.size() > 0 && paths[paths.size()-1].config == config && !paths[paths.size()-1].done)
return &paths[paths.size()-1];
paths.push_back(GCodePath());
GCodePath* ret = &paths[paths.size()-1];
ret->retract = false;
ret->config = config;
ret->extruder = currentExtruder;
ret->done = false;
return ret;
}
void GCodePlanner::forceNewPathStart()
{
if (paths.size() > 0)
paths[paths.size()-1].done = true;
}
GCodePlanner::GCodePlanner(GCodeExport& gcode, int travelSpeed, int retractionMinimalDistance)
: gcode(gcode), travelConfig(travelSpeed, 0, "travel")
{
lastPosition = gcode.getPositionXY();
comb = NULL;
extrudeSpeedFactor = 100;
travelSpeedFactor = 100;
extraTime = 0.0;
totalPrintTime = 0.0;
forceRetraction = false;
alwaysRetract = false;
currentExtruder = gcode.getExtruderNr();
this->retractionMinimalDistance = retractionMinimalDistance;
}
GCodePlanner::~GCodePlanner()
{
if (comb)
delete comb;
}
void GCodePlanner::addTravel(Point p)
{
GCodePath* path = getLatestPathWithConfig(&travelConfig);
if (forceRetraction)
{
if (!shorterThen(lastPosition - p, retractionMinimalDistance))
{
path->retract = true;
}
forceRetraction = false;
}else if (comb != NULL)
{
vector<Point> pointList;
if (comb->calc(lastPosition, p, pointList))
{
for(unsigned int n=0; n<pointList.size(); n++)
{
path->points.push_back(pointList[n]);
}
}else{
if (!shorterThen(lastPosition - p, retractionMinimalDistance))
path->retract = true;
}
}else if (alwaysRetract)
{
if (!shorterThen(lastPosition - p, retractionMinimalDistance))
path->retract = true;
}
path->points.push_back(p);
lastPosition = p;
}
void GCodePlanner::addExtrusionMove(Point p, GCodePathConfig* config)
{
getLatestPathWithConfig(config)->points.push_back(p);
lastPosition = p;
}
void GCodePlanner::moveInsideCombBoundary(int distance)
{
if (!comb || comb->checkInside(lastPosition)) return;
Point p = lastPosition;
if (comb->moveInside(&p, distance))
{
//Move inside again, so we move out of tight 90deg corners
comb->moveInside(&p, distance);
if (comb->checkInside(p))
{
addTravel(p);
//Make sure the that any retraction happens after this move, not before it by starting a new move path.
forceNewPathStart();
}
}
}
void GCodePlanner::addPolygon(PolygonRef polygon, int startIdx, GCodePathConfig* config)
{
Point p0 = polygon[startIdx];
addTravel(p0);
for(unsigned int i=1; i<polygon.size(); i++)
{
Point p1 = polygon[(startIdx + i) % polygon.size()];
addExtrusionMove(p1, config);
p0 = p1;
}
if (polygon.size() > 2)
addExtrusionMove(polygon[startIdx], config);
}
void GCodePlanner::addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* config)
{
PathOrderOptimizer orderOptimizer(lastPosition);
for(unsigned int i=0;i<polygons.size();i++)
orderOptimizer.addPolygon(polygons[i]);
orderOptimizer.optimize();
for(unsigned int i=0;i<orderOptimizer.polyOrder.size();i++)
{
int nr = orderOptimizer.polyOrder[i];
addPolygon(polygons[nr], orderOptimizer.polyStart[nr], config);
}
}
void GCodePlanner::forceMinimalLayerTime(double minTime, int minimalSpeed)
{
Point p0 = gcode.getPositionXY();
double travelTime = 0.0;
double extrudeTime = 0.0;
for(unsigned int n=0; n<paths.size(); n++)
{
GCodePath* path = &paths[n];
for(unsigned int i=0; i<path->points.size(); i++)
{
double thisTime = vSizeMM(p0 - path->points[i]) / double(path->config->speed);
if (path->config->lineWidth != 0)
extrudeTime += thisTime;
else
travelTime += thisTime;
p0 = path->points[i];
}
}
double totalTime = extrudeTime + travelTime;
if (totalTime < minTime && extrudeTime > 0.0)
{
double minExtrudeTime = minTime - travelTime;
if (minExtrudeTime < 1)
minExtrudeTime = 1;
double factor = extrudeTime / minExtrudeTime;
for(unsigned int n=0; n<paths.size(); n++)
{
GCodePath* path = &paths[n];
if (path->config->lineWidth == 0)
continue;
int speed = path->config->speed * factor;
if (speed < minimalSpeed)
factor = double(minimalSpeed) / double(path->config->speed);
}
//Only slow down with the minimal time if that will be slower then a factor already set. First layer slowdown also sets the speed factor.
if (factor * 100 < getExtrudeSpeedFactor())
setExtrudeSpeedFactor(factor * 100);
else
factor = getExtrudeSpeedFactor() / 100.0;
if (minTime - (extrudeTime / factor) - travelTime > 0.1)
{
//TODO: Use up this extra time (circle around the print?)
this->extraTime = minTime - (extrudeTime / factor) - travelTime;
}
this->totalPrintTime = (extrudeTime / factor) + travelTime;
}else{
this->totalPrintTime = totalTime;
}
}
void GCodePlanner::writeGCode(bool liftHeadIfNeeded, int layerThickness)
{
GCodePathConfig* lastConfig = NULL;
int extruder = gcode.getExtruderNr();
for(unsigned int n=0; n<paths.size(); n++)
{
GCodePath* path = &paths[n];
if (extruder != path->extruder)
{
extruder = path->extruder;
gcode.switchExtruder(extruder);
}else if (path->retract)
{
gcode.addRetraction();
}
if (path->config != &travelConfig && lastConfig != path->config)
{
gcode.addComment("TYPE:%s", path->config->name);
lastConfig = path->config;
}
int speed = path->config->speed;
if (path->config->lineWidth != 0)// Only apply the extrudeSpeedFactor to extrusion moves
speed = speed * extrudeSpeedFactor / 100;
else
speed = speed * travelSpeedFactor / 100;
if (path->points.size() == 1 && path->config != &travelConfig && shorterThen(gcode.getPositionXY() - path->points[0], path->config->lineWidth * 2))
{
//Check for lots of small moves and combine them into one large line
Point p0 = path->points[0];
unsigned int i = n + 1;
while(i < paths.size() && paths[i].points.size() == 1 && shorterThen(p0 - paths[i].points[0], path->config->lineWidth * 2))
{
p0 = paths[i].points[0];
i ++;
}
if (paths[i-1].config == &travelConfig)
i --;
if (i > n + 2)
{
p0 = gcode.getPositionXY();
for(unsigned int x=n; x<i-1; x+=2)
{
int64_t oldLen = vSize(p0 - paths[x].points[0]);
Point newPoint = (paths[x].points[0] + paths[x+1].points[0]) / 2;
int64_t newLen = vSize(gcode.getPositionXY() - newPoint);
if (newLen > 0)
gcode.addMove(newPoint, speed, path->config->lineWidth * oldLen / newLen);
p0 = paths[x+1].points[0];
}
gcode.addMove(paths[i-1].points[0], speed, path->config->lineWidth);
n = i - 1;
continue;
}
}
bool spiralize = path->config->spiralize;
if (spiralize)
{
//Check if we are the last spiralize path in the list, if not, do not spiralize.
for(unsigned int m=n+1; m<paths.size(); m++)
{
if (paths[m].config->spiralize)
spiralize = false;
}
}
if (spiralize)
{
//If we need to spiralize then raise the head slowly by 1 layer as this path progresses.
float totalLength = 0.0;
int z = gcode.getPositionZ();
Point p0 = gcode.getPositionXY();
for(unsigned int i=0; i<path->points.size(); i++)
{
Point p1 = path->points[i];
totalLength += vSizeMM(p0 - p1);
p0 = p1;
}
float length = 0.0;
p0 = gcode.getPositionXY();
for(unsigned int i=0; i<path->points.size(); i++)
{
Point p1 = path->points[i];
length += vSizeMM(p0 - p1);
p0 = p1;
gcode.setZ(z + layerThickness * length / totalLength);
gcode.addMove(path->points[i], speed, path->config->lineWidth);
}
}else{
for(unsigned int i=0; i<path->points.size(); i++)
{
gcode.addMove(path->points[i], speed, path->config->lineWidth);
}
}
}
gcode.updateTotalPrintTime();
if (liftHeadIfNeeded && extraTime > 0.0)
{
gcode.addComment("Small layer, adding delay of %f", extraTime);
gcode.addRetraction();
gcode.setZ(gcode.getPositionZ() + 3000);
gcode.addMove(gcode.getPositionXY(), travelConfig.speed, 0);
gcode.addMove(gcode.getPositionXY() - Point(-20000, 0), travelConfig.speed, 0);
gcode.addDelay(extraTime);
}
}
-212
Ver Arquivo
@@ -1,212 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef GCODEEXPORT_H
#define GCODEEXPORT_H
#include <stdio.h>
#include "settings.h"
#include "comb.h"
#include "utils/intpoint.h"
#include "utils/polygon.h"
#include "timeEstimate.h"
class GCodeExport
{
private:
FILE* f;
double extrusionAmount;
double extrusionPerMM;
double retractionAmount;
double extruderSwitchRetraction;
double minimalExtrusionBeforeRetraction;
double extrusionAmountAtPreviousRetraction;
Point3 currentPosition;
Point extruderOffset[MAX_EXTRUDERS];
int currentSpeed, retractionSpeed;
int zPos;
bool isRetracted;
int extruderNr;
int currentFanSpeed;
int flavor;
double totalFilament[MAX_EXTRUDERS];
double totalPrintTime;
TimeEstimateCalculator estimateCalculator;
public:
GCodeExport();
~GCodeExport();
void replaceTagInStart(const char* tag, const char* replaceValue);
void setExtruderOffset(int id, Point p);
void setFlavor(int flavor);
int getFlavor();
void setFilename(const char* filename);
bool isValid();
void setExtrusion(int layerThickness, int filamentDiameter, int flow);
void setRetractionSettings(int retractionAmount, int retractionSpeed, int extruderSwitchRetraction, int minimalExtrusionBeforeRetraction);
void setZ(int z);
Point getPositionXY();
int getPositionZ();
int getExtruderNr();
double getTotalFilamentUsed(int e);
double getTotalPrintTime();
void updateTotalPrintTime();
void addComment(const char* comment, ...);
void addLine(const char* line, ...);
void resetExtrusionValue();
void addDelay(double timeAmount);
void addMove(Point p, int speed, int lineWidth);
void addRetraction();
void switchExtruder(int newExtruder);
void addCode(const char* str);
void addFanCommand(int speed);
int getFileSize();
void tellFileSize();
};
class GCodePathConfig
{
public:
int speed;
int lineWidth;
const char* name;
bool spiralize;
GCodePathConfig() : speed(0), lineWidth(0), name(NULL), spiralize(false) {}
GCodePathConfig(int speed, int lineWidth, const char* name) : speed(speed), lineWidth(lineWidth), name(name), spiralize(false) {}
void setData(int speed, int lineWidth, const char* name)
{
this->speed = speed;
this->lineWidth = lineWidth;
this->name = name;
}
};
class GCodePath
{
public:
GCodePathConfig* config;
bool retract;
int extruder;
vector<Point> points;
bool done;//Path is finished, no more moves should be added, and a new path should be started instead of any appending done to this one.
};
class GCodePlanner
{
private:
GCodeExport& gcode;
Point lastPosition;
vector<GCodePath> paths;
Comb* comb;
GCodePathConfig travelConfig;
int extrudeSpeedFactor;
int travelSpeedFactor;
int currentExtruder;
int retractionMinimalDistance;
bool forceRetraction;
bool alwaysRetract;
double extraTime;
double totalPrintTime;
private:
GCodePath* getLatestPathWithConfig(GCodePathConfig* config);
void forceNewPathStart();
public:
GCodePlanner(GCodeExport& gcode, int travelSpeed, int retractionMinimalDistance);
~GCodePlanner();
bool setExtruder(int extruder)
{
if (extruder == currentExtruder)
return false;
currentExtruder = extruder;
return true;
}
int getExtruder()
{
return currentExtruder;
}
void setCombBoundary(Polygons* polygons)
{
if (comb)
delete comb;
if (polygons)
comb = new Comb(*polygons);
else
comb = NULL;
}
void setAlwaysRetract(bool alwaysRetract)
{
this->alwaysRetract = alwaysRetract;
}
void forceRetract()
{
forceRetraction = true;
}
void setExtrudeSpeedFactor(int speedFactor)
{
if (speedFactor < 1) speedFactor = 1;
this->extrudeSpeedFactor = speedFactor;
}
int getExtrudeSpeedFactor()
{
return this->extrudeSpeedFactor;
}
void setTravelSpeedFactor(int speedFactor)
{
if (speedFactor < 1) speedFactor = 1;
this->travelSpeedFactor = speedFactor;
}
int getTravelSpeedFactor()
{
return this->travelSpeedFactor;
}
void addTravel(Point p);
void addExtrusionMove(Point p, GCodePathConfig* config);
void moveInsideCombBoundary(int distance);
void addPolygon(PolygonRef polygon, int startIdx, GCodePathConfig* config);
void addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* config);
void forceMinimalLayerTime(double minTime, int minimalSpeed);
void writeGCode(bool liftHeadIfNeeded, int layerThickness);
};
#endif//GCODEEXPORT_H
-79
Ver Arquivo
@@ -1,79 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "infill.h"
void generateConcentricInfill(Polygons outline, Polygons& result, int offsets[], int offsetsSize)
{
int step = 0;
while(1)
{
for(unsigned int polygonNr=0; polygonNr<outline.size(); polygonNr++)
result.add(outline[polygonNr]);
outline = outline.offset(-offsets[step]);
if (outline.size() < 1)
break;
step = (step + 1) % offsetsSize;
}
}
int compare_int64_t(const void* a, const void* b)
{
int64_t n = (*(int64_t*)a) - (*(int64_t*)b);
if (n < 0) return -1;
if (n > 0) return 1;
return 0;
}
void generateLineInfill(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation)
{
Polygons outline = in_outline.offset(extrusionWidth * infillOverlap / 100);
PointMatrix matrix(rotation);
outline.applyMatrix(matrix);
AABB boundary(outline);
boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing;
int lineCount = (boundary.max.X - boundary.min.X + (lineSpacing - 1)) / lineSpacing;
vector<vector<int64_t> > cutList;
for(int n=0; n<lineCount; n++)
cutList.push_back(vector<int64_t>());
for(unsigned int polyNr=0; polyNr < outline.size(); polyNr++)
{
Point p1 = outline[polyNr][outline[polyNr].size()-1];
for(unsigned int i=0; i < outline[polyNr].size(); i++)
{
Point p0 = outline[polyNr][i];
int idx0 = (p0.X - boundary.min.X) / lineSpacing;
int idx1 = (p1.X - boundary.min.X) / lineSpacing;
int64_t xMin = p0.X, xMax = p1.X;
if (p0.X > p1.X) { xMin = p1.X; xMax = p0.X; }
if (idx0 > idx1) { int tmp = idx0; idx0 = idx1; idx1 = tmp; }
for(int idx = idx0; idx<=idx1; idx++)
{
int x = (idx * lineSpacing) + boundary.min.X + lineSpacing / 2;
if (x < xMin) continue;
if (x >= xMax) continue;
int y = p0.Y + (p1.Y - p0.Y) * (x - p0.X) / (p1.X - p0.X);
cutList[idx].push_back(y);
}
p1 = p0;
}
}
int idx = 0;
for(int64_t x = boundary.min.X + lineSpacing / 2; x < boundary.max.X; x += lineSpacing)
{
qsort(cutList[idx].data(), cutList[idx].size(), sizeof(int64_t), compare_int64_t);
for(unsigned int i = 0; i + 1 < cutList[idx].size(); i+=2)
{
if (cutList[idx][i+1] - cutList[idx][i] < extrusionWidth / 5)
continue;
PolygonRef p = result.newPoly();
p.add(matrix.unapply(Point(x, cutList[idx][i])));
p.add(matrix.unapply(Point(x, cutList[idx][i+1])));
}
idx += 1;
}
}
-10
Ver Arquivo
@@ -1,10 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef INFILL_H
#define INFILL_H
#include "utils/polygon.h"
void generateConcentricInfill(Polygons outline, Polygons& result, int offsets[], int offsetsSize);
void generateLineInfill(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation);
#endif//INFILL_H
-45
Ver Arquivo
@@ -1,45 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "inset.h"
#include "polygonOptimizer.h"
void generateInsets(SliceLayerPart* part, int offset, int insetCount)
{
part->combBoundery = part->outline.offset(-offset);
if (insetCount == 0)
{
part->insets.push_back(part->outline);
return;
}
for(int i=0; i<insetCount; i++)
{
part->insets.push_back(Polygons());
part->insets[i] = part->outline.offset(-offset * i - offset/2);
optimizePolygons(part->insets[i]);
if (part->insets[i].size() < 1)
{
part->insets.pop_back();
break;
}
}
}
void generateInsets(SliceLayer* layer, int offset, int insetCount)
{
for(unsigned int partNr = 0; partNr < layer->parts.size(); partNr++)
{
generateInsets(&layer->parts[partNr], offset, insetCount);
}
//Remove the parts which did not generate an inset. As these parts are too small to print,
// and later code can now assume that there is always minimal 1 inset line.
for(unsigned int partNr = 0; partNr < layer->parts.size(); partNr++)
{
if (layer->parts[partNr].insets.size() < 1)
{
layer->parts.erase(layer->parts.begin() + partNr);
partNr -= 1;
}
}
}
-11
Ver Arquivo
@@ -1,11 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef INSET_H
#define INSET_H
#include "sliceDataStorage.h"
void generateInsets(SliceLayerPart* part, int offset, int insetCount);
void generateInsets(SliceLayer* layer, int offset, int insetCount);
#endif//INSET_H
+3
Ver Arquivo
@@ -0,0 +1,3 @@
These libraries are extern, and while they're utilized by this project,
they are in fact not actually developed on this repository.
If changes are desired for these projects, please refer to their official repositories.
+26 -26
Ver Arquivo
@@ -1,26 +1,26 @@
The Clipper Library (including Delphi, C++ & C# source code, other accompanying
code, examples and documentation), hereafter called "the Software", has been
released under the following license, terms and conditions:
Boost Software License - Version 1.0 - August 17th, 2003
http://www.boost.org/LICENSE_1_0.txt
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the Software covered by this license to use, reproduce,
display, distribute, execute, and transmit the Software, and to prepare
derivative works of the Software, and to permit third-parties to whom the
Software is furnished to do so, all subject to the following:
The copyright notices in the Software and this entire statement, including the
above license grant, this restriction and the following disclaimer, must be
included in all copies of the Software, in whole or in part, and all derivative
works of the Software, unless such copies or derivative works are solely in the
form of machine-executable object code generated by a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY
DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
The Clipper Library (including Delphi, C++ & C# source code, other accompanying
code, examples and documentation), hereafter called "the Software", has been
released under the following license, terms and conditions:
Boost Software License - Version 1.0 - August 17th, 2003
http://www.boost.org/LICENSE_1_0.txt
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the Software covered by this license to use, reproduce,
display, distribute, execute, and transmit the Software, and to prepare
derivative works of the Software, and to permit third-parties to whom the
Software is furnished to do so, all subject to the following:
The copyright notices in the Software and this entire statement, including the
above license grant, this restriction and the following disclaimer, must be
included in all copies of the Software, in whole or in part, and all derivative
works of the Software, unless such copies or derivative works are solely in the
form of machine-executable object code generated by a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY
DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+375 -364
Ver Arquivo
@@ -1,365 +1,376 @@
============================================================
Clipper Change Log
============================================================
v6.1.2 (15 December 2013)
* Fixed broken C++ header file.
* Minor improvement to joining polygons.
v6.1.1 (13 December 2013)
* Fixed a couple of bugs affecting open paths that could
raise unhandled exceptions.
v6.1.0 (12 December 2013)
* Deleted: Previously deprecated code has been removed.
* Modified: The OffsetPaths function is now deprecated as it has
been replaced by the ClipperOffset class which is much more
flexible.
* Bugfixes: Several minor bugs have been fixed including
occasionally an incorrect nesting within the PolyTree structure.
v6.0.0 (30 October 2013)
* Added: Open path (polyline) clipping. A new 'Curves' demo
application showcases this (see the 'Curves' directory).
* Update: Major improvement in the merging of
shared/collinear edges in clip solutions (see Execute).
* Added: The IntPoint structure now has an optional 'Z' member.
(See the precompiler directive use_xyz.)
* Added: Users can now force Clipper to use 32bit integers
(via the precompiler directive use_int32) instead of using
64bit integers.
* Modified: To accommodate open paths, the Polygon and Polygons
structures have been renamed Path and Paths respectively. The
AddPolygon and AddPolygons methods of the ClipperBase class
have been renamed AddPath and AddPaths respectively. Several
other functions have been similarly renamed.
* Modified: The PolyNode Class has a new IsOpen property.
* Modified: The Clipper class has a new ZFillFunction property.
* Added: MinkowskiSum and MinkowskiDiff functions added.
* Added: Several other new functions have been added including
PolyTreeToPaths, OpenPathsFromPolyTree and ClosedPathsFromPolyTree.
* Added: The Clipper constructor now accepts an optional InitOptions
parameter to simplify setting properties.
* Bugfixes: Numerous minor bugs have been fixed.
* Deprecated: Version 6 is a major upgrade from previous versions
and quite a number of changes have been made to exposed structures
and functions. To minimize inconvenience to existing library users,
some code has been retained and some added to maintain backward
compatibility. However, because this code will be removed in a
future update, it has been marked as deprecated and a precompiler
directive use_deprecated has been defined.
v5.1.6 (23 May 2013)
* BugFix: CleanPolygon function was buggy.
* Changed: The behaviour of the 'miter' JoinType has been
changed so that when squaring occurs, it's no longer
extended up to the miter limit but is squared off at
exactly 'delta' units. (This improves the look of mitering
with larger limits at acute angles.)
* Added: New OffsetPolyLines function
* Update: Minor code refactoring and optimisations
v5.1.5 (5 May 2013)
* Added: ForceSimple property to Clipper class
* Update: Improved documentation
v5.1.4 (24 March 2013)
* Update: CleanPolygon function enhanced.
* Update: Documentation improved.
v5.1.3 (14 March 2013)
* Bugfix: Minor bugfixes.
* Update: Documentation significantly improved.
v5.1.2 (26 February 2013)
* Bugfix: PolyNode class was missing a constructor.
* Update: The MiterLimit parameter in the OffsetPolygons
function has been renamed Limit and can now also be used to
limit the number of vertices used to construct arcs when
JoinType is set to jtRound.
v5.1.0 (17 February 2013)
* Update: ExPolygons has been replaced with the PolyTree &
PolyNode classes to more fully represent the parent-child
relationships of the polygons returned by Clipper.
* Added: New CleanPolygon and CleanPolygons functions.
* Bugfix: Another orientation bug fixed.
v5.0.2 - 30 December 2012
* Bugfix: Significant fixes in and tidy of the internal
Int128 class (which is used only when polygon coordinate
values are greater than ±0x3FFFFFFF (~1.07e9)).
* Update: The Area algorithm has been updated and is faster.
* Update: Documentation updates. The newish but undocumented
'CheckInputs' parameter of the OffsetPolygons function has been
renamed 'AutoFix' and documented too. The comments on rounding
have also been improved (ie clearer and expanded).
v4.10.0 - 25 December 2012
* Bugfix: Orientation bugs should now be resolved (finally!).
* Bugfix: Bug in Int128 class
v4.9.8 - 2 December 2012
* Bugfix: Further fixes to rare Orientation bug.
v4.9.7 - 29 November 2012
* Bugfix: Bug that very rarely returned the wrong polygon
orientation.
* Bugfix: Obscure bug affecting OffsetPolygons when using
jtRound for the JoinType parameter and when polygons also
contain very large coordinate values (> +/-100000000000).
v4.9.6 - 9 November 2012
* Bugfix: Another obscure bug related to joining polygons.
v4.9.4 - 2 November 2012
* Bugfix: Bugs in Int128 class occasionally causing
wrong orientations.
* Bugfix: Further fixes related to joining polygons.
v4.9.0 - 9 October 2012
* Bugfix: Obscure bug related to joining polygons.
v4.8.9 - 25 September 2012
* Bugfix: Obscure bug related to precision of intersections.
v4.8.8 - 30 August 2012
* Bugfix: Fixed bug in OffsetPolygons function introduced in
version 4.8.5.
v4.8.7 - 24 August 2012
* Bugfix: ReversePolygon function in C++ translation was broken.
* Bugfix: Two obscure bugs affecting orientation fixed too.
v4.8.6 - 11 August 2012
* Bugfix: Potential for memory overflow errors when using
ExPolygons structure.
* Bugfix: The polygon coordinate range has been reduced to
+/- 0x3FFFFFFFFFFFFFFF (4.6e18).
* Update: ReversePolygons function was misnamed ReversePoints in C++.
* Update: SimplifyPolygon function now takes a PolyFillType parameter.
v4.8.5 - 15 July 2012
* Bugfix: Potential for memory overflow errors in OffsetPolygons().
v4.8.4 - 1 June 2012
* Bugfix: Another obscure bug affecting ExPolygons structure.
v4.8.3 - 27 May 2012
* Bugfix: Obscure bug causing incorrect removal of a vertex.
v4.8.2 - 21 May 2012
* Bugfix: Obscure bug could cause an exception when using
ExPolygon structure.
v4.8.1 - 12 May 2012
* Update: Cody tidy and minor bug fixes.
v4.8.0 - 30 April 2012
* Bugfix: Occasional errors in orientation fixed.
* Update: Added notes on rounding to the documentation.
v4.7.6 - 11 April 2012
* Fixed a bug in Orientation function (affecting C# translations only).
* Minor documentation update.
v4.7.5 - 28 March 2012
* Bugfix: Fixed a recently introduced bug that occasionally caused an
unhandled exception in C++ and C# translations.
v4.7.4 - 15 March 2012
* Bugfix: Another minor bugfix.
v4.7.2 - 4 March 2012
* Bugfix: Fixed bug introduced in ver 4.7 which sometimes caused
an exception if ExPolygon structure was passed to Clipper's
Execute method.
v4.7.1 - 3 March 2012
* Bugfix: Rare crash when JoinCommonEdges joined polygons that
'cancelled' each other.
* Bugfix: Clipper's internal Orientation method occasionally
returned wrong result.
* Update: Improved C# code (thanks to numerous excellent suggestions
from David Piepgrass)
v4.7 - 10 February 2012
* Improved the joining of output polygons sharing a common edge.
v4.6.6 - 3 February 2012
* Bugfix: Another obscure bug occasionally causing incorrect
polygon orientation.
v4.6.5 - 17 January 2012
* Bugfix: Obscure bug occasionally causing incorrect hole
assignment in ExPolygon structure.
v4.6.4 - 8 November 2011
* Added: SimplifyPolygon and SimplifyPolygons functions.
v4.6.3 - 11 November 2011
* Bugfix: Fixed another minor mitering bug in OffsetPolygons.
v4.6.2 - 10 November 2011
* Bugfix: Fixed a rare bug in the orientation of polygons
returned by Clipper's Execute() method.
* Bugfix: Previous update introduced a mitering bug in the
OffsetPolygons function.
v4.6 - 29 October 2011
* Added: Support for Positive and Negative polygon fill
types (in addition to the EvenOdd and NonZero fill types).
* Bugfix: The OffsetPolygons function was generating the
occasional artefact when 'shrinking' polygons.
v4.5.5 - 8 October 2011
* Bugfix: Fixed an obscure bug in Clipper's JoinCommonEdges
method.
* Update: Replaced IsClockwise function with Orientation
function. The orientation issues affecting OffsetPolygons
should now be finally resolved.
* Change: The Area function once again returns a signed value.
v4.5.1 - 28 September 2011
* Deleted: The UseFullCoordinateRange property has been
deleted since integer range is now managed implicitly.
* BugFix: Minor bug in OffsetPolygon mitering.
* Change: C# JoinType enum moved from Clipper class to
ClipperLib namespace.
* Change: The Area function now returns the absolute area
(irrespective of orientation).
* Change: The IsClockwise function now requires a second
parameter - YAxisPositiveUpward - to accommodate displays
with Y-axis oriented in either direction
v4.4.4 - 10 September 2011
* Change: Deleted jtButt from JoinType (used by the
OffsetPolygons function).
* BugFix: Fixed another minor bug in OffsetPolygons function.
* Update: Further improvements to the help file
v4.4.3 - 29 August 2011
* BugFix: fixed a minor rounding issue in OffsetPolygons
function (affected C++ & C# translations).
* BugFix: fixed a minor bug in OffsetPolygons' function
declaration (affected C++ translation only).
* Change: 'clipper' namespace changed to 'ClipperLib'
namespace in both C++ and C# code to remove the ambiguity
between the Clipper class and the namespace. (This also
required numerous updates to the accompanying demos.)
v4.4.2 - 26 August 2011
* BugFix: minor bugfixes in Clipper.
* Update: the OffsetPolygons function has been significantly
improved by offering 4 different join styles.
v4.4.0 - 6 August 2011
* BugFix: A number of minor bugs have been fixed that mostly
affected the new ExPolygons structure.
v4.3.0 - 17 June 2011
* New: ExPolygons structure that explicitly associates 'hole'
polygons with their 'outer' container polygons.
* New: Execute method overloaded so the solution parameter
can now be either Polygons or ExPolygons.
* BugFix: Fixed a rare bug in solution polygons orientation.
v4.2.8 - 21 May 2011
* Update: JoinCommonEdges() improved once more.
* BugFix: Several minor bugs fixed.
v4.2.6 - 1 May 2011
* Bugfix: minor bug in SlopesEqual function.
* Update: Merging of output polygons sharing common edges
has been significantly inproved
v4.2.4 - 26 April 2011
Input polygon coordinates can now contain the full range of
signed 64bit integers (ie +/-9,223,372,036,854,775,807). This
means that floating point values can be converted to and from
Clipper's 64bit integer coordinates structure (IntPoint) and
still retain a precision of up to 18 decimal places. However,
since the large-integer math that supports this expanded range
imposes a small cost on performance (~15%), a new property
UseFullCoordinateRange has been added to the Clipper class to
allow users the choice of whether or not to use this expanded
coordinate range. If this property is disabled, coordinate values
are restricted to +/-1,500,000,000.
v4.2 - 12 April 2011
JoinCommonEdges() code significantly improved plus other minor
improvements.
v4.1.2 - 9 April 2011
* Update: Minor code tidy.
* Bugfix: Possible endless loop in JoinCommonEdges() in clipper.pas.
v4.1.1 - 8 April 2011
* Update: All polygon coordinates are now stored as 64bit integers
(though they're still restricted to range -1.5e9 to +1.5e9 pending
the inclusion of code supporting 64bit math).
* Change: AddPolygon and AddPolygons methods now return boolean
values.
* Bugfix: Bug in JoinCommonEdges() caused potential endless loop.
* Bugfix: Bug in IsClockwise(). (C++ code only)
v4.0 - 5 April 2011
* Clipper 4 is a major rewrite of earlier versions. The biggest
change is that floating point values are no longer used,
except for the storing of edge slope values. The main benefit
of this is the issue of numerical robustness has been
addressed. Due to other major code improvements Clipper v4
is approximately 40% faster than Clipper v3.
* The AddPolyPolygon method has been renamed to AddPolygons.
* The IgnoreOrientation property has been removed.
* The clipper_misc library has been merged back into the
main clipper library.
v3.1.0 - 17 February 2011
* Bugfix: Obscure bug in TClipperBase.SetDx method that caused
problems with very small edges ( edges <1/1000th pixel in size).
v3.0.3 - 9 February 2011
* Bugfix: Significant bug, but only in C# code.
* Update: Minor refactoring.
v3.0 - 31 January 2011
* Update: Major rewrite of the portion of code that calculates
the output polygons' orientation.
* Update: Help file significantly improved.
* Change: Renamed ForceOrientation property to IgnoreOrientation.
If the orientation of output polygons is not important, or can
be managed separately, clipping routines can be sped up by about
60% by setting IgnoreOrientation to true. Defaults to false.
* Change: The OffsetPolygon and Area functions have been moved to
the new unit - clipper_misc.
2.99 - 15 January 2011
* Bugfix: Obscure bug in AddPolygon method could cause an endless loop.
2.8 - 20 November 2010
* Updated: Output polygons which previously shared a common
edge are now merged.
* Changed: The orientation of outer polygons is now clockwise
when the display's Y axis is positive downwards (as is
typical for most Windows applications). Inner polygons
(holes) have the opposite orientation.
* Added: Support module for Cairo Graphics Library (with demo).
* Updated: C# and C++ demos.
2.522 - 15 October 2010
* Added C# translation (thanks to Olivier Lejeune) and
a link to Ruby bindings (thanks to Mike Owens).
2.0 - 30 July 2010
* Clipper now clips using both the Even-Odd (alternate) and
Non-Zero (winding) polygon filling rules. (Previously Clipper
assumed the Even-Odd rule for polygon filling.)
1.4c - 16 June 2010
* Added C++ support for AGG graphics library
1.2s - 2 June 2010
* Added C++ translation of clipper.pas
=====================================================================
Clipper Change Log
=====================================================================
v6.1.3 (19 January 2014)
* Fixed potential endless loop condition when adding open
paths to Clipper.
* Fixed missing implementation of SimplifyPolygon function
in C++ code.
* Fixed incorrect upper range constant for polygon coordinates
in Delphi code.
* Added PointInPolygon function.
* Overloaded MinkowskiSum function to accommodate multi-contour
paths.
v6.1.2 (15 December 2013)
* Fixed broken C++ header file.
* Minor improvement to joining polygons.
v6.1.1 (13 December 2013)
* Fixed a couple of bugs affecting open paths that could
raise unhandled exceptions.
v6.1.0 (12 December 2013)
* Deleted: Previously deprecated code has been removed.
* Modified: The OffsetPaths function is now deprecated as it has
been replaced by the ClipperOffset class which is much more
flexible.
* Bugfixes: Several minor bugs have been fixed including
occasionally an incorrect nesting within the PolyTree structure.
v6.0.0 (30 October 2013)
* Added: Open path (polyline) clipping. A new 'Curves' demo
application showcases this (see the 'Curves' directory).
* Update: Major improvement in the merging of
shared/collinear edges in clip solutions (see Execute).
* Added: The IntPoint structure now has an optional 'Z' member.
(See the precompiler directive use_xyz.)
* Added: Users can now force Clipper to use 32bit integers
(via the precompiler directive use_int32) instead of using
64bit integers.
* Modified: To accommodate open paths, the Polygon and Polygons
structures have been renamed Path and Paths respectively. The
AddPolygon and AddPolygons methods of the ClipperBase class
have been renamed AddPath and AddPaths respectively. Several
other functions have been similarly renamed.
* Modified: The PolyNode Class has a new IsOpen property.
* Modified: The Clipper class has a new ZFillFunction property.
* Added: MinkowskiSum and MinkowskiDiff functions added.
* Added: Several other new functions have been added including
PolyTreeToPaths, OpenPathsFromPolyTree and ClosedPathsFromPolyTree.
* Added: The Clipper constructor now accepts an optional InitOptions
parameter to simplify setting properties.
* Bugfixes: Numerous minor bugs have been fixed.
* Deprecated: Version 6 is a major upgrade from previous versions
and quite a number of changes have been made to exposed structures
and functions. To minimize inconvenience to existing library users,
some code has been retained and some added to maintain backward
compatibility. However, because this code will be removed in a
future update, it has been marked as deprecated and a precompiler
directive use_deprecated has been defined.
v5.1.6 (23 May 2013)
* BugFix: CleanPolygon function was buggy.
* Changed: The behaviour of the 'miter' JoinType has been
changed so that when squaring occurs, it's no longer
extended up to the miter limit but is squared off at
exactly 'delta' units. (This improves the look of mitering
with larger limits at acute angles.)
* Added: New OffsetPolyLines function
* Update: Minor code refactoring and optimisations
v5.1.5 (5 May 2013)
* Added: ForceSimple property to Clipper class
* Update: Improved documentation
v5.1.4 (24 March 2013)
* Update: CleanPolygon function enhanced.
* Update: Documentation improved.
v5.1.3 (14 March 2013)
* Bugfix: Minor bugfixes.
* Update: Documentation significantly improved.
v5.1.2 (26 February 2013)
* Bugfix: PolyNode class was missing a constructor.
* Update: The MiterLimit parameter in the OffsetPolygons
function has been renamed Limit and can now also be used to
limit the number of vertices used to construct arcs when
JoinType is set to jtRound.
v5.1.0 (17 February 2013)
* Update: ExPolygons has been replaced with the PolyTree &
PolyNode classes to more fully represent the parent-child
relationships of the polygons returned by Clipper.
* Added: New CleanPolygon and CleanPolygons functions.
* Bugfix: Another orientation bug fixed.
v5.0.2 - 30 December 2012
* Bugfix: Significant fixes in and tidy of the internal
Int128 class (which is used only when polygon coordinate
values are greater than ±0x3FFFFFFF (~1.07e9)).
* Update: The Area algorithm has been updated and is faster.
* Update: Documentation updates. The newish but undocumented
'CheckInputs' parameter of the OffsetPolygons function has been
renamed 'AutoFix' and documented too. The comments on rounding
have also been improved (ie clearer and expanded).
v4.10.0 - 25 December 2012
* Bugfix: Orientation bugs should now be resolved (finally!).
* Bugfix: Bug in Int128 class
v4.9.8 - 2 December 2012
* Bugfix: Further fixes to rare Orientation bug.
v4.9.7 - 29 November 2012
* Bugfix: Bug that very rarely returned the wrong polygon
orientation.
* Bugfix: Obscure bug affecting OffsetPolygons when using
jtRound for the JoinType parameter and when polygons also
contain very large coordinate values (> +/-100000000000).
v4.9.6 - 9 November 2012
* Bugfix: Another obscure bug related to joining polygons.
v4.9.4 - 2 November 2012
* Bugfix: Bugs in Int128 class occasionally causing
wrong orientations.
* Bugfix: Further fixes related to joining polygons.
v4.9.0 - 9 October 2012
* Bugfix: Obscure bug related to joining polygons.
v4.8.9 - 25 September 2012
* Bugfix: Obscure bug related to precision of intersections.
v4.8.8 - 30 August 2012
* Bugfix: Fixed bug in OffsetPolygons function introduced in
version 4.8.5.
v4.8.7 - 24 August 2012
* Bugfix: ReversePolygon function in C++ translation was broken.
* Bugfix: Two obscure bugs affecting orientation fixed too.
v4.8.6 - 11 August 2012
* Bugfix: Potential for memory overflow errors when using
ExPolygons structure.
* Bugfix: The polygon coordinate range has been reduced to
+/- 0x3FFFFFFFFFFFFFFF (4.6e18).
* Update: ReversePolygons function was misnamed ReversePoints in C++.
* Update: SimplifyPolygon function now takes a PolyFillType parameter.
v4.8.5 - 15 July 2012
* Bugfix: Potential for memory overflow errors in OffsetPolygons().
v4.8.4 - 1 June 2012
* Bugfix: Another obscure bug affecting ExPolygons structure.
v4.8.3 - 27 May 2012
* Bugfix: Obscure bug causing incorrect removal of a vertex.
v4.8.2 - 21 May 2012
* Bugfix: Obscure bug could cause an exception when using
ExPolygon structure.
v4.8.1 - 12 May 2012
* Update: Cody tidy and minor bug fixes.
v4.8.0 - 30 April 2012
* Bugfix: Occasional errors in orientation fixed.
* Update: Added notes on rounding to the documentation.
v4.7.6 - 11 April 2012
* Fixed a bug in Orientation function (affecting C# translations only).
* Minor documentation update.
v4.7.5 - 28 March 2012
* Bugfix: Fixed a recently introduced bug that occasionally caused an
unhandled exception in C++ and C# translations.
v4.7.4 - 15 March 2012
* Bugfix: Another minor bugfix.
v4.7.2 - 4 March 2012
* Bugfix: Fixed bug introduced in ver 4.7 which sometimes caused
an exception if ExPolygon structure was passed to Clipper's
Execute method.
v4.7.1 - 3 March 2012
* Bugfix: Rare crash when JoinCommonEdges joined polygons that
'cancelled' each other.
* Bugfix: Clipper's internal Orientation method occasionally
returned wrong result.
* Update: Improved C# code (thanks to numerous excellent suggestions
from David Piepgrass)
v4.7 - 10 February 2012
* Improved the joining of output polygons sharing a common edge.
v4.6.6 - 3 February 2012
* Bugfix: Another obscure bug occasionally causing incorrect
polygon orientation.
v4.6.5 - 17 January 2012
* Bugfix: Obscure bug occasionally causing incorrect hole
assignment in ExPolygon structure.
v4.6.4 - 8 November 2011
* Added: SimplifyPolygon and SimplifyPolygons functions.
v4.6.3 - 11 November 2011
* Bugfix: Fixed another minor mitering bug in OffsetPolygons.
v4.6.2 - 10 November 2011
* Bugfix: Fixed a rare bug in the orientation of polygons
returned by Clipper's Execute() method.
* Bugfix: Previous update introduced a mitering bug in the
OffsetPolygons function.
v4.6 - 29 October 2011
* Added: Support for Positive and Negative polygon fill
types (in addition to the EvenOdd and NonZero fill types).
* Bugfix: The OffsetPolygons function was generating the
occasional artefact when 'shrinking' polygons.
v4.5.5 - 8 October 2011
* Bugfix: Fixed an obscure bug in Clipper's JoinCommonEdges
method.
* Update: Replaced IsClockwise function with Orientation
function. The orientation issues affecting OffsetPolygons
should now be finally resolved.
* Change: The Area function once again returns a signed value.
v4.5.1 - 28 September 2011
* Deleted: The UseFullCoordinateRange property has been
deleted since integer range is now managed implicitly.
* BugFix: Minor bug in OffsetPolygon mitering.
* Change: C# JoinType enum moved from Clipper class to
ClipperLib namespace.
* Change: The Area function now returns the absolute area
(irrespective of orientation).
* Change: The IsClockwise function now requires a second
parameter - YAxisPositiveUpward - to accommodate displays
with Y-axis oriented in either direction
v4.4.4 - 10 September 2011
* Change: Deleted jtButt from JoinType (used by the
OffsetPolygons function).
* BugFix: Fixed another minor bug in OffsetPolygons function.
* Update: Further improvements to the help file
v4.4.3 - 29 August 2011
* BugFix: fixed a minor rounding issue in OffsetPolygons
function (affected C++ & C# translations).
* BugFix: fixed a minor bug in OffsetPolygons' function
declaration (affected C++ translation only).
* Change: 'clipper' namespace changed to 'ClipperLib'
namespace in both C++ and C# code to remove the ambiguity
between the Clipper class and the namespace. (This also
required numerous updates to the accompanying demos.)
v4.4.2 - 26 August 2011
* BugFix: minor bugfixes in Clipper.
* Update: the OffsetPolygons function has been significantly
improved by offering 4 different join styles.
v4.4.0 - 6 August 2011
* BugFix: A number of minor bugs have been fixed that mostly
affected the new ExPolygons structure.
v4.3.0 - 17 June 2011
* New: ExPolygons structure that explicitly associates 'hole'
polygons with their 'outer' container polygons.
* New: Execute method overloaded so the solution parameter
can now be either Polygons or ExPolygons.
* BugFix: Fixed a rare bug in solution polygons orientation.
v4.2.8 - 21 May 2011
* Update: JoinCommonEdges() improved once more.
* BugFix: Several minor bugs fixed.
v4.2.6 - 1 May 2011
* Bugfix: minor bug in SlopesEqual function.
* Update: Merging of output polygons sharing common edges
has been significantly inproved
v4.2.4 - 26 April 2011
Input polygon coordinates can now contain the full range of
signed 64bit integers (ie +/-9,223,372,036,854,775,807). This
means that floating point values can be converted to and from
Clipper's 64bit integer coordinates structure (IntPoint) and
still retain a precision of up to 18 decimal places. However,
since the large-integer math that supports this expanded range
imposes a small cost on performance (~15%), a new property
UseFullCoordinateRange has been added to the Clipper class to
allow users the choice of whether or not to use this expanded
coordinate range. If this property is disabled, coordinate values
are restricted to +/-1,500,000,000.
v4.2 - 12 April 2011
JoinCommonEdges() code significantly improved plus other minor
improvements.
v4.1.2 - 9 April 2011
* Update: Minor code tidy.
* Bugfix: Possible endless loop in JoinCommonEdges() in clipper.pas.
v4.1.1 - 8 April 2011
* Update: All polygon coordinates are now stored as 64bit integers
(though they're still restricted to range -1.5e9 to +1.5e9 pending
the inclusion of code supporting 64bit math).
* Change: AddPolygon and AddPolygons methods now return boolean
values.
* Bugfix: Bug in JoinCommonEdges() caused potential endless loop.
* Bugfix: Bug in IsClockwise(). (C++ code only)
v4.0 - 5 April 2011
* Clipper 4 is a major rewrite of earlier versions. The biggest
change is that floating point values are no longer used,
except for the storing of edge slope values. The main benefit
of this is the issue of numerical robustness has been
addressed. Due to other major code improvements Clipper v4
is approximately 40% faster than Clipper v3.
* The AddPolyPolygon method has been renamed to AddPolygons.
* The IgnoreOrientation property has been removed.
* The clipper_misc library has been merged back into the
main clipper library.
v3.1.0 - 17 February 2011
* Bugfix: Obscure bug in TClipperBase.SetDx method that caused
problems with very small edges ( edges <1/1000th pixel in size).
v3.0.3 - 9 February 2011
* Bugfix: Significant bug, but only in C# code.
* Update: Minor refactoring.
v3.0 - 31 January 2011
* Update: Major rewrite of the portion of code that calculates
the output polygons' orientation.
* Update: Help file significantly improved.
* Change: Renamed ForceOrientation property to IgnoreOrientation.
If the orientation of output polygons is not important, or can
be managed separately, clipping routines can be sped up by about
60% by setting IgnoreOrientation to true. Defaults to false.
* Change: The OffsetPolygon and Area functions have been moved to
the new unit - clipper_misc.
2.99 - 15 January 2011
* Bugfix: Obscure bug in AddPolygon method could cause an endless loop.
2.8 - 20 November 2010
* Updated: Output polygons which previously shared a common
edge are now merged.
* Changed: The orientation of outer polygons is now clockwise
when the display's Y axis is positive downwards (as is
typical for most Windows applications). Inner polygons
(holes) have the opposite orientation.
* Added: Support module for Cairo Graphics Library (with demo).
* Updated: C# and C++ demos.
2.522 - 15 October 2010
* Added C# translation (thanks to Olivier Lejeune) and
a link to Ruby bindings (thanks to Mike Owens).
2.0 - 30 July 2010
* Clipper now clips using both the Even-Odd (alternate) and
Non-Zero (winding) polygon filling rules. (Previously Clipper
assumed the Even-Odd rule for polygon filling.)
1.4c - 16 June 2010
* Added C++ support for AGG graphics library
1.2s - 2 June 2010
* Added C++ translation of clipper.pas
1.0 - 9 May 2010
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+398 -396
Ver Arquivo
@@ -1,396 +1,398 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.1.2 *
* Date : 15 December 2013 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2013 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
* http://www.boost.org/LICENSE_1_0.txt *
* *
* Attributions: *
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
* "A generic solution to polygon clipping" *
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
* http://portal.acm.org/citation.cfm?id=129906 *
* *
* Computer graphics and geometric modeling: implementation and algorithms *
* By Max K. Agoston *
* Springer; 1 edition (January 4, 2005) *
* http://books.google.com/books?q=vatti+clipping+agoston *
* *
* See also: *
* "Polygon Offsetting by Computing Winding Numbers" *
* Paper no. DETC2005-85513 pp. 565-575 *
* ASME 2005 International Design Engineering Technical Conferences *
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
* September 24-28, 2005 , Long Beach, California, USA *
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
* *
*******************************************************************************/
#ifndef clipper_hpp
#define clipper_hpp
#define CLIPPER_VERSION "6.1.2"
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
//improve performance but coordinate values are limited to the range +/- 46340
//#define use_int32
//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
//#define use_xyz
//use_lines: Enables line clipping. Adds a very minor cost to performance.
//#define use_lines
//use_deprecated: Enables support for the obsolete OffsetPaths() function
//which has been replace with the ClipperOffset class.
#define use_deprecated
#include <vector>
#include <set>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
#include <functional>
namespace ClipperLib {
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
enum PolyType { ptSubject, ptClip };
//By far the most widely used winding rules for polygon filling are
//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
//see http://glprogramming.com/red/chapter11.html
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
#ifdef use_int32
typedef int cInt;
typedef unsigned int cUInt;
#else
typedef signed long long cInt;
typedef unsigned long long cUInt;
#endif
struct IntPoint {
cInt X;
cInt Y;
#ifdef use_xyz
cInt Z;
IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {};
#else
IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {};
#endif
friend inline bool operator== (const IntPoint& a, const IntPoint& b)
{
return a.X == b.X && a.Y == b.Y;
}
friend inline bool operator!= (const IntPoint& a, const IntPoint& b)
{
return a.X != b.X || a.Y != b.Y;
}
};
//------------------------------------------------------------------------------
typedef std::vector< IntPoint > Path;
typedef std::vector< Path > Paths;
inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;}
std::ostream& operator <<(std::ostream &s, const IntPoint &p);
std::ostream& operator <<(std::ostream &s, const Path &p);
std::ostream& operator <<(std::ostream &s, const Paths &p);
struct DoublePoint
{
double X;
double Y;
DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {}
};
//------------------------------------------------------------------------------
#ifdef use_xyz
typedef void (*TZFillCallback)(IntPoint& z1, IntPoint& z2, IntPoint& pt);
#endif
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
enum JoinType {jtSquare, jtRound, jtMiter};
enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound};
#ifdef use_deprecated
enum EndType_ {etClosed, etButt = 2, etSquare, etRound};
#endif
class PolyNode;
typedef std::vector< PolyNode* > PolyNodes;
class PolyNode
{
public:
PolyNode();
Path Contour;
PolyNodes Childs;
PolyNode* Parent;
PolyNode* GetNext() const;
bool IsHole() const;
bool IsOpen() const;
int ChildCount() const;
private:
unsigned Index; //node index in Parent.Childs
bool m_IsOpen;
JoinType m_jointype;
EndType m_endtype;
PolyNode* GetNextSiblingUp() const;
void AddChild(PolyNode& child);
friend class Clipper; //to access Index
friend class ClipperOffset;
};
class PolyTree: public PolyNode
{
public:
~PolyTree(){Clear();};
PolyNode* GetFirst() const;
void Clear();
int Total() const;
private:
PolyNodes AllNodes;
friend class Clipper; //to access AllNodes
};
bool Orientation(const Path &poly);
double Area(const Path &poly);
#ifdef use_deprecated
void OffsetPaths(const Paths &in_polys, Paths &out_polys,
double delta, JoinType jointype, EndType_ endtype, double limit = 0);
#endif
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415);
void CleanPolygon(Path& poly, double distance = 1.415);
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415);
void CleanPolygons(Paths& polys, double distance = 1.415);
void MinkowskiSum(const Path& poly, const Path& path, Paths& solution, bool isClosed);
void MinkowskiDiff(const Path& poly, const Path& path, Paths& solution, bool isClosed);
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths);
void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths);
void ReversePath(Path& p);
void ReversePaths(Paths& p);
struct IntRect { cInt left; cInt top; cInt right; cInt bottom; };
//enums that are used internally ...
enum EdgeSide { esLeft = 1, esRight = 2};
//forward declarations (for stuff used internally) ...
struct TEdge;
struct IntersectNode;
struct LocalMinima;
struct Scanbeam;
struct OutPt;
struct OutRec;
struct Join;
typedef std::vector < OutRec* > PolyOutList;
typedef std::vector < TEdge* > EdgeList;
typedef std::vector < Join* > JoinList;
typedef std::vector < IntersectNode* > IntersectList;
//------------------------------------------------------------------------------
//ClipperBase is the ancestor to the Clipper class. It should not be
//instantiated directly. This class simply abstracts the conversion of sets of
//polygon coordinates into edge objects that are stored in a LocalMinima list.
class ClipperBase
{
public:
ClipperBase();
virtual ~ClipperBase();
bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
virtual void Clear();
IntRect GetBounds();
bool PreserveCollinear() {return m_PreserveCollinear;};
void PreserveCollinear(bool value) {m_PreserveCollinear = value;};
protected:
void DisposeLocalMinimaList();
TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
void PopLocalMinima();
virtual void Reset();
TEdge* ProcessBound(TEdge* E, bool IsClockwise);
void InsertLocalMinima(LocalMinima *newLm);
void DoMinimaLML(TEdge* E1, TEdge* E2, bool IsClosed);
TEdge* DescendToMin(TEdge *&E);
void AscendToMax(TEdge *&E, bool Appending, bool IsClosed);
LocalMinima *m_CurrentLM;
LocalMinima *m_MinimaList;
bool m_UseFullRange;
EdgeList m_edges;
bool m_PreserveCollinear;
bool m_HasOpenPaths;
};
//------------------------------------------------------------------------------
class Clipper : public virtual ClipperBase
{
public:
Clipper(int initOptions = 0);
~Clipper();
bool Execute(ClipType clipType,
Paths &solution,
PolyFillType subjFillType = pftEvenOdd,
PolyFillType clipFillType = pftEvenOdd);
bool Execute(ClipType clipType,
PolyTree &polytree,
PolyFillType subjFillType = pftEvenOdd,
PolyFillType clipFillType = pftEvenOdd);
void Clear();
bool ReverseSolution() {return m_ReverseOutput;};
void ReverseSolution(bool value) {m_ReverseOutput = value;};
bool StrictlySimple() {return m_StrictSimple;};
void StrictlySimple(bool value) {m_StrictSimple = value;};
//set the callback function for z value filling on intersections (otherwise Z is 0)
#ifdef use_xyz
void ZFillFunction(TZFillCallback zFillFunc);
#endif
protected:
void Reset();
virtual bool ExecuteInternal();
private:
PolyOutList m_PolyOuts;
JoinList m_Joins;
JoinList m_GhostJoins;
IntersectList m_IntersectList;
ClipType m_ClipType;
std::set< cInt, std::greater<cInt> > m_Scanbeam;
TEdge *m_ActiveEdges;
TEdge *m_SortedEdges;
bool m_ExecuteLocked;
PolyFillType m_ClipFillType;
PolyFillType m_SubjFillType;
bool m_ReverseOutput;
bool m_UsingPolyTree;
bool m_StrictSimple;
#ifdef use_xyz
TZFillCallback m_ZFill; //custom callback
#endif
void SetWindingCount(TEdge& edge);
bool IsEvenOddFillType(const TEdge& edge) const;
bool IsEvenOddAltFillType(const TEdge& edge) const;
void InsertScanbeam(const cInt Y);
cInt PopScanbeam();
void InsertLocalMinimaIntoAEL(const cInt botY);
void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
void AddEdgeToSEL(TEdge *edge);
void CopyAELToSEL();
void DeleteFromSEL(TEdge *e);
void DeleteFromAEL(TEdge *e);
void UpdateEdgeIntoAEL(TEdge *&e);
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
bool IsContributing(const TEdge& edge) const;
bool IsTopHorz(const cInt XPos);
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
void DoMaxima(TEdge *e);
void PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam);
void ProcessHorizontals(bool IsTopOfScanbeam);
void ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam);
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutRec* GetOutRec(int idx);
void AppendPolygon(TEdge *e1, TEdge *e2);
void IntersectEdges(TEdge *e1, TEdge *e2,
const IntPoint &pt, bool protect = false);
OutRec* CreateOutRec();
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
void DisposeAllOutRecs();
void DisposeOutRec(PolyOutList::size_type index);
bool ProcessIntersections(const cInt botY, const cInt topY);
void BuildIntersectList(const cInt botY, const cInt topY);
void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
void BuildResult(Paths& polys);
void BuildResult2(PolyTree& polytree);
void SetHoleState(TEdge *e, OutRec *outrec);
void DisposeIntersectNodes();
bool FixupIntersectionOrder();
void FixupOutPolygon(OutRec &outrec);
bool IsHole(TEdge *e);
bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
void FixHoleLinkage(OutRec &outrec);
void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt);
void ClearJoins();
void ClearGhostJoins();
void AddGhostJoin(OutPt *op, const IntPoint offPt);
bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2);
void JoinCommonEdges();
void DoSimplePolygons();
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec);
#ifdef use_xyz
void SetZ(IntPoint& pt, TEdge& e);
#endif
};
//------------------------------------------------------------------------------
class ClipperOffset
{
public:
ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25);
~ClipperOffset();
void AddPath(const Path& path, JoinType joinType, EndType endType);
void AddPaths(const Paths& paths, JoinType joinType, EndType endType);
void Execute(Paths& solution, double delta);
void Execute(PolyTree& solution, double delta);
void Clear();
double MiterLimit;
double ArcTolerance;
private:
Paths m_destPolys;
Path m_srcPoly;
Path m_destPoly;
std::vector<DoublePoint> m_normals;
double m_delta, m_sinA, m_sin, m_cos;
double m_miterLim, m_StepsPerRad;
IntPoint m_lowest;
PolyNode m_polyNodes;
void FixOrientations();
void DoOffset(double delta);
void OffsetPoint(int j, int& k, JoinType jointype);
void DoSquare(int j, int k);
void DoMiter(int j, int k, double r);
void DoRound(int j, int k);
};
//------------------------------------------------------------------------------
class clipperException : public std::exception
{
public:
clipperException(const char* description): m_descr(description) {}
virtual ~clipperException() throw() {}
virtual const char* what() const throw() {return m_descr.c_str();}
private:
std::string m_descr;
};
//------------------------------------------------------------------------------
} //ClipperLib namespace
#endif //clipper_hpp
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 6.1.3a *
* Date : 22 January 2014 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2014 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
* http://www.boost.org/LICENSE_1_0.txt *
* *
* Attributions: *
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
* "A generic solution to polygon clipping" *
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
* http://portal.acm.org/citation.cfm?id=129906 *
* *
* Computer graphics and geometric modeling: implementation and algorithms *
* By Max K. Agoston *
* Springer; 1 edition (January 4, 2005) *
* http://books.google.com/books?q=vatti+clipping+agoston *
* *
* See also: *
* "Polygon Offsetting by Computing Winding Numbers" *
* Paper no. DETC2005-85513 pp. 565-575 *
* ASME 2005 International Design Engineering Technical Conferences *
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
* September 24-28, 2005 , Long Beach, California, USA *
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
* *
*******************************************************************************/
#ifndef clipper_hpp
#define clipper_hpp
#define CLIPPER_VERSION "6.1.3"
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
//improve performance but coordinate values are limited to the range +/- 46340
//#define use_int32
//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
//#define use_xyz
//use_lines: Enables line clipping. Adds a very minor cost to performance.
//#define use_lines
//use_deprecated: Enables support for the obsolete OffsetPaths() function
//which has been replace with the ClipperOffset class.
#define use_deprecated
#include <vector>
#include <set>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
#include <functional>
namespace ClipperLib {
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
enum PolyType { ptSubject, ptClip };
//By far the most widely used winding rules for polygon filling are
//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
//see http://glprogramming.com/red/chapter11.html
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
#ifdef use_int32
typedef int cInt;
typedef unsigned int cUInt;
#else
typedef signed long long cInt;
typedef unsigned long long cUInt;
#endif
struct IntPoint {
cInt X;
cInt Y;
#ifdef use_xyz
cInt Z;
IntPoint(cInt x = 0, cInt y = 0, cInt z = 0): X(x), Y(y), Z(z) {};
#else
IntPoint(cInt x = 0, cInt y = 0): X(x), Y(y) {};
#endif
friend inline bool operator== (const IntPoint& a, const IntPoint& b)
{
return a.X == b.X && a.Y == b.Y;
}
friend inline bool operator!= (const IntPoint& a, const IntPoint& b)
{
return a.X != b.X || a.Y != b.Y;
}
};
//------------------------------------------------------------------------------
typedef std::vector< IntPoint > Path;
typedef std::vector< Path > Paths;
inline Path& operator <<(Path& poly, const IntPoint& p) {poly.push_back(p); return poly;}
inline Paths& operator <<(Paths& polys, const Path& p) {polys.push_back(p); return polys;}
std::ostream& operator <<(std::ostream &s, const IntPoint &p);
std::ostream& operator <<(std::ostream &s, const Path &p);
std::ostream& operator <<(std::ostream &s, const Paths &p);
struct DoublePoint
{
double X;
double Y;
DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {}
DoublePoint(IntPoint ip) : X((double)ip.X), Y((double)ip.Y) {}
};
//------------------------------------------------------------------------------
#ifdef use_xyz
typedef void (*TZFillCallback)(IntPoint& z1, IntPoint& z2, IntPoint& pt);
#endif
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
enum JoinType {jtSquare, jtRound, jtMiter};
enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound};
#ifdef use_deprecated
enum EndType_ {etClosed, etButt = 2, etSquare, etRound};
#endif
class PolyNode;
typedef std::vector< PolyNode* > PolyNodes;
class PolyNode
{
public:
PolyNode();
Path Contour;
PolyNodes Childs;
PolyNode* Parent;
PolyNode* GetNext() const;
bool IsHole() const;
bool IsOpen() const;
int ChildCount() const;
private:
unsigned Index; //node index in Parent.Childs
bool m_IsOpen;
JoinType m_jointype;
EndType m_endtype;
PolyNode* GetNextSiblingUp() const;
void AddChild(PolyNode& child);
friend class Clipper; //to access Index
friend class ClipperOffset;
};
class PolyTree: public PolyNode
{
public:
~PolyTree(){Clear();};
PolyNode* GetFirst() const;
void Clear();
int Total() const;
private:
PolyNodes AllNodes;
friend class Clipper; //to access AllNodes
};
bool Orientation(const Path &poly);
double Area(const Path &poly);
int PointInPolygon(const IntPoint &pt, const Path &path);
#ifdef use_deprecated
void OffsetPaths(const Paths &in_polys, Paths &out_polys,
double delta, JoinType jointype, EndType_ endtype, double limit = 0);
#endif
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
void CleanPolygon(const Path& in_poly, Path& out_poly, double distance = 1.415);
void CleanPolygon(Path& poly, double distance = 1.415);
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.415);
void CleanPolygons(Paths& polys, double distance = 1.415);
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
void MinkowskiSum(const Path& pattern, const Paths& paths,
Paths& solution, PolyFillType pathFillType, bool pathIsClosed);
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths);
void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths);
void ReversePath(Path& p);
void ReversePaths(Paths& p);
struct IntRect { cInt left; cInt top; cInt right; cInt bottom; };
//enums that are used internally ...
enum EdgeSide { esLeft = 1, esRight = 2};
//forward declarations (for stuff used internally) ...
struct TEdge;
struct IntersectNode;
struct LocalMinima;
struct Scanbeam;
struct OutPt;
struct OutRec;
struct Join;
typedef std::vector < OutRec* > PolyOutList;
typedef std::vector < TEdge* > EdgeList;
typedef std::vector < Join* > JoinList;
typedef std::vector < IntersectNode* > IntersectList;
//------------------------------------------------------------------------------
//ClipperBase is the ancestor to the Clipper class. It should not be
//instantiated directly. This class simply abstracts the conversion of sets of
//polygon coordinates into edge objects that are stored in a LocalMinima list.
class ClipperBase
{
public:
ClipperBase();
virtual ~ClipperBase();
bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
virtual void Clear();
IntRect GetBounds();
bool PreserveCollinear() {return m_PreserveCollinear;};
void PreserveCollinear(bool value) {m_PreserveCollinear = value;};
protected:
void DisposeLocalMinimaList();
TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
void PopLocalMinima();
virtual void Reset();
TEdge* ProcessBound(TEdge* E, bool IsClockwise);
void InsertLocalMinima(LocalMinima *newLm);
void DoMinimaLML(TEdge* E1, TEdge* E2, bool IsClosed);
TEdge* DescendToMin(TEdge *&E);
void AscendToMax(TEdge *&E, bool Appending, bool IsClosed);
LocalMinima *m_CurrentLM;
LocalMinima *m_MinimaList;
bool m_UseFullRange;
EdgeList m_edges;
bool m_PreserveCollinear;
bool m_HasOpenPaths;
};
//------------------------------------------------------------------------------
class Clipper : public virtual ClipperBase
{
public:
Clipper(int initOptions = 0);
~Clipper();
bool Execute(ClipType clipType,
Paths &solution,
PolyFillType subjFillType = pftEvenOdd,
PolyFillType clipFillType = pftEvenOdd);
bool Execute(ClipType clipType,
PolyTree &polytree,
PolyFillType subjFillType = pftEvenOdd,
PolyFillType clipFillType = pftEvenOdd);
bool ReverseSolution() {return m_ReverseOutput;};
void ReverseSolution(bool value) {m_ReverseOutput = value;};
bool StrictlySimple() {return m_StrictSimple;};
void StrictlySimple(bool value) {m_StrictSimple = value;};
//set the callback function for z value filling on intersections (otherwise Z is 0)
#ifdef use_xyz
void ZFillFunction(TZFillCallback zFillFunc);
#endif
protected:
void Reset();
virtual bool ExecuteInternal();
private:
PolyOutList m_PolyOuts;
JoinList m_Joins;
JoinList m_GhostJoins;
IntersectList m_IntersectList;
ClipType m_ClipType;
std::set< cInt, std::greater<cInt> > m_Scanbeam;
TEdge *m_ActiveEdges;
TEdge *m_SortedEdges;
bool m_ExecuteLocked;
PolyFillType m_ClipFillType;
PolyFillType m_SubjFillType;
bool m_ReverseOutput;
bool m_UsingPolyTree;
bool m_StrictSimple;
#ifdef use_xyz
TZFillCallback m_ZFill; //custom callback
#endif
void SetWindingCount(TEdge& edge);
bool IsEvenOddFillType(const TEdge& edge) const;
bool IsEvenOddAltFillType(const TEdge& edge) const;
void InsertScanbeam(const cInt Y);
cInt PopScanbeam();
void InsertLocalMinimaIntoAEL(const cInt botY);
void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
void AddEdgeToSEL(TEdge *edge);
void CopyAELToSEL();
void DeleteFromSEL(TEdge *e);
void DeleteFromAEL(TEdge *e);
void UpdateEdgeIntoAEL(TEdge *&e);
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
bool IsContributing(const TEdge& edge) const;
bool IsTopHorz(const cInt XPos);
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
void DoMaxima(TEdge *e);
void PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam);
void ProcessHorizontals(bool IsTopOfScanbeam);
void ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam);
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutRec* GetOutRec(int idx);
void AppendPolygon(TEdge *e1, TEdge *e2);
void IntersectEdges(TEdge *e1, TEdge *e2,
const IntPoint &pt, bool protect = false);
OutRec* CreateOutRec();
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
void DisposeAllOutRecs();
void DisposeOutRec(PolyOutList::size_type index);
bool ProcessIntersections(const cInt botY, const cInt topY);
void BuildIntersectList(const cInt botY, const cInt topY);
void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
void BuildResult(Paths& polys);
void BuildResult2(PolyTree& polytree);
void SetHoleState(TEdge *e, OutRec *outrec);
void DisposeIntersectNodes();
bool FixupIntersectionOrder();
void FixupOutPolygon(OutRec &outrec);
bool IsHole(TEdge *e);
bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
void FixHoleLinkage(OutRec &outrec);
void AddJoin(OutPt *op1, OutPt *op2, const IntPoint offPt);
void ClearJoins();
void ClearGhostJoins();
void AddGhostJoin(OutPt *op, const IntPoint offPt);
bool JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2);
void JoinCommonEdges();
void DoSimplePolygons();
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec);
#ifdef use_xyz
void SetZ(IntPoint& pt, TEdge& e);
#endif
};
//------------------------------------------------------------------------------
class ClipperOffset
{
public:
ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25);
~ClipperOffset();
void AddPath(const Path& path, JoinType joinType, EndType endType);
void AddPaths(const Paths& paths, JoinType joinType, EndType endType);
void Execute(Paths& solution, double delta);
void Execute(PolyTree& solution, double delta);
void Clear();
double MiterLimit;
double ArcTolerance;
private:
Paths m_destPolys;
Path m_srcPoly;
Path m_destPoly;
std::vector<DoublePoint> m_normals;
double m_delta, m_sinA, m_sin, m_cos;
double m_miterLim, m_StepsPerRad;
IntPoint m_lowest;
PolyNode m_polyNodes;
void FixOrientations();
void DoOffset(double delta);
void OffsetPoint(int j, int& k, JoinType jointype);
void DoSquare(int j, int k);
void DoMiter(int j, int k, double r);
void DoRound(int j, int k);
};
//------------------------------------------------------------------------------
class clipperException : public std::exception
{
public:
clipperException(const char* description): m_descr(description) {}
virtual ~clipperException() throw() {}
virtual const char* what() const throw() {return m_descr.c_str();}
private:
std::string m_descr;
};
//------------------------------------------------------------------------------
} //ClipperLib namespace
#endif //clipper_hpp
+249
Ver Arquivo
@@ -0,0 +1,249 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ALLOCATORS_H_
#define RAPIDJSON_ALLOCATORS_H_
#include "rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Allocator
/*! \class rapidjson::Allocator
\brief Concept for allocating, resizing and freeing memory block.
Note that Malloc() and Realloc() are non-static but Free() is static.
So if an allocator need to support Free(), it needs to put its pointer in
the header of memory block.
\code
concept Allocator {
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
// Allocate a memory block.
// \param size of the memory block in bytes.
// \returns pointer to the memory block.
void* Malloc(size_t size);
// Resize a memory block.
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
// \param newSize the new size in bytes.
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
// Free a memory block.
// \param pointer to the memory block. Null pointer is permitted.
static void Free(void *ptr);
};
\endcode
*/
///////////////////////////////////////////////////////////////////////////////
// CrtAllocator
//! C-runtime library allocator.
/*! This class is just wrapper for standard C library memory routines.
\note implements Allocator concept
*/
class CrtAllocator {
public:
static const bool kNeedFree = true;
void* Malloc(size_t size) {
if (size) // behavior of malloc(0) is implementation defined.
return std::malloc(size);
else
return NULL; // standardize to returning NULL.
}
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; return std::realloc(originalPtr, newSize); }
static void Free(void *ptr) { std::free(ptr); }
};
///////////////////////////////////////////////////////////////////////////////
// MemoryPoolAllocator
//! Default memory allocator used by the parser and DOM.
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
It does not free memory blocks. And Realloc() only allocate new memory.
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
User may also supply a buffer as the first chunk.
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
The user-buffer is not deallocated by this allocator.
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
\note implements Allocator concept
*/
template <typename BaseAllocator = CrtAllocator>
class MemoryPoolAllocator {
public:
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
//! Constructor with chunkSize.
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{
}
//! Constructor with user-supplied buffer.
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
The user buffer will not be deallocated when this allocator is destructed.
\param buffer User supplied buffer.
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
\param baseAllocator The allocator for allocating memory chunks.
*/
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
{
RAPIDJSON_ASSERT(buffer != 0);
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
chunkHead_->capacity = size - sizeof(ChunkHeader);
chunkHead_->size = 0;
chunkHead_->next = 0;
}
//! Destructor.
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
*/
~MemoryPoolAllocator() {
Clear();
RAPIDJSON_DELETE(ownBaseAllocator_);
}
//! Deallocates all memory chunks, excluding the user-supplied buffer.
void Clear() {
while(chunkHead_ != 0 && chunkHead_ != userBuffer_) {
ChunkHeader* next = chunkHead_->next;
baseAllocator_->Free(chunkHead_);
chunkHead_ = next;
}
}
//! Computes the total capacity of allocated memory chunks.
/*! \return total capacity in bytes.
*/
size_t Capacity() const {
size_t capacity = 0;
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
capacity += c->capacity;
return capacity;
}
//! Computes the memory blocks allocated.
/*! \return total used bytes.
*/
size_t Size() const {
size_t size = 0;
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
size += c->size;
return size;
}
//! Allocates a memory block. (concept Allocator)
void* Malloc(size_t size) {
if (!size)
return NULL;
size = RAPIDJSON_ALIGN(size);
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size);
void *buffer = reinterpret_cast<char *>(chunkHead_ + 1) + chunkHead_->size;
chunkHead_->size += size;
return buffer;
}
//! Resizes a memory block (concept Allocator)
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
if (originalPtr == 0)
return Malloc(newSize);
// Do not shrink if new size is smaller than original
if (originalSize >= newSize)
return originalPtr;
// Simply expand it if it is the last allocation and there is sufficient space
if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) {
size_t increment = static_cast<size_t>(newSize - originalSize);
increment = RAPIDJSON_ALIGN(increment);
if (chunkHead_->size + increment <= chunkHead_->capacity) {
chunkHead_->size += increment;
return originalPtr;
}
}
// Realloc process: allocate and copy memory, do not free original buffer.
void* newBuffer = Malloc(newSize);
RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly.
if (originalSize)
std::memcpy(newBuffer, originalPtr, originalSize);
return newBuffer;
}
//! Frees a memory block (concept Allocator)
static void Free(void *ptr) { (void)ptr; } // Do nothing
private:
//! Copy constructor is not permitted.
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
//! Copy assignment operator is not permitted.
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
//! Creates a new chunk.
/*! \param capacity Capacity of the chunk in bytes.
*/
void AddChunk(size_t capacity) {
if (!baseAllocator_)
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity));
chunk->capacity = capacity;
chunk->size = 0;
chunk->next = chunkHead_;
chunkHead_ = chunk;
}
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
//! Chunk header for perpending to each chunk.
/*! Chunks are stored as a singly linked list.
*/
struct ChunkHeader {
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
size_t size; //!< Current size of allocated memory in bytes.
ChunkHeader *next; //!< Next chunk in the linked list.
};
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
void *userBuffer_; //!< User supplied buffer.
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ENCODINGS_H_
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+261
Ver Arquivo
@@ -0,0 +1,261 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
#define RAPIDJSON_ENCODEDSTREAM_H_
#include "rapidjson.h"
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Input byte stream wrapper with a statically bound encoding.
/*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
*/
template <typename Encoding, typename InputByteStream>
class EncodedInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public:
typedef typename Encoding::Ch Ch;
EncodedInputStream(InputByteStream& is) : is_(is) {
current_ = Encoding::TakeBOM(is_);
}
Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
size_t Tell() const { return is_.Tell(); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
EncodedInputStream(const EncodedInputStream&);
EncodedInputStream& operator=(const EncodedInputStream&);
InputByteStream& is_;
Ch current_;
};
//! Output byte stream wrapper with statically bound encoding.
/*!
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
\tparam InputByteStream Type of input byte stream. For example, FileWriteStream.
*/
template <typename Encoding, typename OutputByteStream>
class EncodedOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public:
typedef typename Encoding::Ch Ch;
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
if (putBOM)
Encoding::PutBOM(os_);
}
void Put(Ch c) { Encoding::Put(os_, c); }
void Flush() { os_.Flush(); }
// Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); }
Ch Take() { RAPIDJSON_ASSERT(false); }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
EncodedOutputStream(const EncodedOutputStream&);
EncodedOutputStream& operator=(const EncodedOutputStream&);
OutputByteStream& os_;
};
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
\tparam CharType Type of character for reading.
\tparam InputByteStream type of input byte stream to be wrapped.
*/
template <typename CharType, typename InputByteStream>
class AutoUTFInputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
public:
typedef CharType Ch;
//! Constructor.
/*!
\param is input stream to be wrapped.
\param type UTF encoding type if it is not detected from the stream.
*/
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
DetectType();
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
takeFunc_ = f[type_];
current_ = takeFunc_(*is_);
}
UTFType GetType() const { return type_; }
bool HasBOM() const { return hasBOM_; }
Ch Peek() const { return current_; }
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
size_t Tell() const { return is_->Tell(); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
AutoUTFInputStream(const AutoUTFInputStream&);
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
// Detect encoding type with BOM or RFC 4627
void DetectType() {
// BOM (Byte Order Mark):
// 00 00 FE FF UTF-32BE
// FF FE 00 00 UTF-32LE
// FE FF UTF-16BE
// FF FE UTF-16LE
// EF BB BF UTF-8
const unsigned char* c = (const unsigned char *)is_->Peek4();
if (!c)
return;
unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24);
hasBOM_ = false;
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
// RFC 4627: Section 3
// "Since the first two characters of a JSON text will always be ASCII
// characters [RFC0020], it is possible to determine whether an octet
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
// at the pattern of nulls in the first four octets."
// 00 00 00 xx UTF-32BE
// 00 xx 00 xx UTF-16BE
// xx 00 00 00 UTF-32LE
// xx 00 xx 00 UTF-16LE
// xx xx xx xx UTF-8
if (!hasBOM_) {
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
switch (pattern) {
case 0x08: type_ = kUTF32BE; break;
case 0x0A: type_ = kUTF16BE; break;
case 0x01: type_ = kUTF32LE; break;
case 0x05: type_ = kUTF16LE; break;
case 0x0F: type_ = kUTF8; break;
default: break; // Use type defined by user.
}
}
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
}
typedef Ch (*TakeFunc)(InputByteStream& is);
InputByteStream* is_;
UTFType type_;
Ch current_;
TakeFunc takeFunc_;
bool hasBOM_;
};
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
/*!
\tparam CharType Type of character for writing.
\tparam InputByteStream type of output byte stream to be wrapped.
*/
template <typename CharType, typename OutputByteStream>
class AutoUTFOutputStream {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
public:
typedef CharType Ch;
//! Constructor.
/*!
\param os output stream to be wrapped.
\param type UTF encoding type.
\param putBOM Whether to write BOM at the beginning of the stream.
*/
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
putFunc_ = f[type_];
if (putBOM)
PutBOM();
}
UTFType GetType() const { return type_; }
void Put(Ch c) { putFunc_(*os_, c); }
void Flush() { os_->Flush(); }
// Not implemented
Ch Peek() const { RAPIDJSON_ASSERT(false); }
Ch Take() { RAPIDJSON_ASSERT(false); }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
private:
AutoUTFOutputStream(const AutoUTFOutputStream&);
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
void PutBOM() {
typedef void (*PutBOMFunc)(OutputByteStream&);
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
f[type_](*os_);
}
typedef void (*PutFunc)(OutputByteStream&, Ch);
OutputByteStream* os_;
UTFType type_;
PutFunc putFunc_;
};
#undef RAPIDJSON_ENCODINGS_FUNC
RAPIDJSON_NAMESPACE_END
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_FILESTREAM_H_
+625
Ver Arquivo
@@ -0,0 +1,625 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ENCODINGS_H_
#define RAPIDJSON_ENCODINGS_H_
#include "rapidjson.h"
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
RAPIDJSON_DIAG_OFF(4702) // unreachable code
#elif defined(__GNUC__)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
RAPIDJSON_DIAG_OFF(overflow)
#endif
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Encoding
/*! \class rapidjson::Encoding
\brief Concept for encoding of Unicode characters.
\code
concept Encoding {
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
//! \brief Encode a Unicode codepoint to an output stream.
//! \param os Output stream.
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint);
//! \brief Decode a Unicode codepoint from an input stream.
//! \param is Input stream.
//! \param codepoint Output of the unicode codepoint.
//! \return true if a valid codepoint can be decoded from the stream.
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint);
//! \brief Validate one Unicode codepoint from an encoded stream.
//! \param is Input stream to obtain codepoint.
//! \param os Output for copying one codepoint.
//! \return true if it is valid.
//! \note This function just validating and copying the codepoint without actually decode it.
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os);
// The following functions are deal with byte streams.
//! Take a character from input byte stream, skip BOM if exist.
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is);
//! Take a character from input byte stream.
template <typename InputByteStream>
static Ch Take(InputByteStream& is);
//! Put BOM to output byte stream.
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os);
//! Put a character to output byte stream.
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c);
};
\endcode
*/
///////////////////////////////////////////////////////////////////////////////
// UTF8
//! UTF-8 encoding.
/*! http://en.wikipedia.org/wiki/UTF-8
http://tools.ietf.org/html/rfc3629
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
\note implements Encoding concept
*/
template<typename CharType = char>
struct UTF8 {
typedef CharType Ch;
enum { supportUnicode = 1 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
if (codepoint <= 0x7F)
os.Put(static_cast<Ch>(codepoint & 0xFF));
else if (codepoint <= 0x7FF) {
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
}
else if (codepoint <= 0xFFFF) {
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
else {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
}
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu)
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70)
Ch c = is.Take();
if (!(c & 0x80)) {
*codepoint = (unsigned char)c;
return true;
}
unsigned char type = GetRange((unsigned char)c);
*codepoint = (0xFF >> type) & (unsigned char)c;
bool result = true;
switch (type) {
case 2: TAIL(); return result;
case 3: TAIL(); TAIL(); return result;
case 4: COPY(); TRANS(0x50); TAIL(); return result;
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
case 6: TAIL(); TAIL(); TAIL(); return result;
case 10: COPY(); TRANS(0x20); TAIL(); return result;
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
default: return false;
}
#undef COPY
#undef TRANS
#undef TAIL
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
#define COPY() os.Put(c = is.Take())
#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0)
#define TAIL() COPY(); TRANS(0x70)
Ch c;
COPY();
if (!(c & 0x80))
return true;
bool result = true;
switch (GetRange((unsigned char)c)) {
case 2: TAIL(); return result;
case 3: TAIL(); TAIL(); return result;
case 4: COPY(); TRANS(0x50); TAIL(); return result;
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
case 6: TAIL(); TAIL(); TAIL(); return result;
case 10: COPY(); TRANS(0x20); TAIL(); return result;
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
default: return false;
}
#undef COPY
#undef TRANS
#undef TAIL
}
static unsigned char GetRange(unsigned char c) {
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
static const unsigned char type[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
};
return type[c];
}
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
Ch c = Take(is);
if ((unsigned char)c != 0xEFu) return c;
c = is.Take();
if ((unsigned char)c != 0xBBu) return c;
c = is.Take();
if ((unsigned char)c != 0xBFu) return c;
c = is.Take();
return c;
}
template <typename InputByteStream>
static Ch Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return is.Take();
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(c));
}
};
///////////////////////////////////////////////////////////////////////////////
// UTF16
//! UTF-16 encoding.
/*! http://en.wikipedia.org/wiki/UTF-16
http://tools.ietf.org/html/rfc2781
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
\note implements Encoding concept
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF16LE and UTF16BE, which handle endianness.
*/
template<typename CharType = wchar_t>
struct UTF16 {
typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
enum { supportUnicode = 1 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
if (codepoint <= 0xFFFF) {
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
}
else {
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
unsigned v = codepoint - 0x10000;
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
os.Put((v & 0x3FF) | 0xDC00);
}
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
Ch c = is.Take();
if (c < 0xD800 || c > 0xDFFF) {
*codepoint = c;
return true;
}
else if (c <= 0xDBFF) {
*codepoint = (c & 0x3FF) << 10;
c = is.Take();
*codepoint |= (c & 0x3FF);
*codepoint += 0x10000;
return c >= 0xDC00 && c <= 0xDFFF;
}
return false;
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
Ch c;
os.Put(c = is.Take());
if (c < 0xD800 || c > 0xDFFF)
return true;
else if (c <= 0xDBFF) {
os.Put(c = is.Take());
return c >= 0xDC00 && c <= 0xDFFF;
}
return false;
}
};
//! UTF-16 little endian encoding.
template<typename CharType = wchar_t>
struct UTF16LE : UTF16<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take();
c |= (unsigned char)is.Take() << 8;
return c;
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFFu); os.Put(0xFEu);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(c & 0xFFu);
os.Put((c >> 8) & 0xFFu);
}
};
//! UTF-16 big endian encoding.
template<typename CharType = wchar_t>
struct UTF16BE : UTF16<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return (unsigned short)c == 0xFEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take() << 8;
c |= (unsigned char)is.Take();
return c;
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFEu); os.Put(0xFFu);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put((c >> 8) & 0xFFu);
os.Put(c & 0xFFu);
}
};
///////////////////////////////////////////////////////////////////////////////
// UTF32
//! UTF-32 encoding.
/*! http://en.wikipedia.org/wiki/UTF-32
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
\note implements Encoding concept
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
For streaming, use UTF32LE and UTF32BE, which handle endianness.
*/
template<typename CharType = unsigned>
struct UTF32 {
typedef CharType Ch;
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
enum { supportUnicode = 1 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
os.Put(codepoint);
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
Ch c = is.Take();
*codepoint = c;
return c <= 0x10FFFF;
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
Ch c;
os.Put(c = is.Take());
return c <= 0x10FFFF;
}
};
//! UTF-32 little endian enocoding.
template<typename CharType = unsigned>
struct UTF32LE : UTF32<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take();
c |= (unsigned char)is.Take() << 8;
c |= (unsigned char)is.Take() << 16;
c |= (unsigned char)is.Take() << 24;
return c;
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(c & 0xFFu);
os.Put((c >> 8) & 0xFFu);
os.Put((c >> 16) & 0xFFu);
os.Put((c >> 24) & 0xFFu);
}
};
//! UTF-32 big endian encoding.
template<typename CharType = unsigned>
struct UTF32BE : UTF32<CharType> {
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = Take(is);
return (unsigned)c == 0x0000FEFFu ? Take(is) : c;
}
template <typename InputByteStream>
static CharType Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
CharType c = (unsigned char)is.Take() << 24;
c |= (unsigned char)is.Take() << 16;
c |= (unsigned char)is.Take() << 8;
c |= (unsigned char)is.Take();
return c;
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu);
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, CharType c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put((c >> 24) & 0xFFu);
os.Put((c >> 16) & 0xFFu);
os.Put((c >> 8) & 0xFFu);
os.Put(c & 0xFFu);
}
};
///////////////////////////////////////////////////////////////////////////////
// ASCII
//! ASCII encoding.
/*! http://en.wikipedia.org/wiki/ASCII
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
\note implements Encoding concept
*/
template<typename CharType = char>
struct ASCII {
typedef CharType Ch;
enum { supportUnicode = 0 };
template<typename OutputStream>
static void Encode(OutputStream& os, unsigned codepoint) {
RAPIDJSON_ASSERT(codepoint <= 0x7F);
os.Put(static_cast<Ch>(codepoint & 0xFF));
}
template <typename InputStream>
static bool Decode(InputStream& is, unsigned* codepoint) {
unsigned char c = static_cast<unsigned char>(is.Take());
*codepoint = c;
return c <= 0X7F;
}
template <typename InputStream, typename OutputStream>
static bool Validate(InputStream& is, OutputStream& os) {
unsigned char c = is.Take();
os.Put(c);
return c <= 0x7F;
}
template <typename InputByteStream>
static CharType TakeBOM(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
Ch c = Take(is);
return c;
}
template <typename InputByteStream>
static Ch Take(InputByteStream& is) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
return is.Take();
}
template <typename OutputByteStream>
static void PutBOM(OutputByteStream& os) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
(void)os;
}
template <typename OutputByteStream>
static void Put(OutputByteStream& os, Ch c) {
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
os.Put(static_cast<typename OutputByteStream::Ch>(c));
}
};
///////////////////////////////////////////////////////////////////////////////
// AutoUTF
//! Runtime-specified UTF encoding type of a stream.
enum UTFType {
kUTF8 = 0, //!< UTF-8.
kUTF16LE = 1, //!< UTF-16 little endian.
kUTF16BE = 2, //!< UTF-16 big endian.
kUTF32LE = 3, //!< UTF-32 little endian.
kUTF32BE = 4 //!< UTF-32 big endian.
};
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
*/
template<typename CharType>
struct AutoUTF {
typedef CharType Ch;
enum { supportUnicode = 1 };
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
template<typename OutputStream>
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
typedef void (*EncodeFunc)(OutputStream&, unsigned);
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
(*f[os.GetType()])(os, codepoint);
}
template <typename InputStream>
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
return (*f[is.GetType()])(is, codepoint);
}
template <typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
return (*f[is.GetType()])(is, os);
}
#undef RAPIDJSON_ENCODINGS_FUNC
};
///////////////////////////////////////////////////////////////////////////////
// Transcoder
//! Encoding conversion.
template<typename SourceEncoding, typename TargetEncoding>
struct Transcoder {
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false;
TargetEncoding::Encode(os, codepoint);
return true;
}
//! Validate one Unicode codepoint from an encoded stream.
template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
return Transcode(is, os); // Since source/target encoding is different, must transcode.
}
};
//! Specialization of Transcoder with same source and target encoding.
template<typename Encoding>
struct Transcoder<Encoding, Encoding> {
template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
return true;
}
template<typename InputStream, typename OutputStream>
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
return Encoding::Validate(is, os); // source/target encoding are the same
}
};
RAPIDJSON_NAMESPACE_END
#if defined(__GNUC__) || defined(_MSV_VER)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_ENCODINGS_H_
+65
Ver Arquivo
@@ -0,0 +1,65 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_EN_H__
#define RAPIDJSON_ERROR_EN_H__
#include "error.h"
RAPIDJSON_NAMESPACE_BEGIN
//! Maps error code of parsing into error message.
/*!
\ingroup RAPIDJSON_ERRORS
\param parseErrorCode Error code obtained in parsing.
\return the error message.
\note User can make a copy of this function for localization.
Using switch-case is safer for future modification of error codes.
*/
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
switch (parseErrorCode) {
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values.");
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
default:
return RAPIDJSON_ERROR_STRING("Unknown error.");
}
}
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ERROR_EN_H__
+144
Ver Arquivo
@@ -0,0 +1,144 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ERROR_ERROR_H__
#define RAPIDJSON_ERROR_ERROR_H__
/*! \file error.h */
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ERROR_CHARTYPE
//! Character type of error messages.
/*! \ingroup RAPIDJSON_ERRORS
The default character type is \c char.
On Windows, user can define this macro as \c TCHAR for supporting both
unicode/non-unicode settings.
*/
#ifndef RAPIDJSON_ERROR_CHARTYPE
#define RAPIDJSON_ERROR_CHARTYPE char
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ERROR_STRING
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
/*! \ingroup RAPIDJSON_ERRORS
By default this conversion macro does nothing.
On Windows, user can define this macro as \c _T(x) for supporting both
unicode/non-unicode settings.
*/
#ifndef RAPIDJSON_ERROR_STRING
#define RAPIDJSON_ERROR_STRING(x) x
#endif
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// ParseErrorCode
//! Error code of parsing.
/*! \ingroup RAPIDJSON_ERRORS
\see GenericReader::Parse, GenericReader::GetParseErrorCode
*/
enum ParseErrorCode {
kParseErrorNone = 0, //!< No error.
kParseErrorDocumentEmpty, //!< The document is empty.
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
kParseErrorValueInvalid, //!< Invalid value.
kParseErrorObjectMissName, //!< Missing a name for object member.
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
kParseErrorNumberMissExponent, //!< Miss exponent in number.
kParseErrorTermination, //!< Parsing was terminated.
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
};
//! Result of parsing (wraps ParseErrorCode)
/*!
\ingroup RAPIDJSON_ERRORS
\code
Document doc;
ParseResult ok = doc.Parse("[42]");
if (!ok) {
fprintf(stderr, "JSON parse error: %s (%u)",
GetParseError_En(ok.Code()), ok.Offset());
exit(EXIT_FAILURE);
}
\endcode
\see GenericReader::Parse, GenericDocument::Parse
*/
struct ParseResult {
//! Default constructor, no error.
ParseResult() : code_(kParseErrorNone), offset_(0) {}
//! Constructor to set an error.
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
//! Get the error code.
ParseErrorCode Code() const { return code_; }
//! Get the error offset, if \ref IsError(), 0 otherwise.
size_t Offset() const { return offset_; }
//! Conversion to \c bool, returns \c true, iff !\ref IsError().
operator bool() const { return !IsError(); }
//! Whether the result is an error.
bool IsError() const { return code_ != kParseErrorNone; }
bool operator==(const ParseResult& that) const { return code_ == that.code_; }
bool operator==(ParseErrorCode code) const { return code_ == code; }
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
//! Reset error code.
void Clear() { Set(kParseErrorNone); }
//! Update error code and offset.
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
private:
ParseErrorCode code_;
size_t offset_;
};
//! Function pointer type of GetParseError().
/*! \ingroup RAPIDJSON_ERRORS
This is the prototype for \c GetParseError_X(), where \c X is a locale.
User can dynamically change locale in runtime, e.g.:
\code
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
\endcode
*/
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ERROR_ERROR_H__
+88
Ver Arquivo
@@ -0,0 +1,88 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEREADSTREAM_H_
#define RAPIDJSON_FILEREADSTREAM_H_
#include "rapidjson.h"
#include <cstdio>
RAPIDJSON_NAMESPACE_BEGIN
//! File byte stream for input using fread().
/*!
\note implements Stream concept
*/
class FileReadStream {
public:
typedef char Ch; //!< Character type (byte).
//! Constructor.
/*!
\param fp File pointer opened for read.
\param buffer user-supplied buffer.
\param bufferSize size of buffer in bytes. Must >=4 bytes.
*/
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
RAPIDJSON_ASSERT(fp_ != 0);
RAPIDJSON_ASSERT(bufferSize >= 4);
Read();
}
Ch Peek() const { return *current_; }
Ch Take() { Ch c = *current_; Read(); return c; }
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
// Not implemented
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const {
return (current_ + 4 <= bufferLast_) ? current_ : 0;
}
private:
void Read() {
if (current_ < bufferLast_)
++current_;
else if (!eof_) {
count_ += readCount_;
readCount_ = fread(buffer_, 1, bufferSize_, fp_);
bufferLast_ = buffer_ + readCount_ - 1;
current_ = buffer_;
if (readCount_ < bufferSize_) {
buffer_[readCount_] = '\0';
++bufferLast_;
eof_ = true;
}
}
}
std::FILE* fp_;
Ch *buffer_;
size_t bufferSize_;
Ch *bufferLast_;
Ch *current_;
size_t readCount_;
size_t count_; //!< Number of characters read
bool eof_;
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_FILESTREAM_H_
+91
Ver Arquivo
@@ -0,0 +1,91 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
#define RAPIDJSON_FILEWRITESTREAM_H_
#include "rapidjson.h"
#include <cstdio>
RAPIDJSON_NAMESPACE_BEGIN
//! Wrapper of C file stream for input using fread().
/*!
\note implements Stream concept
*/
class FileWriteStream {
public:
typedef char Ch; //!< Character type. Only support char.
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
RAPIDJSON_ASSERT(fp_ != 0);
}
void Put(char c) {
if (current_ >= bufferEnd_)
Flush();
*current_++ = c;
}
void PutN(char c, size_t n) {
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
while (n > avail) {
std::memset(current_, c, avail);
current_ += avail;
Flush();
n -= avail;
avail = static_cast<size_t>(bufferEnd_ - current_);
}
if (n > 0) {
std::memset(current_, c, n);
current_ += n;
}
}
void Flush() {
if (current_ != buffer_) {
fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
current_ = buffer_;
}
}
// Not implemented
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
char Take() { RAPIDJSON_ASSERT(false); return 0; }
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
private:
// Prohibit copy constructor & assignment operator.
FileWriteStream(const FileWriteStream&);
FileWriteStream& operator=(const FileWriteStream&);
std::FILE* fp_;
char *buffer_;
char *bufferEnd_;
char *current_;
};
//! Implement specialized version of PutN() with memset() for better performance.
template<>
inline void PutN(FileWriteStream& stream, char c, size_t n) {
stream.PutN(c, n);
}
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_FILESTREAM_H_
+280
Ver Arquivo
@@ -0,0 +1,280 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_BIGINTEGER_H_
#define RAPIDJSON_BIGINTEGER_H_
#include "../rapidjson.h"
#if defined(_MSC_VER) && defined(_M_AMD64)
#include <intrin.h> // for _umul128
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
class BigInteger {
public:
typedef uint64_t Type;
BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
}
explicit BigInteger(uint64_t u) : count_(1) {
digits_[0] = u;
}
BigInteger(const char* decimals, size_t length) : count_(1) {
RAPIDJSON_ASSERT(length > 0);
digits_[0] = 0;
size_t i = 0;
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
while (length >= kMaxDigitPerIteration) {
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
length -= kMaxDigitPerIteration;
i += kMaxDigitPerIteration;
}
if (length > 0)
AppendDecimal64(decimals + i, decimals + i + length);
}
BigInteger& operator=(uint64_t u) {
digits_[0] = u;
count_ = 1;
return *this;
}
BigInteger& operator+=(uint64_t u) {
Type backup = digits_[0];
digits_[0] += u;
for (size_t i = 0; i < count_ - 1; i++) {
if (digits_[i] >= backup)
return *this; // no carry
backup = digits_[i + 1];
digits_[i + 1] += 1;
}
// Last carry
if (digits_[count_ - 1] < backup)
PushBack(1);
return *this;
}
BigInteger& operator*=(uint64_t u) {
if (u == 0) return *this = 0;
if (u == 1) return *this;
if (*this == 1) return *this = u;
uint64_t k = 0;
for (size_t i = 0; i < count_; i++) {
uint64_t hi;
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
k = hi;
}
if (k > 0)
PushBack(k);
return *this;
}
BigInteger& operator*=(uint32_t u) {
if (u == 0) return *this = 0;
if (u == 1) return *this;
if (*this == 1) return *this = u;
uint32_t k = 0;
for (size_t i = 0; i < count_; i++) {
const uint64_t c = digits_[i] >> 32;
const uint64_t d = digits_[i] & 0xFFFFFFFF;
const uint64_t uc = u * c;
const uint64_t ud = u * d;
const uint64_t p0 = ud + k;
const uint64_t p1 = uc + (p0 >> 32);
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
k = p1 >> 32;
}
if (k > 0)
PushBack(k);
return *this;
}
BigInteger& operator<<=(size_t shift) {
if (IsZero() || shift == 0) return *this;
size_t offset = shift / kTypeBit;
size_t interShift = shift % kTypeBit;
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
if (interShift == 0) {
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
count_ += offset;
}
else {
digits_[count_] = 0;
for (size_t i = count_; i > 0; i--)
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
digits_[offset] = digits_[0] << interShift;
count_ += offset;
if (digits_[count_])
count_++;
}
std::memset(digits_, 0, offset * sizeof(Type));
return *this;
}
bool operator==(const BigInteger& rhs) const {
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
}
bool operator==(const Type rhs) const {
return count_ == 1 && digits_[0] == rhs;
}
BigInteger& MultiplyPow5(unsigned exp) {
static const uint32_t kPow5[12] = {
5,
5 * 5,
5 * 5 * 5,
5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
};
if (exp == 0) return *this;
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
if (exp > 0) *this *= kPow5[exp - 1];
return *this;
}
// Compute absolute difference of this and rhs.
// Assume this != rhs
bool Difference(const BigInteger& rhs, BigInteger* out) const {
int cmp = Compare(rhs);
RAPIDJSON_ASSERT(cmp != 0);
const BigInteger *a, *b; // Makes a > b
bool ret;
if (cmp < 0) { a = &rhs; b = this; ret = true; }
else { a = this; b = &rhs; ret = false; }
Type borrow = 0;
for (size_t i = 0; i < a->count_; i++) {
Type d = a->digits_[i] - borrow;
if (i < b->count_)
d -= b->digits_[i];
borrow = (d > a->digits_[i]) ? 1 : 0;
out->digits_[i] = d;
if (d != 0)
out->count_ = i + 1;
}
return ret;
}
int Compare(const BigInteger& rhs) const {
if (count_ != rhs.count_)
return count_ < rhs.count_ ? -1 : 1;
for (size_t i = count_; i-- > 0;)
if (digits_[i] != rhs.digits_[i])
return digits_[i] < rhs.digits_[i] ? -1 : 1;
return 0;
}
size_t GetCount() const { return count_; }
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
private:
void AppendDecimal64(const char* begin, const char* end) {
uint64_t u = ParseUint64(begin, end);
if (IsZero())
*this = u;
else {
unsigned exp = static_cast<unsigned>(end - begin);
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
}
}
void PushBack(Type digit) {
RAPIDJSON_ASSERT(count_ < kCapacity);
digits_[count_++] = digit;
}
static uint64_t ParseUint64(const char* begin, const char* end) {
uint64_t r = 0;
for (const char* p = begin; p != end; ++p) {
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
r = r * 10 + (*p - '0');
}
return r;
}
// Assume a * b + k < 2^128
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
#if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t low = _umul128(a, b, outHigh) + k;
if (low < k)
(*outHigh)++;
return low;
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
p += k;
*outHigh = p >> 64;
return static_cast<uint64_t>(p);
#else
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
x1 += (x0 >> 32); // can't give carry
x1 += x2;
if (x1 < x2)
x3 += (static_cast<uint64_t>(1) << 32);
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
uint64_t hi = x3 + (x1 >> 32);
lo += k;
if (lo < k)
hi++;
*outHigh = hi;
return lo;
#endif
}
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
static const size_t kCapacity = kBitCount / sizeof(Type);
static const size_t kTypeBit = sizeof(Type) * 8;
Type digits_[kCapacity];
size_t count_;
};
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_BIGINTEGER_H_
+247
Ver Arquivo
@@ -0,0 +1,247 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
#ifndef RAPIDJSON_DIYFP_H_
#define RAPIDJSON_DIYFP_H_
#if defined(_MSC_VER)
#include <intrin.h>
#if defined(_M_AMD64)
#pragma intrinsic(_BitScanReverse64)
#endif
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
struct DiyFp {
DiyFp() {}
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
explicit DiyFp(double d) {
union {
double d;
uint64_t u64;
} u = { d };
int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize;
uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0) {
f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias;
}
else {
f = significand;
e = kDpMinExponent + 1;
}
}
DiyFp operator-(const DiyFp& rhs) const {
return DiyFp(f - rhs.f, e);
}
DiyFp operator*(const DiyFp& rhs) const {
#if defined(_MSC_VER) && defined(_M_AMD64)
uint64_t h;
uint64_t l = _umul128(f, rhs.f, &h);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
__extension__ typedef unsigned __int128 uint128;
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
uint64_t h = p >> 64;
uint64_t l = static_cast<uint64_t>(p);
if (l & (uint64_t(1) << 63)) // rounding
h++;
return DiyFp(h, e + rhs.e + 64);
#else
const uint64_t M32 = 0xFFFFFFFF;
const uint64_t a = f >> 32;
const uint64_t b = f & M32;
const uint64_t c = rhs.f >> 32;
const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c;
const uint64_t bc = b * c;
const uint64_t ad = a * d;
const uint64_t bd = b * d;
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
tmp += 1U << 31; /// mult_round
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
#endif
}
DiyFp Normalize() const {
#if defined(_MSC_VER) && defined(_M_AMD64)
unsigned long index;
_BitScanReverse64(&index, f);
return DiyFp(f << (63 - index), e - (63 - index));
#elif defined(__GNUC__) && __GNUC__ >= 4
int s = __builtin_clzll(f);
return DiyFp(f << s, e - s);
#else
DiyFp res = *this;
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
res.f <<= 1;
res.e--;
}
return res;
#endif
}
DiyFp NormalizeBoundary() const {
DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1))) {
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
return res;
}
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*plus = pl;
*minus = mi;
}
double ToDouble() const {
union {
double d;
uint64_t u64;
}u;
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
static_cast<uint64_t>(e + kDpExponentBias);
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
return u.d;
}
static const int kDiySignificandSize = 64;
static const int kDpSignificandSize = 52;
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
static const int kDpMinExponent = -kDpExponentBias;
static const int kDpDenormalExponent = -kDpExponentBias + 1;
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
uint64_t f;
int e;
};
inline DiyFp GetCachedPowerByIndex(size_t index) {
// 10^-348, 10^-340, ..., 10^340
static const uint64_t kCachedPowers_F[] = {
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
};
static const int16_t kCachedPowers_E[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
907, 933, 960, 986, 1013, 1039, 1066
};
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
inline DiyFp GetCachedPower(int e, int* K) {
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
int k = static_cast<int>(dk);
if (dk - k > 0.0)
k++;
unsigned index = static_cast<unsigned>((k >> 3) + 1);
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
return GetCachedPowerByIndex(index);
}
inline DiyFp GetCachedPower10(int exp, int *outExp) {
unsigned index = (exp + 348) / 8;
*outExp = -348 + index * 8;
return GetCachedPowerByIndex(index);
}
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_DIYFP_H_
+217
Ver Arquivo
@@ -0,0 +1,217 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
#ifndef RAPIDJSON_DTOA_
#define RAPIDJSON_DTOA_
#include "itoa.h" // GetDigitsLut()
#include "diyfp.h"
#include "ieee754.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
while (rest < wp_w && delta - rest >= ten_kappa &&
(rest + ten_kappa < wp_w || /// closer
wp_w - rest > rest + ten_kappa - wp_w)) {
buffer[len - 1]--;
rest += ten_kappa;
}
}
inline unsigned CountDecimalDigit32(uint32_t n) {
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
// Will not reach 10 digits in DigitGen()
//if (n < 1000000000) return 9;
//return 10;
return 9;
}
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
const DiyFp wp_w = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
uint64_t p2 = Mp.f & (one.f - 1);
int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0;
while (kappa > 0) {
uint32_t d = 0;
switch (kappa) {
case 9: d = p1 / 100000000; p1 %= 100000000; break;
case 8: d = p1 / 10000000; p1 %= 10000000; break;
case 7: d = p1 / 1000000; p1 %= 1000000; break;
case 6: d = p1 / 100000; p1 %= 100000; break;
case 5: d = p1 / 10000; p1 %= 10000; break;
case 4: d = p1 / 1000; p1 %= 1000; break;
case 3: d = p1 / 100; p1 %= 100; break;
case 2: d = p1 / 10; p1 %= 10; break;
case 1: d = p1; p1 = 0; break;
default:;
}
if (d || *len)
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
kappa--;
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
if (tmp <= delta) {
*K += kappa;
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
return;
}
}
// kappa = 0
for (;;) {
p2 *= 10;
delta *= 10;
char d = static_cast<char>(p2 >> -one.e);
if (d || *len)
buffer[(*len)++] = static_cast<char>('0' + d);
p2 &= one.f - 1;
kappa--;
if (p2 < delta) {
*K += kappa;
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]);
return;
}
}
}
inline void Grisu2(double value, char* buffer, int* length, int* K) {
const DiyFp v(value);
DiyFp w_m, w_p;
v.NormalizedBoundaries(&w_m, &w_p);
const DiyFp c_mk = GetCachedPower(w_p.e, K);
const DiyFp W = v.Normalize() * c_mk;
DiyFp Wp = w_p * c_mk;
DiyFp Wm = w_m * c_mk;
Wm.f++;
Wp.f--;
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
}
inline char* WriteExponent(int K, char* buffer) {
if (K < 0) {
*buffer++ = '-';
K = -K;
}
if (K >= 100) {
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
K %= 100;
const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else if (K >= 10) {
const char* d = GetDigitsLut() + K * 2;
*buffer++ = d[0];
*buffer++ = d[1];
}
else
*buffer++ = static_cast<char>('0' + static_cast<char>(K));
return buffer;
}
inline char* Prettify(char* buffer, int length, int k) {
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
if (length <= kk && kk <= 21) {
// 1234e7 -> 12340000000
for (int i = length; i < kk; i++)
buffer[i] = '0';
buffer[kk] = '.';
buffer[kk + 1] = '0';
return &buffer[kk + 2];
}
else if (0 < kk && kk <= 21) {
// 1234e-2 -> 12.34
std::memmove(&buffer[kk + 1], &buffer[kk], length - kk);
buffer[kk] = '.';
return &buffer[length + 1];
}
else if (-6 < kk && kk <= 0) {
// 1234e-6 -> 0.001234
const int offset = 2 - kk;
std::memmove(&buffer[offset], &buffer[0], length);
buffer[0] = '0';
buffer[1] = '.';
for (int i = 2; i < offset; i++)
buffer[i] = '0';
return &buffer[length + offset];
}
else if (length == 1) {
// 1e30
buffer[1] = 'e';
return WriteExponent(kk - 1, &buffer[2]);
}
else {
// 1234e30 -> 1.234e33
std::memmove(&buffer[2], &buffer[1], length - 1);
buffer[1] = '.';
buffer[length + 1] = 'e';
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
}
}
inline char* dtoa(double value, char* buffer) {
Double d(value);
if (d.IsZero()) {
if (d.Sign())
*buffer++ = '-'; // -0.0, Issue #289
buffer[0] = '0';
buffer[1] = '.';
buffer[2] = '0';
return &buffer[3];
}
else {
if (value < 0) {
*buffer++ = '-';
value = -value;
}
int length, K;
Grisu2(value, buffer, &length, &K);
return Prettify(buffer, length, K);
}
}
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_DTOA_
+77
Ver Arquivo
@@ -0,0 +1,77 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_IEEE754_
#define RAPIDJSON_IEEE754_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
class Double {
public:
Double() {}
Double(double d) : d(d) {}
Double(uint64_t u) : u(u) {}
double Value() const { return d; }
uint64_t Uint64Value() const { return u; }
double NextPositiveDouble() const {
RAPIDJSON_ASSERT(!Sign());
return Double(u + 1).Value();
}
bool Sign() const { return (u & kSignMask) != 0; }
uint64_t Significand() const { return u & kSignificandMask; }
int Exponent() const { return ((u & kExponentMask) >> kSignificandSize) - kExponentBias; }
bool IsNan() const { return (u & kExponentMask) == kExponentMask && Significand() != 0; }
bool IsInf() const { return (u & kExponentMask) == kExponentMask && Significand() == 0; }
bool IsNormal() const { return (u & kExponentMask) != 0 || Significand() == 0; }
bool IsZero() const { return (u & (kExponentMask | kSignificandMask)) == 0; }
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
uint64_t ToBias() const { return (u & kSignMask) ? ~u + 1 : u | kSignMask; }
static unsigned EffectiveSignificandSize(int order) {
if (order >= -1021)
return 53;
else if (order <= -1074)
return 0;
else
return order + 1074;
}
private:
static const int kSignificandSize = 52;
static const int kExponentBias = 0x3FF;
static const int kDenormalExponent = 1 - kExponentBias;
static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
union {
double d;
uint64_t u;
};
};
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_IEEE754_
+304
Ver Arquivo
@@ -0,0 +1,304 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_ITOA_
#define RAPIDJSON_ITOA_
#include "../rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
inline const char* GetDigitsLut() {
static const char cDigitsLut[200] = {
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
};
return cDigitsLut;
}
inline char* u32toa(uint32_t value, char* buffer) {
const char* cDigitsLut = GetDigitsLut();
if (value < 10000) {
const uint32_t d1 = (value / 100) << 1;
const uint32_t d2 = (value % 100) << 1;
if (value >= 1000)
*buffer++ = cDigitsLut[d1];
if (value >= 100)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 10)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
}
else if (value < 100000000) {
// value = bbbbcccc
const uint32_t b = value / 10000;
const uint32_t c = value % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
else {
// value = aabbbbcccc in decimal
const uint32_t a = value / 100000000; // 1 to 42
value %= 100000000;
if (a >= 10) {
const unsigned i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
const uint32_t b = value / 10000; // 0 to 9999
const uint32_t c = value % 10000; // 0 to 9999
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
return buffer;
}
inline char* i32toa(int32_t value, char* buffer) {
uint32_t u = static_cast<uint32_t>(value);
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
return u32toa(u, buffer);
}
inline char* u64toa(uint64_t value, char* buffer) {
const char* cDigitsLut = GetDigitsLut();
const uint64_t kTen8 = 100000000;
const uint64_t kTen9 = kTen8 * 10;
const uint64_t kTen10 = kTen8 * 100;
const uint64_t kTen11 = kTen8 * 1000;
const uint64_t kTen12 = kTen8 * 10000;
const uint64_t kTen13 = kTen8 * 100000;
const uint64_t kTen14 = kTen8 * 1000000;
const uint64_t kTen15 = kTen8 * 10000000;
const uint64_t kTen16 = kTen8 * kTen8;
if (value < kTen8) {
uint32_t v = static_cast<uint32_t>(value);
if (v < 10000) {
const uint32_t d1 = (v / 100) << 1;
const uint32_t d2 = (v % 100) << 1;
if (v >= 1000)
*buffer++ = cDigitsLut[d1];
if (v >= 100)
*buffer++ = cDigitsLut[d1 + 1];
if (v >= 10)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
}
else {
// value = bbbbcccc
const uint32_t b = v / 10000;
const uint32_t c = v % 10000;
const uint32_t d1 = (b / 100) << 1;
const uint32_t d2 = (b % 100) << 1;
const uint32_t d3 = (c / 100) << 1;
const uint32_t d4 = (c % 100) << 1;
if (value >= 10000000)
*buffer++ = cDigitsLut[d1];
if (value >= 1000000)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= 100000)
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
}
}
else if (value < kTen16) {
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
if (value >= kTen15)
*buffer++ = cDigitsLut[d1];
if (value >= kTen14)
*buffer++ = cDigitsLut[d1 + 1];
if (value >= kTen13)
*buffer++ = cDigitsLut[d2];
if (value >= kTen12)
*buffer++ = cDigitsLut[d2 + 1];
if (value >= kTen11)
*buffer++ = cDigitsLut[d3];
if (value >= kTen10)
*buffer++ = cDigitsLut[d3 + 1];
if (value >= kTen9)
*buffer++ = cDigitsLut[d4];
if (value >= kTen8)
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
else {
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
value %= kTen16;
if (a < 10)
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
else if (a < 100) {
const uint32_t i = a << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else if (a < 1000) {
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
const uint32_t i = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
}
else {
const uint32_t i = (a / 100) << 1;
const uint32_t j = (a % 100) << 1;
*buffer++ = cDigitsLut[i];
*buffer++ = cDigitsLut[i + 1];
*buffer++ = cDigitsLut[j];
*buffer++ = cDigitsLut[j + 1];
}
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
const uint32_t b0 = v0 / 10000;
const uint32_t c0 = v0 % 10000;
const uint32_t d1 = (b0 / 100) << 1;
const uint32_t d2 = (b0 % 100) << 1;
const uint32_t d3 = (c0 / 100) << 1;
const uint32_t d4 = (c0 % 100) << 1;
const uint32_t b1 = v1 / 10000;
const uint32_t c1 = v1 % 10000;
const uint32_t d5 = (b1 / 100) << 1;
const uint32_t d6 = (b1 % 100) << 1;
const uint32_t d7 = (c1 / 100) << 1;
const uint32_t d8 = (c1 % 100) << 1;
*buffer++ = cDigitsLut[d1];
*buffer++ = cDigitsLut[d1 + 1];
*buffer++ = cDigitsLut[d2];
*buffer++ = cDigitsLut[d2 + 1];
*buffer++ = cDigitsLut[d3];
*buffer++ = cDigitsLut[d3 + 1];
*buffer++ = cDigitsLut[d4];
*buffer++ = cDigitsLut[d4 + 1];
*buffer++ = cDigitsLut[d5];
*buffer++ = cDigitsLut[d5 + 1];
*buffer++ = cDigitsLut[d6];
*buffer++ = cDigitsLut[d6 + 1];
*buffer++ = cDigitsLut[d7];
*buffer++ = cDigitsLut[d7 + 1];
*buffer++ = cDigitsLut[d8];
*buffer++ = cDigitsLut[d8 + 1];
}
return buffer;
}
inline char* i64toa(int64_t value, char* buffer) {
uint64_t u = static_cast<uint64_t>(value);
if (value < 0) {
*buffer++ = '-';
u = ~u + 1;
}
return u64toa(u, buffer);
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_ITOA_
+183
Ver Arquivo
@@ -0,0 +1,183 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_META_H_
#define RAPIDJSON_INTERNAL_META_H_
#ifndef RAPIDJSON_RAPIDJSON_H_
#error <rapidjson.h> not yet included. Do not include this file directly.
#endif
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
#if defined(_MSC_VER)
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(6334)
#endif
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
#include <type_traits>
#endif
//@cond RAPIDJSON_INTERNAL
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
template <typename T> struct Void { typedef void Type; };
///////////////////////////////////////////////////////////////////////////////
// BoolType, TrueType, FalseType
//
template <bool Cond> struct BoolType {
static const bool Value = Cond;
typedef BoolType Type;
};
typedef BoolType<true> TrueType;
typedef BoolType<false> FalseType;
///////////////////////////////////////////////////////////////////////////////
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
//
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
template <> struct AndExprCond<true, true> : TrueType {};
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
template <> struct OrExprCond<false, false> : FalseType {};
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
///////////////////////////////////////////////////////////////////////////////
// AddConst, MaybeAddConst, RemoveConst
template <typename T> struct AddConst { typedef const T Type; };
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
template <typename T> struct RemoveConst { typedef T Type; };
template <typename T> struct RemoveConst<const T> { typedef T Type; };
///////////////////////////////////////////////////////////////////////////////
// IsSame, IsConst, IsMoreConst, IsPointer
//
template <typename T, typename U> struct IsSame : FalseType {};
template <typename T> struct IsSame<T, T> : TrueType {};
template <typename T> struct IsConst : FalseType {};
template <typename T> struct IsConst<const T> : TrueType {};
template <typename CT, typename T>
struct IsMoreConst
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
template <typename T> struct IsPointer : FalseType {};
template <typename T> struct IsPointer<T*> : TrueType {};
///////////////////////////////////////////////////////////////////////////////
// IsBaseOf
//
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
template <typename B, typename D> struct IsBaseOf
: BoolType< ::std::is_base_of<B,D>::value> {};
#else // simplified version adopted from Boost
template<typename B, typename D> struct IsBaseOfImpl {
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
typedef char (&Yes)[1];
typedef char (&No) [2];
template <typename T>
static Yes Check(const D*, T);
static No Check(const B*, int);
struct Host {
operator const B*() const;
operator const D*();
};
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
};
template <typename B, typename D> struct IsBaseOf
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
//////////////////////////////////////////////////////////////////////////
// EnableIf / DisableIf
//
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
template <typename Condition, typename T = void>
struct EnableIf : EnableIfCond<Condition::Value, T> {};
template <typename Condition, typename T = void>
struct DisableIf : DisableIfCond<Condition::Value, T> {};
// SFINAE helpers
struct SfinaeTag {};
template <typename T> struct RemoveSfinaeTag;
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
#define RAPIDJSON_REMOVEFPTR_(type) \
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
#define RAPIDJSON_ENABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_DISABLEIF(cond) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
<RAPIDJSON_REMOVEFPTR_(cond), \
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
} // namespace internal
RAPIDJSON_NAMESPACE_END
//@endcond
#if defined(__GNUC__) || defined(_MSC_VER)
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_INTERNAL_META_H_
+53
Ver Arquivo
@@ -0,0 +1,53 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_POW10_
#define RAPIDJSON_POW10_
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
//! Computes integer powers of 10 in double (10.0^n).
/*! This function uses lookup table for fast and accurate results.
\param n non-negative exponent. Must <= 308.
\return 10.0^n
*/
inline double Pow10(int n) {
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
1e+0,
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
};
RAPIDJSON_ASSERT(n >= 0 && n <= 308);
return e[n];
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_POW10_
+177
Ver Arquivo
@@ -0,0 +1,177 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_STACK_H_
#define RAPIDJSON_INTERNAL_STACK_H_
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
///////////////////////////////////////////////////////////////////////////////
// Stack
//! A type-unsafe stack for storing different types of data.
/*! \tparam Allocator Allocator for allocating stack memory.
*/
template <typename Allocator>
class Stack {
public:
// Optimization note: Do not allocate memory for stack_ in constructor.
// Do it lazily when first Push() -> Expand() -> Resize().
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
RAPIDJSON_ASSERT(stackCapacity > 0);
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Stack(Stack&& rhs)
: allocator_(rhs.allocator_),
ownAllocator_(rhs.ownAllocator_),
stack_(rhs.stack_),
stackTop_(rhs.stackTop_),
stackEnd_(rhs.stackEnd_),
initialCapacity_(rhs.initialCapacity_)
{
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.stack_ = 0;
rhs.stackTop_ = 0;
rhs.stackEnd_ = 0;
rhs.initialCapacity_ = 0;
}
#endif
~Stack() {
Destroy();
}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
Stack& operator=(Stack&& rhs) {
if (&rhs != this)
{
Destroy();
allocator_ = rhs.allocator_;
ownAllocator_ = rhs.ownAllocator_;
stack_ = rhs.stack_;
stackTop_ = rhs.stackTop_;
stackEnd_ = rhs.stackEnd_;
initialCapacity_ = rhs.initialCapacity_;
rhs.allocator_ = 0;
rhs.ownAllocator_ = 0;
rhs.stack_ = 0;
rhs.stackTop_ = 0;
rhs.stackEnd_ = 0;
rhs.initialCapacity_ = 0;
}
return *this;
}
#endif
void Clear() { stackTop_ = stack_; }
void ShrinkToFit() {
if (Empty()) {
// If the stack is empty, completely deallocate the memory.
Allocator::Free(stack_);
stack_ = 0;
stackTop_ = 0;
stackEnd_ = 0;
}
else
Resize(GetSize());
}
// Optimization note: try to minimize the size of this function for force inline.
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
template<typename T>
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
// Expand the stack if needed
if (stackTop_ + sizeof(T) * count >= stackEnd_)
Expand<T>(count);
T* ret = reinterpret_cast<T*>(stackTop_);
stackTop_ += sizeof(T) * count;
return ret;
}
template<typename T>
T* Pop(size_t count) {
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
stackTop_ -= count * sizeof(T);
return reinterpret_cast<T*>(stackTop_);
}
template<typename T>
T* Top() {
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
}
template<typename T>
T* Bottom() { return (T*)stack_; }
Allocator& GetAllocator() { return *allocator_; }
bool Empty() const { return stackTop_ == stack_; }
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
private:
template<typename T>
void Expand(size_t count) {
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
size_t newCapacity;
if (stack_ == 0) {
if (!allocator_)
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
newCapacity = initialCapacity_;
} else {
newCapacity = GetCapacity();
newCapacity += (newCapacity + 1) / 2;
}
size_t newSize = GetSize() + sizeof(T) * count;
if (newCapacity < newSize)
newCapacity = newSize;
Resize(newCapacity);
}
void Resize(size_t newCapacity) {
const size_t size = GetSize(); // Backup the current size
stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity);
stackTop_ = stack_ + size;
stackEnd_ = stack_ + newCapacity;
}
void Destroy() {
Allocator::Free(stack_);
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
}
// Prohibit copy constructor & assignment operator.
Stack(const Stack&);
Stack& operator=(const Stack&);
Allocator* allocator_;
Allocator* ownAllocator_;
char *stack_;
char *stackTop_;
char *stackEnd_;
size_t initialCapacity_;
};
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_STACK_H_
+37
Ver Arquivo
@@ -0,0 +1,37 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
#define RAPIDJSON_INTERNAL_STRFUNC_H_
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
//! Custom strlen() which works on different character types.
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
\param s Null-terminated input string.
\return Number of characters in the string.
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
*/
template <typename Ch>
inline SizeType StrLen(const Ch* s) {
const Ch* p = s;
while (*p) ++p;
return SizeType(p - s);
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
+265
Ver Arquivo
@@ -0,0 +1,265 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_STRTOD_
#define RAPIDJSON_STRTOD_
#include "../rapidjson.h"
#include "ieee754.h"
#include "biginteger.h"
#include "diyfp.h"
#include "pow10.h"
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
inline double FastPath(double significand, int exp) {
if (exp < -308)
return 0.0;
else if (exp >= 0)
return significand * internal::Pow10(exp);
else
return significand / internal::Pow10(-exp);
}
inline double StrtodNormalPrecision(double d, int p) {
if (p < -308) {
// Prevent expSum < -308, making Pow10(p) = 0
d = FastPath(d, -308);
d = FastPath(d, p + 308);
}
else
d = FastPath(d, p);
return d;
}
template <typename T>
inline T Min3(T a, T b, T c) {
T m = a;
if (m > b) m = b;
if (m > c) m = c;
return m;
}
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
const Double db(b);
const uint64_t bInt = db.IntegerSignificand();
const int bExp = db.IntegerExponent();
const int hExp = bExp - 1;
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
// Adjust for decimal exponent
if (dExp >= 0) {
dS_Exp2 += dExp;
dS_Exp5 += dExp;
}
else {
bS_Exp2 -= dExp;
bS_Exp5 -= dExp;
hS_Exp2 -= dExp;
hS_Exp5 -= dExp;
}
// Adjust for binary exponent
if (bExp >= 0)
bS_Exp2 += bExp;
else {
dS_Exp2 -= bExp;
hS_Exp2 -= bExp;
}
// Adjust for half ulp exponent
if (hExp >= 0)
hS_Exp2 += hExp;
else {
dS_Exp2 -= hExp;
bS_Exp2 -= hExp;
}
// Remove common power of two factor from all three scaled values
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
dS_Exp2 -= common_Exp2;
bS_Exp2 -= common_Exp2;
hS_Exp2 -= common_Exp2;
BigInteger dS = d;
dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2;
BigInteger bS(bInt);
bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2;
BigInteger hS(1);
hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2;
BigInteger delta(0);
dS.Difference(bS, &delta);
return delta.Compare(hS);
}
inline bool StrtodFast(double d, int p, double* result) {
// Use fast path for string-to-double conversion if possible
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
if (p > 22 && p < 22 + 16) {
// Fast Path Cases In Disguise
d *= internal::Pow10(p - 22);
p = 22;
}
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
*result = FastPath(d, p);
return true;
}
else
return false;
}
// Compute an approximation and see if it is within 1/2 ULP
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
uint64_t significand = 0;
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
for (; i < length; i++) {
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
break;
significand = significand * 10 + (decimals[i] - '0');
}
if (i < length && decimals[i] >= '5') // Rounding
significand++;
size_t remaining = length - i;
const unsigned kUlpShift = 3;
const unsigned kUlp = 1 << kUlpShift;
int error = (remaining == 0) ? 0 : kUlp / 2;
DiyFp v(significand, 0);
v = v.Normalize();
error <<= -v.e;
const int dExp = (int)decimalPosition - (int)i + exp;
int actualExp;
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
if (actualExp != dExp) {
static const DiyFp kPow10[] = {
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
};
int adjustment = dExp - actualExp - 1;
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
v = v * kPow10[adjustment];
if (length + adjustment > 19) // has more digits than decimal digits in 64-bit
error += kUlp / 2;
}
v = v * cachedPower;
error += kUlp + (error == 0 ? 0 : 1);
const int oldExp = v.e;
v = v.Normalize();
error <<= oldExp - v.e;
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
unsigned precisionSize = 64 - effectiveSignificandSize;
if (precisionSize + kUlpShift >= 64) {
unsigned scaleExp = (precisionSize + kUlpShift) - 63;
v.f >>= scaleExp;
v.e += scaleExp;
error = (error >> scaleExp) + 1 + kUlp;
precisionSize -= scaleExp;
}
DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
if (precisionBits >= halfWay + error)
rounded.f++;
*result = rounded.ToDouble();
return halfWay - error >= precisionBits || precisionBits >= halfWay + error;
}
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
const BigInteger dInt(decimals, length);
const int dExp = (int)decimalPosition - (int)length + exp;
Double a(approx);
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
if (cmp < 0)
return a.Value(); // within half ULP
else if (cmp == 0) {
// Round towards even
if (a.Significand() & 1)
return a.NextPositiveDouble();
else
return a.Value();
}
else // adjustment
return a.NextPositiveDouble();
}
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
RAPIDJSON_ASSERT(d >= 0.0);
RAPIDJSON_ASSERT(length >= 1);
double result;
if (StrtodFast(d, p, &result))
return result;
// Trim leading zeros
while (*decimals == '0' && length > 1) {
length--;
decimals++;
decimalPosition--;
}
// Trim trailing zeros
while (decimals[length - 1] == '0' && length > 1) {
length--;
decimalPosition--;
exp++;
}
// Trim right-most digits
const int kMaxDecimalDigit = 780;
if ((int)length > kMaxDecimalDigit) {
int delta = (int(length) - kMaxDecimalDigit);
exp += delta;
decimalPosition -= delta;
length = kMaxDecimalDigit;
}
// If too small, underflow to zero
if (int(length) + exp < -324)
return 0.0;
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
return result;
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
}
} // namespace internal
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_STRTOD_
+70
Ver Arquivo
@@ -0,0 +1,70 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_MEMORYBUFFER_H_
#define RAPIDJSON_MEMORYBUFFER_H_
#include "rapidjson.h"
#include "internal/stack.h"
RAPIDJSON_NAMESPACE_BEGIN
//! Represents an in-memory output byte stream.
/*!
This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
Differences between MemoryBuffer and StringBuffer:
1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
\tparam Allocator type for allocating memory buffer.
\note implements Stream concept
*/
template <typename Allocator = CrtAllocator>
struct GenericMemoryBuffer {
typedef char Ch; // byte
GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
void Flush() {}
void Clear() { stack_.Clear(); }
void ShrinkToFit() { stack_.ShrinkToFit(); }
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
const Ch* GetBuffer() const {
return stack_.template Bottom<Ch>();
}
size_t GetSize() const { return stack_.GetSize(); }
static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_;
};
typedef GenericMemoryBuffer<> MemoryBuffer;
//! Implement specialized version of PutN() with memset() for better performance.
template<>
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
}
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_MEMORYBUFFER_H_
+61
Ver Arquivo
@@ -0,0 +1,61 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_MEMORYSTREAM_H_
#define RAPIDJSON_MEMORYSTREAM_H_
#include "rapidjson.h"
RAPIDJSON_NAMESPACE_BEGIN
//! Represents an in-memory input byte stream.
/*!
This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
Differences between MemoryStream and StringStream:
1. StringStream has encoding but MemoryStream is a byte stream.
2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
\note implements Stream concept
*/
struct MemoryStream {
typedef char Ch; // byte
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
Ch Peek() const { return (src_ == end_) ? '\0' : *src_; }
Ch Take() { return (src_ == end_) ? '\0' : *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
// For encoding detection only.
const Ch* Peek4() const {
return Tell() + 4 <= size_ ? src_ : 0;
}
const Ch* src_; //!< Current read position.
const Ch* begin_; //!< Original head of the string.
const Ch* end_; //!< End of stream.
size_t size_; //!< Size of the stream.
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_MEMORYBUFFER_H_
+316
Ver Arquivo
@@ -0,0 +1,316 @@
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006-2013 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the product 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 AUTHOR ``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 AUTHOR 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.
//
///////////////////////////////////////////////////////////////////////////////
// The above software in this distribution may have been modified by
// THL A29 Limited ("Tencent Modifications").
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
#ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ]
#ifndef _MSC_INTTYPES_H_ // [
#define _MSC_INTTYPES_H_
#if _MSC_VER > 1000
#pragma once
#endif
#include "stdint.h"
// miloyip: VC supports inttypes.h since VC2013
#if _MSC_VER >= 1800
#include <inttypes.h>
#else
// 7.8 Format conversion of integer types
typedef struct {
intmax_t quot;
intmax_t rem;
} imaxdiv_t;
// 7.8.1 Macros for format specifiers
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
// The fprintf macros for signed integers are:
#define PRId8 "d"
#define PRIi8 "i"
#define PRIdLEAST8 "d"
#define PRIiLEAST8 "i"
#define PRIdFAST8 "d"
#define PRIiFAST8 "i"
#define PRId16 "hd"
#define PRIi16 "hi"
#define PRIdLEAST16 "hd"
#define PRIiLEAST16 "hi"
#define PRIdFAST16 "hd"
#define PRIiFAST16 "hi"
#define PRId32 "I32d"
#define PRIi32 "I32i"
#define PRIdLEAST32 "I32d"
#define PRIiLEAST32 "I32i"
#define PRIdFAST32 "I32d"
#define PRIiFAST32 "I32i"
#define PRId64 "I64d"
#define PRIi64 "I64i"
#define PRIdLEAST64 "I64d"
#define PRIiLEAST64 "I64i"
#define PRIdFAST64 "I64d"
#define PRIiFAST64 "I64i"
#define PRIdMAX "I64d"
#define PRIiMAX "I64i"
#define PRIdPTR "Id"
#define PRIiPTR "Ii"
// The fprintf macros for unsigned integers are:
#define PRIo8 "o"
#define PRIu8 "u"
#define PRIx8 "x"
#define PRIX8 "X"
#define PRIoLEAST8 "o"
#define PRIuLEAST8 "u"
#define PRIxLEAST8 "x"
#define PRIXLEAST8 "X"
#define PRIoFAST8 "o"
#define PRIuFAST8 "u"
#define PRIxFAST8 "x"
#define PRIXFAST8 "X"
#define PRIo16 "ho"
#define PRIu16 "hu"
#define PRIx16 "hx"
#define PRIX16 "hX"
#define PRIoLEAST16 "ho"
#define PRIuLEAST16 "hu"
#define PRIxLEAST16 "hx"
#define PRIXLEAST16 "hX"
#define PRIoFAST16 "ho"
#define PRIuFAST16 "hu"
#define PRIxFAST16 "hx"
#define PRIXFAST16 "hX"
#define PRIo32 "I32o"
#define PRIu32 "I32u"
#define PRIx32 "I32x"
#define PRIX32 "I32X"
#define PRIoLEAST32 "I32o"
#define PRIuLEAST32 "I32u"
#define PRIxLEAST32 "I32x"
#define PRIXLEAST32 "I32X"
#define PRIoFAST32 "I32o"
#define PRIuFAST32 "I32u"
#define PRIxFAST32 "I32x"
#define PRIXFAST32 "I32X"
#define PRIo64 "I64o"
#define PRIu64 "I64u"
#define PRIx64 "I64x"
#define PRIX64 "I64X"
#define PRIoLEAST64 "I64o"
#define PRIuLEAST64 "I64u"
#define PRIxLEAST64 "I64x"
#define PRIXLEAST64 "I64X"
#define PRIoFAST64 "I64o"
#define PRIuFAST64 "I64u"
#define PRIxFAST64 "I64x"
#define PRIXFAST64 "I64X"
#define PRIoMAX "I64o"
#define PRIuMAX "I64u"
#define PRIxMAX "I64x"
#define PRIXMAX "I64X"
#define PRIoPTR "Io"
#define PRIuPTR "Iu"
#define PRIxPTR "Ix"
#define PRIXPTR "IX"
// The fscanf macros for signed integers are:
#define SCNd8 "d"
#define SCNi8 "i"
#define SCNdLEAST8 "d"
#define SCNiLEAST8 "i"
#define SCNdFAST8 "d"
#define SCNiFAST8 "i"
#define SCNd16 "hd"
#define SCNi16 "hi"
#define SCNdLEAST16 "hd"
#define SCNiLEAST16 "hi"
#define SCNdFAST16 "hd"
#define SCNiFAST16 "hi"
#define SCNd32 "ld"
#define SCNi32 "li"
#define SCNdLEAST32 "ld"
#define SCNiLEAST32 "li"
#define SCNdFAST32 "ld"
#define SCNiFAST32 "li"
#define SCNd64 "I64d"
#define SCNi64 "I64i"
#define SCNdLEAST64 "I64d"
#define SCNiLEAST64 "I64i"
#define SCNdFAST64 "I64d"
#define SCNiFAST64 "I64i"
#define SCNdMAX "I64d"
#define SCNiMAX "I64i"
#ifdef _WIN64 // [
# define SCNdPTR "I64d"
# define SCNiPTR "I64i"
#else // _WIN64 ][
# define SCNdPTR "ld"
# define SCNiPTR "li"
#endif // _WIN64 ]
// The fscanf macros for unsigned integers are:
#define SCNo8 "o"
#define SCNu8 "u"
#define SCNx8 "x"
#define SCNX8 "X"
#define SCNoLEAST8 "o"
#define SCNuLEAST8 "u"
#define SCNxLEAST8 "x"
#define SCNXLEAST8 "X"
#define SCNoFAST8 "o"
#define SCNuFAST8 "u"
#define SCNxFAST8 "x"
#define SCNXFAST8 "X"
#define SCNo16 "ho"
#define SCNu16 "hu"
#define SCNx16 "hx"
#define SCNX16 "hX"
#define SCNoLEAST16 "ho"
#define SCNuLEAST16 "hu"
#define SCNxLEAST16 "hx"
#define SCNXLEAST16 "hX"
#define SCNoFAST16 "ho"
#define SCNuFAST16 "hu"
#define SCNxFAST16 "hx"
#define SCNXFAST16 "hX"
#define SCNo32 "lo"
#define SCNu32 "lu"
#define SCNx32 "lx"
#define SCNX32 "lX"
#define SCNoLEAST32 "lo"
#define SCNuLEAST32 "lu"
#define SCNxLEAST32 "lx"
#define SCNXLEAST32 "lX"
#define SCNoFAST32 "lo"
#define SCNuFAST32 "lu"
#define SCNxFAST32 "lx"
#define SCNXFAST32 "lX"
#define SCNo64 "I64o"
#define SCNu64 "I64u"
#define SCNx64 "I64x"
#define SCNX64 "I64X"
#define SCNoLEAST64 "I64o"
#define SCNuLEAST64 "I64u"
#define SCNxLEAST64 "I64x"
#define SCNXLEAST64 "I64X"
#define SCNoFAST64 "I64o"
#define SCNuFAST64 "I64u"
#define SCNxFAST64 "I64x"
#define SCNXFAST64 "I64X"
#define SCNoMAX "I64o"
#define SCNuMAX "I64u"
#define SCNxMAX "I64x"
#define SCNXMAX "I64X"
#ifdef _WIN64 // [
# define SCNoPTR "I64o"
# define SCNuPTR "I64u"
# define SCNxPTR "I64x"
# define SCNXPTR "I64X"
#else // _WIN64 ][
# define SCNoPTR "lo"
# define SCNuPTR "lu"
# define SCNxPTR "lx"
# define SCNXPTR "lX"
#endif // _WIN64 ]
#endif // __STDC_FORMAT_MACROS ]
// 7.8.2 Functions for greatest-width integer types
// 7.8.2.1 The imaxabs function
#define imaxabs _abs64
// 7.8.2.2 The imaxdiv function
// This is modified version of div() function from Microsoft's div.c found
// in %MSVC.NET%\crt\src\div.c
#ifdef STATIC_IMAXDIV // [
static
#else // STATIC_IMAXDIV ][
_inline
#endif // STATIC_IMAXDIV ]
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
{
imaxdiv_t result;
result.quot = numer / denom;
result.rem = numer % denom;
if (numer < 0 && result.rem > 0) {
// did division wrong; must fix up
++result.quot;
result.rem -= denom;
}
return result;
}
// 7.8.2.3 The strtoimax and strtoumax functions
#define strtoimax _strtoi64
#define strtoumax _strtoui64
// 7.8.2.4 The wcstoimax and wcstoumax functions
#define wcstoimax _wcstoi64
#define wcstoumax _wcstoui64
#endif // _MSC_VER >= 1800
#endif // _MSC_INTTYPES_H_ ]
+300
Ver Arquivo
@@ -0,0 +1,300 @@
// ISO C9x compliant stdint.h for Microsoft Visual Studio
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
//
// Copyright (c) 2006-2013 Alexander Chemeris
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. 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.
//
// 3. Neither the name of the product 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 AUTHOR ``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 AUTHOR 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.
//
///////////////////////////////////////////////////////////////////////////////
// The above software in this distribution may have been modified by
// THL A29 Limited ("Tencent Modifications").
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
#ifndef _MSC_VER // [
#error "Use this header only with Microsoft Visual C++ compilers!"
#endif // _MSC_VER ]
#ifndef _MSC_STDINT_H_ // [
#define _MSC_STDINT_H_
#if _MSC_VER > 1000
#pragma once
#endif
// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
#if _MSC_VER >= 1600 // [
#include <stdint.h>
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
#undef INT8_C
#undef INT16_C
#undef INT32_C
#undef INT64_C
#undef UINT8_C
#undef UINT16_C
#undef UINT32_C
#undef UINT64_C
// 7.18.4.1 Macros for minimum-width integer constants
#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64
#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64
// 7.18.4.2 Macros for greatest-width integer constants
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
// Check out Issue 9 for the details.
#ifndef INTMAX_C // [
# define INTMAX_C INT64_C
#endif // INTMAX_C ]
#ifndef UINTMAX_C // [
# define UINTMAX_C UINT64_C
#endif // UINTMAX_C ]
#endif // __STDC_CONSTANT_MACROS ]
#else // ] _MSC_VER >= 1700 [
#include <limits.h>
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
// or compiler give many errors like this:
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
#ifdef __cplusplus
extern "C" {
#endif
# include <wchar.h>
#ifdef __cplusplus
}
#endif
// Define _W64 macros to mark types changing their size, like intptr_t.
#ifndef _W64
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
# define _W64 __w64
# else
# define _W64
# endif
#endif
// 7.18.1 Integer types
// 7.18.1.1 Exact-width integer types
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
// realize that, e.g. char has the same size as __int8
// so we give up on __intX for them.
#if (_MSC_VER < 1300)
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#else
typedef signed __int8 int8_t;
typedef signed __int16 int16_t;
typedef signed __int32 int32_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
#endif
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
// 7.18.1.2 Minimum-width integer types
typedef int8_t int_least8_t;
typedef int16_t int_least16_t;
typedef int32_t int_least32_t;
typedef int64_t int_least64_t;
typedef uint8_t uint_least8_t;
typedef uint16_t uint_least16_t;
typedef uint32_t uint_least32_t;
typedef uint64_t uint_least64_t;
// 7.18.1.3 Fastest minimum-width integer types
typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;
// 7.18.1.4 Integer types capable of holding object pointers
#ifdef _WIN64 // [
typedef signed __int64 intptr_t;
typedef unsigned __int64 uintptr_t;
#else // _WIN64 ][
typedef _W64 signed int intptr_t;
typedef _W64 unsigned int uintptr_t;
#endif // _WIN64 ]
// 7.18.1.5 Greatest-width integer types
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
// 7.18.2 Limits of specified-width integer types
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
// 7.18.2.1 Limits of exact-width integer types
#define INT8_MIN ((int8_t)_I8_MIN)
#define INT8_MAX _I8_MAX
#define INT16_MIN ((int16_t)_I16_MIN)
#define INT16_MAX _I16_MAX
#define INT32_MIN ((int32_t)_I32_MIN)
#define INT32_MAX _I32_MAX
#define INT64_MIN ((int64_t)_I64_MIN)
#define INT64_MAX _I64_MAX
#define UINT8_MAX _UI8_MAX
#define UINT16_MAX _UI16_MAX
#define UINT32_MAX _UI32_MAX
#define UINT64_MAX _UI64_MAX
// 7.18.2.2 Limits of minimum-width integer types
#define INT_LEAST8_MIN INT8_MIN
#define INT_LEAST8_MAX INT8_MAX
#define INT_LEAST16_MIN INT16_MIN
#define INT_LEAST16_MAX INT16_MAX
#define INT_LEAST32_MIN INT32_MIN
#define INT_LEAST32_MAX INT32_MAX
#define INT_LEAST64_MIN INT64_MIN
#define INT_LEAST64_MAX INT64_MAX
#define UINT_LEAST8_MAX UINT8_MAX
#define UINT_LEAST16_MAX UINT16_MAX
#define UINT_LEAST32_MAX UINT32_MAX
#define UINT_LEAST64_MAX UINT64_MAX
// 7.18.2.3 Limits of fastest minimum-width integer types
#define INT_FAST8_MIN INT8_MIN
#define INT_FAST8_MAX INT8_MAX
#define INT_FAST16_MIN INT16_MIN
#define INT_FAST16_MAX INT16_MAX
#define INT_FAST32_MIN INT32_MIN
#define INT_FAST32_MAX INT32_MAX
#define INT_FAST64_MIN INT64_MIN
#define INT_FAST64_MAX INT64_MAX
#define UINT_FAST8_MAX UINT8_MAX
#define UINT_FAST16_MAX UINT16_MAX
#define UINT_FAST32_MAX UINT32_MAX
#define UINT_FAST64_MAX UINT64_MAX
// 7.18.2.4 Limits of integer types capable of holding object pointers
#ifdef _WIN64 // [
# define INTPTR_MIN INT64_MIN
# define INTPTR_MAX INT64_MAX
# define UINTPTR_MAX UINT64_MAX
#else // _WIN64 ][
# define INTPTR_MIN INT32_MIN
# define INTPTR_MAX INT32_MAX
# define UINTPTR_MAX UINT32_MAX
#endif // _WIN64 ]
// 7.18.2.5 Limits of greatest-width integer types
#define INTMAX_MIN INT64_MIN
#define INTMAX_MAX INT64_MAX
#define UINTMAX_MAX UINT64_MAX
// 7.18.3 Limits of other integer types
#ifdef _WIN64 // [
# define PTRDIFF_MIN _I64_MIN
# define PTRDIFF_MAX _I64_MAX
#else // _WIN64 ][
# define PTRDIFF_MIN _I32_MIN
# define PTRDIFF_MAX _I32_MAX
#endif // _WIN64 ]
#define SIG_ATOMIC_MIN INT_MIN
#define SIG_ATOMIC_MAX INT_MAX
#ifndef SIZE_MAX // [
# ifdef _WIN64 // [
# define SIZE_MAX _UI64_MAX
# else // _WIN64 ][
# define SIZE_MAX _UI32_MAX
# endif // _WIN64 ]
#endif // SIZE_MAX ]
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
#ifndef WCHAR_MIN // [
# define WCHAR_MIN 0
#endif // WCHAR_MIN ]
#ifndef WCHAR_MAX // [
# define WCHAR_MAX _UI16_MAX
#endif // WCHAR_MAX ]
#define WINT_MIN 0
#define WINT_MAX _UI16_MAX
#endif // __STDC_LIMIT_MACROS ]
// 7.18.4 Limits of other integer types
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
// 7.18.4.1 Macros for minimum-width integer constants
#define INT8_C(val) val##i8
#define INT16_C(val) val##i16
#define INT32_C(val) val##i32
#define INT64_C(val) val##i64
#define UINT8_C(val) val##ui8
#define UINT16_C(val) val##ui16
#define UINT32_C(val) val##ui32
#define UINT64_C(val) val##ui64
// 7.18.4.2 Macros for greatest-width integer constants
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
// Check out Issue 9 for the details.
#ifndef INTMAX_C // [
# define INTMAX_C INT64_C
#endif // INTMAX_C ]
#ifndef UINTMAX_C // [
# define UINTMAX_C UINT64_C
#endif // UINTMAX_C ]
#endif // __STDC_CONSTANT_MACROS ]
#endif // _MSC_VER >= 1600 ]
#endif // _MSC_STDINT_H_ ]
+207
Ver Arquivo
@@ -0,0 +1,207 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_PRETTYWRITER_H_
#define RAPIDJSON_PRETTYWRITER_H_
#include "writer.h"
#ifdef __GNUC__
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(effc++)
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Writer with indentation and spacing.
/*!
\tparam OutputStream Type of ouptut os.
\tparam SourceEncoding Encoding of source string.
\tparam TargetEncoding Encoding of output stream.
\tparam StackAllocator Type of allocator for allocating memory of stack.
*/
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> {
public:
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
typedef typename Base::Ch Ch;
//! Constructor
/*! \param os Output stream.
\param allocator User supplied allocator. If it is null, it will create a private one.
\param levelDepth Initial capacity of stack.
*/
PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
//! Set custom indentation.
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
\param indentCharCount Number of indent characters for each indentation level.
\note The default indentation is 4 spaces.
*/
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
indentChar_ = indentChar;
indentCharCount_ = indentCharCount;
return *this;
}
/*! @name Implementation of Handler
\see Handler
*/
//@{
bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
bool String(const Ch* str, SizeType length, bool copy = false) {
(void)copy;
PrettyPrefix(kStringType);
return Base::WriteString(str, length);
}
#if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) {
return String(str.data(), SizeType(str.size()));
}
#endif
bool StartObject() {
PrettyPrefix(kObjectType);
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
return Base::WriteStartObject();
}
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
bool EndObject(SizeType memberCount = 0) {
(void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) {
Base::os_->Put('\n');
WriteIndent();
}
bool ret = Base::WriteEndObject();
(void)ret;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush();
return true;
}
bool StartArray() {
PrettyPrefix(kArrayType);
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
return Base::WriteStartArray();
}
bool EndArray(SizeType memberCount = 0) {
(void)memberCount;
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
if (!empty) {
Base::os_->Put('\n');
WriteIndent();
}
bool ret = Base::WriteEndArray();
(void)ret;
RAPIDJSON_ASSERT(ret == true);
if (Base::level_stack_.Empty()) // end of json text
Base::os_->Flush();
return true;
}
//@}
/*! @name Convenience extensions */
//@{
//! Simpler but slower overload.
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
//@}
protected:
void PrettyPrefix(Type type) {
(void)type;
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
if (level->inArray) {
if (level->valueCount > 0) {
Base::os_->Put(','); // add comma if it is not the first element in array
Base::os_->Put('\n');
}
else
Base::os_->Put('\n');
WriteIndent();
}
else { // in object
if (level->valueCount > 0) {
if (level->valueCount % 2 == 0) {
Base::os_->Put(',');
Base::os_->Put('\n');
}
else {
Base::os_->Put(':');
Base::os_->Put(' ');
}
}
else
Base::os_->Put('\n');
if (level->valueCount % 2 == 0)
WriteIndent();
}
if (!level->inArray && level->valueCount % 2 == 0)
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
level->valueCount++;
}
else {
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
Base::hasRoot_ = true;
}
}
void WriteIndent() {
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
PutN(*Base::os_, indentChar_, count);
}
Ch indentChar_;
unsigned indentCharCount_;
private:
// Prohibit copy constructor & assignment operator.
PrettyWriter(const PrettyWriter&);
PrettyWriter& operator=(const PrettyWriter&);
};
RAPIDJSON_NAMESPACE_END
#ifdef __GNUC__
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_RAPIDJSON_H_
+620
Ver Arquivo
@@ -0,0 +1,620 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_RAPIDJSON_H_
#define RAPIDJSON_RAPIDJSON_H_
/*!\file rapidjson.h
\brief common definitions and configuration
\see RAPIDJSON_CONFIG
*/
/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
\brief Configuration macros for library features
Some RapidJSON features are configurable to adapt the library to a wide
variety of platforms, environments and usage scenarios. Most of the
features can be configured in terms of overriden or predefined
preprocessor macros at compile-time.
Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
\note These macros should be given on the compiler command-line
(where applicable) to avoid inconsistent values when compiling
different translation units of a single application.
*/
#include <cstdlib> // malloc(), realloc(), free(), size_t
#include <cstring> // memset(), memcpy(), memmove(), memcmp()
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NAMESPACE_(BEGIN|END)
/*! \def RAPIDJSON_NAMESPACE
\ingroup RAPIDJSON_CONFIG
\brief provide custom rapidjson namespace
In order to avoid symbol clashes and/or "One Definition Rule" errors
between multiple inclusions of (different versions of) RapidJSON in
a single binary, users can customize the name of the main RapidJSON
namespace.
In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple
levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
RAPIDJSON_NAMESPACE_END need to be defined as well:
\code
// in some .cpp file
#define RAPIDJSON_NAMESPACE my::rapidjson
#define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
#define RAPIDJSON_NAMESPACE_END } }
#include "rapidjson/..."
\endcode
\see rapidjson
*/
/*! \def RAPIDJSON_NAMESPACE_BEGIN
\ingroup RAPIDJSON_CONFIG
\brief provide custom rapidjson namespace (opening expression)
\see RAPIDJSON_NAMESPACE
*/
/*! \def RAPIDJSON_NAMESPACE_END
\ingroup RAPIDJSON_CONFIG
\brief provide custom rapidjson namespace (closing expression)
\see RAPIDJSON_NAMESPACE
*/
#ifndef RAPIDJSON_NAMESPACE
#define RAPIDJSON_NAMESPACE rapidjson
#endif
#ifndef RAPIDJSON_NAMESPACE_BEGIN
#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
#endif
#ifndef RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_NAMESPACE_END }
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NO_INT64DEFINE
/*! \def RAPIDJSON_NO_INT64DEFINE
\ingroup RAPIDJSON_CONFIG
\brief Use external 64-bit integer types.
RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types
to be available at global scope.
If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
prevent RapidJSON from defining its own types.
*/
#ifndef RAPIDJSON_NO_INT64DEFINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#ifdef _MSC_VER
#include "msinttypes/stdint.h"
#include "msinttypes/inttypes.h"
#else
// Other compilers should have this.
#include <stdint.h>
#include <inttypes.h>
#endif
//!@endcond
#ifdef RAPIDJSON_DOXYGEN_RUNNING
#define RAPIDJSON_NO_INT64DEFINE
#endif
#endif // RAPIDJSON_NO_INT64TYPEDEF
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_FORCEINLINE
#ifndef RAPIDJSON_FORCEINLINE
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#if defined(_MSC_VER) && !defined(NDEBUG)
#define RAPIDJSON_FORCEINLINE __forceinline
#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG)
#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
#else
#define RAPIDJSON_FORCEINLINE
#endif
//!@endcond
#endif // RAPIDJSON_FORCEINLINE
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ENDIAN
#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
//! Endianness of the machine.
/*!
\def RAPIDJSON_ENDIAN
\ingroup RAPIDJSON_CONFIG
GCC 4.6 provided macro for detecting endianness of the target machine. But other
compilers may not have this. User can define RAPIDJSON_ENDIAN to either
\ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
Default detection implemented with reference to
\li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
\li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
*/
#ifndef RAPIDJSON_ENDIAN
// Detect with GCC 4.6's macro
# ifdef __BYTE_ORDER__
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# else
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
# endif // __BYTE_ORDER__
// Detect with GLIBC's endian.h
# elif defined(__GLIBC__)
# include <endian.h>
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif (__BYTE_ORDER == __BIG_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# else
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
# endif // __GLIBC__
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
// Detect with architecture macros
# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
# define RAPIDJSON_ENDIAN
# else
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
# endif
#endif // RAPIDJSON_ENDIAN
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_64BIT
//! Whether using 64-bit architecture
#ifndef RAPIDJSON_64BIT
#if defined(__LP64__) || defined(_WIN64)
#define RAPIDJSON_64BIT 1
#else
#define RAPIDJSON_64BIT 0
#endif
#endif // RAPIDJSON_64BIT
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ALIGN
//! Data alignment of the machine.
/*! \ingroup RAPIDJSON_CONFIG
\param x pointer to align
Some machines require strict data alignment. Currently the default uses 4 bytes
alignment. User can customize by defining the RAPIDJSON_ALIGN function macro.,
*/
#ifndef RAPIDJSON_ALIGN
#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u)
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_UINT64_C2
//! Construct a 64-bit literal by a pair of 32-bit integer.
/*!
64-bit literal with or without ULL suffix is prone to compiler warnings.
UINT64_C() is C macro which cause compilation problems.
Use this macro to define 64-bit constants by a pair of 32-bit integer.
*/
#ifndef RAPIDJSON_UINT64_C2
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
/*! \def RAPIDJSON_SIMD
\ingroup RAPIDJSON_CONFIG
\brief Enable SSE2/SSE4.2 optimization.
RapidJSON supports optimized implementations for some parsing operations
based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
processors.
To enable these optimizations, two different symbols can be defined;
\code
// Enable SSE2 optimization.
#define RAPIDJSON_SSE2
// Enable SSE4.2 optimization.
#define RAPIDJSON_SSE42
\endcode
\c RAPIDJSON_SSE42 takes precedence, if both are defined.
If any of these symbols is defined, RapidJSON defines the macro
\c RAPIDJSON_SIMD to indicate the availability of the optimized code.
*/
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
|| defined(RAPIDJSON_DOXYGEN_RUNNING)
#define RAPIDJSON_SIMD
#endif
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_NO_SIZETYPEDEFINE
#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
\ingroup RAPIDJSON_CONFIG
\brief User-provided \c SizeType definition.
In order to avoid using 32-bit size types for indexing strings and arrays,
define this preprocessor symbol and provide the type rapidjson::SizeType
before including RapidJSON:
\code
#define RAPIDJSON_NO_SIZETYPEDEFINE
namespace rapidjson { typedef ::std::size_t SizeType; }
#include "rapidjson/..."
\endcode
\see rapidjson::SizeType
*/
#ifdef RAPIDJSON_DOXYGEN_RUNNING
#define RAPIDJSON_NO_SIZETYPEDEFINE
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! Size type (for string lengths, array sizes, etc.)
/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
instead of using \c size_t. Users may override the SizeType by defining
\ref RAPIDJSON_NO_SIZETYPEDEFINE.
*/
typedef unsigned SizeType;
RAPIDJSON_NAMESPACE_END
#endif
// always import std::size_t to rapidjson namespace
RAPIDJSON_NAMESPACE_BEGIN
using std::size_t;
RAPIDJSON_NAMESPACE_END
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_ASSERT
//! Assertion.
/*! \ingroup RAPIDJSON_CONFIG
By default, rapidjson uses C \c assert() for internal assertions.
User can override it by defining RAPIDJSON_ASSERT(x) macro.
\note Parsing errors are handled and can be customized by the
\ref RAPIDJSON_ERRORS APIs.
*/
#ifndef RAPIDJSON_ASSERT
#include <cassert>
#define RAPIDJSON_ASSERT(x) assert(x)
#endif // RAPIDJSON_ASSERT
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_STATIC_ASSERT
// Adopt from boost
#ifndef RAPIDJSON_STATIC_ASSERT
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
RAPIDJSON_NAMESPACE_BEGIN
template <bool x> struct STATIC_ASSERTION_FAILURE;
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
template<int x> struct StaticAssertTest {};
RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
#if defined(__GNUC__)
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
#else
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif
//!@endcond
/*! \def RAPIDJSON_STATIC_ASSERT
\brief (Internal) macro to check for conditions at compile-time
\param x compile-time condition
\hideinitializer
*/
#define RAPIDJSON_STATIC_ASSERT(x) \
typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
#endif
///////////////////////////////////////////////////////////////////////////////
// Helpers
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
#define RAPIDJSON_MULTILINEMACRO_END \
} while((void)0, 0)
// adopted from Boost
#define RAPIDJSON_VERSION_CODE(x,y,z) \
(((x)*100000) + ((y)*100) + (z))
// token stringification
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
#define RAPIDJSON_DO_STRINGIFY(x) #x
///////////////////////////////////////////////////////////////////////////////
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
#if defined(__GNUC__)
#define RAPIDJSON_GNUC \
RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
#endif
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
#define RAPIDJSON_DIAG_OFF(x) \
RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
// push/pop support in Clang and GCC>=4.6
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
#else // GCC >= 4.2, < 4.6
#define RAPIDJSON_DIAG_PUSH /* ignored */
#define RAPIDJSON_DIAG_POP /* ignored */
#endif
#elif defined(_MSC_VER)
// pragma (MSVC specific)
#define RAPIDJSON_PRAGMA(x) __pragma(x)
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
#else
#define RAPIDJSON_DIAG_OFF(x) /* ignored */
#define RAPIDJSON_DIAG_PUSH /* ignored */
#define RAPIDJSON_DIAG_POP /* ignored */
#endif // RAPIDJSON_DIAG_*
///////////////////////////////////////////////////////////////////////////////
// C++11 features
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
#if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) && \
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1600)
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
#else
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
#endif
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
#if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
#else
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
#endif
#endif
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
#define RAPIDJSON_NOEXCEPT noexcept
#else
#define RAPIDJSON_NOEXCEPT /* noexcept */
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
// no automatic detection, yet
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
#endif
//!@endcond
///////////////////////////////////////////////////////////////////////////////
// new/delete
#ifndef RAPIDJSON_NEW
///! customization point for global \c new
#define RAPIDJSON_NEW(x) new x
#endif
#ifndef RAPIDJSON_DELETE
///! customization point for global \c delete
#define RAPIDJSON_DELETE(x) delete x
#endif
///////////////////////////////////////////////////////////////////////////////
// Allocators and Encodings
#include "allocators.h"
#include "encodings.h"
/*! \namespace rapidjson
\brief main RapidJSON namespace
\see RAPIDJSON_NAMESPACE
*/
RAPIDJSON_NAMESPACE_BEGIN
///////////////////////////////////////////////////////////////////////////////
// Stream
/*! \class rapidjson::Stream
\brief Concept for reading and writing characters.
For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
For write-only stream, only need to implement Put() and Flush().
\code
concept Stream {
typename Ch; //!< Character type of the stream.
//! Read the current character from stream without moving the read cursor.
Ch Peek() const;
//! Read the current character from stream and moving the read cursor to next character.
Ch Take();
//! Get the current read cursor.
//! \return Number of characters read from start.
size_t Tell();
//! Begin writing operation at the current read pointer.
//! \return The begin writer pointer.
Ch* PutBegin();
//! Write a character.
void Put(Ch c);
//! Flush the buffer.
void Flush();
//! End the writing operation.
//! \param begin The begin write pointer returned by PutBegin().
//! \return Number of characters written.
size_t PutEnd(Ch* begin);
}
\endcode
*/
//! Provides additional information for stream.
/*!
By using traits pattern, this type provides a default configuration for stream.
For custom stream, this type can be specialized for other configuration.
See TEST(Reader, CustomStringStream) in readertest.cpp for example.
*/
template<typename Stream>
struct StreamTraits {
//! Whether to make local copy of stream for optimization during parsing.
/*!
By default, for safety, streams do not use local copy optimization.
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
*/
enum { copyOptimization = 0 };
};
//! Put N copies of a character to a stream.
template<typename Stream, typename Ch>
inline void PutN(Stream& stream, Ch c, size_t n) {
for (size_t i = 0; i < n; i++)
stream.Put(c);
}
///////////////////////////////////////////////////////////////////////////////
// StringStream
//! Read-only string stream.
/*! \note implements Stream concept
*/
template <typename Encoding>
struct GenericStringStream {
typedef typename Encoding::Ch Ch;
GenericStringStream(const Ch *src) : src_(src), head_(src) {}
Ch Peek() const { return *src_; }
Ch Take() { return *src_++; }
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
void Put(Ch) { RAPIDJSON_ASSERT(false); }
void Flush() { RAPIDJSON_ASSERT(false); }
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
const Ch* src_; //!< Current read position.
const Ch* head_; //!< Original head of the string.
};
template <typename Encoding>
struct StreamTraits<GenericStringStream<Encoding> > {
enum { copyOptimization = 1 };
};
//! String stream with UTF8 encoding.
typedef GenericStringStream<UTF8<> > StringStream;
///////////////////////////////////////////////////////////////////////////////
// InsituStringStream
//! A read-write string stream.
/*! This string stream is particularly designed for in-situ parsing.
\note implements Stream concept
*/
template <typename Encoding>
struct GenericInsituStringStream {
typedef typename Encoding::Ch Ch;
GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
// Read
Ch Peek() { return *src_; }
Ch Take() { return *src_++; }
size_t Tell() { return static_cast<size_t>(src_ - head_); }
// Write
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
Ch* PutBegin() { return dst_ = src_; }
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
void Flush() {}
Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
void Pop(size_t count) { dst_ -= count; }
Ch* src_;
Ch* dst_;
Ch* head_;
};
template <typename Encoding>
struct StreamTraits<GenericInsituStringStream<Encoding> > {
enum { copyOptimization = 1 };
};
//! Insitu string stream with UTF8 encoding.
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
///////////////////////////////////////////////////////////////////////////////
// Type
//! Type of JSON value
enum Type {
kNullType = 0, //!< null
kFalseType = 1, //!< false
kTrueType = 2, //!< true
kObjectType = 3, //!< object
kArrayType = 4, //!< array
kStringType = 5, //!< string
kNumberType = 6 //!< number
};
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_RAPIDJSON_H_
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+93
Ver Arquivo
@@ -0,0 +1,93 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_STRINGBUFFER_H_
#define RAPIDJSON_STRINGBUFFER_H_
#include "rapidjson.h"
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
#include <utility> // std::move
#endif
#include "internal/stack.h"
RAPIDJSON_NAMESPACE_BEGIN
//! Represents an in-memory output stream.
/*!
\tparam Encoding Encoding of the stream.
\tparam Allocator type for allocating memory buffer.
\note implements Stream concept
*/
template <typename Encoding, typename Allocator = CrtAllocator>
class GenericStringBuffer {
public:
typedef typename Encoding::Ch Ch;
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
if (&rhs != this)
stack_ = std::move(rhs.stack_);
return *this;
}
#endif
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
void Flush() {}
void Clear() { stack_.Clear(); }
void ShrinkToFit() {
// Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0';
stack_.ShrinkToFit();
stack_.template Pop<Ch>(1);
}
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
const Ch* GetString() const {
// Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0';
stack_.template Pop<Ch>(1);
return stack_.template Bottom<Ch>();
}
size_t GetSize() const { return stack_.GetSize(); }
static const size_t kDefaultCapacity = 256;
mutable internal::Stack<Allocator> stack_;
private:
// Prohibit copy constructor & assignment operator.
GenericStringBuffer(const GenericStringBuffer&);
GenericStringBuffer& operator=(const GenericStringBuffer&);
};
//! String buffer with UTF8 encoding
typedef GenericStringBuffer<UTF8<> > StringBuffer;
//! Implement specialized version of PutN() with memset() for better performance.
template<>
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
}
RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_STRINGBUFFER_H_
+395
Ver Arquivo
@@ -0,0 +1,395 @@
// 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.
//
// Licensed under the MIT License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#ifndef RAPIDJSON_WRITER_H_
#define RAPIDJSON_WRITER_H_
#include "rapidjson.h"
#include "internal/stack.h"
#include "internal/strfunc.h"
#include "internal/dtoa.h"
#include "internal/itoa.h"
#include "stringbuffer.h"
#include <new> // placement new
#if RAPIDJSON_HAS_STDSTRING
#include <string>
#endif
#ifdef _MSC_VER
RAPIDJSON_DIAG_PUSH
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
#endif
RAPIDJSON_NAMESPACE_BEGIN
//! JSON writer
/*! Writer implements the concept Handler.
It generates JSON text by events to an output os.
User may programmatically calls the functions of a writer to generate JSON text.
On the other side, a writer can also be passed to objects that generates events,
for example Reader::Parse() and Document::Accept().
\tparam OutputStream Type of output stream.
\tparam SourceEncoding Encoding of source string.
\tparam TargetEncoding Encoding of output stream.
\tparam StackAllocator Type of allocator for allocating memory of stack.
\note implements Handler concept
*/
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator>
class Writer {
public:
typedef typename SourceEncoding::Ch Ch;
//! Constructor
/*! \param os Output stream.
\param stackAllocator User supplied allocator. If it is null, it will create a private one.
\param levelDepth Initial capacity of stack.
*/
explicit
Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
explicit
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {}
//! Reset the writer with a new stream.
/*!
This function reset the writer with a new stream and default settings,
in order to make a Writer object reusable for output multiple JSONs.
\param os New output stream.
\code
Writer<OutputStream> writer(os1);
writer.StartObject();
// ...
writer.EndObject();
writer.Reset(os2);
writer.StartObject();
// ...
writer.EndObject();
\endcode
*/
void Reset(OutputStream& os) {
os_ = &os;
hasRoot_ = false;
level_stack_.Clear();
}
//! Checks whether the output is a complete JSON.
/*!
A complete JSON has a complete root object or array.
*/
bool IsComplete() const {
return hasRoot_ && level_stack_.Empty();
}
/*!@name Implementation of Handler
\see Handler
*/
//@{
bool Null() { Prefix(kNullType); return WriteNull(); }
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); }
bool Int(int i) { Prefix(kNumberType); return WriteInt(i); }
bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); }
bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); }
bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); }
//! Writes the given \c double value to the stream
/*!
\param d The value to be written.
\return Whether it is succeed.
*/
bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); }
bool String(const Ch* str, SizeType length, bool copy = false) {
(void)copy;
Prefix(kStringType);
return WriteString(str, length);
}
#if RAPIDJSON_HAS_STDSTRING
bool String(const std::basic_string<Ch>& str) {
return String(str.data(), SizeType(str.size()));
}
#endif
bool StartObject() {
Prefix(kObjectType);
new (level_stack_.template Push<Level>()) Level(false);
return WriteStartObject();
}
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
bool EndObject(SizeType memberCount = 0) {
(void)memberCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
level_stack_.template Pop<Level>(1);
bool ret = WriteEndObject();
if (level_stack_.Empty()) // end of json text
os_->Flush();
return ret;
}
bool StartArray() {
Prefix(kArrayType);
new (level_stack_.template Push<Level>()) Level(true);
return WriteStartArray();
}
bool EndArray(SizeType elementCount = 0) {
(void)elementCount;
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
level_stack_.template Pop<Level>(1);
bool ret = WriteEndArray();
if (level_stack_.Empty()) // end of json text
os_->Flush();
return ret;
}
//@}
/*! @name Convenience extensions */
//@{
//! Simpler but slower overload.
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
//@}
protected:
//! Information for each nested level
struct Level {
Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
size_t valueCount; //!< number of values in this level
bool inArray; //!< true if in array, otherwise in object
};
static const size_t kDefaultLevelDepth = 32;
bool WriteNull() {
os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true;
}
bool WriteBool(bool b) {
if (b) {
os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e');
}
else {
os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e');
}
return true;
}
bool WriteInt(int i) {
char buffer[11];
const char* end = internal::i32toa(i, buffer);
for (const char* p = buffer; p != end; ++p)
os_->Put(*p);
return true;
}
bool WriteUint(unsigned u) {
char buffer[10];
const char* end = internal::u32toa(u, buffer);
for (const char* p = buffer; p != end; ++p)
os_->Put(*p);
return true;
}
bool WriteInt64(int64_t i64) {
char buffer[21];
const char* end = internal::i64toa(i64, buffer);
for (const char* p = buffer; p != end; ++p)
os_->Put(*p);
return true;
}
bool WriteUint64(uint64_t u64) {
char buffer[20];
char* end = internal::u64toa(u64, buffer);
for (char* p = buffer; p != end; ++p)
os_->Put(*p);
return true;
}
bool WriteDouble(double d) {
char buffer[25];
char* end = internal::dtoa(d, buffer);
for (char* p = buffer; p != end; ++p)
os_->Put(*p);
return true;
}
bool WriteString(const Ch* str, SizeType length) {
static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
static const char escape[256] = {
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
//0 1 2 3 4 5 6 7 8 9 A B C D E F
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
Z16, Z16, // 30~4F
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
#undef Z16
};
os_->Put('\"');
GenericStringStream<SourceEncoding> is(str);
while (is.Tell() < length) {
const Ch c = is.Peek();
if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) {
// Unicode escaping
unsigned codepoint;
if (!SourceEncoding::Decode(is, &codepoint))
return false;
os_->Put('\\');
os_->Put('u');
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
os_->Put(hexDigits[(codepoint >> 12) & 15]);
os_->Put(hexDigits[(codepoint >> 8) & 15]);
os_->Put(hexDigits[(codepoint >> 4) & 15]);
os_->Put(hexDigits[(codepoint ) & 15]);
}
else {
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
// Surrogate pair
unsigned s = codepoint - 0x010000;
unsigned lead = (s >> 10) + 0xD800;
unsigned trail = (s & 0x3FF) + 0xDC00;
os_->Put(hexDigits[(lead >> 12) & 15]);
os_->Put(hexDigits[(lead >> 8) & 15]);
os_->Put(hexDigits[(lead >> 4) & 15]);
os_->Put(hexDigits[(lead ) & 15]);
os_->Put('\\');
os_->Put('u');
os_->Put(hexDigits[(trail >> 12) & 15]);
os_->Put(hexDigits[(trail >> 8) & 15]);
os_->Put(hexDigits[(trail >> 4) & 15]);
os_->Put(hexDigits[(trail ) & 15]);
}
}
else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) {
is.Take();
os_->Put('\\');
os_->Put(escape[(unsigned char)c]);
if (escape[(unsigned char)c] == 'u') {
os_->Put('0');
os_->Put('0');
os_->Put(hexDigits[(unsigned char)c >> 4]);
os_->Put(hexDigits[(unsigned char)c & 0xF]);
}
}
else
if (!Transcoder<SourceEncoding, TargetEncoding>::Transcode(is, *os_))
return false;
}
os_->Put('\"');
return true;
}
bool WriteStartObject() { os_->Put('{'); return true; }
bool WriteEndObject() { os_->Put('}'); return true; }
bool WriteStartArray() { os_->Put('['); return true; }
bool WriteEndArray() { os_->Put(']'); return true; }
void Prefix(Type type) {
(void)type;
if (level_stack_.GetSize() != 0) { // this value is not at root
Level* level = level_stack_.template Top<Level>();
if (level->valueCount > 0) {
if (level->inArray)
os_->Put(','); // add comma if it is not the first element in array
else // in object
os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
}
if (!level->inArray && level->valueCount % 2 == 0)
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
level->valueCount++;
}
else {
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
hasRoot_ = true;
}
}
OutputStream* os_;
internal::Stack<StackAllocator> level_stack_;
bool hasRoot_;
private:
// Prohibit copy constructor & assignment operator.
Writer(const Writer&);
Writer& operator=(const Writer&);
};
// Full specialization for StringStream to prevent memory copying
template<>
inline bool Writer<StringBuffer>::WriteInt(int i) {
char *buffer = os_->Push(11);
const char* end = internal::i32toa(i, buffer);
os_->Pop(11 - (end - buffer));
return true;
}
template<>
inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
char *buffer = os_->Push(10);
const char* end = internal::u32toa(u, buffer);
os_->Pop(10 - (end - buffer));
return true;
}
template<>
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
char *buffer = os_->Push(21);
const char* end = internal::i64toa(i64, buffer);
os_->Pop(21 - (end - buffer));
return true;
}
template<>
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
char *buffer = os_->Push(20);
const char* end = internal::u64toa(u, buffer);
os_->Pop(20 - (end - buffer));
return true;
}
template<>
inline bool Writer<StringBuffer>::WriteDouble(double d) {
char *buffer = os_->Push(25);
char* end = internal::dtoa(d, buffer);
os_->Pop(25 - (end - buffer));
return true;
}
RAPIDJSON_NAMESPACE_END
#ifdef _MSC_VER
RAPIDJSON_DIAG_POP
#endif
#endif // RAPIDJSON_RAPIDJSON_H_
-199
Ver Arquivo
@@ -1,199 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
#include <execinfo.h>
#include <sys/resource.h>
#endif
#include <stddef.h>
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "sliceDataStorage.h"
#include "modelFile/modelFile.h"
#include "settings.h"
#include "optimizedModel.h"
#include "multiVolumes.h"
#include "polygonOptimizer.h"
#include "slicer.h"
#include "layerPart.h"
#include "inset.h"
#include "skin.h"
#include "infill.h"
#include "bridge.h"
#include "support.h"
#include "pathOrderOptimizer.h"
#include "skirt.h"
#include "raft.h"
#include "comb.h"
#include "gcodeExport.h"
#include "fffProcessor.h"
void print_usage()
{
printf("usage: CuraEngine [-h] [-v] [-m 3x3matrix] [-s <settingkey>=<value>] -o <output.gcode> <model.stl>\n");
}
void signal_FPE(int n)
{
(void)n;
printf("Arithmetic exception.\n");
exit(1);
}
int main(int argc, char **argv)
{
#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
//Lower the process priority on linux and mac.
setpriority(PRIO_PROCESS, 0, 10);
#endif
signal(SIGFPE, signal_FPE);
ConfigSettings config;
fffProcessor processor(config);
config.filamentDiameter = 2890;
config.filamentFlow = 100;
config.initialLayerThickness = 300;
config.layerThickness = 100;
config.extrusionWidth = 400;
config.insetCount = 2;
config.downSkinCount = 6;
config.upSkinCount = 6;
config.initialSpeedupLayers = 4;
config.initialLayerSpeed = 20;
config.printSpeed = 50;
config.infillSpeed = 50;
config.moveSpeed = 200;
config.fanFullOnLayerNr = 2;
config.skirtDistance = 6000;
config.skirtLineCount = 1;
config.skirtMinLength = 0;
config.sparseInfillLineDistance = 100 * config.extrusionWidth / 20;
config.infillOverlap = 15;
config.objectPosition.X = 102500;
config.objectPosition.Y = 102500;
config.objectSink = 0;
config.supportAngle = -1;
config.supportEverywhere = 0;
config.supportLineDistance = config.sparseInfillLineDistance;
config.supportExtruder = -1;
config.supportXYDistance = 700;
config.supportZDistance = 150;
config.retractionAmount = 4500;
config.retractionSpeed = 45;
config.retractionAmountExtruderSwitch = 14500;
config.retractionMinimalDistance = 1500;
config.minimalExtrusionBeforeRetraction = 100;
config.enableOozeShield = 0;
config.enableCombing = 1;
config.wipeTowerSize = 0;
config.multiVolumeOverlap = 0;
config.minimalLayerTime = 5;
config.minimalFeedrate = 10;
config.coolHeadLift = 1;
config.fanSpeedMin = 100;
config.fanSpeedMax = 100;
config.raftMargin = 5000;
config.raftLineSpacing = 1000;
config.raftBaseThickness = 0;
config.raftBaseLinewidth = 0;
config.raftInterfaceThickness = 0;
config.raftInterfaceLinewidth = 0;
config.spiralizeMode = 0;
config.fixHorrible = 0;
config.gcodeFlavor = GCODE_FLAVOR_REPRAP;
memset(config.extruderOffset, 0, sizeof(config.extruderOffset));
config.startCode =
"M109 S210 ;Heatup to 210C\n"
"G21 ;metric values\n"
"G90 ;absolute positioning\n"
"G28 ;Home\n"
"G1 Z15.0 F300 ;move the platform down 15mm\n"
"G92 E0 ;zero the extruded length\n"
"G1 F200 E5 ;extrude 5mm of feed stock\n"
"G92 E0 ;zero the extruded length again\n";
config.endCode =
"M104 S0 ;extruder heater off\n"
"M140 S0 ;heated bed heater off (if you have it)\n"
"G91 ;relative positioning\n"
"G1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\n"
"G1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\n"
"G28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\n"
"M84 ;steppers off\n"
"G90 ;absolute positioning\n";
fprintf(stdout,"Cura_SteamEngine version %s\n", VERSION);
for(int argn = 1; argn < argc; argn++)
{
char* str = argv[argn];
if (str[0] == '-')
{
for(str++; *str; str++)
{
switch(*str)
{
case 'h':
print_usage();
exit(1);
case 'v':
verbose_level++;
break;
case 'b':
argn++;
binaryMeshBlob = fopen(argv[argn], "rb");
break;
case 'o':
argn++;
if (!processor.setTargetFile(argv[argn]))
{
logError("Failed to open %s for output.\n", argv[argn]);
exit(1);
}
break;
case 's':
{
argn++;
char* valuePtr = strchr(argv[argn], '=');
if (valuePtr)
{
*valuePtr++ = '\0';
if (!config.setSetting(argv[argn], valuePtr))
printf("Setting not found: %s %s\n", argv[argn], valuePtr);
}
}
break;
case 'm':
argn++;
sscanf(argv[argn], "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
&config.matrix.m[0][0], &config.matrix.m[0][1], &config.matrix.m[0][2],
&config.matrix.m[1][0], &config.matrix.m[1][1], &config.matrix.m[1][2],
&config.matrix.m[2][0], &config.matrix.m[2][1], &config.matrix.m[2][2]);
break;
default:
logError("Unknown option: %c\n", *str);
break;
}
}
}else{
try {
processor.processFile(argv[argn]);
}catch(...){
printf("Unknown exception\n");
exit(1);
}
}
}
processor.finalize();
}
-177
Ver Arquivo
@@ -1,177 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <string.h>
#include <stdio.h>
#include "modelFile/modelFile.h"
FILE* binaryMeshBlob = NULL;
/* Custom fgets function to support Mac line-ends in Ascii STL files. OpenSCAD produces this when used on Mac */
void* fgets_(char* ptr, size_t len, FILE* f)
{
while(len && fread(ptr, 1, 1, f) > 0)
{
if (*ptr == '\n' || *ptr == '\r')
{
*ptr = '\0';
return ptr;
}
ptr++;
len--;
}
return NULL;
}
SimpleModel* loadModelSTL_ascii(const char* filename, FMatrix3x3& matrix)
{
SimpleModel* m = new SimpleModel();
m->volumes.push_back(SimpleVolume());
SimpleVolume* vol = &m->volumes[0];
FILE* f = fopen(filename, "rt");
char buffer[1024];
FPoint3 vertex;
int n = 0;
Point3 v0(0,0,0), v1(0,0,0), v2(0,0,0);
while(fgets_(buffer, sizeof(buffer), f))
{
if (sscanf(buffer, " vertex %lf %lf %lf", &vertex.x, &vertex.y, &vertex.z) == 3)
{
n++;
switch(n)
{
case 1:
v0 = matrix.apply(vertex);
break;
case 2:
v1 = matrix.apply(vertex);
break;
case 3:
v2 = matrix.apply(vertex);
vol->addFace(v0, v1, v2);
n = 0;
break;
}
}
}
fclose(f);
return m;
}
SimpleModel* loadModelSTL_binary(const char* filename, FMatrix3x3& matrix)
{
FILE* f = fopen(filename, "rb");
char buffer[80];
uint32_t faceCount;
//Skip the header
if (fread(buffer, 80, 1, f) != 1)
{
fclose(f);
return NULL;
}
//Read the face count
if (fread(&faceCount, sizeof(uint32_t), 1, f) != 1)
{
fclose(f);
return NULL;
}
//For each face read:
//float(x,y,z) = normal, float(X,Y,Z)*3 = vertexes, uint16_t = flags
SimpleModel* m = new SimpleModel();
m->volumes.push_back(SimpleVolume());
SimpleVolume* vol = &m->volumes[0];
if(vol == NULL)
{
fclose(f);
return NULL;
}
for(unsigned int i=0;i<faceCount;i++)
{
if (fread(buffer, sizeof(float) * 3, 1, f) != 1)
{
fclose(f);
return NULL;
}
float v[9];
if (fread(v, sizeof(float) * 9, 1, f) != 1)
{
fclose(f);
return NULL;
}
Point3 v0 = matrix.apply(FPoint3(v[0], v[1], v[2]));
Point3 v1 = matrix.apply(FPoint3(v[3], v[4], v[5]));
Point3 v2 = matrix.apply(FPoint3(v[6], v[7], v[8]));
vol->addFace(v0, v1, v2);
if (fread(buffer, sizeof(uint16_t), 1, f) != 1)
{
fclose(f);
return NULL;
}
}
fclose(f);
return m;
}
SimpleModel* loadModelSTL(const char* filename, FMatrix3x3& matrix)
{
FILE* f = fopen(filename, "r");
char buffer[6];
if (f == NULL)
return NULL;
if (fread(buffer, 5, 1, f) != 1)
{
fclose(f);
return NULL;
}
fclose(f);
buffer[5] = '\0';
if (strcasecmp(buffer, "SOLID") == 0)
{
return loadModelSTL_ascii(filename, matrix);
}
return loadModelSTL_binary(filename, matrix);
}
SimpleModel* loadModel(const char* filename, FMatrix3x3& matrix)
{
const char* ext = strrchr(filename, '.');
if (ext && strcasecmp(ext, ".stl") == 0)
{
return loadModelSTL(filename, matrix);
}
if (filename[0] == '#' && binaryMeshBlob != NULL)
{
SimpleModel* m = new SimpleModel();
while(*filename == '#')
{
filename++;
m->volumes.push_back(SimpleVolume());
SimpleVolume* vol = &m->volumes[m->volumes.size()-1];
int32_t n, pNr = 0;
if (fread(&n, 1, sizeof(int32_t), binaryMeshBlob) < 1)
return NULL;
printf("Reading mesh from binary blob with %i vertexes\n", n);
Point3 v[3];
while(n)
{
float f[3];
if (fread(f, 3, sizeof(float), binaryMeshBlob) < 1)
return NULL;
FPoint3 fp(f[0], f[1], f[2]);
v[pNr++] = matrix.apply(fp);
if (pNr == 3)
{
vol->addFace(v[0], v[1], v[2]);
pNr = 0;
}
n--;
}
}
return m;
}
return NULL;
}
-110
Ver Arquivo
@@ -1,110 +0,0 @@
/** 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 <vector>
using std::vector;
#include "utils/intpoint.h"
#include "utils/floatpoint.h"
extern FILE* binaryMeshBlob;
#define SET_MIN(n, m) do { if ((m) < (n)) n = m; } while(0)
#define SET_MAX(n, m) do { if ((m) > (n)) n = m; } while(0)
/* A SimpleFace is a 3 dimensional model triangle with 3 points. These points are already converted to integers */
class SimpleFace
{
public:
Point3 v[3];
SimpleFace(Point3& v0, Point3& v1, Point3& v2) { v[0] = v0; v[1] = v1; v[2] = v2; }
};
/* A SimpleVolume is the most basic reprisentation of a 3D model. It contains all the faces as SimpleTriangles, with nothing fancy. */
class SimpleVolume
{
public:
vector<SimpleFace> faces;
void addFace(Point3& v0, Point3& v1, Point3& v2)
{
faces.push_back(SimpleFace(v0, v1, v2));
}
Point3 min()
{
Point3 ret = faces[0].v[0];
for(unsigned int i=0; i<faces.size(); i++)
{
SET_MIN(ret.x, faces[i].v[0].x);
SET_MIN(ret.y, faces[i].v[0].y);
SET_MIN(ret.z, faces[i].v[0].z);
SET_MIN(ret.x, faces[i].v[1].x);
SET_MIN(ret.y, faces[i].v[1].y);
SET_MIN(ret.z, faces[i].v[1].z);
SET_MIN(ret.x, faces[i].v[2].x);
SET_MIN(ret.y, faces[i].v[2].y);
SET_MIN(ret.z, faces[i].v[2].z);
}
return ret;
}
Point3 max()
{
Point3 ret = faces[0].v[0];
for(unsigned int i=0; i<faces.size(); i++)
{
SET_MAX(ret.x, faces[i].v[0].x);
SET_MAX(ret.y, faces[i].v[0].y);
SET_MAX(ret.z, faces[i].v[0].z);
SET_MAX(ret.x, faces[i].v[1].x);
SET_MAX(ret.y, faces[i].v[1].y);
SET_MAX(ret.z, faces[i].v[1].z);
SET_MAX(ret.x, faces[i].v[2].x);
SET_MAX(ret.y, faces[i].v[2].y);
SET_MAX(ret.z, faces[i].v[2].z);
}
return ret;
}
};
//A SimpleModel is a 3D model with 1 or more 3D volumes.
class SimpleModel
{
public:
vector<SimpleVolume> volumes;
Point3 min()
{
Point3 ret = volumes[0].min();
for(unsigned int i=0; i<volumes.size(); i++)
{
Point3 v = volumes[i].min();
SET_MIN(ret.x, v.x);
SET_MIN(ret.y, v.y);
SET_MIN(ret.z, v.z);
}
return ret;
}
Point3 max()
{
Point3 ret = volumes[0].max();
for(unsigned int i=0; i<volumes.size(); i++)
{
Point3 v = volumes[i].max();
SET_MAX(ret.x, v.x);
SET_MAX(ret.y, v.y);
SET_MAX(ret.z, v.z);
}
return ret;
}
};
SimpleModel* loadModel(const char* filename, FMatrix3x3& matrix);
#endif//MODELFILE_H
-141
Ver Arquivo
@@ -1,141 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdio.h>
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "optimizedModel.h"
#define MELD_DIST 30
OptimizedVolume::OptimizedVolume(SimpleVolume* volume, OptimizedModel* model)
: model(model)
{
points.reserve(volume->faces.size() * 3);
faces.reserve(volume->faces.size());
std::map<uint32_t, std::vector<uint32_t> > indexMap;
double t = getTime();
for(uint32_t i=0; i<volume->faces.size(); i++)
{
OptimizedFace f;
if((i%1000==0) && (getTime()-t)>2.0) logProgress("optimized", i + 1, volume->faces.size());
for(uint32_t j=0; j<3; j++)
{
Point3 p = volume->faces[i].v[j];
int hash = ((p.x + MELD_DIST/2) / MELD_DIST) ^ (((p.y + MELD_DIST/2) / MELD_DIST) << 10) ^ (((p.z + MELD_DIST/2) / MELD_DIST) << 20);
uint32_t idx;
bool add = true;
for(unsigned int n = 0; n < indexMap[hash].size(); n++)
{
if ((points[indexMap[hash][n]].p - p).testLength(MELD_DIST))
{
idx = indexMap[hash][n];
add = false;
break;
}
}
if (add)
{
indexMap[hash].push_back(points.size());
idx = points.size();
points.push_back(p);
}
f.index[j] = idx;
}
if (f.index[0] != f.index[1] && f.index[0] != f.index[2] && f.index[1] != f.index[2])
{
//Check if there is a face with the same points
bool duplicate = false;
for(unsigned int _idx0 = 0; _idx0 < points[f.index[0]].faceIndexList.size(); _idx0++)
{
for(unsigned int _idx1 = 0; _idx1 < points[f.index[1]].faceIndexList.size(); _idx1++)
{
for(unsigned int _idx2 = 0; _idx2 < points[f.index[2]].faceIndexList.size(); _idx2++)
{
if (points[f.index[0]].faceIndexList[_idx0] == points[f.index[1]].faceIndexList[_idx1] && points[f.index[0]].faceIndexList[_idx0] == points[f.index[2]].faceIndexList[_idx2])
duplicate = true;
}
}
}
if (!duplicate)
{
points[f.index[0]].faceIndexList.push_back(faces.size());
points[f.index[1]].faceIndexList.push_back(faces.size());
points[f.index[2]].faceIndexList.push_back(faces.size());
faces.push_back(f);
}
}
}
//fprintf(stdout, "\rAll faces are optimized in %5.1fs.\n",timeElapsed(t));
int openFacesCount = 0;
for(unsigned int i=0;i<faces.size();i++)
{
OptimizedFace* f = &faces[i];
f->touching[0] = getFaceIdxWithPoints(f->index[0], f->index[1], i);
f->touching[1] = getFaceIdxWithPoints(f->index[1], f->index[2], i);
f->touching[2] = getFaceIdxWithPoints(f->index[2], f->index[0], i);
if (f->touching[0] == -1)
openFacesCount++;
if (f->touching[1] == -1)
openFacesCount++;
if (f->touching[2] == -1)
openFacesCount++;
}
//fprintf(stdout, " Number of open faces: %i\n", openFacesCount);
}
void OptimizedModel::saveDebugSTL(const char* filename)
{
char buffer[80] = "Cura_Engine_STL_export";
uint32_t n;
uint16_t s;
float flt;
OptimizedVolume* vol = &volumes[0];
FILE* f = fopen(filename, "wb");
fwrite(buffer, 80, 1, f);
n = vol->faces.size();
fwrite(&n, sizeof(n), 1, f);
for(unsigned int i=0;i<vol->faces.size();i++)
{
flt = 0;
s = 0;
fwrite(&flt, sizeof(flt), 1, f);
fwrite(&flt, sizeof(flt), 1, f);
fwrite(&flt, sizeof(flt), 1, f);
flt = vol->points[vol->faces[i].index[0]].p.x / 1000.0; fwrite(&flt, sizeof(flt), 1, f);
flt = vol->points[vol->faces[i].index[0]].p.y / 1000.0; fwrite(&flt, sizeof(flt), 1, f);
flt = vol->points[vol->faces[i].index[0]].p.z / 1000.0; fwrite(&flt, sizeof(flt), 1, f);
flt = vol->points[vol->faces[i].index[1]].p.x / 1000.0; fwrite(&flt, sizeof(flt), 1, f);
flt = vol->points[vol->faces[i].index[1]].p.y / 1000.0; fwrite(&flt, sizeof(flt), 1, f);
flt = vol->points[vol->faces[i].index[1]].p.z / 1000.0; fwrite(&flt, sizeof(flt), 1, f);
flt = vol->points[vol->faces[i].index[2]].p.x / 1000.0; fwrite(&flt, sizeof(flt), 1, f);
flt = vol->points[vol->faces[i].index[2]].p.y / 1000.0; fwrite(&flt, sizeof(flt), 1, f);
flt = vol->points[vol->faces[i].index[2]].p.z / 1000.0; fwrite(&flt, sizeof(flt), 1, f);
fwrite(&s, sizeof(s), 1, f);
}
fclose(f);
//Export the open faces so you can view the with Cura (hacky)
/*
char gcodeFilename[1024];
strcpy(gcodeFilename, filename);
strcpy(strchr(gcodeFilename, '.'), ".gcode");
f = fopen(gcodeFilename, "w");
for(unsigned int i=0;i<faces.size();i++)
{
for(int j=0;j<3;j++)
{
if (faces[i].touching[j] == -1)
{
Point3 p0 = points[faces[i].index[j]].p;
Point3 p1 = points[faces[i].index[(j+1)%3]].p;
fprintf(f, ";Model error(open face): (%f, %f, %f) (%f, %f, %f)\n", p0.x / 1000.0, p0.y / 1000.0, p0.z / 1000.0, p1.x / 1000.0, p1.y / 1000.0, p1.z / 1000.0);
}
}
}
fclose(f);
*/
}
-77
Ver Arquivo
@@ -1,77 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef OPTIMIZED_MODEL_H
#define OPTIMIZED_MODEL_H
#include <map>
#include "modelFile/modelFile.h"
class OptimizedFace
{
public:
int index[3];
int touching[3];
};
class OptimizedPoint3
{
public:
Point3 p;
vector<uint32_t> faceIndexList;
OptimizedPoint3(Point3 p): p(p) {}
};
class OptimizedModel;
class OptimizedVolume
{
public:
OptimizedModel* model;
vector<OptimizedPoint3> points;
vector<OptimizedFace> faces;
OptimizedVolume(SimpleVolume* volume, OptimizedModel* model);
int getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx)
{
for(unsigned int i=0;i<points[idx0].faceIndexList.size();i++)
{
int f0 = points[idx0].faceIndexList[i];
if (f0 == notFaceIdx) continue;
for(unsigned int j=0;j<points[idx1].faceIndexList.size();j++)
{
int f1 = points[idx1].faceIndexList[j];
if (f1 == notFaceIdx) continue;
if (f0 == f1) return f0;
}
}
return -1;
}
};
class OptimizedModel
{
public:
vector<OptimizedVolume> volumes;
Point3 modelSize;
Point3 vMin, vMax;
OptimizedModel(SimpleModel* model, Point3 center)
{
for(unsigned int i=0; i<model->volumes.size(); i++)
volumes.push_back(OptimizedVolume(&model->volumes[i], this));
vMin = model->min();
vMax = model->max();
Point3 vOffset((vMin.x + vMax.x) / 2, (vMin.y + vMax.y) / 2, vMin.z);
vOffset -= center;
for(unsigned int i=0; i<volumes.size(); i++)
for(unsigned int n=0; n<volumes[i].points.size(); n++)
volumes[i].points[n].p -= vOffset;
modelSize = vMax - vMin;
vMin -= vOffset;
vMax -= vOffset;
}
void saveDebugSTL(const char* filename);
};
#endif//OPTIMIZED_MODEL_H
-95
Ver Arquivo
@@ -1,95 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "pathOrderOptimizer.h"
void PathOrderOptimizer::optimize()
{
std::vector<bool> picked;
for(unsigned int i=0;i<polygons.size(); i++)
{
int best = -1;
float bestDist = 0xFFFFFFFFFFFFFFFFLL;
PolygonRef poly = polygons[i];
for(unsigned int j=0; j<poly.size(); j++)
{
float dist = vSize2f(poly[j] - startPoint);
if (dist < bestDist)
{
best = j;
bestDist = dist;
}
}
polyStart.push_back(best);
picked.push_back(false);
}
Point p0 = startPoint;
for(unsigned int n=0; n<polygons.size(); n++)
{
int best = -1;
float bestDist = 0xFFFFFFFFFFFFFFFFLL;
for(unsigned int i=0;i<polygons.size(); i++)
{
if (picked[i] || polygons[i].size() < 1)
continue;
if (polygons[i].size() == 2)
{
float dist = vSize2f(polygons[i][0] - p0);
if (dist < bestDist)
{
best = i;
bestDist = dist;
polyStart[i] = 0;
}
dist = vSize2f(polygons[i][1] - p0);
if (dist < bestDist)
{
best = i;
bestDist = dist;
polyStart[i] = 1;
}
}else{
float dist = vSize2f(polygons[i][polyStart[i]] - p0);
if (dist < bestDist)
{
best = i;
bestDist = dist;
}
}
}
if (best > -1)
{
if (polygons[best].size() == 2)
{
p0 = polygons[best][(polyStart[best] + 1) % 2];
}else{
p0 = polygons[best][polyStart[best]];
}
picked[best] = true;
polyOrder.push_back(best);
}
}
p0 = startPoint;
for(unsigned int n=0; n<polyOrder.size(); n++)
{
int nr = polyOrder[n];
int best = -1;
float bestDist = 0xFFFFFFFFFFFFFFFFLL;
for(unsigned int i=0;i<polygons[nr].size(); i++)
{
float dist = vSize2f(polygons[nr][i] - p0);
if (dist < bestDist)
{
best = i;
bestDist = dist;
}
}
polyStart[nr] = best;
if (polygons[nr].size() <= 2)
{
p0 = polygons[nr][(best + 1) % 2];
}else{
p0 = polygons[nr][best];
}
}
}
-35
Ver Arquivo
@@ -1,35 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef PATHOPTIMIZER_H
#define PATHOPTIMIZER_H
#include <stdint.h>
#include "utils/polygon.h"
class PathOrderOptimizer
{
public:
Point startPoint;
vector<PolygonRef> polygons;
vector<int> polyStart;
vector<int> polyOrder;
PathOrderOptimizer(Point startPoint)
{
this->startPoint = startPoint;
}
void addPolygon(PolygonRef polygon)
{
this->polygons.push_back(polygon);
}
void addPolygons(Polygons& polygons)
{
for(unsigned int i=0;i<polygons.size(); i++)
this->polygons.push_back(polygons[i]);
}
void optimize();
};
#endif//PATHOPTIMIZER_H
-19
Ver Arquivo
@@ -1,19 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "raft.h"
#include "support.h"
void generateRaft(SliceDataStorage& storage, int distance)
{
for(unsigned int volumeIdx = 0; volumeIdx < storage.volumes.size(); volumeIdx++)
{
if (storage.volumes[volumeIdx].layers.size() < 1) continue;
SliceLayer* layer = &storage.volumes[volumeIdx].layers[0];
for(unsigned int i=0; i<layer->parts.size(); i++)
{
storage.raftOutline = storage.raftOutline.unionPolygons(layer->parts[i].outline.offset(distance));
}
}
SupportPolyGenerator supportGenerator(storage.support, 0);
storage.raftOutline = storage.raftOutline.unionPolygons(supportGenerator.polygons);
}
-101
Ver Arquivo
@@ -1,101 +0,0 @@
#include <stdio.h>
#include "settings.h"
#define STRINGIFY(_s) #_s
#define SETTING(name) _index.push_back(_ConfigSettingIndex(STRINGIFY(name), &name))
#define SETTING2(name, altName) _index.push_back(_ConfigSettingIndex(STRINGIFY(name), &name)); _index.push_back(_ConfigSettingIndex(STRINGIFY(altName), &name))
ConfigSettings::ConfigSettings()
{
SETTING(layerThickness);
SETTING(initialLayerThickness);
SETTING(filamentDiameter);
SETTING(filamentFlow);
SETTING(extrusionWidth);
SETTING(insetCount);
SETTING(downSkinCount);
SETTING(upSkinCount);
SETTING(sparseInfillLineDistance);
SETTING(infillOverlap);
SETTING(skirtDistance);
SETTING(skirtLineCount);
SETTING(skirtMinLength);
SETTING(initialSpeedupLayers);
SETTING(initialLayerSpeed);
SETTING(printSpeed);
SETTING(infillSpeed);
SETTING(moveSpeed);
SETTING(fanFullOnLayerNr);
SETTING(supportAngle);
SETTING(supportEverywhere);
SETTING(supportLineDistance);
SETTING(supportXYDistance);
SETTING(supportZDistance);
SETTING(supportExtruder);
SETTING(retractionAmount);
SETTING(retractionSpeed);
SETTING(retractionAmountExtruderSwitch);
SETTING(retractionMinimalDistance);
SETTING(minimalExtrusionBeforeRetraction);
SETTING(enableCombing);
SETTING(enableOozeShield);
SETTING(wipeTowerSize);
SETTING(multiVolumeOverlap);
SETTING2(objectPosition.X, posx);
SETTING2(objectPosition.Y, posy);
SETTING(objectSink);
SETTING(raftMargin);
SETTING(raftLineSpacing);
SETTING(raftBaseThickness);
SETTING(raftBaseLinewidth);
SETTING(raftInterfaceThickness);
SETTING(raftInterfaceLinewidth);
SETTING(minimalLayerTime);
SETTING(minimalFeedrate);
SETTING(coolHeadLift);
SETTING(fanSpeedMin);
SETTING(fanSpeedMax);
SETTING(fixHorrible);
SETTING(spiralizeMode);
SETTING(gcodeFlavor);
SETTING(extruderOffset[1].X);
SETTING(extruderOffset[1].Y);
SETTING(extruderOffset[2].X);
SETTING(extruderOffset[2].Y);
SETTING(extruderOffset[3].X);
SETTING(extruderOffset[3].Y);
}
#undef STRINGIFY
#undef SETTING
bool ConfigSettings::setSetting(const char* key, const char* value)
{
for(unsigned int n=0; n < _index.size(); n++)
{
if (strcasecmp(key, _index[n].key) == 0)
{
*_index[n].ptr = atoi(value);
return true;
}
}
if (strcasecmp(key, "startCode") == 0)
{
this->startCode = value;
return true;
}
if (strcasecmp(key, "endCode") == 0)
{
this->endCode = value;
return true;
}
return false;
}
-130
Ver Arquivo
@@ -1,130 +0,0 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include <utils/floatpoint.h>
#include <vector>
#define VERSION "13.12"
#define FIX_HORRIBLE_UNION_ALL_TYPE_A 0x01
#define FIX_HORRIBLE_UNION_ALL_TYPE_B 0x02
#define FIX_HORRIBLE_EXTENSIVE_STITCHING 0x04
#define FIX_HORRIBLE_UNION_ALL_TYPE_C 0x08
#define FIX_HORRIBLE_KEEP_NONE_CLOSED 0x10
/**
* RepRap flavored GCode is Marlin/Sprinter/Repetier based GCode.
* This is the most commonly used GCode set.
* G0 for moves, G1 for extrusion.
* E values give mm of filament extrusion.
* Retraction is done on E values with G1. Start/end code is added.
* M106 Sxxx and M107 are used to turn the fan on/off.
**/
#define GCODE_FLAVOR_REPRAP 0
/**
* UltiGCode flavored is Marlin based GCode.
* UltiGCode uses less settings on the slicer and puts more settings in the firmware. This makes for more hardware/material independed GCode.
* G0 for moves, G1 for extrusion.
* E values give mm^3 of filament extrusion. Ignores the filament diameter setting.
* Retraction is done with G10 and G11. Retraction settings are ignored. G10 S1 is used for multi-extruder switch retraction.
* Start/end code is not added.
* M106 Sxxx and M107 are used to turn the fan on/off.
**/
#define GCODE_FLAVOR_ULTIGCODE 1
/**
* Makerbot flavored GCode.
* Looks a lot like RepRap GCode with a few changes. Requires MakerWare to convert to X3G files.
* Heating needs to be done with M104 Sxxx T0
* No G21 or G90
* Fan ON is M126 T0 (No fan strength control?)
* Fan OFF is M127 T0
* Homing is done with G162 X Y F2000
**/
#define GCODE_FLAVOR_MAKERBOT 2
#define MAX_EXTRUDERS 16
class _ConfigSettingIndex
{
public:
const char* key;
int* ptr;
_ConfigSettingIndex(const char* key, int* ptr) : key(key), ptr(ptr) {}
};
class ConfigSettings
{
private:
std::vector<_ConfigSettingIndex> _index;
public:
int layerThickness;
int initialLayerThickness;
int filamentDiameter;
int filamentFlow;
int extrusionWidth;
int insetCount;
int downSkinCount;
int upSkinCount;
int sparseInfillLineDistance;
int infillOverlap;
int skirtDistance;
int skirtLineCount;
int skirtMinLength;
int retractionAmount;
int retractionAmountExtruderSwitch;
int retractionSpeed;
int retractionMinimalDistance;
int minimalExtrusionBeforeRetraction;
int enableCombing;
int enableOozeShield;
int wipeTowerSize;
int multiVolumeOverlap;
int initialSpeedupLayers;
int initialLayerSpeed;
int printSpeed;
int infillSpeed;
int moveSpeed;
int fanFullOnLayerNr;
//Support material
int supportAngle;
int supportEverywhere;
int supportLineDistance;
int supportXYDistance;
int supportZDistance;
int supportExtruder;
//Cool settings
int minimalLayerTime;
int minimalFeedrate;
int coolHeadLift;
int fanSpeedMin;
int fanSpeedMax;
//Raft settings
int raftMargin;
int raftLineSpacing;
int raftBaseThickness;
int raftBaseLinewidth;
int raftInterfaceThickness;
int raftInterfaceLinewidth;
FMatrix3x3 matrix;
IntPoint objectPosition;
int objectSink;
int fixHorrible;
int spiralizeMode;
int gcodeFlavor;
IntPoint extruderOffset[MAX_EXTRUDERS];
const char* startCode;
const char* endCode;
ConfigSettings();
bool setSetting(const char* key, const char* value);
};
#endif//SETTINGS_H
-116
Ver Arquivo
@@ -1,116 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "skin.h"
void generateSkins(int layerNr, SliceVolumeStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount, int infillOverlap)
{
SliceLayer* layer = &storage.layers[layerNr];
for(unsigned int partNr=0; partNr<layer->parts.size(); partNr++)
{
SliceLayerPart* part = &layer->parts[partNr];
Polygons upskin = part->insets[part->insets.size() - 1].offset(-extrusionWidth/2);
Polygons downskin = upskin;
if (part->insets.size() > 1)
{
//Add thin wall filling by taking the area between the insets.
Polygons thinWalls = part->insets[0].offset(-extrusionWidth / 2 - extrusionWidth * infillOverlap / 100).difference(part->insets[1].offset(extrusionWidth * 6 / 10));
upskin.add(thinWalls);
downskin.add(thinWalls);
}
if (int(layerNr - downSkinCount) >= 0)
{
SliceLayer* layer2 = &storage.layers[layerNr - downSkinCount];
for(unsigned int partNr2=0; partNr2<layer2->parts.size(); partNr2++)
{
if (part->boundaryBox.hit(layer2->parts[partNr2].boundaryBox))
downskin = downskin.difference(layer2->parts[partNr2].insets[layer2->parts[partNr2].insets.size() - 1]);
}
}
if (int(layerNr + upSkinCount) < (int)storage.layers.size())
{
SliceLayer* layer2 = &storage.layers[layerNr + upSkinCount];
for(unsigned int partNr2=0; partNr2<layer2->parts.size(); partNr2++)
{
if (part->boundaryBox.hit(layer2->parts[partNr2].boundaryBox))
upskin = upskin.difference(layer2->parts[partNr2].insets[layer2->parts[partNr2].insets.size() - 1]);
}
}
part->skinOutline = upskin.unionPolygons(downskin);
double minAreaSize = (2 * M_PI * (double(extrusionWidth) / 1000.0) * (double(extrusionWidth) / 1000.0)) * 0.3;
for(unsigned int i=0; i<part->skinOutline.size(); i++)
{
double area = fabs(part->skinOutline[i].area()) / 1000.0 / 1000.0;
if (area < minAreaSize) // Only create an up/down skin if the area is large enough. So you do not create tiny blobs of "trying to fill"
{
part->skinOutline.remove(i);
i -= 1;
}
}
}
}
void generateSparse(int layerNr, SliceVolumeStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount)
{
SliceLayer* layer = &storage.layers[layerNr];
for(unsigned int partNr=0; partNr<layer->parts.size(); partNr++)
{
SliceLayerPart* part = &layer->parts[partNr];
Polygons sparse = part->insets[part->insets.size() - 1].offset(-extrusionWidth/2);
Polygons downskin = sparse;
Polygons upskin = sparse;
if (int(layerNr - downSkinCount) >= 0)
{
SliceLayer* layer2 = &storage.layers[layerNr - downSkinCount];
for(unsigned int partNr2=0; partNr2<layer2->parts.size(); partNr2++)
{
if (part->boundaryBox.hit(layer2->parts[partNr2].boundaryBox))
{
if (layer2->parts[partNr2].insets.size() > 1)
{
downskin = downskin.difference(layer2->parts[partNr2].insets[layer2->parts[partNr2].insets.size() - 2]);
}else{
downskin = downskin.difference(layer2->parts[partNr2].insets[layer2->parts[partNr2].insets.size() - 1]);
}
}
}
}
if (int(layerNr + upSkinCount) < (int)storage.layers.size())
{
SliceLayer* layer2 = &storage.layers[layerNr + upSkinCount];
for(unsigned int partNr2=0; partNr2<layer2->parts.size(); partNr2++)
{
if (part->boundaryBox.hit(layer2->parts[partNr2].boundaryBox))
{
if (layer2->parts[partNr2].insets.size() > 1)
{
upskin = upskin.difference(layer2->parts[partNr2].insets[layer2->parts[partNr2].insets.size() - 2]);
}else{
upskin = upskin.difference(layer2->parts[partNr2].insets[layer2->parts[partNr2].insets.size() - 1]);
}
}
}
}
Polygons result = upskin.unionPolygons(downskin);
double minAreaSize = 3.0;//(2 * M_PI * (double(config.extrusionWidth) / 1000.0) * (double(config.extrusionWidth) / 1000.0)) * 3;
for(unsigned int i=0; i<result.size(); i++)
{
double area = fabs(result[i].area()) / 1000.0 / 1000.0;
if (area < minAreaSize) /* Only create an up/down skin if the area is large enough. So you do not create tiny blobs of "trying to fill" */
{
result.remove(i);
i -= 1;
}
}
part->sparseOutline = sparse.difference(result);
}
}
-10
Ver Arquivo
@@ -1,10 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef SKIN_H
#define SKIN_H
#include "sliceDataStorage.h"
void generateSkins(int layerNr, SliceVolumeStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount, int infillOverlap);
void generateSparse(int layerNr, SliceVolumeStorage& storage, int extrusionWidth, int downSkinCount, int upSkinCount);
#endif//SKIN_H
-39
Ver Arquivo
@@ -1,39 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "skirt.h"
#include "support.h"
void generateSkirt(SliceDataStorage& storage, int distance, int extrusionWidth, int count, int minLength, int initialLayerHeight)
{
for(int skirtNr=0; skirtNr<count;skirtNr++)
{
int offsetDistance = distance + extrusionWidth * skirtNr + extrusionWidth / 2;
Polygons skirtPolygons(storage.wipeTower.offset(offsetDistance));
for(unsigned int volumeIdx = 0; volumeIdx < storage.volumes.size(); volumeIdx++)
{
if (storage.volumes[volumeIdx].layers.size() < 1) continue;
SliceLayer* layer = &storage.volumes[volumeIdx].layers[0];
for(unsigned int i=0; i<layer->parts.size(); i++)
{
skirtPolygons = skirtPolygons.unionPolygons(layer->parts[i].outline.offset(offsetDistance));
}
}
SupportPolyGenerator supportGenerator(storage.support, initialLayerHeight);
skirtPolygons = skirtPolygons.unionPolygons(supportGenerator.polygons.offset(offsetDistance));
//Remove small inner skirt holes. Holes have a negative area, remove anything smaller then 100x extrusion "area"
for(unsigned int n=0; n<skirtPolygons.size(); n++)
{
double area = skirtPolygons[n].area();
if (area < 0 && area > -extrusionWidth * extrusionWidth * 100)
skirtPolygons.remove(n--);
}
storage.skirt.add(skirtPolygons);
int lenght = storage.skirt.polygonLength();
if (skirtNr + 1 >= count && lenght > 0 && lenght < minLength)
count++;
}
}
-9
Ver Arquivo
@@ -1,9 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef SKIRT_H
#define SKIRT_H
#include "sliceDataStorage.h"
void generateSkirt(SliceDataStorage& storage, int distance, int extrusionWidth, int count, int minLength, int initialLayerHeight);
#endif//SKIRT_H
-83
Ver Arquivo
@@ -1,83 +0,0 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef SLICE_DATA_STORAGE_H
#define SLICE_DATA_STORAGE_H
#include "utils/intpoint.h"
#include "utils/polygon.h"
/*
SliceData
+ Layers[]
+ LayerParts[]
+ OutlinePolygons[]
+ Insets[]
+ Polygons[]
+ SkinPolygons[]
*/
class SliceLayerPart
{
public:
AABB boundaryBox;
Polygons outline;
Polygons combBoundery;
vector<Polygons> insets;
Polygons skinOutline;
Polygons sparseOutline;
int bridgeAngle;
};
class SliceLayer
{
public:
vector<SliceLayerPart> parts;
};
/******************/
class SupportPoint
{
public:
int32_t z;
double cosAngle;
SupportPoint(int32_t z, double cosAngle) : z(z), cosAngle(cosAngle) {}
};
class SupportStorage
{
public:
bool generated;
int angle;
bool everywhere;
int XYDistance;
int ZDistance;
Point gridOffset;
int32_t gridScale;
int32_t gridWidth, gridHeight;
vector<SupportPoint>* grid;
SupportStorage(){grid = NULL;}
~SupportStorage(){if(grid) delete [] grid;}
};
/******************/
class SliceVolumeStorage
{
public:
vector<SliceLayer> layers;
};
class SliceDataStorage
{
public:
Point3 modelSize, modelMin, modelMax;
Polygons skirt;
Polygons raftOutline;
vector<Polygons> oozeShield;
vector<SliceVolumeStorage> volumes;
SupportStorage support;
Polygons wipeTower;
Point wipePoint;
};
#endif//SLICE_DATA_STORAGE_H
+473
Ver Arquivo
@@ -0,0 +1,473 @@
#include "Weaver.h"
#include <cmath> // sqrt
#include <fstream> // debug IO
#include <unistd.h>
#include "weaveDataStorage.h"
namespace cura
{
void Weaver::weave(PrintObject* object, CommandSocket* commandSocket)
{
int maxz = object->max().z;
int layer_count = (maxz - initial_layer_thickness) / connectionHeight + 1;
DEBUG_SHOW(layer_count);
std::vector<cura::Slicer*> slicerList;
for(Mesh& mesh : object->meshes)
{
cura::Slicer* slicer = new cura::Slicer(&mesh, initial_layer_thickness, connectionHeight, layer_count, mesh.getSettingBoolean("meshfix_keep_open_polygons"), mesh.getSettingBoolean("meshfix_extensive_stitching"));
slicerList.push_back(slicer);
}
int starting_layer_idx;
{ // find first non-empty layer
for (starting_layer_idx = 0; starting_layer_idx < layer_count; starting_layer_idx++)
{
Polygons parts;
for (cura::Slicer* slicer : slicerList)
parts.add(slicer->layers[starting_layer_idx].polygonList);
if (parts.size() > 0)
break;
}
if (starting_layer_idx > 0)
{
logError("First %i layers are empty!\n", starting_layer_idx);
}
}
std::cerr<< "chainifying layers..." << std::endl;
{
int starting_z = -1;
for (cura::Slicer* slicer : slicerList)
wireFrame.bottom_outline.add(slicer->layers[starting_layer_idx].polygonList);
if (commandSocket)
commandSocket->sendPolygons(Inset0Type, 0, wireFrame.bottom_outline, 1);
wireFrame.z_bottom = slicerList[0]->layers[starting_layer_idx].z;
Point starting_point_in_layer;
if (wireFrame.bottom_outline.size() > 0)
starting_point_in_layer = (wireFrame.bottom_outline.max() + wireFrame.bottom_outline.min()) / 2;
else
starting_point_in_layer = (Point(0,0) + object->max() + object->min()) / 2;
for (int layer_idx = starting_layer_idx + 1; layer_idx < layer_count; layer_idx++)
{
logProgress("inset", layer_idx+1, layer_count); // abuse the progress system of the normal mode of CuraEngine
Polygons parts1;
for (cura::Slicer* slicer : slicerList)
parts1.add(slicer->layers[layer_idx].polygonList);
Polygons chainified;
chainify_polygons(parts1, starting_point_in_layer, chainified, false);
if (commandSocket)
commandSocket->sendPolygons(Inset0Type, layer_idx - starting_layer_idx, chainified, 1);
if (chainified.size() > 0)
{
if (starting_z == -1) starting_z = slicerList[0]->layers[layer_idx-1].z;
wireFrame.layers.emplace_back();
WeaveLayer& layer = wireFrame.layers.back();
layer.z0 = slicerList[0]->layers[layer_idx-1].z - starting_z;
layer.z1 = slicerList[0]->layers[layer_idx].z - starting_z;
layer.supported = chainified;
starting_point_in_layer = layer.supported.back().back();
}
}
}
std::cerr<< "finding horizontal parts..." << std::endl;
{
Polygons* lower_top_parts = &wireFrame.bottom_outline;
for (unsigned int layer_idx = 0; layer_idx < wireFrame.layers.size(); layer_idx++)
{
logProgress("skin", layer_idx+1, wireFrame.layers.size()); // abuse the progress system of the normal mode of CuraEngine
WeaveLayer& layer = wireFrame.layers[layer_idx];
Polygons empty;
Polygons& layer_above = (layer_idx+1 < wireFrame.layers.size())? wireFrame.layers[layer_idx+1].supported : empty;
createHorizontalFill(*lower_top_parts, layer, layer_above, layer.z1);
lower_top_parts = &layer.supported;
}
}
// at this point layer.supported still only contains the polygons to be connected
// when connecting layers, we further add the supporting polygons created by the roofs
std::cerr<< "connecting layers..." << std::endl;
{
Polygons* lower_top_parts = &wireFrame.bottom_outline;
int last_z = wireFrame.z_bottom;
for (unsigned int layer_idx = 0; layer_idx < wireFrame.layers.size(); layer_idx++) // use top of every layer but the last
{
WeaveLayer& layer = wireFrame.layers[layer_idx];
connect_polygons(*lower_top_parts, last_z, layer.supported, layer.z1, layer);
layer.supported.add(layer.roofs.roof_outlines);
lower_top_parts = &layer.supported;
last_z = layer.z1;
}
}
{ // roofs:
WeaveLayer& top_layer = wireFrame.layers.back();
Polygons to_be_supported; // empty for the top layer
fillRoofs(top_layer.supported, to_be_supported, -1, top_layer.z1, top_layer.roofs);
}
{ // bottom:
Polygons to_be_supported; // is empty for the bottom layer, cause the order of insets doesn't really matter (in a sense everything is to be supported)
fillRoofs(wireFrame.bottom_outline, to_be_supported, -1, wireFrame.layers.front().z0, wireFrame.bottom_infill);
}
}
void Weaver::createHorizontalFill(Polygons& lower_top_parts, WeaveLayer& layer, Polygons& layer_above, int z1)
{
int64_t bridgable_dist = connectionHeight;
Polygons& polys_below = lower_top_parts;
Polygons& polys_here = layer.supported;
Polygons& polys_above = layer_above;
{ // roofs
Polygons to_be_supported = polys_above.offset(bridgable_dist);
fillRoofs(polys_here, to_be_supported, -1, layer.z1, layer.roofs);
}
{ // floors
Polygons to_be_supported = polys_above.offset(-bridgable_dist);
fillFloors(polys_here, to_be_supported, 1, layer.z1, layer.roofs);
}
{// optimize away doubly printed regions (boundaries of holes in layer etc.)
for (WeaveRoofPart& inset : layer.roofs.roof_insets)
connections2moves(inset);
}
}
void Weaver::fillRoofs(Polygons& supporting, Polygons& to_be_supported, int direction, int z, WeaveRoof& horizontals)
{
std::vector<WeaveRoofPart>& insets = horizontals.roof_insets;
if (supporting.size() == 0) return; // no parts to start the roof from!
Polygons roofs = supporting.difference(to_be_supported);
roofs = roofs.offset(-roof_inset).offset(roof_inset);
if (roofs.size() == 0) return;
Polygons roof_outlines;
Polygons roof_holes;
{ // split roofs into outlines and holes
std::vector<Polygons> roof_parts = roofs.splitIntoParts();
for (Polygons& roof_part : roof_parts)
{
roof_outlines.add(roof_part[0]);
for (unsigned int hole_idx = 1; hole_idx < roof_part.size(); hole_idx++)
{
roof_holes.add(roof_part[hole_idx]);
roof_holes.back().reverse();
}
}
}
Polygons supporting_outlines;
std::vector<Polygons> supporting_parts = supporting.splitIntoParts();
for (Polygons& supporting_part : supporting_parts)
supporting_outlines.add(supporting_part[0]); // only add outlines, not the holes
Polygons inset1;
Polygons last_inset;
Polygons last_supported = supporting;
for (Polygons inset0 = supporting_outlines; inset0.size() > 0; inset0 = last_inset)
{
last_inset = inset0.offset(direction * roof_inset, ClipperLib::jtRound);
inset1 = last_inset.intersection(roof_outlines); // stay within roof area
inset1 = inset1.unionPolygons(roof_holes);// make insets go around holes
if (inset1.size() == 0) break;
insets.emplace_back();
connect(last_supported, z, inset1, z, insets.back(), true);
inset1 = inset1.remove(roof_holes); // throw away holes which appear in every intersection
inset1 = inset1.remove(roof_outlines);// throw away fully filled regions
last_supported = insets.back().supported; // chainified
}
horizontals.roof_outlines.add(roofs); // TODO just add the new lines, not the lines of the roofs which are already supported ==> make outlines into a connection from which we only print the top, not the connection
}
void Weaver::fillFloors(Polygons& supporting, Polygons& to_be_supported, int direction, int z, WeaveRoof& horizontals)
{
std::vector<WeaveRoofPart>& outsets = horizontals.roof_insets;
if (to_be_supported.size() == 0) return; // no parts to start the floor from!
if (supporting.size() == 0) return; // no parts to start the floor from!
Polygons floors = to_be_supported.difference(supporting);
floors = floors.offset(-roof_inset).offset(roof_inset);
if (floors.size() == 0) return;
std::vector<Polygons> floor_parts = floors.splitIntoParts();
Polygons floor_outlines;
Polygons floor_holes;
for (Polygons& floor_part : floor_parts)
{
floor_outlines.add(floor_part[0]);
for (unsigned int hole_idx = 1; hole_idx < floor_part.size(); hole_idx++)
{
floor_holes.add(floor_part[hole_idx]);
//floor_holes.back().reverse();
}
}
Polygons outset1;
Polygons last_supported = supporting;
for (Polygons outset0 = supporting; outset0.size() > 0; outset0 = outset1)
{
outset1 = outset0.offset(roof_inset * direction, ClipperLib::jtRound).intersection(floors);
outset1 = outset1.remove(floor_holes); // throw away holes which appear in every intersection
outset1 = outset1.remove(floor_outlines); // throw away holes which appear in every intersection
outsets.emplace_back();
connect(last_supported, z, outset1, z, outsets.back(), true);
outset1 = outset1.remove(floor_outlines);// throw away fully filled regions
last_supported = outsets.back().supported; // chainified
}
horizontals.roof_outlines.add(floors);
}
void Weaver::connections2moves(WeaveRoofPart& inset)
{
bool include_half_of_last_down = true;
for (WeaveConnectionPart& part : inset.connections)
{
std::vector<WeaveConnectionSegment>& segments = part.connection.segments;
for (unsigned int idx = 0; idx < part.connection.segments.size(); idx += 2)
{
WeaveConnectionSegment& segment = segments[idx];
assert(segment.segmentType == WeaveSegmentType::UP);
Point3 from = (idx == 0)? part.connection.from : segments[idx-1].to;
bool skipped = (segment.to - from).vSize2() < extrusionWidth * extrusionWidth;
if (skipped)
{
unsigned int begin = idx;
for (; idx < segments.size(); idx += 2)
{
WeaveConnectionSegment& segment = segments[idx];
assert(segments[idx].segmentType == WeaveSegmentType::UP);
Point3 from = (idx == 0)? part.connection.from : segments[idx-1].to;
bool skipped = (segment.to - from).vSize2() < extrusionWidth * extrusionWidth;
if (!skipped)
break;
}
int end = idx - ((include_half_of_last_down)? 2 : 1);
if (idx >= segments.size())
segments.erase(segments.begin() + begin, segments.end());
else
{
segments.erase(segments.begin() + begin, segments.begin() + end);
if (begin < segments.size())
{
segments[begin].segmentType = WeaveSegmentType::MOVE;
if (include_half_of_last_down)
segments[begin+1].segmentType = WeaveSegmentType::DOWN_AND_FLAT;
}
idx = begin + ((include_half_of_last_down)? 2 : 1);
}
}
}
}
}
void Weaver::connect(Polygons& parts0, int z0, Polygons& parts1, int z1, WeaveConnection& result, bool include_last)
{
// TODO: convert polygons (with outset + difference) such that after printing the first polygon, we can't be in the way of the printed stuff
// something like:
// for (m > n)
// parts[m] = parts[m].difference(parts[n].offset(nozzle_top_diameter))
// according to the printing order!
//
// OR! :
//
// unify different parts if gap is too small
Polygons& supported = result.supported;
if (parts1.size() == 0) return;
Point& start_close_to = (parts0.size() > 0)? parts0.back().back() : parts1.back().back();
chainify_polygons(parts1, start_close_to, supported, include_last);
if (parts0.size() == 0) return;
connect_polygons(parts0, z0, supported, z1, result);
}
void Weaver::chainify_polygons(Polygons& parts1, Point start_close_to, Polygons& result, bool include_last)
{
for (unsigned int prt = 0 ; prt < parts1.size(); prt++)
{
const PolygonRef upperPart = parts1[prt];
ClosestPolygonPoint closestInPoly = findClosest(start_close_to, upperPart);
PolygonRef part_top = result.newPoly();
GivenDistPoint next_upper;
bool found = true;
int idx = 0;
for (Point upper_point = upperPart[closestInPoly.pos]; found; upper_point = next_upper.location)
{
found = getNextPointWithDistance(upper_point, nozzle_top_diameter, upperPart, idx, closestInPoly.pos, next_upper);
if (!found)
{
break;
}
part_top.add(upper_point);
idx = next_upper.pos;
}
if (part_top.size() > 0)
start_close_to = part_top.back();
else
result.remove(result.size()-1);
}
}
void Weaver::connect_polygons(Polygons& supporting, int z0, Polygons& supported, int z1, WeaveConnection& result)
{
if (supporting.size() < 1)
{
DEBUG_PRINTLN("lower layer has zero parts!");
return;
}
result.z0 = z0;
result.z1 = z1;
std::vector<WeaveConnectionPart>& parts = result.connections;
for (unsigned int prt = 0 ; prt < supported.size(); prt++)
{
const PolygonRef upperPart = supported[prt];
parts.emplace_back(prt);
WeaveConnectionPart& part = parts.back();
PolyLine3& connection = part.connection;
Point3 last_upper;
bool firstIter = true;
for (const Point& upper_point : upperPart)
{
ClosestPolygonPoint lowerPolyPoint = findClosest(upper_point, supporting);
Point& lower = lowerPolyPoint.location;
Point3 lower3 = Point3(lower.X, lower.Y, z0);
Point3 upper3 = Point3(upper_point.X, upper_point.Y, z1);
if (firstIter)
connection.from = lower3;
else
connection.segments.emplace_back<>(lower3, WeaveSegmentType::DOWN);
connection.segments.emplace_back<>(upper3, WeaveSegmentType::UP);
last_upper = upper3;
firstIter = false;
}
}
}
} // namespace cura
+153
Ver Arquivo
@@ -0,0 +1,153 @@
#ifndef WEAVER_H
#define WEAVER_H
#include "weaveDataStorage.h"
#include "commandSocket.h"
#include "settings.h"
#include "modelFile/modelFile.h" // PrintObject
#include "slicer.h"
#include "utils/polygon.h"
#include "utils/polygonUtils.h"
#include "debug.h"
namespace cura
{
/*!
* The main weaver / WirePrint / wireframe printing class, which computes the basic paths to be followed.
*/
class Weaver : public SettingsBase
{
friend class Wireframe2gcode;
private:
static const int HIGHER_BEND_NO_STRAIGHTEN = 0;
static const int MOVE_TO_STRAIGHTEN = 1;
static const int RETRACT_TO_STRAIGHTEN = 2;
int initial_layer_thickness;
int connectionHeight;
int extrusionWidth;
int roof_inset;
int nozzle_outer_diameter;
double nozzle_expansion_angle;
int nozzle_clearance;
int nozzle_top_diameter;
public:
Weaver(SettingsBase* settings_base) : SettingsBase(settings_base)
{
initial_layer_thickness = getSettingInMicrons("layer_height_0");
connectionHeight = getSettingInMicrons("wireframe_height");
extrusionWidth = getSettingInMicrons("wall_line_width_x");
roof_inset = getSettingInMicrons("wireframe_roof_inset");
nozzle_outer_diameter = getSettingInMicrons("machine_nozzle_tip_outer_diameter"); // ___ ___ .
nozzle_expansion_angle = getSettingInAngleRadians("machine_nozzle_expansion_angle"); // \_U_/ .
nozzle_clearance = getSettingInMicrons("wireframe_nozzle_clearance"); // at least line width
nozzle_top_diameter = tan(nozzle_expansion_angle) * connectionHeight + nozzle_outer_diameter + nozzle_clearance;
}
/*!
* 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
*/
void weave(PrintObject* object, CommandSocket* commandSocket);
private:
WireFrame wireFrame;
/*!
* Connect two polygons, chainify the second and generate connections from it, supporting on the first polygon.
*
* \param supporting The polygons from which to start the connection
* \param z0 The height of the \p supporting
* \param supported The polygons to be supported by the connection from \p supporting to \p supported
* \param z1 the height of \p supported
* \param include_last Whether the last full link should be included in the chainified \p parts1 if the last link would be shorter than the normal link size.
*/
void connect(Polygons& parts0, int z0, Polygons& parts1, int z1, WeaveConnection& result, bool include_last);
/*!
* Convert polygons, such that they consist of segments/links of uniform size, namely \p nozzle_top_diameter.
*
* \param parts1 The polygons to be chainified
* \param start_close_to The point from which to start the first link
* \param include_last governs whether the last segment is smaller or grater than the \p nozzle_top_diameter.
* If true, the last segment may be smaller.
*/
void chainify_polygons(Polygons& parts1, Point start_close_to, Polygons& result, bool include_last);
/*!
* The main weaving function.
* Generate connections between two polygons.
* The connections consist of zig zags of which the zig is a line from a point in \p supported to the closest point in \p supporting
* and the zag is a diagonal line from the same point in \p supported to a point in \p supporting
* with a distance equal to Weaver::nozzle_top_diameter from the other point in \p supporting of the zig.
*
* \param supporting The polygons from which to start the connection
* \param z0 The height of the \p supporting
* \param supported The polygons to be supported by the connection from \p supporting to \p supported
* \param z1 the height of \p supported
* \param result The resulting connection
*/
void connect_polygons(Polygons& supporting, int z0, Polygons& supported, int z1, WeaveConnection& result);
/*!
* Creates the roofs and floors which are laid down horizontally.
*/
void createHorizontalFill(Polygons& lower_top_parts, WeaveLayer& layer, Polygons& layer_above, int z1);
/*!
* Fill roofs starting from the outlines of \p supporting.
* The area to be filled in is difference( \p to_be_supported , \p supporting ).
*
* The basic algorithm performs insets on \p supported until the whole area of \p to_be_supported is filled.
* In order to not fill holes in the roof, the hole-areas are unioned with the insets, which results in connections where the UP move has close to zero length;
* pieces of the area between two consecutive insets have close to zero distance at these points.
* These parts of the horizontal infills are converted into moves by the function \p connections2moves.
*
* Note that the new inset is computed from the last inset, while the connections are between the last chainified inset and the new chainified inset.
*
*/
void fillRoofs(Polygons& supporting, Polygons& to_be_supported, int direction, int z, WeaveRoof& roofs);
/*!
* Fill floors starting from the outlines of \p supporting.
* The area to be filled in is \p floors = difference( \p to_be_supported , \p supporting ).
*
* The basic algorithm performs outsets until the whole area of [to_be_supported] is filled.
* In order to not fill too much, the outsets are intersected with the [floors] area, which results in connections where the UP move has close to zero length.
* These parts of the horizontal infills are converted into moves by the function [connections2moves].
*
* The first supporting polygons are \p supporting while the supporting polygons in consecutive iterations are sub-areas of \p floors.
*
* Note that the new outset is computed from the last outset, while the connections are between the last chainified outset and the new (chainified) outset.
*
*/
void fillFloors(Polygons& supporting, Polygons& to_be_supported, int direction, int z, WeaveRoof& roofs);
/*!
* Filter out parts of connections with small distances; replace by moves.
*
*/
void connections2moves(WeaveRoofPart& inset);
};
}//namespace cura
#endif//WEAVER_H
+555
Ver Arquivo
@@ -0,0 +1,555 @@
#include "Wireframe2gcode.h"
#include <cmath> // sqrt
#include <fstream> // debug IO
#include "weaveDataStorage.h"
namespace cura
{
void Wireframe2gcode::writeGCode(CommandSocket* commandSocket, int& maxObjectHeight)
{
if (commandSocket)
commandSocket->beginGCode();
maxObjectHeight = wireFrame.layers.back().z1;
{ // starting Gcode
if (hasSetting("material_bed_temperature") && getSettingInDegreeCelsius("material_bed_temperature") > 0)
gcode.writeBedTemperatureCommand(getSettingInDegreeCelsius("material_bed_temperature"), true);
if (hasSetting("material_print_temperature") && getSettingInDegreeCelsius("material_print_temperature") > 0)
gcode.writeTemperatureCommand(getSettingAsIndex("extruder_nr"), getSettingInDegreeCelsius("material_print_temperature"));
gcode.writeCode(getSettingString("machine_start_gcode").c_str());
if (gcode.getFlavor() == GCODE_FLAVOR_BFB)
{
gcode.writeComment("enable auto-retraction");
std::ostringstream tmp;
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?)
gcode.writeLine(tmp.str().c_str());
}
}
unsigned int totalLayers = wireFrame.layers.size();
gcode.writeLayerComment(0);
gcode.writeTypeComment("SKIRT");
gcode.setZ(initial_layer_thickness);
for (PolygonRef bottom_part : wireFrame.bottom_infill.roof_outlines)
{
if (bottom_part.size() == 0) continue;
writeMoveWithRetract(bottom_part[bottom_part.size()-1]);
for (Point& segment_to : bottom_part)
{
gcode.writeMove(segment_to, speedBottom, extrusion_per_mm_flat);
}
}
// bottom:
Polygons empty_outlines;
writeFill(wireFrame.bottom_infill.roof_insets, empty_outlines,
[this](Wireframe2gcode& thiss, WeaveRoofPart& inset, WeaveConnectionPart& part, unsigned int segment_idx) {
WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
if (segment.segmentType == WeaveSegmentType::MOVE || segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT) // this is the case when an inset overlaps with a hole
{
writeMoveWithRetract(segment.to);
} else
{
gcode.writeMove(segment.to, speedBottom, extrusion_per_mm_connection);
}
}
,
[this](Wireframe2gcode& thiss, WeaveConnectionSegment& segment) {
if (segment.segmentType == WeaveSegmentType::MOVE)
writeMoveWithRetract(segment.to);
else if (segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT)
return; // do nothing
else
gcode.writeMove(segment.to, speedBottom, extrusion_per_mm_flat);
}
);
for (unsigned int layer_nr = 0; layer_nr < wireFrame.layers.size(); layer_nr++)
{
logProgress("export", layer_nr+1, totalLayers); // abuse the progress system of the normal mode of CuraEngine
if (commandSocket) commandSocket->sendProgress(2.0/3.0 + 1.0/3.0 * float(layer_nr) / float(totalLayers));
WeaveLayer& layer = wireFrame.layers[layer_nr];
gcode.writeLayerComment(layer_nr+1);
int fanSpeed = getSettingInPercentage("cool_fan_speed_max");
if (layer_nr == 0)
fanSpeed = getSettingInPercentage("cool_fan_speed_min");
gcode.writeFanCommand(fanSpeed);
for (unsigned int part_nr = 0; part_nr < layer.connections.size(); part_nr++)
{
WeaveConnectionPart& part = layer.connections[part_nr];
if (part.connection.segments.size() == 0) continue;
gcode.writeTypeComment("SUPPORT"); // connection
{
if (vSize2(gcode.getPositionXY() - part.connection.from) > connectionHeight)
{
Point3 point_same_height(part.connection.from.x, part.connection.from.y, layer.z1+100);
writeMoveWithRetract(point_same_height);
}
writeMoveWithRetract(part.connection.from);
for (unsigned int segment_idx = 0; segment_idx < part.connection.segments.size(); segment_idx++)
{
handle_segment(layer, part, segment_idx);
}
}
gcode.writeTypeComment("WALL-OUTER"); // top
{
for (unsigned int segment_idx = 0; segment_idx < part.connection.segments.size(); segment_idx++)
{
WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
if (segment.segmentType == WeaveSegmentType::DOWN) continue;
if (segment.segmentType == WeaveSegmentType::MOVE)
{
writeMoveWithRetract(segment.to);
} else
{
gcode.writeMove(segment.to, speedFlat, extrusion_per_mm_flat);
gcode.writeDelay(flat_delay);
}
}
}
}
// roofs:
gcode.setZ(layer.z1);
std::function<void (Wireframe2gcode& thiss, WeaveRoofPart& inset, WeaveConnectionPart& part, unsigned int segment_idx)>
handle_roof = &Wireframe2gcode::handle_roof_segment;
writeFill(layer.roofs.roof_insets, layer.roofs.roof_outlines,
handle_roof,
[this](Wireframe2gcode& thiss, WeaveConnectionSegment& segment) { // handle flat segments
if (segment.segmentType == WeaveSegmentType::MOVE)
{
writeMoveWithRetract(segment.to);
} else if (segment.segmentType == WeaveSegmentType::DOWN_AND_FLAT)
{
// do nothing
} else
{
gcode.writeMove(segment.to, speedFlat, extrusion_per_mm_flat);
gcode.writeDelay(flat_delay);
}
});
}
gcode.setZ(maxObjectHeight);
gcode.writeRetraction(&standard_retraction_config);
gcode.updateTotalPrintTime();
gcode.writeDelay(0.3);
gcode.writeFanCommand(0);
if (commandSocket)
{
gcode.finalize(maxObjectHeight, getSettingInMillimetersPerSecond("speed_travel"), getSettingString("machine_end_gcode").c_str());
for(int e=0; e<MAX_EXTRUDERS; e++)
gcode.writeTemperatureCommand(e, 0, false);
commandSocket->sendGCodeLayer();
commandSocket->endSendSlicedObject();
}
}
void Wireframe2gcode::go_down(WeaveLayer& layer, WeaveConnectionPart& part, unsigned int segment_idx)
{
WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to;
if (go_back_to_last_top)
gcode.writeMove(from, speedDown, 0);
if (straight_first_when_going_down <= 0)
{
gcode.writeMove(segment.to, speedDown, extrusion_per_mm_connection);
} else
{
Point3& to = segment.to;
Point3 from = gcode.getPosition();// segment.from;
Point3 vec = to - from;
Point3 in_between = from + vec * straight_first_when_going_down / 100;
Point3 up(in_between.x, in_between.y, from.z);
int64_t new_length = (up - from).vSize() + (to - up).vSize() + 5;
int64_t orr_length = vec.vSize();
double enlargement = new_length / orr_length;
gcode.writeMove(up, speedDown*enlargement, extrusion_per_mm_connection / enlargement);
gcode.writeMove(to, speedDown*enlargement, extrusion_per_mm_connection / enlargement);
}
gcode.writeDelay(bottom_delay);
if (up_dist_half_speed > 0)
{
gcode.writeMove(Point3(0,0,up_dist_half_speed) + gcode.getPosition(), speedUp / 2, extrusion_per_mm_connection * 2);
}
}
void Wireframe2gcode::strategy_knot(WeaveLayer& layer, WeaveConnectionPart& part, unsigned int segment_idx)
{
WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
gcode.writeMove(segment.to, speedUp, extrusion_per_mm_connection);
Point3 next_vector;
if (segment_idx + 1 < part.connection.segments.size())
{
WeaveConnectionSegment& next_segment = part.connection.segments[segment_idx+1];
next_vector = next_segment.to - segment.to;
} else
{
next_vector = part.connection.segments[0].to - segment.to;
}
Point next_dir_2D(next_vector.x, next_vector.y);
next_dir_2D = next_dir_2D * top_jump_dist / vSize(next_dir_2D);
Point3 next_dir (next_dir_2D.X / 2, next_dir_2D.Y / 2, -top_jump_dist);
Point3 current_pos = gcode.getPosition();
gcode.writeMove(current_pos - next_dir, speedUp, 0);
gcode.writeDelay(top_delay);
gcode.writeMove(current_pos + next_dir_2D, speedUp, 0);
}
void Wireframe2gcode::strategy_retract(WeaveLayer& layer, WeaveConnectionPart& part, unsigned int segment_idx)
{
WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to;
RetractionConfig retraction_config;
// TODO: get these from the settings!
retraction_config.amount = 500; //INT2MM(getSettingInt("retractionAmount"))
retraction_config.primeAmount = 0;//INT2MM(getSettingInt("retractionPrime
retraction_config.speed = 20; // 40;
retraction_config.primeSpeed = 15; // 30;
retraction_config.zHop = 0; //getSettingInt("retraction_hop");
double top_retract_pause = 2.0;
int retract_hop_dist = 1000;
bool after_retract_hop = false;
//bool go_horizontal_first = true;
bool lower_retract_start = true;
Point3& to = segment.to;
if (lower_retract_start)
{
Point3 vec = to - from;
Point3 lowering = vec * retract_hop_dist / 2 / vec.vSize();
Point3 lower = to - lowering;
gcode.writeMove(lower, speedUp, extrusion_per_mm_connection);
gcode.writeRetraction(&retraction_config);
gcode.writeMove(to + lowering, speedUp, 0);
gcode.writeDelay(top_retract_pause);
if (after_retract_hop)
gcode.writeMove(to + Point3(0, 0, retract_hop_dist), speedFlat, 0);
} else
{
gcode.writeMove(to, speedUp, extrusion_per_mm_connection);
gcode.writeRetraction(&retraction_config);
gcode.writeMove(to + Point3(0, 0, retract_hop_dist), speedFlat, 0);
gcode.writeDelay(top_retract_pause);
if (after_retract_hop)
gcode.writeMove(to + Point3(0, 0, retract_hop_dist*3), speedFlat, 0);
}
}
void Wireframe2gcode::strategy_compensate(WeaveLayer& layer, WeaveConnectionPart& part, unsigned int segment_idx)
{
WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to;
Point3 to = segment.to + Point3(0, 0, fall_down*(segment.to - from).vSize() / connectionHeight);
Point3 vector = segment.to - from;
Point3 dir = vector * drag_along / vector.vSize();
Point3 next_point;
if (segment_idx + 1 < part.connection.segments.size())
{
WeaveConnectionSegment& next_segment = part.connection.segments[segment_idx+1];
next_point = next_segment.to;
} else
{
next_point = part.connection.segments[0].to;
}
Point3 next_vector = next_point - segment.to;
Point next_dir_2D(next_vector.x, next_vector.y);
int64_t next_dir_2D_size = vSize(next_dir_2D);
if (next_dir_2D_size > 0)
next_dir_2D = next_dir_2D * drag_along / next_dir_2D_size;
Point3 next_dir (next_dir_2D.X, next_dir_2D.Y, 0);
Point3 newTop = to - next_dir + dir;
int64_t orrLength = (segment.to - from).vSize() + next_vector.vSize() + 1; // + 1 in order to avoid division by zero
int64_t newLength = (newTop - from).vSize() + (next_point - newTop).vSize() + 1; // + 1 in order to avoid division by zero
gcode.writeMove(newTop, speedUp * newLength / orrLength, extrusion_per_mm_connection * orrLength / newLength);
}
void Wireframe2gcode::handle_segment(WeaveLayer& layer, WeaveConnectionPart& part, unsigned int segment_idx)
{
WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
switch(segment.segmentType)
{
case WeaveSegmentType::MOVE:
writeMoveWithRetract(segment.to);
break;
case WeaveSegmentType::DOWN:
go_down(layer, part, segment_idx);
break;
case WeaveSegmentType::FLAT:
DEBUG_SHOW("flat piece in connection?!!?!");
break;
case WeaveSegmentType::UP:
if (strategy == STRATEGY_KNOT)
{
strategy_knot(layer, part, segment_idx);
} else if (strategy == STRATEGY_RETRACT)
{
strategy_retract(layer, part, segment_idx);
} else if (strategy == STRATEGY_COMPENSATE)
{
strategy_compensate(layer, part, segment_idx);
}
break;
case WeaveSegmentType::DOWN_AND_FLAT:
logError("Down and flat move in non-horizontal connection!");
break;
}
}
void Wireframe2gcode::handle_roof_segment(WeaveRoofPart& inset, WeaveConnectionPart& part, unsigned int segment_idx)
{
WeaveConnectionSegment& segment = part.connection.segments[segment_idx];
Point3 from = (segment_idx == 0)? part.connection.from : part.connection.segments[segment_idx - 1].to;
WeaveConnectionSegment* next_segment = nullptr;
if (segment_idx + 1 < part.connection.segments.size())
next_segment = &part.connection.segments[segment_idx+1];
switch(segment.segmentType)
{
case WeaveSegmentType::MOVE:
case WeaveSegmentType::DOWN_AND_FLAT:
if (next_segment && next_segment->segmentType != WeaveSegmentType::DOWN_AND_FLAT)
{
writeMoveWithRetract(segment.to);
}
break;
case WeaveSegmentType::UP:
{
Point3 to = segment.to + Point3(0, 0, roof_fall_down);
Point3 vector = segment.to - from;
if (vector.vSize2() == 0) return;
Point3 dir = vector * roof_drag_along / vector.vSize();
Point3 next_vector;
if (next_segment)
{
next_vector = next_segment->to - segment.to;
} else
{
next_vector = part.connection.segments[0].to - segment.to;
}
Point next_dir_2D(next_vector.x, next_vector.y);
Point3 detoured = to + dir;
if (vSize2(next_dir_2D) > 0)
{
next_dir_2D = next_dir_2D * roof_drag_along / vSize(next_dir_2D);
Point3 next_dir (next_dir_2D.X, next_dir_2D.Y, 0);
detoured -= next_dir;
}
gcode.writeMove(detoured, speedUp, extrusion_per_mm_connection);
}
break;
case WeaveSegmentType::DOWN:
gcode.writeMove(segment.to, speedDown, extrusion_per_mm_connection);
gcode.writeDelay(roof_outer_delay);
break;
case WeaveSegmentType::FLAT:
logError("Flat move in connection!");
break;
}
}
void Wireframe2gcode::writeFill(std::vector<WeaveRoofPart>& fill_insets, Polygons& roof_outlines
, std::function<void (Wireframe2gcode& thiss, WeaveRoofPart& inset, WeaveConnectionPart& part, unsigned int segment_idx)> connectionHandler
, std::function<void (Wireframe2gcode& thiss, WeaveConnectionSegment& p)> flatHandler)
{
// bottom:
gcode.writeTypeComment("FILL");
for (unsigned int inset_idx = 0; inset_idx < fill_insets.size(); inset_idx++)
{
WeaveRoofPart& inset = fill_insets[inset_idx];
for (unsigned int inset_part_nr = 0; inset_part_nr < inset.connections.size(); inset_part_nr++)
{
WeaveConnectionPart& inset_part = inset.connections[inset_part_nr];
std::vector<WeaveConnectionSegment>& segments = inset_part.connection.segments;
gcode.writeTypeComment("SUPPORT"); // connection
if (segments.size() == 0) continue;
Point3 first_extrusion_from = inset_part.connection.from;
unsigned int first_segment_idx;
for (first_segment_idx = 0; first_segment_idx < segments.size() && segments[first_segment_idx].segmentType == WeaveSegmentType::MOVE; first_segment_idx++)
{ // finds the first segment which is not a move
first_extrusion_from = segments[first_segment_idx].to;
}
if (first_segment_idx == segments.size())
continue;
writeMoveWithRetract(first_extrusion_from);
for (unsigned int segment_idx = first_segment_idx; segment_idx < segments.size(); segment_idx++)
{
connectionHandler(*this, inset, inset_part, segment_idx);
}
gcode.writeTypeComment("WALL-INNER"); // top
for (unsigned int segment_idx = 0; segment_idx < segments.size(); segment_idx++)
{
WeaveConnectionSegment& segment = segments[segment_idx];
if (segment.segmentType == WeaveSegmentType::DOWN) continue;
flatHandler(*this, segment);
}
}
}
gcode.writeTypeComment("WALL-OUTER"); // outer perimeter of the flat parts
for (PolygonRef poly : roof_outlines)
{
writeMoveWithRetract(poly[poly.size() - 1]);
for (Point& p : poly)
{
Point3 to(p.X, p.Y, gcode.getPositionZ());
WeaveConnectionSegment segment(to, WeaveSegmentType::FLAT);
flatHandler(*this, segment);
}
}
}
void Wireframe2gcode::writeMoveWithRetract(Point3 to)
{
if ((gcode.getPosition() - to).vSize2() >= nozzle_top_diameter * nozzle_top_diameter * 2 * 2)
gcode.writeRetraction(&standard_retraction_config);
gcode.writeMove(to, moveSpeed, 0);
}
void Wireframe2gcode::writeMoveWithRetract(Point to)
{
if (vSize2(gcode.getPositionXY() - to) >= nozzle_top_diameter * nozzle_top_diameter * 2 * 2)
gcode.writeRetraction(&standard_retraction_config);
gcode.writeMove(to, moveSpeed, 0);
}
Wireframe2gcode::Wireframe2gcode(Weaver& weaver, GCodeExport& gcode, SettingsBase* settings_base)
: SettingsBase(settings_base)
, gcode(gcode)
{
wireFrame = weaver.wireFrame;
initial_layer_thickness = getSettingInMicrons("layer_height_0");
connectionHeight = getSettingInMicrons("wireframe_height");
roof_inset = getSettingInMicrons("wireframe_roof_inset");
filament_diameter = getSettingInMicrons("material_diameter");
extrusionWidth = getSettingInMicrons("wall_line_width_x");
flowConnection = getSettingInPercentage("wireframe_flow_connection");
flowFlat = getSettingInPercentage("wireframe_flow_flat");
double filament_area = /* M_PI * */ (INT2MM(filament_diameter) / 2.0) * (INT2MM(filament_diameter) / 2.0);
double lineArea = /* M_PI * */ (INT2MM(extrusionWidth) / 2.0) * (INT2MM(extrusionWidth) / 2.0);
extrusion_per_mm_connection = lineArea / filament_area * double(flowConnection) / 100.0;
extrusion_per_mm_flat = lineArea / filament_area * double(flowFlat) / 100.0;
nozzle_outer_diameter = getSettingInMicrons("machine_nozzle_tip_outer_diameter"); // ___ ___ .
nozzle_head_distance = getSettingInMicrons("machine_nozzle_head_distance"); // | | .
nozzle_expansion_angle = getSettingInAngleRadians("machine_nozzle_expansion_angle"); // \_U_/ .
nozzle_clearance = getSettingInMicrons("wireframe_nozzle_clearance"); // at least line width
nozzle_top_diameter = tan(nozzle_expansion_angle) * connectionHeight + nozzle_outer_diameter + nozzle_clearance;
moveSpeed = 40;
speedBottom = getSettingInMillimetersPerSecond("wireframe_printspeed_bottom");
speedUp = getSettingInMillimetersPerSecond("wireframe_printspeed_up");
speedDown = getSettingInMillimetersPerSecond("wireframe_printspeed_down");
speedFlat = getSettingInMillimetersPerSecond("wireframe_printspeed_flat");
flat_delay = getSettingInSeconds("wireframe_flat_delay");
bottom_delay = getSettingInSeconds("wireframe_bottom_delay");
top_delay = getSettingInSeconds("wireframe_top_delay");
up_dist_half_speed = getSettingInMicrons("wireframe_up_half_speed");
top_jump_dist = getSettingInMicrons("wireframe_top_jump");
fall_down = getSettingInMicrons("wireframe_fall_down");
drag_along = getSettingInMicrons("wireframe_drag_along");
strategy = STRATEGY_COMPENSATE;
if (getSettingString("wireframe_strategy") == "Compensate")
strategy = STRATEGY_COMPENSATE;
if (getSettingString("wireframe_strategy") == "Knot")
strategy = STRATEGY_KNOT;
if (getSettingString("wireframe_strategy") == "Retract")
strategy = STRATEGY_RETRACT;
go_back_to_last_top = false;
straight_first_when_going_down = getSettingInPercentage("wireframe_straight_before_down");
roof_fall_down = getSettingInMicrons("wireframe_roof_fall_down");
roof_drag_along = getSettingInMicrons("wireframe_roof_drag_along");
roof_outer_delay = getSettingInSeconds("wireframe_roof_outer_delay");
standard_retraction_config.amount = INT2MM(getSettingInMicrons("retraction_amount"));
standard_retraction_config.primeAmount = INT2MM(getSettingInMicrons("retraction_extra_prime_amount"));
standard_retraction_config.speed = getSettingInMillimetersPerSecond("retraction_retract_speed");
standard_retraction_config.primeSpeed = getSettingInMillimetersPerSecond("retraction_prime_speed");
standard_retraction_config.zHop = getSettingInMicrons("retraction_hop");
}
} // namespace cura
+155
Ver Arquivo
@@ -0,0 +1,155 @@
#ifndef WIREFRAME2GCODE_H
#define WIREFRAME2GCODE_H
#include <functional> // passing function pointer or lambda as argument to a function
#include "weaveDataStorage.h"
#include "commandSocket.h"
#include "settings.h"
#include "modelFile/modelFile.h" // PrintObject
#include "slicer.h"
#include "utils/polygon.h"
#include "Weaver.h"
#include "debug.h"
namespace cura
{
/*!
* Export class for exporting wireframe print gcode / weaver gcode / wireprint gcode.
*/
class Wireframe2gcode : public SettingsBase
{
private:
static const int STRATEGY_COMPENSATE = 0;
static const int STRATEGY_KNOT = 1;
static const int STRATEGY_RETRACT = 2;
int initial_layer_thickness;
int filament_diameter;
int extrusionWidth;
int flowConnection;// = getSettingInt("wireframeFlowConnection");
int flowFlat; // = getSettingInt("wireframeFlowFlat");
double extrusion_per_mm_connection; // = lineArea / filament_area * double(flowConnection) / 100.0;
double extrusion_per_mm_flat; // = lineArea / filament_area * double(flowFlat) / 100.0;
int nozzle_outer_diameter; // = getSettingInt("machineNozzleTipOuterDiameter"); // ___ ___ .
int nozzle_head_distance; // = getSettingInt("machineNozzleHeadDistance"); // | | .
int nozzle_expansion_angle; // = getSettingInt("machineNozzleExpansionAngle"); // \_U_/ .
int nozzle_clearance; // = getSettingInt("wireframeNozzleClearance"); // at least line width
int nozzle_top_diameter; // = tan(static_cast<double>(nozzle_expansion_angle)/180.0 * M_PI) * connectionHeight + nozzle_outer_diameter + nozzle_clearance;
int moveSpeed; // = 40;
int speedBottom; // = getSettingInt("wireframePrintspeedBottom");
int speedUp; // = getSettingInt("wireframePrintspeedUp");
int speedDown; // = getSettingInt("wireframePrintspeedDown");
int speedFlat; // = getSettingInt("wireframePrintspeedFlat");
int connectionHeight; // = getSettingInt("wireframeConnectionHeight");
int roof_inset; // = getSettingInt("wireframeRoofInset");
double flat_delay; // = getSettingInt("wireframeFlatDelay")/100.0;
double bottom_delay; // = getSettingInt("wireframeBottomDelay")/100.0;
double top_delay; // = getSettingInt("wireframeTopDelay")/100.0;
int up_dist_half_speed; // = getSettingInt("wireframeUpDistHalfSpeed");
int top_jump_dist; // = getSettingInt("wireframeTopJump");
int fall_down; // = getSettingInt("wireframeFallDown");
int drag_along; // = getSettingInt("wireframeDragAlong");
int strategy; // = getSettingInt("wireframeStrategy"); // HIGHER_BEND_NO_STRAIGHTEN; // RETRACT_TO_STRAIGHTEN; // MOVE_TO_STRAIGHTEN; //
double go_back_to_last_top; // = false;
int straight_first_when_going_down; // = getSettingInt("wireframeStraightBeforeDown"); // %
int roof_fall_down; // = getSettingInt("wireframeRoofFallDown");
int roof_drag_along; // = getSettingInt("wireframeRoofDragAlong");
double roof_outer_delay; // = getSettingInt("wireframeRoofOuterDelay")/100.0;
RetractionConfig standard_retraction_config; //!< The standard retraction settings used for moves between parts etc.
public:
GCodeExport& gcode; //!< Where the result is 'stored'
Wireframe2gcode(Weaver& weaver, GCodeExport& gcode, SettingsBase* settings_base);
void writeGCode(CommandSocket* commandSocket, int& maxObjectHeight);
private:
WireFrame wireFrame;
void writeFill(std::vector<WeaveRoofPart>& fill_insets, Polygons& outlines
, std::function<void (Wireframe2gcode& thiss, WeaveRoofPart& inset, WeaveConnectionPart& part, unsigned int segment_idx)> connectionHandler
, std::function<void (Wireframe2gcode& thiss, WeaveConnectionSegment& p)> flatHandler);
/*!
* Function for writing the gcode for a diagonally down movement of a connection.
*
* \param layer The layer in which the segment is
* \param part The part in which the segment is
* \param segment_idx The index of the segment in the \p part
*/
void go_down(WeaveLayer& layer, WeaveConnectionPart& part, unsigned int segment_idx);
/*!
* Function for writing the gcode of an upward move of a connection, which does a couple of small moves at the top.
*
* \param layer The layer in which the segment is
* \param part The part in which the segment is
* \param segment_idx The index of the segment in the \p part
*/
void strategy_knot(WeaveLayer& layer, WeaveConnectionPart& part, unsigned int segment_idx);
/*!
* Function for writing the gcode of an upward move of a connection, which does a retract at the top.
*
* \param layer The layer in which the segment is
* \param part The part in which the segment is
* \param segment_idx The index of the segment in the \p part
*/
void strategy_retract(WeaveLayer& layer, WeaveConnectionPart& part, unsigned int segment_idx);
/*!
* Function for writing the gcode of an upward move of a connection, which goes Wireframe2gcode::fall_down further up
* and Wireframe2gcode::drag_along back from the direction it will go to next.
*
* \param layer The layer in which the segment is
* \param part The part in which the segment is
* \param segment_idx The index of the segment in the \p part
*/
void strategy_compensate(WeaveLayer& layer, WeaveConnectionPart& part, unsigned int segment_idx);
/*!
* Function writing the gcode of a segment in the connection between two layers.
*
* \param layer The layer in which the segment is
* \param part The part in which the segment is
* \param segment_idx The index of the segment in the \p part
*/
void handle_segment(WeaveLayer& layer, WeaveConnectionPart& part, unsigned int segment_idx);
/*!
* Function for writing the gcode of a segment in the connection between two roof insets / floor outsets.
*
* \param inset The inset in which the segment is
* \param part the part in which the segment is
* \param segment_idx The index of the segment in the \p part
*/
void handle_roof_segment(WeaveRoofPart& inset, WeaveConnectionPart& part, unsigned int segment_idx);
/*!
* Write a move action to gcode, inserting a retraction if neccesary.
*
* \param to The 3D destination of the move
*/
void writeMoveWithRetract(Point3 to);
/*!
* Write a move action to gcode, inserting a retraction if neccesary.
*
* \param to The 2D destination of the move
*/
void writeMoveWithRetract(Point to);
};
}//namespace cura
#endif//WIREFRAME2GCODE_H
+59 -56
Ver Arquivo
@@ -1,56 +1,59 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "bridge.h"
#include "utils/polygondebug.h"
int bridgeAngle(SliceLayerPart* part, SliceLayer* prevLayer)
{
//To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer.
// This gives us the islands that the layer rests on.
Polygons islands;
for(unsigned int n=0; n<prevLayer->parts.size(); n++)
{
if (!part->boundaryBox.hit(prevLayer->parts[n].boundaryBox)) continue;
islands.add(part->outline.intersection(prevLayer->parts[n].outline));
}
if (islands.size() > 5)
return -1;
//Next find the 2 largest islands that we rest on.
double area1 = 0;
double area2 = 0;
int idx1 = -1;
int idx2 = -1;
for(unsigned int n=0; n<islands.size(); n++)
{
//Skip internal holes
if (!islands[n].orientation())
continue;
double area = fabs(islands[n].area());
if (area > area1)
{
if (area1 > area2)
{
area2 = area1;
idx2 = idx1;
}
area1 = area;
idx1 = n;
}else if (area > area2)
{
area2 = area;
idx2 = n;
}
}
if (idx1 < 0 || idx2 < 0)
return -1;
Point center1 = islands[idx1].centerOfMass();
Point center2 = islands[idx2].centerOfMass();
double angle = atan2(center2.X - center1.X, center2.Y - center1.Y) / M_PI * 180;
if (angle < 0) angle += 360;
return angle;
}
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "bridge.h"
namespace cura {
int bridgeAngle(Polygons outline, SliceLayer* prevLayer)
{
AABB boundaryBox(outline);
//To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer.
// This gives us the islands that the layer rests on.
Polygons islands;
for(auto prevLayerPart : prevLayer->parts)
{
if (!boundaryBox.hit(prevLayerPart.boundaryBox))
continue;
islands.add(outline.intersection(prevLayerPart.outline));
}
if (islands.size() > 5 || islands.size() < 1)
return -1;
//Next find the 2 largest islands that we rest on.
double area1 = 0;
double area2 = 0;
int idx1 = -1;
int idx2 = -1;
for(unsigned int n=0; n<islands.size(); n++)
{
//Skip internal holes
if (!islands[n].orientation())
continue;
double area = fabs(islands[n].area());
if (area > area1)
{
if (area1 > area2)
{
area2 = area1;
idx2 = idx1;
}
area1 = area;
idx1 = n;
}else if (area > area2)
{
area2 = area;
idx2 = n;
}
}
if (idx1 < 0 || idx2 < 0)
return -1;
Point center1 = islands[idx1].centerOfMass();
Point center2 = islands[idx2].centerOfMass();
return angle(center2 - center1);
}
}//namespace cura
+13 -9
Ver Arquivo
@@ -1,9 +1,13 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef BRIDGE_H
#define BRIDGE_H
#include "sliceDataStorage.h"
int bridgeAngle(SliceLayerPart* part, SliceLayer* prevLayer);
#endif//BRIDGE_H
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef BRIDGE_H
#define BRIDGE_H
#include "sliceDataStorage.h"
namespace cura {
int bridgeAngle(Polygons outline, SliceLayer* prevLayer);
}//namespace cura
#endif//BRIDGE_H
+237 -256
Ver Arquivo
@@ -1,256 +1,237 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "comb.h"
bool Comb::preTest(Point startPoint, Point endPoint)
{
return collisionTest(startPoint, endPoint);
}
bool Comb::collisionTest(Point startPoint, Point endPoint)
{
Point diff = endPoint - startPoint;
matrix = PointMatrix(diff);
sp = matrix.apply(startPoint);
ep = matrix.apply(endPoint);
for(unsigned int n=0; n<boundery.size(); n++)
{
if (boundery[n].size() < 1)
continue;
Point p0 = matrix.apply(boundery[n][boundery[n].size()-1]);
for(unsigned int i=0; i<boundery[n].size(); i++)
{
Point p1 = matrix.apply(boundery[n][i]);
if ((p0.Y > sp.Y && p1.Y < sp.Y) || (p1.Y > sp.Y && p0.Y < sp.Y))
{
int64_t x = p0.X + (p1.X - p0.X) * (sp.Y - p0.Y) / (p1.Y - p0.Y);
if (x > sp.X && x < ep.X)
return true;
}
p0 = p1;
}
}
return false;
}
void Comb::calcMinMax()
{
for(unsigned int n=0; n<boundery.size(); n++)
{
minX[n] = LLONG_MAX;
maxX[n] = LLONG_MIN;
Point p0 = matrix.apply(boundery[n][boundery[n].size()-1]);
for(unsigned int i=0; i<boundery[n].size(); i++)
{
Point p1 = matrix.apply(boundery[n][i]);
if ((p0.Y > sp.Y && p1.Y < sp.Y) || (p1.Y > sp.Y && p0.Y < sp.Y))
{
int64_t x = p0.X + (p1.X - p0.X) * (sp.Y - p0.Y) / (p1.Y - p0.Y);
if (x >= sp.X && x <= ep.X)
{
if (x < minX[n]) { minX[n] = x; minIdx[n] = i; }
if (x > maxX[n]) { maxX[n] = x; maxIdx[n] = i; }
}
}
p0 = p1;
}
}
}
unsigned int Comb::getPolygonAbove(int64_t x)
{
int64_t min = LLONG_MAX;
unsigned int ret = UINT_MAX;
for(unsigned int n=0; n<boundery.size(); n++)
{
if (minX[n] > x && minX[n] < min)
{
min = minX[n];
ret = n;
}
}
return ret;
}
Point Comb::getBounderyPointWithOffset(unsigned int polygonNr, unsigned int idx)
{
Point p0 = boundery[polygonNr][(idx > 0) ? (idx - 1) : (boundery[polygonNr].size() - 1)];
Point p1 = boundery[polygonNr][idx];
Point p2 = boundery[polygonNr][(idx < (boundery[polygonNr].size() - 1)) ? (idx + 1) : (0)];
Point off0 = crossZ(normal(p1 - p0, 1000));
Point off1 = crossZ(normal(p2 - p1, 1000));
Point n = normal(off0 + off1, 200);
return p1 + n;
}
Comb::Comb(Polygons& _boundery)
: boundery(_boundery)
{
minX = new int64_t[boundery.size()];
maxX = new int64_t[boundery.size()];
minIdx = new unsigned int[boundery.size()];
maxIdx = new unsigned int[boundery.size()];
}
Comb::~Comb()
{
delete[] minX;
delete[] maxX;
delete[] minIdx;
delete[] maxIdx;
}
bool Comb::checkInside(Point p)
{
//Check if we are inside the comb boundary. We do this by tracing from the point towards the negative X direction,
// every boundary we cross increments the crossings counter. If we have an even number of crossings then we are not inside the boundary
int crossings = 0;
for(unsigned int n=0; n<boundery.size(); n++)
{
if (boundery[n].size() < 1)
continue;
Point p0 = boundery[n][boundery[n].size()-1];
for(unsigned int i=0; i<boundery[n].size(); i++)
{
Point p1 = boundery[n][i];
if ((p0.Y >= p.Y && p1.Y < p.Y) || (p1.Y > p.Y && p0.Y <= p.Y))
{
int64_t x = p0.X + (p1.X - p0.X) * (p.Y - p0.Y) / (p1.Y - p0.Y);
if (x >= p.X)
crossings ++;
}
p0 = p1;
}
}
if ((crossings % 2) == 0)
return false;
return true;
}
bool Comb::moveInside(Point* p, int distance)
{
Point ret = *p;
int64_t bestDist = 2000LL * 2000LL;
for(unsigned int n=0; n<boundery.size(); n++)
{
if (boundery[n].size() < 1)
continue;
Point p0 = boundery[n][boundery[n].size()-1];
for(unsigned int i=0; i<boundery[n].size(); i++)
{
Point p1 = boundery[n][i];
//Q = A + Normal( B - A ) * ((( B - A ) dot ( P - A )) / VSize( A - B ));
Point pDiff = p1 - p0;
int64_t lineLength = vSize(pDiff);
int64_t distOnLine = dot(pDiff, *p - p0) / lineLength;
if (distOnLine < 10)
distOnLine = 10;
if (distOnLine > lineLength - 10)
distOnLine = lineLength - 10;
Point q = p0 + pDiff * distOnLine / lineLength;
int64_t dist = vSize2(q - *p);
if (dist < bestDist)
{
bestDist = dist;
ret = q + crossZ(normal(p1 - p0, distance));
}
p0 = p1;
}
}
if (bestDist < 2000LL * 2000LL)
{
*p = ret;
return true;
}
return false;
}
bool Comb::calc(Point startPoint, Point endPoint, vector<Point>& combPoints)
{
if (shorterThen(endPoint - startPoint, 1500))
return true;
bool addEndpoint = false;
//Check if we are inside the comb boundaries
if (!checkInside(startPoint))
{
if (!moveInside(&startPoint)) //If we fail to move the point inside the comb boundary we need to retract.
return false;
combPoints.push_back(startPoint);
}
if (!checkInside(endPoint))
{
if (!moveInside(&endPoint)) //If we fail to move the point inside the comb boundary we need to retract.
return false;
addEndpoint = true;
}
//Check if we are crossing any bounderies, and pre-calculate some values.
if (!preTest(startPoint, endPoint))
{
//We're not crossing any boundaries. So skip the comb generation.
if (!addEndpoint && combPoints.size() == 0) //Only skip if we didn't move the start and end point.
return true;
}
//Calculate the minimum and maximum positions where we cross the comb boundary
calcMinMax();
int64_t x = sp.X;
vector<Point> pointList;
//Now walk trough the crossings, for every boundary we cross, find the initial cross point and the exit point. Then add all the points in between
// to the pointList and continue with the next boundary we will cross, until there are no more boundaries to cross.
// This gives a path from the start to finish curved around the holes that it encounters.
while(true)
{
unsigned int n = getPolygonAbove(x);
if (n == UINT_MAX) break;
pointList.push_back(matrix.unapply(Point(minX[n] - 200, sp.Y)));
if ( (minIdx[n] - maxIdx[n] + boundery[n].size()) % boundery[n].size() > (maxIdx[n] - minIdx[n] + boundery[n].size()) % boundery[n].size())
{
for(unsigned int i=minIdx[n]; i != maxIdx[n]; i = (i < boundery[n].size() - 1) ? (i + 1) : (0))
{
pointList.push_back(getBounderyPointWithOffset(n, i));
}
}else{
minIdx[n]--;
if (minIdx[n] == UINT_MAX) minIdx[n] = boundery[n].size() - 1;
maxIdx[n]--;
if (maxIdx[n] == UINT_MAX) maxIdx[n] = boundery[n].size() - 1;
for(unsigned int i=minIdx[n]; i != maxIdx[n]; i = (i > 0) ? (i - 1) : (boundery[n].size() - 1))
{
pointList.push_back(getBounderyPointWithOffset(n, i));
}
}
pointList.push_back(matrix.unapply(Point(maxX[n] + 200, sp.Y)));
x = maxX[n];
}
pointList.push_back(endPoint);
//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.
Point p0 = startPoint;
for(unsigned int n=1; n<pointList.size(); n++)
{
if (collisionTest(p0, pointList[n]))
{
if (collisionTest(p0, pointList[n-1]))
return false;
p0 = pointList[n-1];
combPoints.push_back(p0);
}
}
if (addEndpoint)
combPoints.push_back(endPoint);
return true;
}
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "comb.h"
namespace cura {
bool Comb::preTest(Point startPoint, Point endPoint)
{
return collisionTest(startPoint, endPoint);
}
bool Comb::collisionTest(Point startPoint, Point endPoint)
{
Point diff = endPoint - startPoint;
matrix = PointMatrix(diff);
sp = matrix.apply(startPoint);
ep = matrix.apply(endPoint);
for(unsigned int n=0; n<boundery.size(); n++)
{
if (boundery[n].size() < 1)
continue;
Point p0 = matrix.apply(boundery[n][boundery[n].size()-1]);
for(unsigned int i=0; i<boundery[n].size(); i++)
{
Point p1 = matrix.apply(boundery[n][i]);
if ((p0.Y > sp.Y && p1.Y < sp.Y) || (p1.Y > sp.Y && p0.Y < sp.Y))
{
int64_t x = p0.X + (p1.X - p0.X) * (sp.Y - p0.Y) / (p1.Y - p0.Y);
if (x > sp.X && x < ep.X)
return true;
}
p0 = p1;
}
}
return false;
}
void Comb::calcMinMax()
{
for(unsigned int n=0; n<boundery.size(); n++)
{
minX[n] = INT64_MAX;
maxX[n] = INT64_MIN;
Point p0 = matrix.apply(boundery[n][boundery[n].size()-1]);
for(unsigned int i=0; i<boundery[n].size(); i++)
{
Point p1 = matrix.apply(boundery[n][i]);
if ((p0.Y > sp.Y && p1.Y < sp.Y) || (p1.Y > sp.Y && p0.Y < sp.Y))
{
int64_t x = p0.X + (p1.X - p0.X) * (sp.Y - p0.Y) / (p1.Y - p0.Y);
if (x >= sp.X && x <= ep.X)
{
if (x < minX[n]) { minX[n] = x; minIdx[n] = i; }
if (x > maxX[n]) { maxX[n] = x; maxIdx[n] = i; }
}
}
p0 = p1;
}
}
}
unsigned int Comb::getPolygonAbove(int64_t x)
{
int64_t min = POINT_MAX;
unsigned int ret = NO_INDEX;
for(unsigned int n=0; n<boundery.size(); n++)
{
if (minX[n] > x && minX[n] < min)
{
min = minX[n];
ret = n;
}
}
return ret;
}
Point Comb::getBounderyPointWithOffset(unsigned int polygonNr, unsigned int idx)
{
Point p0 = boundery[polygonNr][(idx > 0) ? (idx - 1) : (boundery[polygonNr].size() - 1)];
Point p1 = boundery[polygonNr][idx];
Point p2 = boundery[polygonNr][(idx < (boundery[polygonNr].size() - 1)) ? (idx + 1) : (0)];
Point off0 = crossZ(normal(p1 - p0, MM2INT(1.0)));
Point off1 = crossZ(normal(p2 - p1, MM2INT(1.0)));
Point n = normal(off0 + off1, MM2INT(0.2));
return p1 + n;
}
Comb::Comb(Polygons& _boundery)
: boundery(_boundery)
{
minX = new int64_t[boundery.size()];
maxX = new int64_t[boundery.size()];
minIdx = new unsigned int[boundery.size()];
maxIdx = new unsigned int[boundery.size()];
}
Comb::~Comb()
{
delete[] minX;
delete[] maxX;
delete[] minIdx;
delete[] maxIdx;
}
bool Comb::moveInside(Point* p, int distance)
{
Point ret = *p;
int64_t bestDist = MM2INT(2.0) * MM2INT(2.0);
for(unsigned int n=0; n<boundery.size(); n++)
{
if (boundery[n].size() < 1)
continue;
Point p0 = boundery[n][boundery[n].size()-1];
for(unsigned int i=0; i<boundery[n].size(); i++)
{
Point p1 = boundery[n][i];
//Q = A + Normal( B - A ) * ((( B - A ) dot ( P - A )) / VSize( A - B ));
Point pDiff = p1 - p0;
int64_t lineLength = vSize(pDiff);
int64_t distOnLine = dot(pDiff, *p - p0) / lineLength;
if (distOnLine < 10)
distOnLine = 10;
if (distOnLine > lineLength - 10)
distOnLine = lineLength - 10;
Point q = p0 + pDiff * distOnLine / lineLength;
int64_t dist = vSize2(q - *p);
if (dist < bestDist)
{
bestDist = dist;
ret = q + crossZ(normal(p1 - p0, distance));
}
p0 = p1;
}
}
if (bestDist < MM2INT(2.0) * MM2INT(2.0))
{
*p = ret;
return true;
}
return false;
}
bool Comb::calc(Point startPoint, Point endPoint, std::vector<Point>& combPoints)
{
if (shorterThen(endPoint - startPoint, MM2INT(1.5)))
return true;
bool addEndpoint = false;
//Check if we are inside the comb boundaries
if (!boundery.inside(startPoint))
{
if (!moveInside(&startPoint)) //If we fail to move the point inside the comb boundary we need to retract.
return false;
combPoints.push_back(startPoint);
}
if (!boundery.inside(endPoint))
{
if (!moveInside(&endPoint)) //If we fail to move the point inside the comb boundary we need to retract.
return false;
addEndpoint = true;
}
//Check if we are crossing any bounderies, and pre-calculate some values.
if (!preTest(startPoint, endPoint))
{
//We're not crossing any boundaries. So skip the comb generation.
if (!addEndpoint && combPoints.size() == 0) //Only skip if we didn't move the start and end point.
return true;
}
//Calculate the minimum and maximum positions where we cross the comb boundary
calcMinMax();
int64_t x = sp.X;
std::vector<Point> pointList;
//Now walk trough the crossings, for every boundary we cross, find the initial cross point and the exit point. Then add all the points in between
// to the pointList and continue with the next boundary we will cross, until there are no more boundaries to cross.
// This gives a path from the start to finish curved around the holes that it encounters.
while(true)
{
unsigned int n = getPolygonAbove(x);
if (n == NO_INDEX) break;
pointList.push_back(matrix.unapply(Point(minX[n] - MM2INT(0.2), sp.Y)));
if ( (minIdx[n] - maxIdx[n] + boundery[n].size()) % boundery[n].size() > (maxIdx[n] - minIdx[n] + boundery[n].size()) % boundery[n].size())
{
for(unsigned int i=minIdx[n]; i != maxIdx[n]; i = (i < boundery[n].size() - 1) ? (i + 1) : (0))
{
pointList.push_back(getBounderyPointWithOffset(n, i));
}
}else{
if (minIdx[n] == 0)
minIdx[n] = boundery[n].size() - 1;
else
minIdx[n]--;
if (maxIdx[n] == 0)
maxIdx[n] = boundery[n].size() - 1;
else
maxIdx[n]--;
for(unsigned int i=minIdx[n]; i != maxIdx[n]; i = (i > 0) ? (i - 1) : (boundery[n].size() - 1))
{
pointList.push_back(getBounderyPointWithOffset(n, i));
}
}
pointList.push_back(matrix.unapply(Point(maxX[n] + MM2INT(0.2), sp.Y)));
x = maxX[n];
}
pointList.push_back(endPoint);
//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.
Point p0 = startPoint;
for(unsigned int n=1; n<pointList.size(); n++)
{
if (collisionTest(p0, pointList[n]))
{
if (collisionTest(p0, pointList[n-1]))
return false;
p0 = pointList[n-1];
combPoints.push_back(p0);
}
}
if (addEndpoint)
combPoints.push_back(endPoint);
return true;
}
}//namespace cura
+44 -41
Ver Arquivo
@@ -1,41 +1,44 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef COMB_H
#define COMB_H
#include "utils/polygon.h"
class Comb
{
private:
Polygons& boundery;
int64_t* minX;
int64_t* maxX;
unsigned int* minIdx;
unsigned int* maxIdx;
PointMatrix matrix;
Point sp;
Point ep;
bool preTest(Point startPoint, Point endPoint);
bool collisionTest(Point startPoint, Point endPoint);
void calcMinMax();
unsigned int getPolygonAbove(int64_t x);
Point getBounderyPointWithOffset(unsigned int polygonNr, unsigned int idx);
public:
Comb(Polygons& _boundery);
~Comb();
bool checkInside(Point p);
bool moveInside(Point* p, int distance = 100);
bool calc(Point startPoint, Point endPoint, vector<Point>& combPoints);
};
#endif//COMB_H
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef COMB_H
#define COMB_H
#include "utils/polygon.h"
namespace cura {
class Comb
{
private:
Polygons& boundery;
int64_t* minX;
int64_t* maxX;
unsigned int* minIdx;
unsigned int* maxIdx;
PointMatrix matrix;
Point sp;
Point ep;
bool preTest(Point startPoint, Point endPoint);
bool collisionTest(Point startPoint, Point endPoint);
void calcMinMax();
unsigned int getPolygonAbove(int64_t x);
Point getBounderyPointWithOffset(unsigned int polygonNr, unsigned int idx);
public:
Comb(Polygons& _boundery);
~Comb();
bool inside(const Point p) { return boundery.inside(p); }
bool moveInside(Point* p, int distance = 100);
bool calc(Point startPoint, Point endPoint, std::vector<Point>& combPoints);
};
}//namespace cura
#endif//COMB_H
+274
Ver Arquivo
@@ -0,0 +1,274 @@
#include "utils/logoutput.h"
#include "commandSocket.h"
#include "fffProcessor.h"
#include <thread>
#include <cinttypes>
#include <Arcus/Socket.h>
#ifdef _WIN32
#include <windows.h>
#endif
namespace cura {
#define BYTES_PER_FLOAT 4
#define FLOATS_PER_VECTOR 3
#define VECTORS_PER_FACE 3
class CommandSocket::Private
{
public:
Private()
: processor(nullptr)
, socket(nullptr)
, object_count(0)
, current_object_number(0)
, currentSlicedObject(nullptr)
, slicedObjects(0)
{ }
Cura::Layer* getLayerById(int id);
fffProcessor* processor;
Arcus::Socket* socket;
int object_count;
int current_object_number;
std::shared_ptr<Cura::SlicedObjectList> slicedObjectList;
Cura::SlicedObject* currentSlicedObject;
int slicedObjects;
std::vector<int64_t> objectIds;
std::string tempGCodeFile;
std::ostringstream gcode_output_stream;
std::shared_ptr<PrintObject> objectToSlice;
};
CommandSocket::CommandSocket(fffProcessor* processor)
: d(new Private)
{
d->processor = processor;
d->processor->setCommandSocket(this);
}
void CommandSocket::connect(const std::string& ip, int port)
{
d->socket = new Arcus::Socket();
d->socket->registerMessageType(1, &Cura::ObjectList::default_instance());
d->socket->registerMessageType(2, &Cura::SlicedObjectList::default_instance());
d->socket->registerMessageType(3, &Cura::Progress::default_instance());
d->socket->registerMessageType(4, &Cura::GCodeLayer::default_instance());
d->socket->registerMessageType(5, &Cura::ObjectPrintTime::default_instance());
d->socket->registerMessageType(6, &Cura::SettingList::default_instance());
d->socket->registerMessageType(7, &Cura::GCodePrefix::default_instance());
d->socket->connect(ip, port);
while(d->socket->state() != Arcus::SocketState::Closed && d->socket->state() != Arcus::SocketState::Error)
{
if(d->objectToSlice)
{
//TODO: Support all-at-once/one-at-a-time printing
d->processor->processModel(d->objectToSlice.get());
d->objectToSlice.reset();
d->processor->resetFileNumber();
sendPrintTime();
}
Arcus::MessagePtr message = d->socket->takeNextMessage();
Cura::SettingList* settingList = dynamic_cast<Cura::SettingList*>(message.get());
if(settingList)
{
handleSettingList(settingList);
}
Cura::ObjectList* objectList = dynamic_cast<Cura::ObjectList*>(message.get());
if(objectList)
{
handleObjectList(objectList);
}
std::this_thread::sleep_for(std::chrono::milliseconds(250));
if(!d->socket->errorString().empty()) {
logError("%s\n", d->socket->errorString().data());
d->socket->clearError();
}
}
}
void CommandSocket::handleObjectList(Cura::ObjectList* list)
{
FMatrix3x3 matrix;
d->object_count = 0;
d->objectIds.clear();
d->objectToSlice = std::make_shared<PrintObject>(d->processor);
for(auto object : list->objects())
{
d->objectToSlice->meshes.emplace_back(d->objectToSlice.get()); //Construct a new mesh and put it into printObject's mesh list.
Mesh& mesh = d->objectToSlice->meshes.back();
int bytesPerFace = BYTES_PER_FLOAT * FLOATS_PER_VECTOR * VECTORS_PER_FACE;
int faceCount = object.vertices().size() / bytesPerFace;
for(int i = 0; i < faceCount; ++i)
{
//TODO: Apply matrix
std::string data = object.vertices().substr(i * bytesPerFace, bytesPerFace);
const FPoint3* floatVerts = reinterpret_cast<const FPoint3*>(data.data());
Point3 verts[3];
verts[0] = matrix.apply(floatVerts[0]);
verts[1] = matrix.apply(floatVerts[1]);
verts[2] = matrix.apply(floatVerts[2]);
mesh.addFace(verts[0], verts[1], verts[2]);
}
for(auto setting : object.settings())
{
mesh.setSetting(setting.name(), setting.value());
}
d->objectIds.push_back(object.id());
mesh.finish();
}
d->object_count++;
d->objectToSlice->finalize();
}
void CommandSocket::handleSettingList(Cura::SettingList* list)
{
for(auto setting : list->settings())
{
d->processor->setSetting(setting.name(), setting.value());
}
}
void CommandSocket::sendLayerInfo(int layer_nr, int32_t z, int32_t height)
{
if(!d->currentSlicedObject)
{
return;
}
Cura::Layer* layer = d->getLayerById(layer_nr);
layer->set_height(z);
layer->set_thickness(height);
}
void CommandSocket::sendPolygons(PolygonType type, int layer_nr, Polygons& polygons, int line_width)
{
if(!d->currentSlicedObject)
return;
if (polygons.size() == 0)
return;
Cura::Layer* layer = d->getLayerById(layer_nr);
for(unsigned int i = 0; i < polygons.size(); ++i)
{
Cura::Polygon* p = layer->add_polygons();
p->set_type(static_cast<Cura::Polygon_Type>(type));
std::string polydata;
polydata.append(reinterpret_cast<const char*>(polygons[i].data()), polygons[i].size() * sizeof(Point));
p->set_points(polydata);
p->set_line_width(line_width);
}
}
void CommandSocket::sendProgress(float amount)
{
auto message = std::make_shared<Cura::Progress>();
message->set_amount(amount);
d->socket->sendMessage(message);
}
void CommandSocket::sendPrintTime()
{
auto message = std::make_shared<Cura::ObjectPrintTime>();
message->set_time(d->processor->getTotalPrintTime());
message->set_material_amount(d->processor->getTotalFilamentUsed(0));
d->socket->sendMessage(message);
}
void CommandSocket::sendPrintMaterialForObject(int index, int extruder_nr, float print_time)
{
// socket.sendInt32(CMD_OBJECT_PRINT_MATERIAL);
// socket.sendInt32(12);
// socket.sendInt32(index);
// socket.sendInt32(extruder_nr);
// socket.sendFloat32(print_time);
}
void CommandSocket::beginSendSlicedObject()
{
if(!d->slicedObjectList)
{
d->slicedObjectList = std::make_shared<Cura::SlicedObjectList>();
}
d->currentSlicedObject = d->slicedObjectList->add_objects();
d->currentSlicedObject->set_id(d->objectIds[d->slicedObjects]);
}
void CommandSocket::endSendSlicedObject()
{
d->slicedObjects++;
if(d->slicedObjects >= d->object_count)
{
d->socket->sendMessage(d->slicedObjectList);
d->slicedObjects = 0;
d->slicedObjectList.reset();
d->currentSlicedObject = nullptr;
}
}
void CommandSocket::beginGCode()
{
d->processor->setTargetStream(&d->gcode_output_stream);
}
void CommandSocket::sendGCodeLayer()
{
auto message = std::make_shared<Cura::GCodeLayer>();
message->set_id(d->objectIds[0]);
message->set_data(d->gcode_output_stream.str());
d->socket->sendMessage(message);
d->gcode_output_stream.str("");
}
void CommandSocket::sendGCodePrefix(std::string prefix)
{
auto message = std::make_shared<Cura::GCodePrefix>();
message->set_data(prefix);
d->socket->sendMessage(message);
}
Cura::Layer* CommandSocket::Private::getLayerById(int id)
{
auto itr = std::find_if(currentSlicedObject->mutable_layers()->begin(), currentSlicedObject->mutable_layers()->end(), [id](Cura::Layer& l) { return l.id() == id; });
Cura::Layer* layer = nullptr;
if(itr != currentSlicedObject->mutable_layers()->end())
{
layer = &(*itr);
}
else
{
layer = currentSlicedObject->add_layers();
layer->set_id(id);
}
return layer;
}
}//namespace cura
+45
Ver Arquivo
@@ -0,0 +1,45 @@
#ifndef COMMAND_SOCKET_H
#define COMMAND_SOCKET_H
#include "utils/socket.h"
#include "utils/polygon.h"
#include "settings.h"
#include <memory>
#include "Cura.pb.h"
namespace cura {
class fffProcessor;
class CommandSocket
{
public:
CommandSocket(fffProcessor* processor);
void connect(const std::string& ip, int port);
void handleObjectList(Cura::ObjectList* list);
void handleSettingList(Cura::SettingList* list);
void sendLayerInfo(int layer_nr, int32_t z, int32_t height);
void sendPolygons(cura::PolygonType type, int layer_nr, cura::Polygons& polygons, int line_width);
void sendProgress(float amount);
void sendPrintTime();
void sendPrintMaterialForObject(int index, int extruder_nr, float material_amount);
void beginSendSlicedObject();
void endSendSlicedObject();
void beginGCode();
void sendGCodeLayer();
void sendGCodePrefix(std::string prefix);
private:
class Private;
const std::unique_ptr<Private> d;
};
}//namespace cura
#endif//COMMAND_SOCKET_H
+61
Ver Arquivo
@@ -0,0 +1,61 @@
#ifndef DEBUG_H
#define DEBUG_H
#include <string.h>
#define __FILE_NAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
#define DEBUG_HERE std::cerr << __FILE_NAME__ << " : " << __LINE__ << std::endl
#define DEBUG 1
#define DEBUG_SHOW_LINE 0
#if DEBUG_SHOW_LINE == 1
#define DEBUG_FILE_LINE __FILE_NAME__ << "." << __LINE__ << ": "
#else
#define DEBUG_FILE_LINE ""
#endif
#if DEBUG == 1
# define DEBUG_DO(x) do { x } while (0)
# define DEBUG_SHOW(x) do { std::cerr << DEBUG_FILE_LINE << #x << " = " << x << std::endl; } while (0)
# define DEBUG_PRINTLN(x) do { std::cerr << DEBUG_FILE_LINE << x << std::endl; } while (0)
#else
# define DEBUG_DO(x)
# define DEBUG_SHOW(x)
# define DEBUG_PRINTLN(x)
#endif
#include <sstream>
#if 0==1
#define ENUM(name, ...) enum class name { __VA_ARGS__, __COUNT};
#endif
#define ENUM(name, ...) enum class name { __VA_ARGS__}; \
inline std::ostream& operator<<(std::ostream& os, name value) { \
std::string enumName = #name; \
std::string str = #__VA_ARGS__; \
int len = str.length(); \
std::vector<std::string> strings; \
std::ostringstream temp; \
for(int i = 0; i < len; i ++) { \
if(isspace(str[i])) continue; \
else if(str[i] == ',') { \
strings.push_back(temp.str()); \
temp.str(std::string());\
} \
else temp<< str[i]; \
} \
strings.push_back(temp.str()); \
os << enumName << "::" << strings[static_cast<int>(value)]; \
return os;}
#endif // DEBUG_H
+1189
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+479
Ver Arquivo
@@ -0,0 +1,479 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdarg.h>
#include <iomanip>
#include "gcodeExport.h"
#include "utils/logoutput.h"
namespace cura {
GCodeExport::GCodeExport()
: output_stream(&std::cout), currentPosition(0,0,0), startPosition(INT32_MIN,INT32_MIN,0)
{
extrusion_amount = 0;
retraction_extrusion_window = 0.0;
extruderSwitchRetraction = 14.5;
current_extruder = 0;
currentFanSpeed = -1;
totalPrintTime = 0.0;
for(unsigned int e=0; e<MAX_EXTRUDERS; e++)
{
totalFilament[e] = 0.0;
currentTemperature[e] = 0;
filament_diameter[e] = 0;
}
currentSpeed = 1;
retractionPrimeSpeed = 1;
isRetracted = false;
isZHopped = false;
setFlavor(GCODE_FLAVOR_REPRAP);
memset(extruderOffset, 0, sizeof(extruderOffset));
}
GCodeExport::~GCodeExport()
{
}
void GCodeExport::setOutputStream(std::ostream* stream)
{
output_stream = stream;
*output_stream << std::fixed;
}
void GCodeExport::setExtruderOffset(int id, Point p)
{
extruderOffset[id] = p;
}
Point GCodeExport::getExtruderOffset(int id)
{
return extruderOffset[id];
}
void GCodeExport::setSwitchExtruderCode(int id, std::string preSwitchExtruderCode, std::string postSwitchExtruderCode)
{
this->preSwitchExtruderCode[id] = preSwitchExtruderCode;
this->postSwitchExtruderCode[id] = postSwitchExtruderCode;
}
void GCodeExport::setFlavor(EGCodeFlavor flavor)
{
this->flavor = flavor;
if (flavor == GCODE_FLAVOR_MACH3)
for(int n=0; n<MAX_EXTRUDERS; n++)
extruderCharacter[n] = 'A' + n;
else
for(int n=0; n<MAX_EXTRUDERS; n++)
extruderCharacter[n] = 'E';
if (flavor == GCODE_FLAVOR_ULTIGCODE || flavor == GCODE_FLAVOR_REPRAP_VOLUMATRIC)
{
is_volumatric = true;
}
else
{
is_volumatric = false;
}
}
EGCodeFlavor GCodeExport::getFlavor()
{
return this->flavor;
}
void GCodeExport::setRetractionSettings(int extruderSwitchRetraction, int extruderSwitchRetractionSpeed, int extruderSwitchPrimeSpeed, int retraction_extrusion_window, int retraction_count_max)
{
this->extruderSwitchRetraction = INT2MM(extruderSwitchRetraction);
this->extruderSwitchRetractionSpeed = extruderSwitchRetractionSpeed;
this->extruderSwitchPrimeSpeed = extruderSwitchPrimeSpeed;
this->retraction_extrusion_window = INT2MM(retraction_extrusion_window);
this->retraction_count_max = retraction_count_max;
}
void GCodeExport::setZ(int z)
{
this->zPos = z;
}
Point3 GCodeExport::getPosition()
{
return currentPosition;
}
Point GCodeExport::getPositionXY()
{
return Point(currentPosition.x, currentPosition.y);
}
int GCodeExport::getPositionZ()
{
return currentPosition.z;
}
void GCodeExport::resetStartPosition()
{
startPosition.x = INT32_MIN;
startPosition.y = INT32_MIN;
}
Point GCodeExport::getStartPositionXY()
{
return Point(startPosition.x, startPosition.y);
}
int GCodeExport::getExtruderNr()
{
return current_extruder;
}
double GCodeExport::getFilamentArea(unsigned int extruder)
{
double r = INT2MM(filament_diameter[extruder]) / 2.0;
double filament_area = M_PI * r * r;
return filament_area;
}
void GCodeExport::setFilamentDiameter(unsigned int n, int diameter)
{
filament_diameter[n] = diameter;
}
double GCodeExport::getExtrusionAmountMM3(unsigned int extruder)
{
if (is_volumatric)
{
return extrusion_amount;
}
else
{
return extrusion_amount * getFilamentArea(extruder);
}
}
double GCodeExport::getTotalFilamentUsed(int e)
{
if (e == current_extruder)
return totalFilament[e] + getExtrusionAmountMM3(e);
return totalFilament[e];
}
double GCodeExport::getTotalPrintTime()
{
return totalPrintTime;
}
void GCodeExport::resetTotalPrintTimeAndFilament()
{
totalPrintTime = 0;
for(unsigned int e=0; e<MAX_EXTRUDERS; e++)
{
totalFilament[e] = 0.0;
currentTemperature[e] = 0;
}
extrusion_amount = 0.0;
estimateCalculator.reset();
}
void GCodeExport::updateTotalPrintTime()
{
totalPrintTime += estimateCalculator.calculate();
estimateCalculator.reset();
}
void GCodeExport::writeComment(std::string comment)
{
*output_stream << ";" << comment << "\n";
}
void GCodeExport::writeTypeComment(const char* type)
{
*output_stream << ";TYPE:" << type << "\n";
}
void GCodeExport::writeLayerComment(int layer_nr)
{
*output_stream << ";LAYER:" << layer_nr << "\n";
}
void GCodeExport::writeLine(const char* line)
{
*output_stream << line << "\n";
}
void GCodeExport::resetExtrusionValue()
{
if (extrusion_amount != 0.0 && flavor != GCODE_FLAVOR_MAKERBOT && flavor != GCODE_FLAVOR_BFB)
{
*output_stream << "G92 " << extruderCharacter[current_extruder] << "0\n";
totalFilament[current_extruder] += getExtrusionAmountMM3(current_extruder);
for (unsigned int i = 0; i < extrusion_amount_at_previous_n_retractions.size(); i++)
extrusion_amount_at_previous_n_retractions[i] -= extrusion_amount;
extrusion_amount = 0.0;
}
}
void GCodeExport::writeDelay(double timeAmount)
{
*output_stream << "G4 P" << int(timeAmount * 1000) << "\n";
totalPrintTime += timeAmount;
}
void GCodeExport::writeMove(Point p, int speed, double extrusion_mm3_per_mm)
{
writeMove(p.X, p.Y, zPos, speed, extrusion_mm3_per_mm);
}
void GCodeExport::writeMove(Point3 p, int speed, double extrusion_mm3_per_mm)
{
writeMove(p.x, p.y, p.z, speed, extrusion_mm3_per_mm);
}
void GCodeExport::writeMove(int x, int y, int z, int speed, double extrusion_mm3_per_mm)
{
if (currentPosition.x == x && currentPosition.y == y && currentPosition.z == z)
return;
double extrusion_per_mm = extrusion_mm3_per_mm;
if (!is_volumatric)
{
extrusion_per_mm = extrusion_mm3_per_mm / getFilamentArea(current_extruder);
}
if (flavor == GCODE_FLAVOR_BFB)
{
//For Bits From Bytes machines, we need to handle this completely differently. As they do not use E values but RPM values.
float fspeed = speed * 60;
float rpm = extrusion_per_mm * speed * 60;
const float mm_per_rpm = 4.0; //All BFB machines have 4mm per RPM extrusion.
rpm /= mm_per_rpm;
if (rpm > 0)
{
if (isRetracted)
{
if (currentSpeed != int(rpm * 10))
{
//fprintf(f, "; %f e-per-mm %d mm-width %d mm/s\n", extrusion_per_mm, lineWidth, speed);
//fprintf(f, "M108 S%0.1f\r\n", rpm);
*output_stream << "M108 S" << std::setprecision(1) << rpm << "\r\n";
currentSpeed = int(rpm * 10);
}
//Add M101 or M201 to enable the proper extruder.
*output_stream << "M" << int((current_extruder + 1) * 100 + 1) << "\r\n";
isRetracted = false;
}
//Fix the speed by the actual RPM we are asking, because of rounding errors we cannot get all RPM values, but we have a lot more resolution in the feedrate value.
// (Trick copied from KISSlicer, thanks Jonathan)
fspeed *= (rpm / (roundf(rpm * 100) / 100));
//Increase the extrusion amount to calculate the amount of filament used.
Point3 diff = Point3(x,y,z) - getPosition();
extrusion_amount += extrusion_per_mm * diff.vSizeMM();
}else{
//If we are not extruding, check if we still need to disable the extruder. This causes a retraction due to auto-retraction.
if (!isRetracted)
{
*output_stream << "M103\r\n";
isRetracted = true;
}
}
*output_stream << std::setprecision(3) << "G1 X" << INT2MM(x - extruderOffset[current_extruder].X) << " Y" << INT2MM(y - extruderOffset[current_extruder].Y) << " Z" << INT2MM(z) << std::setprecision(1) << " F" << fspeed << "\r\n";
}else{
//Normal E handling.
if (extrusion_mm3_per_mm > 0.000001)
{
Point3 diff = Point3(x,y,z) - getPosition();
if (isZHopped > 0)
{
*output_stream << std::setprecision(3) << "G1 Z" << INT2MM(currentPosition.z) << "\n";
isZHopped = false;
}
if (isRetracted)
{
if (flavor == GCODE_FLAVOR_ULTIGCODE || flavor == GCODE_FLAVOR_REPRAP_VOLUMATRIC)
{
*output_stream << "G11\n";
//Assume default UM2 retraction settings.
estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), extrusion_amount), 25.0);
}else{
*output_stream << "G1 F" << (retractionPrimeSpeed * 60) << " " << extruderCharacter[current_extruder] << std::setprecision(5) << extrusion_amount << "\n";
currentSpeed = retractionPrimeSpeed;
estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), extrusion_amount), currentSpeed);
}
if (getExtrusionAmountMM3(current_extruder) > 10000.0) //According to https://github.com/Ultimaker/CuraEngine/issues/14 having more then 21m of extrusion causes inaccuracies. So reset it every 10m, just to be sure.
resetExtrusionValue();
isRetracted = false;
}
extrusion_amount += extrusion_per_mm * diff.vSizeMM();
*output_stream << "G1";
}else{
*output_stream << "G0";
}
if (currentSpeed != speed)
{
*output_stream << " F" << (speed * 60);
currentSpeed = speed;
}
*output_stream << std::setprecision(3) << " X" << INT2MM(x - extruderOffset[current_extruder].X) << " Y" << INT2MM(y - extruderOffset[current_extruder].Y);
if (z != currentPosition.z)
*output_stream << " Z" << INT2MM(z);
if (extrusion_mm3_per_mm > 0.000001)
*output_stream << " " << extruderCharacter[current_extruder] << std::setprecision(5) << extrusion_amount;
*output_stream << "\n";
}
currentPosition = Point3(x, y, z);
startPosition = currentPosition;
estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), extrusion_amount), speed);
}
void GCodeExport::writeRetraction(RetractionConfig* config, bool force)
{
if (flavor == GCODE_FLAVOR_BFB)//BitsFromBytes does automatic retraction.
return;
if (isRetracted)
return;
if (config->amount <= 0)
return;
if (!force && retraction_count_max > 0 && int(extrusion_amount_at_previous_n_retractions.size()) == retraction_count_max - 1
&& extrusion_amount < extrusion_amount_at_previous_n_retractions.back() + retraction_extrusion_window)
return;
if (config->primeAmount > 0)
extrusion_amount += config->primeAmount;
retractionPrimeSpeed = config->primeSpeed;
if (flavor == GCODE_FLAVOR_ULTIGCODE || flavor == GCODE_FLAVOR_REPRAP_VOLUMATRIC)
{
*output_stream << "G10\n";
//Assume default UM2 retraction settings.
double retraction_distance = 4.5;
estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), extrusion_amount - retraction_distance), 25); // TODO: hardcoded values!
}else{
*output_stream << "G1 F" << (config->speed * 60) << " " << extruderCharacter[current_extruder] << std::setprecision(5) << extrusion_amount - config->amount << "\n";
currentSpeed = config->speed;
estimateCalculator.plan(TimeEstimateCalculator::Position(INT2MM(currentPosition.x), INT2MM(currentPosition.y), INT2MM(currentPosition.z), extrusion_amount - config->amount), currentSpeed);
}
if (config->zHop > 0)
{
*output_stream << std::setprecision(3) << "G1 Z" << INT2MM(currentPosition.z + config->zHop) << "\n";
isZHopped = true;
}
extrusion_amount_at_previous_n_retractions.push_front(extrusion_amount);
if (int(extrusion_amount_at_previous_n_retractions.size()) == retraction_count_max)
{
extrusion_amount_at_previous_n_retractions.pop_back();
}
isRetracted = true;
}
void GCodeExport::switchExtruder(int newExtruder)
{
if (current_extruder == newExtruder)
return;
if (flavor == GCODE_FLAVOR_BFB)
{
if (!isRetracted)
*output_stream << "M103\r\n";
isRetracted = true;
return;
}
resetExtrusionValue();
if (flavor == GCODE_FLAVOR_ULTIGCODE || flavor == GCODE_FLAVOR_REPRAP_VOLUMATRIC)
{
*output_stream << "G10 S1\n";
}else{
*output_stream << "G1 F" << (extruderSwitchRetractionSpeed * 60) << " " << extruderCharacter[current_extruder] << std::setprecision(5) << (extrusion_amount - extruderSwitchRetraction) << "\n";
currentSpeed = extruderSwitchRetractionSpeed;
}
current_extruder = newExtruder;
if (flavor == GCODE_FLAVOR_MACH3)
resetExtrusionValue();
isRetracted = true;
writeCode(preSwitchExtruderCode[current_extruder].c_str());
if (flavor == GCODE_FLAVOR_MAKERBOT)
*output_stream << "M135 T" << current_extruder << "\n";
else
*output_stream << "T" << current_extruder << "\n";
writeCode(postSwitchExtruderCode[current_extruder].c_str());
//Change the Z position so it gets re-writting again. We do not know if the switch code modified the Z position.
currentPosition.z += 1;
}
void GCodeExport::writeCode(const char* str)
{
*output_stream << str;
if (flavor == GCODE_FLAVOR_BFB)
*output_stream << "\r\n";
else
*output_stream << "\n";
}
void GCodeExport::writeFanCommand(int speed)
{
if (currentFanSpeed == speed)
return;
if (speed > 0)
{
if (flavor == GCODE_FLAVOR_MAKERBOT)
*output_stream << "M126 T0\n"; //value = speed * 255 / 100 // Makerbot cannot set fan speed...;
else
*output_stream << "M106 S" << (speed * 255 / 100) << "\n";
}
else
{
if (flavor == GCODE_FLAVOR_MAKERBOT)
*output_stream << "M127 T0\n";
else
*output_stream << "M107\n";
}
currentFanSpeed = speed;
}
void GCodeExport::writeTemperatureCommand(int extruder, int temperature, bool wait)
{
if (!wait && currentTemperature[extruder] == temperature)
return;
if (wait)
*output_stream << "M109";
else
*output_stream << "M104";
if (extruder != current_extruder)
*output_stream << " T" << extruder;
*output_stream << " S" << temperature << "\n";
currentTemperature[extruder] = temperature;
}
void GCodeExport::writeBedTemperatureCommand(int temperature, bool wait)
{
if (wait)
*output_stream << "M190 S";
else
*output_stream << "M140 S";
*output_stream << temperature << "\n";
}
void GCodeExport::finalize(int maxObjectHeight, int moveSpeed, const char* endCode)
{
std::cerr << "maxObjectHeight : " << maxObjectHeight << std::endl;
writeFanCommand(0);
setZ(maxObjectHeight + 5000);
writeMove(Point3(0,0,maxObjectHeight + 5000) + getPositionXY(), moveSpeed, 0);
writeCode(endCode);
log("Print time: %d\n", int(getTotalPrintTime()));
log("Filament: %d\n", int(getTotalFilamentUsed(0)));
for(int n=1; n<MAX_EXTRUDERS; n++)
if (getTotalFilamentUsed(n) > 0)
log("Filament%d: %d\n", n + 1, int(getTotalFilamentUsed(n)));
output_stream->flush();
}
}//namespace cura
+199
Ver Arquivo
@@ -0,0 +1,199 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef GCODEEXPORT_H
#define GCODEEXPORT_H
#include <stdio.h>
#include <deque> // for extrusionAmountAtPreviousRetractions
#include "settings.h"
#include "utils/intpoint.h"
#include "timeEstimate.h"
namespace cura {
class RetractionConfig
{
public:
double amount; //!< The amount
int speed;
int primeSpeed;
double primeAmount;
int zHop;
};
//The GCodePathConfig is the configuration for moves/extrusion actions. This defines at which width the line is printed and at which speed.
class GCodePathConfig
{
private:
int speed;
int line_width;
int flow;
int layer_thickness;
double extrusion_mm3_per_mm;
public:
const char* name;
bool spiralize;
RetractionConfig* retraction_config;
GCodePathConfig() : speed(0), line_width(0), extrusion_mm3_per_mm(0.0), name(nullptr), spiralize(false), retraction_config(nullptr) {}
GCodePathConfig(RetractionConfig* retraction_config, const char* name) : speed(0), line_width(0), extrusion_mm3_per_mm(0.0), name(name), spiralize(false), retraction_config(retraction_config) {}
void setSpeed(int speed)
{
this->speed = speed;
}
void setLineWidth(int line_width)
{
this->line_width = line_width;
calculateExtrusion();
}
void setLayerHeight(int layer_height)
{
this->layer_thickness = layer_height;
calculateExtrusion();
}
void setFlow(int flow)
{
this->flow = flow;
calculateExtrusion();
}
void smoothSpeed(int min_speed, int layer_nr, int max_speed_layer)
{
speed = (speed*layer_nr)/max_speed_layer + (min_speed*(max_speed_layer-layer_nr)/max_speed_layer);
}
double getExtrusionMM3perMM()
{
return extrusion_mm3_per_mm;
}
int getSpeed()
{
return speed;
}
int getLineWidth()
{
return line_width;
}
private:
void calculateExtrusion()
{
extrusion_mm3_per_mm = INT2MM(line_width) * INT2MM(layer_thickness) * double(flow) / 100.0;
}
};
//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.
class GCodeExport
{
private:
std::ostream* output_stream;
double extrusion_amount; // in mm or mm^3
double extruderSwitchRetraction;
int extruderSwitchRetractionSpeed;
int extruderSwitchPrimeSpeed;
double retraction_extrusion_window;
int retraction_count_max;
std::deque<double> extrusion_amount_at_previous_n_retractions; // in mm or mm^3
Point3 currentPosition;
Point3 startPosition;
Point extruderOffset[MAX_EXTRUDERS];
char extruderCharacter[MAX_EXTRUDERS];
int currentTemperature[MAX_EXTRUDERS];
int currentSpeed;
int zPos;
bool isRetracted;
bool isZHopped;
int retractionPrimeSpeed;
int current_extruder;
int currentFanSpeed;
EGCodeFlavor flavor;
std::string preSwitchExtruderCode[MAX_EXTRUDERS];
std::string postSwitchExtruderCode[MAX_EXTRUDERS];
double totalFilament[MAX_EXTRUDERS]; // in mm^3
double filament_diameter[MAX_EXTRUDERS]; // in mm^3
double totalPrintTime;
TimeEstimateCalculator estimateCalculator;
bool is_volumatric;
public:
GCodeExport();
~GCodeExport();
void setOutputStream(std::ostream* stream);
void setExtruderOffset(int id, Point p);
Point getExtruderOffset(int id);
void setSwitchExtruderCode(int id, std::string preSwitchExtruderCode, std::string postSwitchExtruderCode);
void setFlavor(EGCodeFlavor flavor);
EGCodeFlavor getFlavor();
void setRetractionSettings(int extruderSwitchRetraction, int extruderSwitchRetractionSpeed, int extruderSwitchPrimeSpeed, int minimalExtrusionBeforeRetraction, int retraction_count_max);
void setZ(int z);
Point3 getPosition();
Point getPositionXY();
void resetStartPosition();
Point getStartPositionXY();
int getPositionZ();
int getExtruderNr();
void setFilamentDiameter(unsigned int n, int diameter);
double getFilamentArea(unsigned int extruder);
double getExtrusionAmountMM3(unsigned int extruder);
double getTotalFilamentUsed(int e);
double getTotalPrintTime();
void updateTotalPrintTime();
void resetTotalPrintTimeAndFilament();
void writeComment(std::string comment);
void writeTypeComment(const char* type);
void writeLayerComment(int layer_nr);
void writeLine(const char* line);
void resetExtrusionValue();
void writeDelay(double timeAmount);
void writeMove(Point p, int speed, double extrusion_per_mm);
void writeMove(Point3 p, int speed, double extrusion_per_mm);
private:
void writeMove(int x, int y, int z, int speed, double extrusion_per_mm);
public:
void writeRetraction(RetractionConfig* config, bool force=false);
void switchExtruder(int newExtruder);
void writeCode(const char* str);
void writeFanCommand(int speed);
void writeTemperatureCommand(int extruder, int temperature, bool wait = false);
void writeBedTemperatureCommand(int temperature, bool wait = false);
void finalize(int maxObjectHeight, int moveSpeed, const char* endCode);
};
}
#endif//GCODEEXPORT_H
+313
Ver Arquivo
@@ -0,0 +1,313 @@
#include "gcodePlanner.h"
#include "pathOrderOptimizer.h"
namespace cura {
GCodePath* GCodePlanner::getLatestPathWithConfig(GCodePathConfig* config)
{
if (paths.size() > 0 && paths[paths.size()-1].config == config && !paths[paths.size()-1].done)
return &paths[paths.size()-1];
paths.push_back(GCodePath());
GCodePath* ret = &paths[paths.size()-1];
ret->retract = false;
ret->config = config;
ret->extruder = currentExtruder;
ret->done = false;
return ret;
}
void GCodePlanner::forceNewPathStart()
{
if (paths.size() > 0)
paths[paths.size()-1].done = true;
}
GCodePlanner::GCodePlanner(GCodeExport& gcode, RetractionConfig* retraction_config, int travelSpeed, int retractionMinimalDistance)
: gcode(gcode), travelConfig(retraction_config, "MOVE")
{
lastPosition = gcode.getPositionXY();
travelConfig.setSpeed(travelSpeed);
comb = nullptr;
extrudeSpeedFactor = 100;
travelSpeedFactor = 100;
extraTime = 0.0;
totalPrintTime = 0.0;
forceRetraction = false;
alwaysRetract = false;
currentExtruder = gcode.getExtruderNr();
this->retractionMinimalDistance = retractionMinimalDistance;
}
GCodePlanner::~GCodePlanner()
{
if (comb)
delete comb;
}
void GCodePlanner::addTravel(Point p)
{
GCodePath* path = getLatestPathWithConfig(&travelConfig);
if (forceRetraction)
{
if (!shorterThen(lastPosition - p, retractionMinimalDistance))
{
path->retract = true;
}
forceRetraction = false;
}else if (comb != nullptr)
{
std::vector<Point> pointList;
if (comb->calc(lastPosition, p, pointList))
{
for(unsigned int n=0; n<pointList.size(); n++)
{
path->points.push_back(pointList[n]);
}
}else{
if (!shorterThen(lastPosition - p, retractionMinimalDistance))
path->retract = true;
}
}else if (alwaysRetract)
{
if (!shorterThen(lastPosition - p, retractionMinimalDistance))
path->retract = true;
}
path->points.push_back(p);
lastPosition = p;
}
void GCodePlanner::addExtrusionMove(Point p, GCodePathConfig* config)
{
getLatestPathWithConfig(config)->points.push_back(p);
lastPosition = p;
}
void GCodePlanner::moveInsideCombBoundary(int distance)
{
if (!comb || comb->inside(lastPosition)) return;
Point p = lastPosition;
if (comb->moveInside(&p, distance))
{
//Move inside again, so we move out of tight 90deg corners
comb->moveInside(&p, distance);
if (comb->inside(p))
{
addTravel(p);
//Make sure the that any retraction happens after this move, not before it by starting a new move path.
forceNewPathStart();
}
}
}
void GCodePlanner::addPolygon(PolygonRef polygon, int startIdx, GCodePathConfig* config)
{
Point p0 = polygon[startIdx];
addTravel(p0);
for(unsigned int i=1; i<polygon.size(); i++)
{
Point p1 = polygon[(startIdx + i) % polygon.size()];
addExtrusionMove(p1, config);
p0 = p1;
}
if (polygon.size() > 2)
addExtrusionMove(polygon[startIdx], config);
}
void GCodePlanner::addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* config)
{
//log("addPolygonsByOptimizer");
PathOrderOptimizer orderOptimizer(lastPosition);
for(unsigned int i=0;i<polygons.size();i++)
orderOptimizer.addPolygon(polygons[i]);
orderOptimizer.optimize();
for(unsigned int i=0;i<orderOptimizer.polyOrder.size();i++)
{
int nr = orderOptimizer.polyOrder[i];
addPolygon(polygons[nr], orderOptimizer.polyStart[nr], config);
}
}
void GCodePlanner::addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config)
{
LineOrderOptimizer orderOptimizer(lastPosition);
for(unsigned int i=0;i<polygons.size();i++)
orderOptimizer.addPolygon(polygons[i]);
orderOptimizer.optimize();
for(unsigned int i=0;i<orderOptimizer.polyOrder.size();i++)
{
int nr = orderOptimizer.polyOrder[i];
addPolygon(polygons[nr], orderOptimizer.polyStart[nr], config);
}
}
void GCodePlanner::forceMinimalLayerTime(double minTime, int minimalSpeed, double travelTime, double extrudeTime)
{
double totalTime = travelTime + extrudeTime;
if (totalTime < minTime && extrudeTime > 0.0)
{
double minExtrudeTime = minTime - travelTime;
if (minExtrudeTime < 1)
minExtrudeTime = 1;
double factor = extrudeTime / minExtrudeTime;
for(unsigned int n=0; n<paths.size(); n++)
{
GCodePath* path = &paths[n];
if (path->config->getExtrusionMM3perMM() == 0)
continue;
int speed = path->config->getSpeed() * factor;
if (speed < minimalSpeed)
factor = double(minimalSpeed) / double(path->config->getSpeed());
}
//Only slow down with the minimal time if that will be slower then a factor already set. First layer slowdown also sets the speed factor.
if (factor * 100 < getExtrudeSpeedFactor())
setExtrudeSpeedFactor(factor * 100);
else
factor = getExtrudeSpeedFactor() / 100.0;
if (minTime - (extrudeTime / factor) - travelTime > 0.1)
{
this->extraTime = minTime - (extrudeTime / factor) - travelTime;
}
this->totalPrintTime = (extrudeTime / factor) + travelTime;
}else{
this->totalPrintTime = totalTime;
}
}
void GCodePlanner::getTimes(double& travelTime, double& extrudeTime)
{
travelTime = 0.0;
extrudeTime = 0.0;
Point p0 = gcode.getPositionXY();
for(unsigned int n=0; n<paths.size(); n++)
{
GCodePath* path = &paths[n];
for(unsigned int i=0; i<path->points.size(); i++)
{
double thisTime = vSizeMM(p0 - path->points[i]) / double(path->config->getSpeed());
if (path->config->getExtrusionMM3perMM() != 0)
extrudeTime += thisTime;
else
travelTime += thisTime;
p0 = path->points[i];
}
}
}
void GCodePlanner::writeGCode(bool liftHeadIfNeeded, int layerThickness)
{
GCodePathConfig* lastConfig = nullptr;
int extruder = gcode.getExtruderNr();
for(unsigned int n=0; n<paths.size(); n++)
{
GCodePath* path = &paths[n];
if (extruder != path->extruder)
{
extruder = path->extruder;
gcode.switchExtruder(extruder);
}else if (path->retract)
{
gcode.writeRetraction(path->config->retraction_config);
}
if (path->config != &travelConfig && lastConfig != path->config)
{
gcode.writeTypeComment(path->config->name);
lastConfig = path->config;
}
int speed = path->config->getSpeed();
if (path->config->getExtrusionMM3perMM() != 0)// Only apply the extrudeSpeedFactor to extrusion moves
speed = speed * extrudeSpeedFactor / 100;
else
speed = speed * travelSpeedFactor / 100;
if (path->points.size() == 1 && path->config != &travelConfig && shorterThen(gcode.getPositionXY() - path->points[0], path->config->getLineWidth() * 2))
{
//Check for lots of small moves and combine them into one large line
Point p0 = path->points[0];
unsigned int i = n + 1;
while(i < paths.size() && paths[i].points.size() == 1 && shorterThen(p0 - paths[i].points[0], path->config->getLineWidth() * 2))
{
p0 = paths[i].points[0];
i ++;
}
if (paths[i-1].config == &travelConfig)
i --;
if (i > n + 2)
{
p0 = gcode.getPositionXY();
for(unsigned int x=n; x<i-1; x+=2)
{
int64_t new_width = vSize(p0 - paths[x].points[0]); // = old_length
Point newPoint = (paths[x].points[0] + paths[x+1].points[0]) / 2;
int64_t old_width = path->config->getLineWidth();
if (old_width > 0)
{
if (new_width > 0)
gcode.writeMove(newPoint, speed * old_width / new_width, path->config->getExtrusionMM3perMM() * new_width / old_width);
else
gcode.writeMove(newPoint, speed, path->config->getExtrusionMM3perMM());
}
p0 = paths[x+1].points[0];
}
gcode.writeMove(paths[i-1].points[0], speed, path->config->getExtrusionMM3perMM());
n = i - 1;
continue;
}
}
bool spiralize = path->config->spiralize;
if (spiralize)
{
//Check if we are the last spiralize path in the list, if not, do not spiralize.
for(unsigned int m=n+1; m<paths.size(); m++)
{
if (paths[m].config->spiralize)
spiralize = false;
}
}
if (spiralize)
{
//If we need to spiralize then raise the head slowly by 1 layer as this path progresses.
float totalLength = 0.0;
int z = gcode.getPositionZ();
Point p0 = gcode.getPositionXY();
for(unsigned int i=0; i<path->points.size(); i++)
{
Point p1 = path->points[i];
totalLength += vSizeMM(p0 - p1);
p0 = p1;
}
float length = 0.0;
p0 = gcode.getPositionXY();
for(unsigned int i=0; i<path->points.size(); i++)
{
Point p1 = path->points[i];
length += vSizeMM(p0 - p1);
p0 = p1;
gcode.setZ(z + layerThickness * length / totalLength);
gcode.writeMove(path->points[i], speed, path->config->getExtrusionMM3perMM());
}
}else{
for(unsigned int i=0; i<path->points.size(); i++)
{
gcode.writeMove(path->points[i], speed, path->config->getExtrusionMM3perMM());
}
}
}
gcode.updateTotalPrintTime();
if (liftHeadIfNeeded && extraTime > 0.0)
{
gcode.writeComment("Small layer, adding delay");
if (lastConfig)
gcode.writeRetraction(lastConfig->retraction_config, true);
gcode.setZ(gcode.getPositionZ() + MM2INT(3.0));
gcode.writeMove(gcode.getPositionXY(), travelConfig.getSpeed(), 0);
gcode.writeMove(gcode.getPositionXY() - Point(-MM2INT(20.0), 0), travelConfig.getSpeed(), 0);
gcode.writeDelay(extraTime);
}
}
}//namespace cura
+126
Ver Arquivo
@@ -0,0 +1,126 @@
#ifndef GCODE_PLANNER_H
#define GCODE_PLANNER_H
#include <vector>
#include "gcodeExport.h"
#include "comb.h"
#include "utils/polygon.h"
#include "utils/logoutput.h"
namespace cura
{
class GCodePath
{
public:
GCodePathConfig* config;
bool retract;
int extruder;
std::vector<Point> points;
bool done;//Path is finished, no more moves should be added, and a new path should be started instead of any appending done to this one.
};
//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.
class GCodePlanner
{
private:
GCodeExport& gcode;
Point lastPosition;
std::vector<GCodePath> paths;
Comb* comb;
GCodePathConfig travelConfig;
int extrudeSpeedFactor;
int travelSpeedFactor;
int currentExtruder;
int retractionMinimalDistance;
bool forceRetraction;
bool alwaysRetract;
double extraTime;
double totalPrintTime;
private:
GCodePath* getLatestPathWithConfig(GCodePathConfig* config);
void forceNewPathStart();
public:
GCodePlanner(GCodeExport& gcode, RetractionConfig* retraction_config, int travelSpeed, int retractionMinimalDistance);
~GCodePlanner();
bool setExtruder(int extruder)
{
if (extruder == currentExtruder)
return false;
currentExtruder = extruder;
return true;
}
int getExtruder()
{
return currentExtruder;
}
void setCombBoundary(Polygons* polygons)
{
if (comb)
delete comb;
if (polygons)
comb = new Comb(*polygons);
else
comb = nullptr;
}
void setAlwaysRetract(bool alwaysRetract)
{
this->alwaysRetract = alwaysRetract;
}
void forceRetract()
{
forceRetraction = true;
}
void setExtrudeSpeedFactor(int speedFactor)
{
if (speedFactor < 1) speedFactor = 1;
this->extrudeSpeedFactor = speedFactor;
}
int getExtrudeSpeedFactor()
{
return this->extrudeSpeedFactor;
}
void setTravelSpeedFactor(int speedFactor)
{
if (speedFactor < 1) speedFactor = 1;
this->travelSpeedFactor = speedFactor;
}
int getTravelSpeedFactor()
{
return this->travelSpeedFactor;
}
void addTravel(Point p);
void addExtrusionMove(Point p, GCodePathConfig* config);
void moveInsideCombBoundary(int distance);
void addPolygon(PolygonRef polygon, int startIdx, GCodePathConfig* config);
void addPolygonsByOptimizer(Polygons& polygons, GCodePathConfig* config);
void addLinesByOptimizer(Polygons& polygons, GCodePathConfig* config);
void forceMinimalLayerTime(double minTime, int minimalSpeed, double travelTime, double extrusionTime);
void getTimes(double& travelTime, double& extrudeTime);
void writeGCode(bool liftHeadIfNeeded, int layerThickness);
};
}//namespace cura
#endif//GCODE_PLANNER_H
+476
Ver Arquivo
@@ -0,0 +1,476 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "infill.h"
#include "functional"
#include "utils/polygonUtils.h"
namespace cura {
void generateConcentricInfillDense(Polygons outline, Polygons& result, Polygons* in_between, int extrusionWidth, bool avoidOverlappingPerimeters)
{
while(outline.size() > 0)
{
for (unsigned int polyNr = 0; polyNr < outline.size(); polyNr++)
{
PolygonRef r = outline[polyNr];
result.add(r);
}
Polygons next_outline;
offsetExtrusionWidth(outline, true, extrusionWidth, next_outline, in_between, avoidOverlappingPerimeters);
outline = next_outline;
}
}
void generateConcentricInfill(Polygons outline, Polygons& result, int inset_value)
{
while(outline.size() > 0)
{
for (unsigned int polyNr = 0; polyNr < outline.size(); polyNr++)
{
PolygonRef r = outline[polyNr];
result.add(r);
}
outline = outline.offset(-inset_value);
}
}
void generateGridInfill(const Polygons& in_outline, int outlineOffset, Polygons& result,
int extrusionWidth, int lineSpacing, int infillOverlap,
double rotation)
{
generateLineInfill(in_outline, outlineOffset, result, extrusionWidth, lineSpacing,
infillOverlap, rotation);
generateLineInfill(in_outline, outlineOffset, result, extrusionWidth, lineSpacing,
infillOverlap, rotation + 90);
}
void generateTriangleInfill(const Polygons& in_outline, int outlineOffset, Polygons& result,
int extrusionWidth, int lineSpacing, int infillOverlap,
double rotation)
{
generateLineInfill(in_outline, outlineOffset, result, extrusionWidth, lineSpacing,
infillOverlap, rotation);
generateLineInfill(in_outline, outlineOffset, result, extrusionWidth, lineSpacing,
infillOverlap, rotation + 60);
generateLineInfill(in_outline, outlineOffset, result, extrusionWidth, lineSpacing,
infillOverlap, rotation + 120);
}
void addLineInfill(Polygons& result, PointMatrix matrix, int scanline_min_idx, int lineSpacing, AABB boundary, std::vector<std::vector<int64_t> > cutList, int extrusionWidth)
{
auto addLine = [&](Point from, Point to)
{
PolygonRef p = result.newPoly();
p.add(matrix.unapply(from));
p.add(matrix.unapply(to));
};
auto compare_int64_t = [](const void* a, const void* b)
{
int64_t n = (*(int64_t*)a) - (*(int64_t*)b);
if (n < 0) return -1;
if (n > 0) return 1;
return 0;
};
int scanline_idx = 0;
for(int64_t x = scanline_min_idx * lineSpacing; x < boundary.max.X; x += lineSpacing)
{
qsort(cutList[scanline_idx].data(), cutList[scanline_idx].size(), sizeof(int64_t), compare_int64_t);
for(unsigned int i = 0; i + 1 < cutList[scanline_idx].size(); i+=2)
{
if (cutList[scanline_idx][i+1] - cutList[scanline_idx][i] < extrusionWidth / 5)
continue;
addLine(Point(x, cutList[scanline_idx][i]), Point(x, cutList[scanline_idx][i+1]));
}
scanline_idx += 1;
}
}
/*!
* generate lines within the area of \p in_outline, at regular intervals of \p lineSpacing
*
* idea:
* intersect a regular grid of 'scanlines' with the area inside \p in_outline
*
* we call the areas between two consecutive scanlines a 'scansegment'.
* Scansegment x is the area between scanline x and scanline x+1
*
* algorithm:
* 1) for each line segment of each polygon:
* store the intersections of that line segment with all scanlines in a mapping (vector of vectors) from scanline to intersections
* (zigzag): add boundary segments to result
* 2) for each scanline:
* sort the associated intersections
* and connect them using the even-odd rule
*
*/
void generateLineInfill(const Polygons& in_outline, int outlineOffset, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation)
{
if (in_outline.size() == 0) return;
Polygons outline = in_outline.offset(extrusionWidth * infillOverlap / 100 + outlineOffset);
if (outline.size() == 0) return;
PointMatrix matrix(rotation);
outline.applyMatrix(matrix);
AABB boundary(outline);
int scanline_min_idx = boundary.min.X / lineSpacing;
int lineCount = (boundary.max.X + (lineSpacing - 1)) / lineSpacing - scanline_min_idx;
std::vector<std::vector<int64_t> > cutList; // mapping from scanline to all intersections with polygon segments
for(int n=0; n<lineCount; n++)
cutList.push_back(std::vector<int64_t>());
for(unsigned int poly_idx=0; poly_idx < outline.size(); poly_idx++)
{
Point p0 = outline[poly_idx][outline[poly_idx].size()-1];
for(unsigned int i=0; i < outline[poly_idx].size(); i++)
{
Point p1 = outline[poly_idx][i];
int64_t xMin = p1.X, xMax = p0.X;
if (xMin == xMax) {
p0 = p1;
continue;
}
if (xMin > xMax) { xMin = p0.X; xMax = p1.X; }
int scanline_idx0 = (p0.X + ((p0.X > 0)? -1 : -lineSpacing)) / lineSpacing; // -1 cause a linesegment on scanline x counts as belonging to scansegment x-1 ...
int scanline_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)
int direction = 1;
if (p0.X > p1.X)
{
direction = -1;
scanline_idx1 += 1; // only consider the scanlines in between the scansegments
} else scanline_idx0 += 1; // only consider the scanlines in between the scansegments
for(int scanline_idx = scanline_idx0; scanline_idx != scanline_idx1+direction; scanline_idx+=direction)
{
int x = scanline_idx * lineSpacing;
int y = p1.Y + (p0.Y - p1.Y) * (x - p1.X) / (p0.X - p1.X);
cutList[scanline_idx - scanline_min_idx].push_back(y);
}
p0 = p1;
}
}
addLineInfill(result, matrix, scanline_min_idx, lineSpacing, boundary, cutList, extrusionWidth);
}
void generateZigZagInfill(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation, bool connect_zigzags, bool use_endPieces)
{
if (use_endPieces) return generateZigZagInfill_endPieces(in_outline, result, extrusionWidth, lineSpacing, infillOverlap, rotation, connect_zigzags);
else return generateZigZagInfill_noEndPieces(in_outline, result, extrusionWidth, lineSpacing, infillOverlap, rotation);
}
/*!
* adapted from generateLineInfill(.)
*
* generate lines within the area of [in_outline], at regular intervals of [lineSpacing]
* idea:
* intersect a regular grid of 'scanlines' with the area inside [in_outline]
* sigzag:
* include pieces of boundary, connecting the lines, forming an accordion like zigzag instead of separate lines |_|^|_|
*
* we call the areas between two consecutive scanlines a 'scansegment'
*
* algorithm:
* 1. for each line segment of each polygon:
* store the intersections of that line segment with all scanlines in a mapping (vector of vectors) from scanline to intersections
* (zigzag): add boundary segments to result
* 2. for each scanline:
* sort the associated intersections
* and connect them using the even-odd rule
*
* zigzag algorithm:
* while walking around (each) polygon (1.)
* if polygon intersects with even scanline
* start boundary segment (add each following segment to the [result])
* when polygon intersects with a scanline again
* stop boundary segment (stop adding segments to the [result])
* if polygon intersects with even scanline again (instead of odd)
* dont add the last line segment to the boundary (unless [connect_zigzags])
*
*
* <--
* ___
* | | |
* | | |
* | |___|
* -->
*
* ^ = even scanline
*
* start boundary from even scanline! :D
*
*
* _____
* | | | ,
* | | | |
* |_____| |__/
*
* ^ ^ ^ scanlines
* ^ disconnected end piece
*/
void generateZigZagInfill_endPieces(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation, bool connect_zigzags)
{
// if (in_outline.size() == 0) return;
// Polygons outline = in_outline.offset(extrusionWidth * infillOverlap / 100 - extrusionWidth / 2);
Polygons empty;
Polygons outline = in_outline.difference(empty); // copy
if (outline.size() == 0) return;
PointMatrix matrix(rotation);
outline.applyMatrix(matrix);
auto addLine = [&](Point from, Point to)
{
PolygonRef p = result.newPoly();
p.add(matrix.unapply(from));
p.add(matrix.unapply(to));
};
AABB boundary(outline);
int scanline_min_idx = boundary.min.X / lineSpacing;
int lineCount = (boundary.max.X + (lineSpacing - 1)) / lineSpacing - scanline_min_idx;
std::vector<std::vector<int64_t> > cutList; // mapping from scanline to all intersections with polygon segments
for(int n=0; n<lineCount; n++)
cutList.push_back(std::vector<int64_t>());
for(unsigned int polyNr=0; polyNr < outline.size(); polyNr++)
{
std::vector<Point> firstBoundarySegment;
std::vector<Point> unevenBoundarySegment; // stored cause for connected_zigzags a boundary segment which ends in an uneven scanline needs to be included
bool isFirstBoundarySegment = true;
bool firstBoundarySegmentEndsInEven;
bool isEvenScanSegment = false;
Point p0 = outline[polyNr][outline[polyNr].size()-1];
Point lastPoint = p0;
for(unsigned int i=0; i < outline[polyNr].size(); i++)
{
Point p1 = outline[polyNr][i];
int64_t xMin = p1.X, xMax = p0.X;
if (xMin == xMax) {
lastPoint = p1;
p0 = p1;
continue;
}
if (xMin > xMax) { xMin = p0.X; xMax = p1.X; }
int scanline_idx0 = (p0.X + ((p0.X > 0)? -1 : -lineSpacing)) / lineSpacing; // -1 cause a linesegment on scanline x counts as belonging to scansegment x-1 ...
int scanline_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)
int direction = 1;
if (p0.X > p1.X)
{
direction = -1;
scanline_idx1 += 1; // only consider the scanlines in between the scansegments
} else scanline_idx0 += 1; // only consider the scanlines in between the scansegments
if (isFirstBoundarySegment) firstBoundarySegment.push_back(p0);
for(int scanline_idx = scanline_idx0; scanline_idx != scanline_idx1+direction; scanline_idx+=direction)
{
int x = scanline_idx * lineSpacing;
int y = p1.Y + (p0.Y - p1.Y) * (x - p1.X) / (p0.X - p1.X);
cutList[scanline_idx - scanline_min_idx].push_back(y);
bool last_isEvenScanSegment = isEvenScanSegment;
if (scanline_idx % 2 == 0) isEvenScanSegment = true;
else isEvenScanSegment = false;
if (!isFirstBoundarySegment)
{
if (last_isEvenScanSegment && (connect_zigzags || !isEvenScanSegment))
addLine(lastPoint, Point(x,y));
else if (connect_zigzags && !last_isEvenScanSegment && !isEvenScanSegment) // if we end an uneven boundary in an uneven segment
{ // add whole unevenBoundarySegment (including the just obtained point)
for (unsigned int p = 1; p < unevenBoundarySegment.size(); p++)
{
addLine(unevenBoundarySegment[p-1], unevenBoundarySegment[p]);
}
addLine(unevenBoundarySegment[unevenBoundarySegment.size()-1], Point(x,y));
unevenBoundarySegment.clear();
}
if (connect_zigzags && last_isEvenScanSegment && !isEvenScanSegment)
unevenBoundarySegment.push_back(Point(x,y));
else
unevenBoundarySegment.clear();
}
lastPoint = Point(x,y);
if (isFirstBoundarySegment)
{
firstBoundarySegment.emplace_back(x,y);
firstBoundarySegmentEndsInEven = isEvenScanSegment;
isFirstBoundarySegment = false;
}
}
if (!isFirstBoundarySegment)
{
if (isEvenScanSegment)
addLine(lastPoint, p1);
else if (connect_zigzags)
unevenBoundarySegment.push_back(p1);
}
lastPoint = p1;
p0 = p1;
}
if (isEvenScanSegment || isFirstBoundarySegment || connect_zigzags)
{
for (unsigned int i = 1; i < firstBoundarySegment.size() ; i++)
{
if (i < firstBoundarySegment.size() - 1 || !firstBoundarySegmentEndsInEven || connect_zigzags) // only add last element if connect_zigzags or boundary segment ends in uneven scanline
addLine(firstBoundarySegment[i-1], firstBoundarySegment[i]);
}
}
else if (!firstBoundarySegmentEndsInEven)
addLine(firstBoundarySegment[firstBoundarySegment.size()-2], firstBoundarySegment[firstBoundarySegment.size()-1]);
}
if (cutList.size() == 0) return;
if (connect_zigzags && cutList.size() == 1 && cutList[0].size() <= 2) return; // don't add connection if boundary already contains whole outline!
addLineInfill(result, matrix, scanline_min_idx, lineSpacing, boundary, cutList, extrusionWidth);
}
void generateZigZagInfill_noEndPieces(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation)
{
if (in_outline.size() == 0) return;
Polygons outline = in_outline.offset(extrusionWidth * infillOverlap / 100 - extrusionWidth / 2);
if (outline.size() == 0) return;
PointMatrix matrix(rotation);
outline.applyMatrix(matrix);
auto addLine = [&](Point from, Point to)
{
PolygonRef p = result.newPoly();
p.add(matrix.unapply(from));
p.add(matrix.unapply(to));
};
AABB boundary(outline);
int scanline_min_idx = boundary.min.X / lineSpacing;
int lineCount = (boundary.max.X + (lineSpacing - 1)) / lineSpacing - scanline_min_idx;
std::vector<std::vector<int64_t> > cutList; // mapping from scanline to all intersections with polygon segments
for(int n=0; n<lineCount; n++)
cutList.push_back(std::vector<int64_t>());
for(unsigned int polyNr=0; polyNr < outline.size(); polyNr++)
{
std::vector<Point> firstBoundarySegment;
std::vector<Point> boundarySegment;
bool isFirstBoundarySegment = true;
bool firstBoundarySegmentEndsInEven;
bool isEvenScanSegment = false;
Point p0 = outline[polyNr][outline[polyNr].size()-1];
for(unsigned int i=0; i < outline[polyNr].size(); i++)
{
Point p1 = outline[polyNr][i];
int64_t xMin = p1.X, xMax = p0.X;
if (xMin == xMax) {
p0 = p1;
continue;
}
if (xMin > xMax) { xMin = p0.X; xMax = p1.X; }
int scanline_idx0 = (p0.X + ((p0.X > 0)? -1 : -lineSpacing)) / lineSpacing; // -1 cause a linesegment on scanline x counts as belonging to scansegment x-1 ...
int scanline_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)
int direction = 1;
if (p0.X > p1.X)
{
direction = -1;
scanline_idx1 += 1; // only consider the scanlines in between the scansegments
} else scanline_idx0 += 1; // only consider the scanlines in between the scansegments
if (isFirstBoundarySegment) firstBoundarySegment.push_back(p0);
else boundarySegment.push_back(p0);
for(int scanline_idx = scanline_idx0; scanline_idx != scanline_idx1+direction; scanline_idx+=direction)
{
int x = scanline_idx * lineSpacing;
int y = p1.Y + (p0.Y - p1.Y) * (x - p1.X) / (p0.X - p1.X);
cutList[scanline_idx - scanline_min_idx].push_back(y);
bool last_isEvenScanSegment = isEvenScanSegment;
if (scanline_idx % 2 == 0) isEvenScanSegment = true;
else isEvenScanSegment = false;
if (!isFirstBoundarySegment)
{
if (last_isEvenScanSegment && !isEvenScanSegment)
{ // add whole boundarySegment (including the just obtained point)
for (unsigned int p = 1; p < boundarySegment.size(); p++)
{
addLine(boundarySegment[p-1], boundarySegment[p]);
}
addLine(boundarySegment[boundarySegment.size()-1], Point(x,y));
boundarySegment.clear();
}
else if (isEvenScanSegment) // we are either in an end piece or an uneven boundary segment
{
boundarySegment.clear();
boundarySegment.emplace_back(x,y);
} else
boundarySegment.clear();
}
if (isFirstBoundarySegment)
{
firstBoundarySegment.emplace_back(x,y);
firstBoundarySegmentEndsInEven = isEvenScanSegment;
isFirstBoundarySegment = false;
boundarySegment.emplace_back(x,y);
}
}
if (!isFirstBoundarySegment && isEvenScanSegment)
boundarySegment.push_back(p1);
p0 = p1;
}
if (!isFirstBoundarySegment && isEvenScanSegment && !firstBoundarySegmentEndsInEven)
{
for (unsigned int i = 1; i < firstBoundarySegment.size() ; i++)
addLine(firstBoundarySegment[i-1], firstBoundarySegment[i]);
}
}
addLineInfill(result, matrix, scanline_min_idx, lineSpacing, boundary, cutList, extrusionWidth);
}
}//namespace cura
+19
Ver Arquivo
@@ -0,0 +1,19 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef INFILL_H
#define INFILL_H
#include "utils/polygon.h"
namespace cura {
void generateConcentricInfill(Polygons outline, Polygons& result, int inset_value);
void generateConcentricInfillDense(Polygons outline, Polygons& result, Polygons* in_between, int extrusionWidth, bool avoidOverlappingPerimeters);
void generateGridInfill(const Polygons& in_outline, int outlineOffset, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation);
void generateTriangleInfill(const Polygons& in_outline, int outlineOffset, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation);
void generateLineInfill(const Polygons& in_outline, int outlineOffset, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation);
void generateZigZagInfill(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation, bool connect_zigzags, bool use_endPieces);
void generateZigZagInfill_endPieces(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation, bool connect_zigzags);
void generateZigZagInfill_noEndPieces(const Polygons& in_outline, Polygons& result, int extrusionWidth, int lineSpacing, int infillOverlap, double rotation);
}//namespace cura
#endif//INFILL_H
+60
Ver Arquivo
@@ -0,0 +1,60 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "inset.h"
#include "polygonOptimizer.h"
#include "utils/polygonUtils.h"
namespace cura {
void generateInsets(SliceLayerPart* part, int line_width_0, int line_width_x, int insetCount, bool avoidOverlappingPerimeters)
{
int combBoundaryInset = line_width_x/2; // hard coded value
part->combBoundery = part->outline.offset(-combBoundaryInset);
if (insetCount == 0)
{
part->insets.push_back(part->outline);
return;
}
for(int i=0; i<insetCount; i++)
{
part->insets.push_back(Polygons());
if (i == 0)
{
offsetSafe(part->outline, - line_width_x/2, line_width_x, part->insets[i], avoidOverlappingPerimeters);
} else if (i == 1)
{
offsetExtrusionWidth(part->insets[i-1], true, line_width_0, part->insets[i], &part->perimeterGaps, avoidOverlappingPerimeters);
} else
{
offsetExtrusionWidth(part->insets[i-1], true, line_width_x, part->insets[i], &part->perimeterGaps, avoidOverlappingPerimeters);
}
optimizePolygons(part->insets[i]);
if (part->insets[i].size() < 1)
{
part->insets.pop_back();
break;
}
}
}
void generateInsets(SliceLayer* layer, int line_width_0, int line_width_x, int insetCount, bool avoidOverlappingPerimeters)
{
for(unsigned int partNr = 0; partNr < layer->parts.size(); partNr++)
{
generateInsets(&layer->parts[partNr], line_width_0, line_width_x, insetCount, avoidOverlappingPerimeters);
}
//Remove the parts which did not generate an inset. As these parts are too small to print,
// and later code can now assume that there is always minimal 1 inset line.
for(unsigned int partNr = 0; partNr < layer->parts.size(); partNr++)
{
if (layer->parts[partNr].insets.size() < 1)
{
layer->parts.erase(layer->parts.begin() + partNr);
partNr -= 1;
}
}
}
}//namespace cura
+34
Ver Arquivo
@@ -0,0 +1,34 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef INSET_H
#define INSET_H
#include "sliceDataStorage.h"
namespace cura
{
/*!
* 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)
*/
void generateInsets(SliceLayerPart* part, int line_width_0, int line_width_x, int insetCount, bool avoidOverlappingPerimeters);
/*!
* 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)
*/
void generateInsets(SliceLayer* layer, int line_width_0, int line_width_x, int insetCount, bool avoidOverlappingPerimeters);
}//namespace cura
#endif//INSET_H
+89 -90
Ver Arquivo
@@ -1,90 +1,89 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdio.h>
#include "layerPart.h"
#include "settings.h"
/*
The layer-part creation step is the first step in creating actual useful data for 3D printing.
It takes the result of the Slice step, which is an unordered list of polygons, and makes groups of polygons,
each of these groups is called a "part", which sometimes are also known as "islands". These parts represent
isolated areas in the 2D layer with possible holes.
Creating "parts" is an important step, as all elements in a single part should be printed before going to another part.
And all every bit inside a single part can be printed without the nozzle leaving the boundery of this part.
It's also the first step that stores the result in the "data storage" so all other steps can access it.
*/
void createLayerWithParts(SliceLayer& storageLayer, SlicerLayer* layer, int unionAllType)
{
if (unionAllType & FIX_HORRIBLE_UNION_ALL_TYPE_B)
{
for(unsigned int i=0; i<layer->polygonList.size(); i++)
{
if (layer->polygonList[i].orientation())
layer->polygonList[i].reverse();
}
}
vector<Polygons> result;
if (unionAllType & FIX_HORRIBLE_UNION_ALL_TYPE_C)
result = layer->polygonList.offset(1000).splitIntoParts(unionAllType);
else
result = layer->polygonList.splitIntoParts(unionAllType);
for(unsigned int i=0; i<result.size(); i++)
{
storageLayer.parts.push_back(SliceLayerPart());
if (unionAllType & FIX_HORRIBLE_UNION_ALL_TYPE_C)
{
storageLayer.parts[i].outline.add(result[i][0]);
storageLayer.parts[i].outline = storageLayer.parts[i].outline.offset(-1000);
}else
storageLayer.parts[i].outline = result[i];
storageLayer.parts[i].boundaryBox.calculate(storageLayer.parts[i].outline);
}
}
void createLayerParts(SliceVolumeStorage& storage, Slicer* slicer, int unionAllType)
{
for(unsigned int layerNr = 0; layerNr < slicer->layers.size(); layerNr++)
{
storage.layers.push_back(SliceLayer());
createLayerWithParts(storage.layers[layerNr], &slicer->layers[layerNr], unionAllType);
}
}
void dumpLayerparts(SliceDataStorage& storage, const char* filename)
{
FILE* out = fopen(filename, "w");
fprintf(out, "<!DOCTYPE html><html><body>");
Point3 modelSize = storage.modelSize;
Point3 modelMin = storage.modelMin;
for(unsigned int volumeIdx=0; volumeIdx<storage.volumes.size(); volumeIdx++)
{
for(unsigned int layerNr=0;layerNr<storage.volumes[volumeIdx].layers.size(); layerNr++)
{
fprintf(out, "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" style=\"width: 500px; height:500px\">\n");
SliceLayer* layer = &storage.volumes[volumeIdx].layers[layerNr];
for(unsigned int i=0;i<layer->parts.size();i++)
{
SliceLayerPart* part = &layer->parts[i];
for(unsigned int j=0;j<part->outline.size();j++)
{
fprintf(out, "<polygon points=\"");
for(unsigned int k=0;k<part->outline[j].size();k++)
fprintf(out, "%f,%f ", float(part->outline[j][k].X - modelMin.x)/modelSize.x*500, float(part->outline[j][k].Y - modelMin.y)/modelSize.y*500);
if (j == 0)
fprintf(out, "\" style=\"fill:gray; stroke:black;stroke-width:1\" />\n");
else
fprintf(out, "\" style=\"fill:red; stroke:black;stroke-width:1\" />\n");
}
}
fprintf(out, "</svg>\n");
}
}
fprintf(out, "</body></html>");
fclose(out);
}
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdio.h>
#include "layerPart.h"
#include "settings.h"
/*
The layer-part creation step is the first step in creating actual useful data for 3D printing.
It takes the result of the Slice step, which is an unordered list of polygons, and makes groups of polygons,
each of these groups is called a "part", which sometimes are also known as "islands". These parts represent
isolated areas in the 2D layer with possible holes.
Creating "parts" is an important step, as all elements in a single part should be printed before going to another part.
And all every bit inside a single part can be printed without the nozzle leaving the boundery of this part.
It's also the first step that stores the result in the "data storage" so all other steps can access it.
*/
namespace cura {
void createLayerWithParts(SliceLayer& storageLayer, SlicerLayer* layer, bool union_layers, bool union_all_remove_holes)
{
storageLayer.openLines = layer->openPolygons;
if (union_all_remove_holes)
{
for(unsigned int i=0; i<layer->polygonList.size(); i++)
{
if (layer->polygonList[i].orientation())
layer->polygonList[i].reverse();
}
}
std::vector<Polygons> result;
result = layer->polygonList.splitIntoParts(union_layers || union_all_remove_holes);
for(unsigned int i=0; i<result.size(); i++)
{
storageLayer.parts.push_back(SliceLayerPart());
storageLayer.parts[i].outline = result[i];
storageLayer.parts[i].boundaryBox.calculate(storageLayer.parts[i].outline);
}
}
void createLayerParts(SliceMeshStorage& storage, Slicer* slicer, bool union_layers, bool union_all_remove_holes)
{
for(unsigned int layer_nr = 0; layer_nr < slicer->layers.size(); layer_nr++)
{
storage.layers.push_back(SliceLayer());
storage.layers[layer_nr].sliceZ = slicer->layers[layer_nr].z;
storage.layers[layer_nr].printZ = slicer->layers[layer_nr].z;
createLayerWithParts(storage.layers[layer_nr], &slicer->layers[layer_nr], union_layers, union_all_remove_holes);
logProgress("layerparts", layer_nr + 1, slicer->layers.size());
}
}
void dumpLayerparts(SliceDataStorage& storage, const char* filename)
{
FILE* out = fopen(filename, "w");
fprintf(out, "<!DOCTYPE html><html><body>");
Point3 modelSize = storage.model_size;
Point3 modelMin = storage.model_min;
for(SliceMeshStorage& mesh : storage.meshes)
{
for(SliceLayer& layer : mesh.layers)
{
fprintf(out, "<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" style=\"width: 500px; height:500px\">\n");
for(SliceLayerPart& part : layer.parts)
{
for(unsigned int j=0;j<part.outline.size();j++)
{
fprintf(out, "<polygon points=\"");
for(unsigned int k=0;k<part.outline[j].size();k++)
fprintf(out, "%f,%f ", float(part.outline[j][k].X - modelMin.x)/modelSize.x*500, float(part.outline[j][k].Y - modelMin.y)/modelSize.y*500);
if (j == 0)
fprintf(out, "\" style=\"fill:gray; stroke:black;stroke-width:1\" />\n");
else
fprintf(out, "\" style=\"fill:red; stroke:black;stroke-width:1\" />\n");
}
}
fprintf(out, "</svg>\n");
}
}
fprintf(out, "</body></html>");
fclose(out);
}
}//namespace cura
+30 -27
Ver Arquivo
@@ -1,27 +1,30 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef LAYERPART_H
#define LAYERPART_H
#include "sliceDataStorage.h"
#include "slicer.h"
/*
The layer-part creation step is the first step in creating actual useful data for 3D printing.
It takes the result of the Slice step, which is an unordered list of polygons, and makes groups of polygons,
each of these groups is called a "part", which sometimes are also known as "islands". These parts represent
isolated areas in the 2D layer with possible holes.
Creating "parts" is an important step, as all elements in a single part should be printed before going to another part.
And all every bit inside a single part can be printed without the nozzle leaving the boundery of this part.
It's also the first step that stores the result in the "data storage" so all other steps can access it.
*/
void createLayerWithParts(SliceLayer& storageLayer, SlicerLayer* layer, int unionAllType);
void createLayerParts(SliceVolumeStorage& storage, Slicer* slicer, int unionAllType);
void dumpLayerparts(SliceDataStorage& storage, const char* filename);
#endif//LAYERPART_H
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef LAYERPART_H
#define LAYERPART_H
#include "sliceDataStorage.h"
#include "slicer.h"
/*
The layer-part creation step is the first step in creating actual useful data for 3D printing.
It takes the result of the Slice step, which is an unordered list of polygons, and makes groups of polygons,
each of these groups is called a "part", which sometimes are also known as "islands". These parts represent
isolated areas in the 2D layer with possible holes.
Creating "parts" is an important step, as all elements in a single part should be printed before going to another part.
And all every bit inside a single part can be printed without the nozzle leaving the boundery of this part.
It's also the first step that stores the result in the "data storage" so all other steps can access it.
*/
namespace cura {
void createLayerWithParts(SliceLayer& storageLayer, SlicerLayer* layer, bool union_layers, bool union_all_remove_holes);
void createLayerParts(SliceMeshStorage& storage, Slicer* slicer, bool union_layers, bool union_all_remove_holes);
void dumpLayerparts(SliceDataStorage& storage, const char* filename);
}//namespace cura
#endif//LAYERPART_H
+210
Ver Arquivo
@@ -0,0 +1,210 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
#include <execinfo.h>
#include <sys/resource.h>
#endif
#include <stddef.h>
#include <vector>
#include "utils/gettime.h"
#include "utils/logoutput.h"
#include "utils/string.h"
#include "sliceDataStorage.h"
#include "modelFile/modelFile.h"
#include "settings.h"
#include "settingRegistry.h"
#include "multiVolumes.h"
#include "polygonOptimizer.h"
#include "slicer.h"
#include "layerPart.h"
#include "inset.h"
#include "skin.h"
#include "infill.h"
#include "bridge.h"
#include "support.h"
#include "pathOrderOptimizer.h"
#include "skirt.h"
#include "raft.h"
#include "comb.h"
#include "gcodeExport.h"
#include "fffProcessor.h"
void print_usage()
{
cura::logError("usage: CuraEngine [-h] [-v] [-m 3x3matrix] [-c <config file>] [-s <settingkey>=<value>] -o <output.gcode> <model.stl>\n");
}
//Signal handler for a "floating point exception", which can also be integer division by zero errors.
void signal_FPE(int n)
{
(void)n;
cura::logError("Arithmetic exception.\n");
exit(1);
}
using namespace cura;
int main(int argc, char **argv)
{
#if defined(__linux__) || (defined(__APPLE__) && defined(__MACH__))
//Lower the process priority on linux and mac. On windows this is done on process creation from the GUI.
setpriority(PRIO_PROCESS, 0, 10);
#endif
#ifndef DEBUG
//Register the exception handling for arithmic exceptions, this prevents the "something went wrong" dialog on windows to pop up on a division by zero.
signal(SIGFPE, signal_FPE);
#endif
fffProcessor processor;
std::vector<std::string> files;
logCopyright("Cura_SteamEngine version %s\n", VERSION);
logCopyright("Copyright (C) 2014 David Braam\n");
logCopyright("\n");
logCopyright("This program is free software: you can redistribute it and/or modify\n");
logCopyright("it under the terms of the GNU Affero General Public License as published by\n");
logCopyright("the Free Software Foundation, either version 3 of the License, or\n");
logCopyright("(at your option) any later version.\n");
logCopyright("\n");
logCopyright("This program is distributed in the hope that it will be useful,\n");
logCopyright("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
logCopyright("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
logCopyright("GNU Affero General Public License for more details.\n");
logCopyright("\n");
logCopyright("You should have received a copy of the GNU Affero General Public License\n");
logCopyright("along with this program. If not, see <http://www.gnu.org/licenses/>.\n");
CommandSocket* commandSocket = NULL;
std::string ip;
int port = 49674;
for(int argn = 1; argn < argc; argn++)
{
char* str = argv[argn];
if (str[0] == '-')
{
if (str[1] == '-')
{
if (stringcasecompare(str, "--connect") == 0)
{
commandSocket = new CommandSocket(&processor);
std::string ip_port(argv[argn + 1]);
if (ip_port.find(':') != std::string::npos)
{
ip = ip_port.substr(0, ip_port.find(':'));
port = std::stoi(ip_port.substr(ip_port.find(':') + 1).data());
}
argn += 1;
}
else if (stringcasecompare(str, "--") == 0)
{
try {
//Catch all exceptions, this prevents the "something went wrong" dialog on windows to pop up on a thrown exception.
// Only ClipperLib currently throws exceptions. And only in case that it makes an internal error.
if (files.size() > 0)
processor.processFiles(files);
files.clear();
}catch(...){
cura::logError("Unknown exception\n");
exit(1);
}
break;
}else{
cura::logError("Unknown option: %s\n", str);
}
}else{
for(str++; *str; str++)
{
switch(*str)
{
case 'h':
print_usage();
exit(1);
case 'v':
cura::increaseVerboseLevel();
break;
case 'j':
argn++;
if (!SettingRegistry::getInstance()->loadJSON(argv[argn]))
{
cura::logError("ERROR: Failed to load json file: %s\n", argv[argn]);
}
break;
case 'p':
cura::enableProgressLogging();
break;
case 'o':
argn++;
if (!processor.setTargetFile(argv[argn]))
{
cura::logError("Failed to open %s for output.\n", argv[argn]);
exit(1);
}
break;
case 's':
{
//Parse the given setting and store it.
argn++;
char* valuePtr = strchr(argv[argn], '=');
if (valuePtr)
{
*valuePtr++ = '\0';
processor.setSetting(argv[argn], valuePtr);
}
}
break;
default:
cura::logError("Unknown option: %c\n", *str);
break;
}
}
}
}else{
files.push_back(argv[argn]);
}
}
if (!SettingRegistry::getInstance()->settingsLoaded())
{
//If no json file has been loaded, try to load the default.
if (!SettingRegistry::getInstance()->loadJSON("fdmprinter.json"))
{
logError("ERROR: Failed to load json file: fdmprinter.json\n");
}
}
if(commandSocket)
{
commandSocket->connect(ip, port);
}
else
{
#ifndef DEBUG
try {
#endif
//Catch all exceptions, this prevents the "something went wrong" dialog on windows to pop up on a thrown exception.
// Only ClipperLib currently throws exceptions. And only in case that it makes an internal error.
if (files.size() > 0)
processor.processFiles(files);
#ifndef DEBUG
}catch(...){
cura::logError("Unknown exception\n");
exit(1);
}
#endif
//Finalize the processor, this adds the end.gcode. And reports statistics.
processor.finalize();
}
return 0;
}
+193
Ver Arquivo
@@ -0,0 +1,193 @@
#include "mesh.h"
#include "utils/logoutput.h"
const int vertex_meld_distance = MM2INT(0.03);
static inline uint32_t pointHash(Point3& p)
{
return ((p.x + vertex_meld_distance/2) / vertex_meld_distance) ^ (((p.y + vertex_meld_distance/2) / vertex_meld_distance) << 10) ^ (((p.z + vertex_meld_distance/2) / vertex_meld_distance) << 20);
}
Mesh::Mesh(SettingsBase* parent)
: SettingsBase(parent)
{
}
void Mesh::addFace(Point3& v0, Point3& v1, Point3& v2)
{
int vi0 = findIndexOfVertex(v0);
int vi1 = findIndexOfVertex(v1);
int vi2 = findIndexOfVertex(v2);
if (vi0 == vi1 || vi1 == vi2 || vi0 == vi2) return; // the face has two vertices which get assigned the same location. Don't add the face.
int idx = faces.size(); // index of face to be added
faces.emplace_back();
MeshFace& face = faces[idx];
face.vertex_index[0] = vi0;
face.vertex_index[1] = vi1;
face.vertex_index[2] = vi2;
vertices[face.vertex_index[0]].connected_faces.push_back(idx);
vertices[face.vertex_index[1]].connected_faces.push_back(idx);
vertices[face.vertex_index[2]].connected_faces.push_back(idx);
}
void Mesh::clear()
{
faces.clear();
vertices.clear();
vertex_hash_map.clear();
}
void Mesh::finish()
{
// Finish up the mesh, clear the vertex_hash_map, as it's no longer needed from this point on and uses quite a bit of memory.
vertex_hash_map.clear();
// For each face, store which other face is connected with it.
for(unsigned int i=0; i<faces.size(); i++)
{
MeshFace& face = faces[i];
face.connected_face_index[0] = getFaceIdxWithPoints(face.vertex_index[0], face.vertex_index[1], i); // faces are connected via the outside
face.connected_face_index[1] = getFaceIdxWithPoints(face.vertex_index[1], face.vertex_index[2], i);
face.connected_face_index[2] = getFaceIdxWithPoints(face.vertex_index[2], face.vertex_index[0], i);
}
}
Point3 Mesh::min()
{
if (vertices.size() < 1)
return Point3(0, 0, 0);
Point3 ret = vertices[0].p;
for(unsigned int i=0; i<vertices.size(); i++)
{
ret.x = std::min(ret.x, vertices[i].p.x);
ret.y = std::min(ret.y, vertices[i].p.y);
ret.z = std::min(ret.z, vertices[i].p.z);
}
return ret;
}
Point3 Mesh::max()
{
if (vertices.size() < 1)
return Point3(0, 0, 0);
Point3 ret = vertices[0].p;
for(unsigned int i=0; i<vertices.size(); i++)
{
ret.x = std::max(ret.x, vertices[i].p.x);
ret.y = std::max(ret.y, vertices[i].p.y);
ret.z = std::max(ret.z, vertices[i].p.z);
}
return ret;
}
int Mesh::findIndexOfVertex(Point3& v)
{
uint32_t hash = pointHash(v);
for(unsigned int idx = 0; idx < vertex_hash_map[hash].size(); idx++)
{
if ((vertices[vertex_hash_map[hash][idx]].p - v).testLength(vertex_meld_distance))
{
return vertex_hash_map[hash][idx];
}
}
vertex_hash_map[hash].push_back(vertices.size());
vertices.emplace_back(v);
return vertices.size() - 1;
}
/*!
Returns the index of the 'other' face connected to the edge between vertices with indices idx0 and idx1.
In case more than two faces are connected via the same edge, the next face in a counter-clockwise ordering (looking from idx1 to idx0) is returned.
\cond DOXYGEN_EXCLUDE
[NON-RENDERED COMENTS]
For two faces abc and abd with normals n and m, we have that:
\f{eqnarray*}{
n &=& \frac{ab \times ac}{\|ab \times ac\|} \\
m &=& \frac{ab \times ad}{\|ab \times ad\|} \\
n \times m &=& \|n\| \cdot \|m\| \mathbf{p} \sin \alpha \\
&& (\mathbf{p} \perp n \wedge \mathbf{p} \perp m) \\
\sin \alpha &=& \|n \times m \|
&=& \left\| \frac{(ab \times ac) \times (ab \times ad)}{\|ab \times ac\| \cdot \|ab \times ad\|} \right\| \\
&=& \left\| \frac{ (ab \cdot (ac \times ad)) ab }{\|ab \times ac\| \cdot \|ab \times ad\|} \right\| \\
&=& \frac{ (ab \cdot (ac \times ad)) \left\| ab \right\| }{\|ab\| \|ac\| \sin bac \cdot \|ab\| \|ad\| \sin bad} \\
&=& \frac{ ab \cdot (ac \times ad) }{\|ab\| \|ac\| \|ad\| \sin bac \sin bad} \\
\f}}
\endcond
See <a href="http://stackoverflow.com/questions/14066933/direct-way-of-computing-clockwise-angle-between-2-vectors">Direct way of computing clockwise angle between 2 vectors</a>
*/
int Mesh::getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx)
{
std::vector<int> candidateFaces; // in case more than two faces meet at an edge, multiple candidates are generated
int notFaceVertexIdx = -1; // index of the third vertex of the face corresponding to notFaceIdx
for(int f : vertices[idx0].connected_faces) // search through all faces connected to the first vertex and find those that are also connected to the second
{
if (f == notFaceIdx)
{
for (int i = 0; i<3; i++) // find the vertex which is not idx0 or idx1
if (faces[f].vertex_index[i] != idx0 && faces[f].vertex_index[i] != idx1)
notFaceVertexIdx = faces[f].vertex_index[i];
continue;
}
if ( faces[f].vertex_index[0] == idx1 // && faces[f].vertex_index[1] == idx0 // next face should have the right direction!
|| faces[f].vertex_index[1] == idx1 // && faces[f].vertex_index[2] == idx0
|| faces[f].vertex_index[2] == idx1 // && faces[f].vertex_index[0] == idx0
) candidateFaces.push_back(f);
}
if (candidateFaces.size() == 0) { cura::logError("Couldn't find face connected to face %i.\n", notFaceIdx); return -1; }
if (candidateFaces.size() == 1) { return candidateFaces[0]; }
if (notFaceVertexIdx < 0) { cura::logError("Couldn't find third point on face %i.\n", notFaceIdx); return -1; }
if (candidateFaces.size() % 2 == 0) cura::log("Warning! Edge with uneven number of faces connecting it!(%i)\n", candidateFaces.size()+1);
FPoint3 vn = vertices[idx1].p - vertices[idx0].p;
FPoint3 n = vn / vn.vSize(); // the normal of the plane in which all normals of faces connected to the edge lie => the normalized normal
FPoint3 v0 = vertices[idx1].p - vertices[idx0].p;
// the normals below are abnormally directed! : these normals all point counterclockwise (viewed from idx1 to idx0) from the face, irrespective of the direction of the face.
FPoint3 n0 = FPoint3(vertices[notFaceVertexIdx].p - vertices[idx0].p).cross(v0);
if (n0.vSize() <= 0) cura::log("Warning! Face %i has zero area!", notFaceIdx);
double smallestAngle = 1000; // more then 2 PI (impossible angle)
int bestIdx = -1;
for (int candidateFace : candidateFaces)
{
int candidateVertex;
{// find third vertex belonging to the face (besides idx0 and idx1)
for (candidateVertex = 0; candidateVertex<3; candidateVertex++)
if (faces[candidateFace].vertex_index[candidateVertex] != idx0 && faces[candidateFace].vertex_index[candidateVertex] != idx1)
break;
}
FPoint3 v1 = vertices[candidateVertex].p -vertices[idx0].p;
FPoint3 n1 = v1.cross(v0);
double dot = n0 * n1;
double det = n * n0.cross(n1);
double angle = std::atan2(det, dot);
if (angle < 0) angle += 2*M_PI; // 0 <= angle < 2* M_PI
if (angle == 0)
{
cura::log("Warning! Overlapping faces: face %i and face %i.\n", notFaceIdx, candidateFace);
std::cerr<< n.vSize() <<"; "<<n1.vSize()<<";"<<n0.vSize() <<std::endl;
}
if (angle < smallestAngle)
{
smallestAngle = angle;
bestIdx = candidateFace;
}
}
if (bestIdx < 0) cura::logError("Couldn't find face connected to face %i.\n", notFaceIdx);
return bestIdx;
}
+82
Ver Arquivo
@@ -0,0 +1,82 @@
#ifndef MESH_H
#define MESH_H
#include "settings.h"
/*!
Vertex type to be used in a Mesh.
Keeps track of which faces connect to it.
*/
class MeshVertex
{
public:
Point3 p; //!< location of the vertex
std::vector<uint32_t> connected_faces; //!< list of the indices of connected faces
MeshVertex(Point3 p) : p(p) {} //!< doesn't set connected_faces
};
/*! A MeshFace is a 3 dimensional model triangle with 3 points. These points are already converted to integers
A face has 3 connected faces, corresponding to its 3 edges.
Note that a correct model may have more than 2 faces connected via a single edge!
In such a case the face_index stored in connected_face_index is the one connected via the outside; see ASCII art below:
: horizontal slice through vertical edge connected to four faces :
\verbatim
[inside] x|
x| <--+--- faces which contain each other in their connected_face_index fiels
xxxxxxx| \|/
-------+-------
^ |xxxxxxx
+-->|x
| |x [inside]
|
faces which contain each other in their connected_face_index fiels
\endverbatim
*/
class MeshFace
{
public:
int vertex_index[3] = {-1}; //!< counter-clockwise ordering
int connected_face_index[3]; //!< same ordering as vertex_index (connected_face 0 is connected via vertex 0 and 1, etc.)
};
/*!
A Mesh is the most basic representation of a 3D model. It contains all the faces as MeshFaces.
See MeshFace for the specifics of how/when faces are connected.
*/
class Mesh : public SettingsBase // 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.
std::map<uint32_t, std::vector<uint32_t> > vertex_hash_map;
public:
std::vector<MeshVertex> vertices;//!< list of all vertices in the mesh
std::vector<MeshFace> faces; //!< list of all faces in the mesh
Mesh(SettingsBase* parent); //!< initializes the settings
void addFace(Point3& v0, Point3& v1, Point3& v2); //!< add a face to the mesh without settings it's connected_faces.
void clear(); //!< clears all data
void finish(); //!< complete the model : set the connected_face_index fields of the faces.
Point3 min(); //!< min (in x,y and z) vertex of the bounding box
Point3 max(); //!< max (in x,y and z) vertex of the bounding box
private:
int findIndexOfVertex(Point3& v); //!< find index of vertex close to the given point, or create a new vertex and return its index.
/*!
Get the index of the face connected to the face with index \p notFaceIdx, via vertices \p idx0 and \p idx1.
In case multiple faces connect with the same edge, return the next counter-clockwise face when viewing from \p idx1 to \p idx0.
*/
int getFaceIdxWithPoints(int idx0, int idx1, int notFaceIdx);
};
#endif//MESH_H
+150
Ver Arquivo
@@ -0,0 +1,150 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <string.h>
#include <strings.h>
#include <stdio.h>
#include "modelFile.h"
#include "../utils/logoutput.h"
#include "../utils/string.h"
FILE* binaryMeshBlob = nullptr;
/* Custom fgets function to support Mac line-ends in Ascii STL files. OpenSCAD produces this when used on Mac */
void* fgets_(char* ptr, size_t len, FILE* f)
{
while(len && fread(ptr, 1, 1, f) > 0)
{
if (*ptr == '\n' || *ptr == '\r')
{
*ptr = '\0';
return ptr;
}
ptr++;
len--;
}
return nullptr;
}
bool loadModelSTL_ascii(Mesh* mesh, const char* filename, FMatrix3x3& matrix)
{
FILE* f = fopen(filename, "rt");
char buffer[1024];
FPoint3 vertex;
int n = 0;
Point3 v0(0,0,0), v1(0,0,0), v2(0,0,0);
while(fgets_(buffer, sizeof(buffer), f))
{
if (sscanf(buffer, " vertex %f %f %f", &vertex.x, &vertex.y, &vertex.z) == 3)
{
n++;
switch(n)
{
case 1:
v0 = matrix.apply(vertex);
break;
case 2:
v1 = matrix.apply(vertex);
break;
case 3:
v2 = matrix.apply(vertex);
mesh->addFace(v0, v1, v2);
n = 0;
break;
}
}
}
fclose(f);
mesh->finish();
return true;
}
bool loadModelSTL_binary(Mesh* mesh, const char* filename, FMatrix3x3& matrix)
{
FILE* f = fopen(filename, "rb");
char buffer[80];
uint32_t faceCount;
//Skip the header
if (fread(buffer, 80, 1, f) != 1)
{
fclose(f);
return false;
}
//Read the face count
if (fread(&faceCount, sizeof(uint32_t), 1, f) != 1)
{
fclose(f);
return false;
}
//For each face read:
//float(x,y,z) = normal, float(X,Y,Z)*3 = vertexes, uint16_t = flags
for(unsigned int i=0;i<faceCount;i++)
{
if (fread(buffer, sizeof(float) * 3, 1, f) != 1)
{
fclose(f);
return false;
}
float v[9];
if (fread(v, sizeof(float) * 9, 1, f) != 1)
{
fclose(f);
return false;
}
Point3 v0 = matrix.apply(FPoint3(v[0], v[1], v[2]));
Point3 v1 = matrix.apply(FPoint3(v[3], v[4], v[5]));
Point3 v2 = matrix.apply(FPoint3(v[6], v[7], v[8]));
mesh->addFace(v0, v1, v2);
if (fread(buffer, sizeof(uint16_t), 1, f) != 1)
{
fclose(f);
return false;
}
}
fclose(f);
mesh->finish();
return true;
}
bool loadModelSTL(Mesh* mesh, const char* filename, FMatrix3x3& matrix)
{
FILE* f = fopen(filename, "r");
char buffer[6];
if (f == nullptr)
return false;
if (fread(buffer, 5, 1, f) != 1)
{
fclose(f);
return false;
}
fclose(f);
buffer[5] = '\0';
if (stringcasecompare(buffer, "solid") == 0)
{
bool load_success = loadModelSTL_ascii(mesh, filename, matrix);
if (!load_success)
return false;
// This logic is used to handle the case where the file starts with
// "solid" but is a binary file.
if (mesh->faces.size() < 1)
{
mesh->clear();
return loadModelSTL_binary(mesh, filename, matrix);
}
return true;
}
return loadModelSTL_binary(mesh, filename, matrix);
}
bool loadMeshFromFile(PrintObject* object, const char* filename, FMatrix3x3& matrix)
{
const char* ext = strrchr(filename, '.');
if (ext && (strcmp(ext, ".stl") == 0 || strcmp(ext, ".STL") == 0))
{
object->meshes.emplace_back(object);
return loadModelSTL(&object->meshes[object->meshes.size()-1], filename, matrix);
}
return false;
}
+98
Ver Arquivo
@@ -0,0 +1,98 @@
/** 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.
class PrintObject : public SettingsBase
{
public:
std::vector<Mesh> meshes;
PrintObject(SettingsBase* settings_base)
: SettingsBase(settings_base)
{
}
Point3 min() //! minimal corner of bounding box
{
if (meshes.size() < 1)
return Point3(0, 0, 0);
Point3 ret = meshes[0].min();
for(unsigned int i=1; i<meshes.size(); i++)
{
Point3 v = 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);
}
return ret;
}
Point3 max() //! maximal corner of bounding box
{
if (meshes.size() < 1)
return Point3(0, 0, 0);
Point3 ret = meshes[0].max();
for(unsigned int i=1; i<meshes.size(); i++)
{
Point3 v = 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);
}
return ret;
}
void clear()
{
for(Mesh& m : meshes)
m.clear();
}
void offset(Point3 offset)
{
for(Mesh& m : meshes)
for(MeshVertex& v : m.vertices)
v.p += offset;
}
void finalize()
{
// If a mesh position was given, put the mesh at this position in 3D space.
if (hasSetting("mesh_position_x") || hasSetting("mesh_position_y") || hasSetting("mesh_position_z"))
{
Point3 object_min = min();
Point3 object_max = max();
Point3 object_size = object_max - object_min;
Point3 object_offset = Point3(-object_min.x - object_size.x / 2, -object_min.y - object_size.y / 2, -object_min.z);
if (hasSetting("mesh_position_x"))
object_offset.x += getSettingInMicrons("mesh_position_x");
if (hasSetting("mesh_position_y"))
object_offset.y += getSettingInMicrons("mesh_position_y");
if (hasSetting("mesh_position_z"))
object_offset.z += getSettingInMicrons("mesh_position_z");
offset(object_offset);
}
//If the machine settings have been supplied, offset the given position vertices to the center of vertices (0,0,0) is at the bed center.
if (hasSetting("machine_center_is_zero") && !getSettingBoolean("machine_center_is_zero"))
{
Point3 object_offset = Point3(0, 0, 0);
if (hasSetting("machine_width"))
object_offset.x = getSettingInMicrons("machine_width") / 2;
if (hasSetting("machine_depth"))
object_offset.y = getSettingInMicrons("machine_depth") / 2;
offset(object_offset);
}
}
};
bool loadMeshFromFile(PrintObject* object, const char* filename, FMatrix3x3& matrix);
#endif//MODELFILE_H
+58 -59
Ver Arquivo
@@ -1,59 +1,58 @@
#ifndef MULTIVOLUMES_H
#define MULTIVOLUMES_H
/* This file contains code to help fixing up and changing layers that are build from multiple volumes. */
void carveMultipleVolumes(vector<SliceVolumeStorage> &volumes)
{
//Go trough all the volumes, and remove the previous volume outlines from our own outline, so we never have overlapped areas.
for(unsigned int idx=0; idx < volumes.size(); idx++)
{
for(unsigned int idx2=0; idx2<idx; idx2++)
{
for(unsigned int layerNr=0; layerNr < volumes[idx].layers.size(); layerNr++)
{
SliceLayer* layer1 = &volumes[idx].layers[layerNr];
SliceLayer* layer2 = &volumes[idx2].layers[layerNr];
for(unsigned int p1 = 0; p1 < layer1->parts.size(); p1++)
{
for(unsigned int p2 = 0; p2 < layer2->parts.size(); p2++)
{
layer1->parts[p1].outline = layer1->parts[p1].outline.difference(layer2->parts[p2].outline);
}
}
}
}
}
}
//Expand each layer a bit and then keep the extra overlapping parts that overlap with other volumes.
//This generates some overlap in dual extrusion, for better bonding in touching parts.
void generateMultipleVolumesOverlap(vector<SliceVolumeStorage> &volumes, int overlap)
{
if (volumes.size() < 2 || overlap <= 0) return;
for(unsigned int layerNr=0; layerNr < volumes[0].layers.size(); layerNr++)
{
Polygons fullLayer;
for(unsigned int volIdx = 0; volIdx < volumes.size(); volIdx++)
{
SliceLayer* layer1 = &volumes[volIdx].layers[layerNr];
for(unsigned int p1 = 0; p1 < layer1->parts.size(); p1++)
{
fullLayer = fullLayer.unionPolygons(layer1->parts[p1].outline.offset(20));
}
}
fullLayer = fullLayer.offset(-20);
for(unsigned int volIdx = 0; volIdx < volumes.size(); volIdx++)
{
SliceLayer* layer1 = &volumes[volIdx].layers[layerNr];
for(unsigned int p1 = 0; p1 < layer1->parts.size(); p1++)
{
layer1->parts[p1].outline = fullLayer.intersection(layer1->parts[p1].outline.offset(overlap / 2));
}
}
}
}
#endif//MULTIVOLUMES_H
#include "multiVolumes.h"
namespace cura {
void carveMultipleVolumes(std::vector<SliceMeshStorage> &volumes)
{
//Go trough all the volumes, and remove the previous volume outlines from our own outline, so we never have overlapped areas.
for(unsigned int idx=0; idx < volumes.size(); idx++)
{
for(unsigned int idx2=0; idx2<idx; idx2++)
{
for(unsigned int layerNr=0; layerNr < volumes[idx].layers.size(); layerNr++)
{
SliceLayer* layer1 = &volumes[idx].layers[layerNr];
SliceLayer* layer2 = &volumes[idx2].layers[layerNr];
for(unsigned int p1 = 0; p1 < layer1->parts.size(); p1++)
{
for(unsigned int p2 = 0; p2 < layer2->parts.size(); p2++)
{
layer1->parts[p1].outline = layer1->parts[p1].outline.difference(layer2->parts[p2].outline);
}
}
}
}
}
}
//Expand each layer a bit and then keep the extra overlapping parts that overlap with other volumes.
//This generates some overlap in dual extrusion, for better bonding in touching parts.
void generateMultipleVolumesOverlap(std::vector<SliceMeshStorage> &volumes, int overlap)
{
if (volumes.size() < 2 || overlap <= 0) return;
for(unsigned int layerNr=0; layerNr < volumes[0].layers.size(); layerNr++)
{
Polygons fullLayer;
for(unsigned int volIdx = 0; volIdx < volumes.size(); volIdx++)
{
SliceLayer* layer1 = &volumes[volIdx].layers[layerNr];
for(unsigned int p1 = 0; p1 < layer1->parts.size(); p1++)
{
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?)
}
}
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?)
for(unsigned int volIdx = 0; volIdx < volumes.size(); volIdx++)
{
SliceLayer* layer1 = &volumes[volIdx].layers[layerNr];
for(unsigned int p1 = 0; p1 < layer1->parts.size(); p1++)
{
layer1->parts[p1].outline = fullLayer.intersection(layer1->parts[p1].outline.offset(overlap / 2));
}
}
}
}
}//namespace cura
+17
Ver Arquivo
@@ -0,0 +1,17 @@
#ifndef MULTIVOLUMES_H
#define MULTIVOLUMES_H
#include "sliceDataStorage.h"
/* This file contains code to help fixing up and changing layers that are build from multiple volumes. */
namespace cura {
void carveMultipleVolumes(std::vector<SliceMeshStorage> &meshes);
//Expand each layer a bit and then keep the extra overlapping parts that overlap with other volumes.
//This generates some overlap in dual extrusion, for better bonding in touching parts.
void generateMultipleVolumesOverlap(std::vector<SliceMeshStorage> &meshes, int overlap);
}//namespace cura
#endif//MULTIVOLUMES_H
+246
Ver Arquivo
@@ -0,0 +1,246 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include <map>
#include "pathOrderOptimizer.h"
#include "utils/logoutput.h"
#include "utils/BucketGrid2D.h"
#define INLINE static inline
namespace cura {
/**
*
*/
void PathOrderOptimizer::optimize()
{
bool picked[polygons.size()];
memset(picked, false, sizeof(bool) * polygons.size());/// initialized as falses
for(unsigned int i_polygon=0 ; i_polygon<polygons.size() ; i_polygon++) /// find closest point to initial starting point within each polygon +initialize picked
{
int best = -1;
float bestDist = std::numeric_limits<float>::infinity();
PolygonRef poly = polygons[i_polygon];
for(unsigned int i_point=0; i_point<poly.size(); i_point++) /// get closest point in polygon
{
float dist = vSize2f(poly[i_point] - startPoint);
if (dist < bestDist)
{
best = i_point;
bestDist = dist;
}
}
polyStart.push_back(best);
//picked.push_back(false); /// initialize all picked values as false
assert(poly.size() != 2);
}
Point prev_point = startPoint;
for(unsigned int i_polygon=0 ; i_polygon<polygons.size() ; i_polygon++) /// actual path order optimizer
{
int best = -1;
float bestDist = std::numeric_limits<float>::infinity();
for(unsigned int i_polygon=0 ; i_polygon<polygons.size() ; i_polygon++)
{
if (picked[i_polygon] || polygons[i_polygon].size() < 1) /// skip single-point-polygons
continue;
assert (polygons[i_polygon].size() != 2);
float dist = vSize2f(polygons[i_polygon][polyStart[i_polygon]] - prev_point);
if (dist < bestDist)
{
best = i_polygon;
bestDist = dist;
}
}
if (best > -1) /// should always be true; we should have been able to identify the best next polygon
{
assert(polygons[best].size() != 2);
prev_point = polygons[best][polyStart[best]];
picked[best] = true;
polyOrder.push_back(best);
}
else
logError("Failed to find next closest polygon.\n");
}
prev_point = startPoint;
for(unsigned int n=0; n<polyOrder.size(); n++) /// decide final starting points in each polygon
{
int i_polygon = polyOrder[n];
int best = getClosestPointInPolygon(prev_point, i_polygon);
polyStart[i_polygon] = best;
prev_point = polygons[i_polygon][best];
}
}
inline int PathOrderOptimizer::getClosestPointInPolygon(Point prev_point, int i_polygon)
{
PolygonRef poly = polygons[i_polygon];
int best = -1;
float bestDist = std::numeric_limits<float>::infinity();
bool orientation = poly.orientation();
for(unsigned int i_point=0 ; i_point<poly.size() ; i_point++)
{
float dist = vSize2f(poly[i_point] - prev_point);
Point n0 = normal(poly[(i_point-1+poly.size())%poly.size()] - poly[i_point], 2000);
Point n1 = normal(poly[i_point] - poly[(i_point + 1) % poly.size()], 2000);
float dot_score = dot(n0, n1) - dot(crossZ(n0), n1); /// prefer binnenbocht
if (orientation)
dot_score = -dot_score;
if (dist + dot_score < bestDist)
{
best = i_point;
bestDist = dist;
}
}
return best;
}
/**
*
*/
void LineOrderOptimizer::optimize()
{
int gridSize = 5000; // the size of the cells in the hash grid.
BucketGrid2D<unsigned int> line_bucket_grid(gridSize);
bool picked[polygons.size()];
memset(picked, false, sizeof(bool) * polygons.size());/// initialized as falses
for(unsigned int i_polygon=0 ; i_polygon<polygons.size() ; i_polygon++) /// find closest point to initial starting point within each polygon +initialize picked
{
int best = -1;
float bestDist = std::numeric_limits<float>::infinity();
PolygonRef poly = polygons[i_polygon];
for(unsigned int i_point=0; i_point<poly.size(); i_point++) /// get closest point from polygon
{
float dist = vSize2f(poly[i_point] - startPoint);
if (dist < bestDist)
{
best = i_point;
bestDist = dist;
}
}
polyStart.push_back(best);
assert(poly.size() == 2);
line_bucket_grid.insert(poly[0], i_polygon);
line_bucket_grid.insert(poly[1], i_polygon);
}
Point incommingPerpundicularNormal(0, 0);
Point prev_point = startPoint;
for(unsigned int i_polygon=0 ; i_polygon<polygons.size() ; i_polygon++) /// actual path order optimizer
{
int best = -1;
float bestDist = std::numeric_limits<float>::infinity();
for(unsigned int i_close_line_polygon : line_bucket_grid.findNearbyObjects(prev_point)) /// check if single-line-polygon is close to last point
{
if (picked[i_close_line_polygon] || polygons[i_close_line_polygon].size() < 1)
continue;
checkIfLineIsBest(i_close_line_polygon, best, bestDist, prev_point, incommingPerpundicularNormal);
}
if (best == -1) /// if single-line-polygon hasn't been found yet
{
for(unsigned int i_polygon=0 ; i_polygon<polygons.size() ; i_polygon++)
{
if (picked[i_polygon] || polygons[i_polygon].size() < 1) /// skip single-point-polygons
continue;
assert(polygons[i_polygon].size() == 2);
checkIfLineIsBest(i_polygon, best, bestDist, prev_point, incommingPerpundicularNormal);
}
}
if (best > -1) /// should always be true; we should have been able to identify the best next polygon
{
assert(polygons[best].size() == 2);
int endIdx = polyStart[best] * -1 + 1; /// 1 -> 0 , 0 -> 1
prev_point = polygons[best][endIdx];
incommingPerpundicularNormal = crossZ(normal(polygons[best][endIdx] - polygons[best][polyStart[best]], 1000));
picked[best] = true;
polyOrder.push_back(best);
}
else
logError("Failed to find next closest line.\n");
}
prev_point = startPoint;
for(unsigned int n=0; n<polyOrder.size(); n++) /// decide final starting points in each polygon
{
int nr = polyOrder[n];
PolygonRef poly = polygons[nr];
int best = -1;
float bestDist = std::numeric_limits<float>::infinity();
bool orientation = poly.orientation();
for(unsigned int i=0;i<poly.size(); i++)
{
float dist = vSize2f(polygons[nr][i] - prev_point);
Point n0 = normal(poly[(i+poly.size()-1)%poly.size()] - poly[i], 2000);
Point n1 = normal(poly[i] - poly[(i + 1) % poly.size()], 2000);
float dot_score = dot(n0, n1) - dot(crossZ(n0), n1);
if (orientation)
dot_score = -dot_score;
if (dist + dot_score < bestDist)
{
best = i;
bestDist = dist + dot_score;
}
}
polyStart[nr] = best;
assert(poly.size() == 2);
prev_point = poly[best *-1 + 1]; /// 1 -> 0 , 0 -> 1
}
}
inline void LineOrderOptimizer::checkIfLineIsBest(unsigned int i_line_polygon, int& best, float& bestDist, Point& prev_point, Point& incommingPerpundicularNormal)
{
{ /// check distance to first point on line (0)
float dist = vSize2f(polygons[i_line_polygon][0] - prev_point);
dist += abs(dot(incommingPerpundicularNormal, normal(polygons[i_line_polygon][1] - polygons[i_line_polygon][0], 1000))) * 0.0001f; /// penalize sharp corners
if (dist < bestDist)
{
best = i_line_polygon;
bestDist = dist;
polyStart[i_line_polygon] = 0;
}
}
{ /// check distance to second point on line (1)
float dist = vSize2f(polygons[i_line_polygon][1] - prev_point);
dist += abs(dot(incommingPerpundicularNormal, normal(polygons[i_line_polygon][0] - polygons[i_line_polygon][1], 1000) )) * 0.0001f; /// penalize sharp corners
if (dist < bestDist)
{
best = i_line_polygon;
bestDist = dist;
polyStart[i_line_polygon] = 1;
}
}
}
}//namespace cura
+83
Ver Arquivo
@@ -0,0 +1,83 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#ifndef PATHOPTIMIZER_H
#define PATHOPTIMIZER_H
#include <stdint.h>
#include "utils/polygon.h"
namespace cura {
//! Parts order optimization class.
/*!
* Utility class for optimizing the path order by minimizing the distance traveled between printing different parts in the layer.
* The order of polygons is optimized and the startingpoint within each polygon is chosen.
*/
class PathOrderOptimizer
{
public:
Point startPoint; //!< The location of the nozzle before starting to print the current layer
std::vector<PolygonRef> polygons; //!< the parts of the layer (in arbitrary order)
std::vector<int> polyStart; //!< polygons[i][polyStart[i]] = point of polygon i which is to be the starting point in printing the polygon
std::vector<int> polyOrder; //!< the optimized order as indices in #polygons
PathOrderOptimizer(Point startPoint)
{
this->startPoint = startPoint;
}
void addPolygon(PolygonRef polygon)
{
this->polygons.push_back(polygon);
}
void addPolygons(Polygons& polygons)
{
for(unsigned int i=0;i<polygons.size(); i++)
this->polygons.push_back(polygons[i]);
}
void optimize(); //!< sets #polyStart and #polyOrder
private:
int getClosestPointInPolygon(Point prev, int i_polygon); //!< returns the index of the closest point
};
//! Line path order optimization class.
/*!
* Utility class for optimizing the path order by minimizing the distance traveled between printing different lines within a part.
*/
class LineOrderOptimizer
{
public:
Point startPoint; //!< The location of the nozzle before starting to print the current layer
std::vector<PolygonRef> polygons; //!< the parts of the layer (in arbitrary order)
std::vector<int> polyStart; //!< polygons[i][polyStart[i]] = point of polygon i which is to be the starting point in printing the polygon
std::vector<int> polyOrder; //!< the optimized order as indices in #polygons
LineOrderOptimizer(Point startPoint)
{
this->startPoint = startPoint;
}
void addPolygon(PolygonRef polygon)
{
this->polygons.push_back(polygon);
}
void addPolygons(Polygons& polygons)
{
for(unsigned int i=0;i<polygons.size(); i++)
this->polygons.push_back(polygons[i]);
}
void optimize(); //!< sets #polyStart and #polyOrder
private:
void checkIfLineIsBest(unsigned int i_line_polygon, int& best, float& bestDist, Point& prev_point, Point& incommingPerpundicularNormal);
};
}//namespace cura
#endif//PATHOPTIMIZER_H
+54 -47
Ver Arquivo
@@ -1,47 +1,54 @@
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "polygonOptimizer.h"
void optimizePolygon(PolygonRef poly)
{
Point p0 = poly[poly.size()-1];
for(unsigned int i=0;i<poly.size();i++)
{
Point p1 = poly[i];
if (shorterThen(p0 - p1, 10))
{
poly.remove(i);
i --;
}else{
Point p2;
if (i < poly.size() - 1)
p2 = poly[i+1];
else
p2 = poly[0];
Point diff0 = normal(p1 - p0, 1000000);
Point diff2 = normal(p1 - p2, 1000000);
int64_t d = dot(diff0, diff2);
if (d < -999999000000LL)
{
poly.remove(i);
i --;
}else{
p0 = p1;
}
}
}
}
void optimizePolygons(Polygons& polys)
{
for(unsigned int n=0;n<polys.size();n++)
{
optimizePolygon(polys[n]);
if (polys[n].size() < 3)
{
polys.remove(n);
n--;
}
}
}
/** Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License */
#include "polygonOptimizer.h"
namespace cura {
void optimizePolygon(PolygonRef poly)
{
Point p0 = poly[poly.size()-1];
for(unsigned int i=0;i<poly.size();i++)
{
Point p1 = poly[i];
if (shorterThen(p0 - p1, MICRON2INT(10)))
{
poly.remove(i);
i --;
}else if (shorterThen(p0 - p1, MICRON2INT(500)))
{
Point p2;
if (i < poly.size() - 1)
p2 = poly[i+1];
else
p2 = poly[0];
Point diff0 = normal(p1 - p0, 10000000);
Point diff2 = normal(p1 - p2, 10000000);
int64_t d = dot(diff0, diff2);
if (d < -99999999999999LL)
{
poly.remove(i);
i --;
}else{
p0 = p1;
}
}else{
p0 = p1;
}
}
}
void optimizePolygons(Polygons& polys)
{
for(unsigned int n=0;n<polys.size();n++)
{
optimizePolygon(polys[n]);
if (polys[n].size() < 3)
{
polys.remove(n);
n--;
}
}
}
}//namespace cura

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais