Skip to content

Commit

Permalink
Tested and updated all examples and their documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
ioannam committed Mar 11, 2024
1 parent 1f5109f commit 1d91a34
Show file tree
Hide file tree
Showing 22 changed files with 260 additions and 243 deletions.
12 changes: 10 additions & 2 deletions docs/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@
Examples
********************************************************************************

Here you can find some examples files for compas_slicer
All of the examples of compas_slicer can be found in the folder `/examples/`.In each example folder you can find:

* the python file that performs the slicing,

* a data folder with all the data required for the slicing

* and a grasshopper file for visualizing the results.

In the links below we go through some of these examples in more detail:

.. toctree::
:numbered:
Expand All @@ -14,4 +22,4 @@ Here you can find some examples files for compas_slicer
examples/03_planar_slicing_vertical_sorting
examples/04_gcode_generation
examples/05_non_planar_slicing_on_custom_base
examples/06_attributes_transfer
examples/06_attributes_transfer
220 changes: 111 additions & 109 deletions docs/examples/01_planar_slicing_simple.rst

Large diffs are not rendered by default.

164 changes: 83 additions & 81 deletions docs/examples/02_curved_slicing_simple.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.. _compas_slicer_example_2:

************************************
Simple curved interpolation slicing
Interpolation slicing
************************************

A general introduction of the concepts organization of compas_slicer can be found in the :ref:`introduction tutorial <compas_slicer_tutorial_1_introduction>`.
Expand All @@ -12,13 +12,25 @@ as it explains the main concepts of compas_slicer.
Having done that, in this example, we go through the basics of using the non-planar interpolation slicer, which generates
paths by interpolating user-defined boundaries.
This example uses the method described in `Print Paths KeyFraming <https://dl.acm.org/doi/fullHtml/10.1145/3424630.3425408>`_.
Its files can be found in the folder `/examples/2_curved_slicing/`

.. figure:: figures/02_curved_slicing.PNG
:figclass: figure
:class: figure-img img-fluid

*Result of simple curved slicing.*

Note that this example has three different data folders (`/data_costa_surface/`, `/data_vase/`, `/data_Y_shape/`). Feel free
to change the DATA_PATH parameter (in the code block below) to point to any of these folders so that you can slice its contents. To visualize the results,
open the `curved_slicing_master.gh` and select the desired folder in the inputs section (top left). You will only be able to visualize
the results after you have run the python file that generates them.

.. figure:: figures/input_folder.png
:figclass: figure
:class: figure-img img-fluid

*Selection of input folder in Grasshopper (from `curved_slicing_master.gh`).*

Imports and initialization
==========================

Expand All @@ -29,23 +41,23 @@ Imports and initialization
import logging
import compas_slicer.utilities as utils
from compas_slicer.slicers import InterpolationSlicer
from compas_slicer.post_processing import simplify_paths_rdp_igl
from compas_slicer.post_processing import simplify_paths_rdp
from compas_slicer.pre_processing import InterpolationSlicingPreprocessor
from compas_slicer.print_organization import set_extruder_toggle, set_linear_velocity_by_range
from compas_slicer.print_organization import add_safety_printpoints
from compas_slicer.pre_processing import create_mesh_boundary_attributes
from compas_slicer.print_organization import InterpolationPrintOrganizer
from compas_slicer.post_processing import seams_smooth
from compas_slicer.print_organization import smooth_printpoints_up_vectors, smooth_printpoints_layer_heights
from compas_slicer.post_processing import generate_brim
from compas_view2 import app
import time
logger = logging.getLogger('logger')
logging.basicConfig(format='%(levelname)s - %(message)s', level=logging.INFO)
DATA_PATH = os.path.join(os.path.dirname(__file__), 'data_basic_example')
DATA_PATH = os.path.join(os.path.dirname(__file__), 'data_Y_shape') # set desired folder name
OUTPUT_PATH = utils.get_output_directory(DATA_PATH)
OBJ_INPUT_NAME = os.path.join(DATA_PATH, 'vase.obj')
OBJ_INPUT_NAME = os.path.join(DATA_PATH, 'mesh.obj')
Slicing process
===============
Expand All @@ -56,9 +68,17 @@ Slicing process
mesh = Mesh.from_obj(os.path.join(DATA_PATH, OBJ_INPUT_NAME))
The interpolation slicer works by interpolating boundaries provided by the user. Each boundary is represented by a list
of vertex indices, that have been saved in the json files.
The interpolation slicer works by interpolating two boundaries provided by the user. Each boundary is represented by a list
of vertex indices, that have been saved in the json files. You can create these json files using the following grasshopper
sequence from the file: `curved_slicing_master.gh`

.. figure:: figures/create_boundaries.png
:figclass: figure
:class: figure-img img-fluid

*Creation of boundary json files (from `curved_slicing_master.gh`).*

Then the boundary json files are loaded as follows:
.. code-block:: python
# --- Load targets (boundaries)
Expand All @@ -74,11 +94,9 @@ determines how dense the layers will be generated on the surface.

.. code-block:: python
avg_layer_height = 15.0
avg_layer_height = 2.0
parameters = {
'avg_layer_height': avg_layer_height, # controls number of curves that will be generated
'min_layer_height': 0.3,
'max_layer_height': 5.0 # 2.0,
}
The ``InterpolationSlicingPreprocessor`` sets up all the data that are necessary for the interpolation process.
Expand All @@ -102,9 +120,8 @@ options are available for all slicers.
slicer.slice_model() # compute_norm_of_gradient contours
# post processing
generate_brim(slicer, layer_width=3.0, number_of_brim_offsets=5)
seams_smooth(slicer, smooth_distance=10)
simplify_paths_rdp_igl(slicer, threshold=1.0)
simplify_paths_rdp(slicer, threshold=0.25)
seams_smooth(slicer, smooth_distance=3)
slicer.printout_info()
utils.save_to_json(slicer.to_data(), OUTPUT_PATH, 'curved_slicer.json')
Expand All @@ -122,13 +139,14 @@ that is necessary for the print process.
print_organizer = InterpolationPrintOrganizer(slicer, parameters, DATA_PATH)
print_organizer.create_printpoints()
smooth_printpoints_up_vectors(print_organizer, strength=0.5, iterations=10)
smooth_printpoints_layer_heights(print_organizer, strength=0.5, iterations=5)
set_linear_velocity_by_range(print_organizer, param_func=lambda ppt: ppt.layer_height,
parameter_range=[avg_layer_height*0.5, avg_layer_height*2.0],
velocity_range=[150, 70], bound_remapping=False)
set_extruder_toggle(print_organizer, slicer)
add_safety_printpoints(print_organizer, z_hop=10.0)
smooth_printpoints_up_vectors(print_organizer, strength=0.5, iterations=10)
smooth_printpoints_layer_heights(print_organizer, strength=0.5, iterations=5)
Output json file with printpoints.

Expand All @@ -138,20 +156,9 @@ Output json file with printpoints.
printpoints_data = print_organizer.output_printpoints_dict()
utils.save_to_json(printpoints_data, OUTPUT_PATH, 'out_printpoints.json')
Visualize the result using compas_viewer2

.. code-block:: python
# ----- Visualize
viewer = app.App(width=1600, height=1000)
# slicer.visualize_on_viewer(viewer, visualize_mesh=False, visualize_paths=True)
print_organizer.visualize_on_viewer(viewer, visualize_printpoints=True)
viewer.show()
Once the slicing process is finished, you can use the compas_slicer grasshopper components to visualize the results,
described in the :ref:`grasshopper tutorial <compas_slicer_tutorial_2>`.
Once the slicing process is finished, you can open the `curved_slicing_master.gh to visualize the results. More information on
this visualization is given in :ref:`grasshopper tutorial <compas_slicer_tutorial_2>`.


Final script
Expand All @@ -166,82 +173,77 @@ The completed final script can be found below:
import logging
import compas_slicer.utilities as utils
from compas_slicer.slicers import InterpolationSlicer
from compas_slicer.post_processing import simplify_paths_rdp_igl
from compas_slicer.post_processing import simplify_paths_rdp
from compas_slicer.pre_processing import InterpolationSlicingPreprocessor
from compas_slicer.print_organization import set_extruder_toggle, set_linear_velocity_by_range
from compas_slicer.print_organization import add_safety_printpoints
from compas_slicer.pre_processing import create_mesh_boundary_attributes
from compas_slicer.print_organization import InterpolationPrintOrganizer
from compas_slicer.post_processing import seams_smooth
from compas_slicer.print_organization import smooth_printpoints_up_vectors, smooth_printpoints_layer_heights
from compas_slicer.post_processing import generate_brim
from compas_view2 import app
import time
logger = logging.getLogger('logger')
logging.basicConfig(format='%(levelname)s - %(message)s', level=logging.INFO)
DATA_PATH = os.path.join(os.path.dirname(__file__), 'data_basic_example')
DATA_PATH = os.path.join(os.path.dirname(__file__), 'data_Y_shape')
OUTPUT_PATH = utils.get_output_directory(DATA_PATH)
OBJ_INPUT_NAME = os.path.join(DATA_PATH, 'vase.obj')
OBJ_INPUT_NAME = os.path.join(DATA_PATH, 'mesh.obj')
start_time = time.time()
def main():
start_time = time.time()
# --- Load initial_mesh
mesh = Mesh.from_obj(os.path.join(DATA_PATH, OBJ_INPUT_NAME))
# --- Load initial_mesh
mesh = Mesh.from_obj(os.path.join(DATA_PATH, OBJ_INPUT_NAME))
# --- Load targets (boundaries)
low_boundary_vs = utils.load_from_json(DATA_PATH, 'boundaryLOW.json')
high_boundary_vs = utils.load_from_json(DATA_PATH, 'boundaryHIGH.json')
create_mesh_boundary_attributes(mesh, low_boundary_vs, high_boundary_vs)
# --- Load targets (boundaries)
low_boundary_vs = utils.load_from_json(DATA_PATH, 'boundaryLOW.json')
high_boundary_vs = utils.load_from_json(DATA_PATH, 'boundaryHIGH.json')
create_mesh_boundary_attributes(mesh, low_boundary_vs, high_boundary_vs)
avg_layer_height = 15.0
avg_layer_height = 2.0
parameters = {
'avg_layer_height': avg_layer_height, # controls number of curves that will be generated
'min_layer_height': 0.3,
'max_layer_height': 5.0 # 2.0,
}
parameters = {
'avg_layer_height': avg_layer_height, # controls number of curves that will be generated
}
preprocessor = InterpolationSlicingPreprocessor(mesh, parameters, DATA_PATH)
preprocessor.create_compound_targets()
g_eval = preprocessor.create_gradient_evaluation(norm_filename='gradient_norm.json', g_filename='gradient.json',
target_1=preprocessor.target_LOW,
target_2=preprocessor.target_HIGH)
preprocessor.find_critical_points(g_eval, output_filenames=['minima.json', 'maxima.json', 'saddles.json'])
preprocessor = InterpolationSlicingPreprocessor(mesh, parameters, DATA_PATH)
preprocessor.create_compound_targets()
g_eval = preprocessor.create_gradient_evaluation(norm_filename='gradient_norm.json', g_filename='gradient.json',
target_1=preprocessor.target_LOW,
target_2=preprocessor.target_HIGH)
preprocessor.find_critical_points(g_eval, output_filenames=['minima.json', 'maxima.json', 'saddles.json'])
# --- slicing
slicer = InterpolationSlicer(mesh, preprocessor, parameters)
slicer.slice_model() # compute_norm_of_gradient contours
generate_brim(slicer, layer_width=3.0, number_of_brim_offsets=5)
seams_smooth(slicer, smooth_distance=10)
# --- slicing
slicer = InterpolationSlicer(mesh, preprocessor, parameters)
slicer.slice_model() # compute_norm_of_gradient contours
simplify_paths_rdp_igl(slicer, threshold=0.5)
slicer.printout_info()
utils.save_to_json(slicer.to_data(), OUTPUT_PATH, 'curved_slicer.json')
simplify_paths_rdp(slicer, threshold=0.25)
seams_smooth(slicer, smooth_distance=3)
slicer.printout_info()
utils.save_to_json(slicer.to_data(), OUTPUT_PATH, 'curved_slicer.json')
# --- Print organizer
print_organizer = InterpolationPrintOrganizer(slicer, parameters, DATA_PATH)
print_organizer.create_printpoints()
# --- Print organizer
print_organizer = InterpolationPrintOrganizer(slicer, parameters, DATA_PATH)
print_organizer.create_printpoints()
set_linear_velocity_by_range(print_organizer, param_func=lambda ppt: ppt.layer_height,
parameter_range=[avg_layer_height*0.5, avg_layer_height*2.0],
velocity_range=[150, 70], bound_remapping=False)
set_extruder_toggle(print_organizer, slicer)
add_safety_printpoints(print_organizer, z_hop=10.0)
smooth_printpoints_up_vectors(print_organizer, strength=0.5, iterations=10)
smooth_printpoints_layer_heights(print_organizer, strength=0.5, iterations=5)
smooth_printpoints_up_vectors(print_organizer, strength=0.5, iterations=10)
smooth_printpoints_layer_heights(print_organizer, strength=0.5, iterations=5)
# --- Save printpoints dictionary to json file
printpoints_data = print_organizer.output_printpoints_dict()
utils.save_to_json(printpoints_data, OUTPUT_PATH, 'out_printpoints.json')
set_linear_velocity_by_range(print_organizer, param_func=lambda ppt: ppt.layer_height,
parameter_range=[avg_layer_height*0.5, avg_layer_height*2.0],
velocity_range=[150, 70], bound_remapping=False)
set_extruder_toggle(print_organizer, slicer)
add_safety_printpoints(print_organizer, z_hop=10.0)
# --- Save printpoints dictionary to json file
printpoints_data = print_organizer.output_printpoints_dict()
utils.save_to_json(printpoints_data, OUTPUT_PATH, 'out_printpoints.json')
end_time = time.time()
print("Total elapsed time", round(end_time - start_time, 2), "seconds")
# ----- Visualize
viewer = app.App(width=1600, height=1000)
# slicer.visualize_on_viewer(viewer, visualize_mesh=False, visualize_paths=True)
print_organizer.visualize_on_viewer(viewer, visualize_printpoints=True)
viewer.show()
end_time = time.time()
print("Total elapsed time", round(end_time - start_time, 2), "seconds")
if __name__ == "__main__":
main()
7 changes: 5 additions & 2 deletions docs/examples/03_planar_slicing_vertical_sorting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ from one path to the next, as it is shown in the illustration below.
*Fabrication path using horizontal sorting (left), and vertical sorting (right). The traveling paths are shown with orange lines.*

In planar slicing, horizontal ordering of paths is the default method, while in non-planar slicing vertical ordering of paths is
the default method. The example below demonstrates how planar paths can be sorted in a vertical logic.
the default method. The example below demonstrates how planar paths can be sorted in a vertical logic. Its files can be found in the folder
`/examples/3_planar_vertical_sorting/`. Once you have
run the python file to generate the results, you can visualize them by opening the grasshopper file.


.. code-block:: python
Expand Down Expand Up @@ -64,7 +67,7 @@ the default method. The example below demonstrates how planar paths can be sorte
slicer.slice_model()
# Sorting into vertical layers and reordering
sort_into_vertical_layers(slicer, max_paths_per_layer=10)
sort_into_vertical_layers(slicer, max_paths_per_layer=25)
reorder_vertical_layers(slicer, align_with="x_axis")
# Post-processing
Expand Down
7 changes: 6 additions & 1 deletion docs/examples/04_gcode_generation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Gcode generation

While compas slicer has been mostly developed for robotic printing, we can also export the gcode of the generated paths
to materialize them in a typical desktop 3D printer. The gcode generation is still at a basic level and is a work in progress.
The following file can be found in `/examples/4_gcode_generation/`. The gcode file is placed in the `/output/` folder.


.. code-block:: python
Expand Down Expand Up @@ -64,4 +65,8 @@ to materialize them in a typical desktop 3D printer. The gcode generation is sti
# create and output gcode
gcode_parameters = {} # leave all to default
gcode_text = print_organizer.output_gcode(gcode_parameters)
utils.save_to_text_file(gcode_text, OUTPUT_DIR, 'my_gcode.gcode')
utils.save_to_text_file(gcode_text, OUTPUT_DIR, 'my_gcode.gcode')
if __name__ == "__main__":
main()
6 changes: 5 additions & 1 deletion docs/examples/05_non_planar_slicing_on_custom_base.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Non-planar slicing on custom base
************************************

In this example we describe the process of non-planar slicing of a mesh, generating paths that are an offset to its
custom base. We are using the ScalarFieldSlicer, which generates paths as contours of a scalar field defined on every
custom base. We are using the ``ScalarFieldSlicer`` cleass, which generates paths as contours of a scalar field defined on every
vertex of the mesh. In this case we create a scalar field with the distance of each vertex from the custom base.

.. figure:: figures/05_scalar_field_slicing.PNG
Expand All @@ -14,6 +14,9 @@ vertex of the mesh. In this case we create a scalar field with the distance of e

*Result of scalar field slicing considering the distance of each vertex from the custom base.*

The files for this example can be found on the folder `/examples/5_non_planar_slicing_on_custom_base/`. Once you have
run the python file to generate the results, you can visualize them by opening the grasshopper file
`visualization_scalar_field_slicing.gh`.

.. code-block:: python
Expand Down Expand Up @@ -57,6 +60,7 @@ vertex of the mesh. In this case we create a scalar field with the distance of e
# --- Slice model by generating contours of scalar field
slicer = ScalarFieldSlicer(mesh, u, no_of_isocurves=50)
slicer.slice_model()
# simplify_paths_rdp(slicer, threshold=0.3)
slicer_utils.save_to_json(slicer.to_data(), OUTPUT_PATH, 'isocontours.json') # save results to json
# --- Print organization calculations (i.e. generation of printpoints with fabrication-related information)
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/06_attributes_transfer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Transferring attributes to PrintPoints

Often in 3D printing we need to transfer information from the mesh that is being sliced to the PrintPoints that
are used in the fabrication process. We might want, for example, to print paths that are generated from different parts of
the geometry using different parameters. This is enabled by the *transfer_mesh_attributes_to_printpoints()* function, as
the geometry using different parameters. In compas_slicer this can be done using the *transfer_mesh_attributes_to_printpoints()* function, as
shown in the example below. During the slicing process each printpoint is projected to the closest mesh face.
It takes directly all the face attributes, and it takes the averaged vertex attributes of the face vertices using
barycentric coordinates.
Expand Down
Binary file added docs/examples/figures/create_boundaries.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/examples/figures/input_folder.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 1d91a34

Please sign in to comment.