Merge remote-tracking branch 'origin/dev' into sla_base_pool
|
|
@ -167,6 +167,7 @@ sub thread_cleanup {
|
||||||
*Slic3r::GUI::PresetHints::DESTROY = sub {};
|
*Slic3r::GUI::PresetHints::DESTROY = sub {};
|
||||||
*Slic3r::GUI::TabIface::DESTROY = sub {};
|
*Slic3r::GUI::TabIface::DESTROY = sub {};
|
||||||
*Slic3r::OctoPrint::DESTROY = sub {};
|
*Slic3r::OctoPrint::DESTROY = sub {};
|
||||||
|
*Slic3r::Duet::DESTROY = sub {};
|
||||||
*Slic3r::PresetUpdater::DESTROY = sub {};
|
*Slic3r::PresetUpdater::DESTROY = sub {};
|
||||||
return undef; # this prevents a "Scalars leaked" warning
|
return undef; # this prevents a "Scalars leaked" warning
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,14 @@ our $appController;
|
||||||
our $VALUE_CHANGE_EVENT = Wx::NewEventType;
|
our $VALUE_CHANGE_EVENT = Wx::NewEventType;
|
||||||
# 2) To inform about a preset selection change or a "modified" status change.
|
# 2) To inform about a preset selection change or a "modified" status change.
|
||||||
our $PRESETS_CHANGED_EVENT = Wx::NewEventType;
|
our $PRESETS_CHANGED_EVENT = Wx::NewEventType;
|
||||||
|
# 3) To inform about a change of object selection
|
||||||
|
our $OBJECT_SELECTION_CHANGED_EVENT = Wx::NewEventType;
|
||||||
|
# 4) To inform about a change of object settings
|
||||||
|
our $OBJECT_SETTINGS_CHANGED_EVENT = Wx::NewEventType;
|
||||||
|
# 5) To inform about a remove of object
|
||||||
|
our $OBJECT_REMOVE_EVENT = Wx::NewEventType;
|
||||||
|
# 6) To inform about a update of the scene
|
||||||
|
our $UPDATE_SCENE_EVENT = Wx::NewEventType;
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, %params) = @_;
|
my ($class, %params) = @_;
|
||||||
|
|
@ -123,6 +131,8 @@ sub new {
|
||||||
|
|
||||||
$self->update_ui_from_settings;
|
$self->update_ui_from_settings;
|
||||||
|
|
||||||
|
Slic3r::GUI::update_mode();
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -142,7 +152,12 @@ sub _init_tabpanel {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!$self->{no_plater}) {
|
if (!$self->{no_plater}) {
|
||||||
$panel->AddPage($self->{plater} = Slic3r::GUI::Plater->new($panel), L("Plater"));
|
$panel->AddPage($self->{plater} = Slic3r::GUI::Plater->new($panel,
|
||||||
|
event_object_selection_changed => $OBJECT_SELECTION_CHANGED_EVENT,
|
||||||
|
event_object_settings_changed => $OBJECT_SETTINGS_CHANGED_EVENT,
|
||||||
|
event_remove_object => $OBJECT_REMOVE_EVENT,
|
||||||
|
event_update_scene => $UPDATE_SCENE_EVENT,
|
||||||
|
), L("Plater"));
|
||||||
if (!$self->{no_controller}) {
|
if (!$self->{no_controller}) {
|
||||||
$panel->AddPage($self->{controller} = Slic3r::GUI::Controller->new($panel), L("Controller"));
|
$panel->AddPage($self->{controller} = Slic3r::GUI::Controller->new($panel), L("Controller"));
|
||||||
}
|
}
|
||||||
|
|
@ -163,6 +178,10 @@ sub _init_tabpanel {
|
||||||
my $value = $event->GetInt();
|
my $value = $event->GetInt();
|
||||||
$self->{plater}->on_extruders_change($value);
|
$self->{plater}->on_extruders_change($value);
|
||||||
}
|
}
|
||||||
|
if ($opt_key eq 'printer_technology'){
|
||||||
|
my $value = $event->GetInt();# 0 ~ "ptFFF"; 1 ~ "ptSLA"
|
||||||
|
$self->{plater}->show_preset_comboboxes($value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
# don't save while loading for the first time
|
# don't save while loading for the first time
|
||||||
$self->config->save($Slic3r::GUI::autosave) if $Slic3r::GUI::autosave && $self->{loaded};
|
$self->config->save($Slic3r::GUI::autosave) if $Slic3r::GUI::autosave && $self->{loaded};
|
||||||
|
|
@ -175,7 +194,7 @@ sub _init_tabpanel {
|
||||||
|
|
||||||
my $tab = Slic3r::GUI::get_preset_tab($tab_name);
|
my $tab = Slic3r::GUI::get_preset_tab($tab_name);
|
||||||
if ($self->{plater}) {
|
if ($self->{plater}) {
|
||||||
# Update preset combo boxes (Print settings, Filament, Printer) from their respective tabs.
|
# Update preset combo boxes (Print settings, Filament, Material, Printer) from their respective tabs.
|
||||||
my $presets = $tab->get_presets;
|
my $presets = $tab->get_presets;
|
||||||
if (defined $presets){
|
if (defined $presets){
|
||||||
my $reload_dependent_tabs = $tab->get_dependent_tabs;
|
my $reload_dependent_tabs = $tab->get_dependent_tabs;
|
||||||
|
|
@ -183,7 +202,7 @@ sub _init_tabpanel {
|
||||||
$self->{plater}->{"selected_item_$tab_name"} = $tab->get_selected_preset_item;
|
$self->{plater}->{"selected_item_$tab_name"} = $tab->get_selected_preset_item;
|
||||||
if ($tab_name eq 'printer') {
|
if ($tab_name eq 'printer') {
|
||||||
# Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
|
# Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
|
||||||
for my $tab_name_other (qw(print filament)) {
|
for my $tab_name_other (qw(print filament sla_material)) {
|
||||||
# If the printer tells us that the print or filament preset has been switched or invalidated,
|
# If the printer tells us that the print or filament preset has been switched or invalidated,
|
||||||
# refresh the print or filament tab page. Otherwise just refresh the combo box.
|
# refresh the print or filament tab page. Otherwise just refresh the combo box.
|
||||||
my $update_action = ($reload_dependent_tabs && (first { $_ eq $tab_name_other } (@{$reload_dependent_tabs})))
|
my $update_action = ($reload_dependent_tabs && (first { $_ eq $tab_name_other } (@{$reload_dependent_tabs})))
|
||||||
|
|
@ -197,9 +216,43 @@ sub _init_tabpanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
# The following event is emited by the C++ Tab implementation on object selection change.
|
||||||
|
EVT_COMMAND($self, -1, $OBJECT_SELECTION_CHANGED_EVENT, sub {
|
||||||
|
my ($self, $event) = @_;
|
||||||
|
my $obj_idx = $event->GetId;
|
||||||
|
my $child = $event->GetInt == 1 ? 1 : undef;
|
||||||
|
|
||||||
|
$self->{plater}->select_object($obj_idx < 0 ? undef: $obj_idx, $child);
|
||||||
|
$self->{plater}->item_changed_selection($obj_idx);
|
||||||
|
});
|
||||||
|
|
||||||
|
# The following event is emited by the C++ GUI implementation on object settings change.
|
||||||
|
EVT_COMMAND($self, -1, $OBJECT_SETTINGS_CHANGED_EVENT, sub {
|
||||||
|
my ($self, $event) = @_;
|
||||||
|
|
||||||
|
my $line = $event->GetString;
|
||||||
|
my ($obj_idx, $parts_changed, $part_settings_changed) = split('',$line);
|
||||||
|
|
||||||
|
$self->{plater}->changed_object_settings($obj_idx, $parts_changed, $part_settings_changed);
|
||||||
|
});
|
||||||
|
|
||||||
|
# The following event is emited by the C++ GUI implementation on object remove.
|
||||||
|
EVT_COMMAND($self, -1, $OBJECT_REMOVE_EVENT, sub {
|
||||||
|
my ($self, $event) = @_;
|
||||||
|
$self->{plater}->remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
# The following event is emited by the C++ GUI implementation on extruder change for object.
|
||||||
|
EVT_COMMAND($self, -1, $UPDATE_SCENE_EVENT, sub {
|
||||||
|
my ($self, $event) = @_;
|
||||||
|
$self->{plater}->update();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
Slic3r::GUI::create_preset_tabs($self->{no_controller}, $VALUE_CHANGE_EVENT, $PRESETS_CHANGED_EVENT);
|
Slic3r::GUI::create_preset_tabs($self->{no_controller}, $VALUE_CHANGE_EVENT, $PRESETS_CHANGED_EVENT);
|
||||||
$self->{options_tabs} = {};
|
$self->{options_tabs} = {};
|
||||||
for my $tab_name (qw(print filament printer)) {
|
for my $tab_name (qw(print filament sla_material printer)) {
|
||||||
$self->{options_tabs}{$tab_name} = Slic3r::GUI::get_preset_tab("$tab_name");
|
$self->{options_tabs}{$tab_name} = Slic3r::GUI::get_preset_tab("$tab_name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -211,9 +264,15 @@ sub _init_tabpanel {
|
||||||
# load initial config
|
# load initial config
|
||||||
my $full_config = wxTheApp->{preset_bundle}->full_config;
|
my $full_config = wxTheApp->{preset_bundle}->full_config;
|
||||||
$self->{plater}->on_config_change($full_config);
|
$self->{plater}->on_config_change($full_config);
|
||||||
|
|
||||||
# Show a correct number of filament fields.
|
# Show a correct number of filament fields.
|
||||||
|
if (defined $full_config->nozzle_diameter){ # nozzle_diameter is undefined when SLA printer is selected
|
||||||
$self->{plater}->on_extruders_change(int(@{$full_config->nozzle_diameter}));
|
$self->{plater}->on_extruders_change(int(@{$full_config->nozzle_diameter}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Show correct preset comboboxes according to the printer_technology
|
||||||
|
$self->{plater}->show_preset_comboboxes(($full_config->printer_technology eq "FFF") ? 0 : 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _init_menubar {
|
sub _init_menubar {
|
||||||
|
|
|
||||||
|
|
@ -378,6 +378,7 @@ sub on_btn_load {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$self->{model_object}->center_around_origin if $self->{parts_changed};
|
||||||
$self->_parts_changed;
|
$self->_parts_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -480,6 +481,7 @@ sub on_btn_delete {
|
||||||
$self->{parts_changed} = 1;
|
$self->{parts_changed} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$self->{model_object}->center_around_origin if $self->{parts_changed};
|
||||||
$self->_parts_changed;
|
$self->_parts_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
BIN
resources/icons/add_object.png
Normal file
|
After Width: | Height: | Size: 829 B |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 36 KiB |
BIN
resources/icons/colorchange_add_off.png
Normal file
|
After Width: | Height: | Size: 600 B |
BIN
resources/icons/colorchange_add_on.png
Normal file
|
After Width: | Height: | Size: 695 B |
BIN
resources/icons/colorchange_delete_off.png
Normal file
|
After Width: | Height: | Size: 589 B |
BIN
resources/icons/colorchange_delete_on.png
Normal file
|
After Width: | Height: | Size: 628 B |
BIN
resources/icons/disclosure_triangle_close.png
Normal file
|
After Width: | Height: | Size: 212 B |
BIN
resources/icons/disclosure_triangle_open.png
Normal file
|
After Width: | Height: | Size: 210 B |
BIN
resources/icons/down_half_circle.png
Normal file
|
After Width: | Height: | Size: 506 B |
BIN
resources/icons/erase.png
Normal file
|
After Width: | Height: | Size: 488 B |
BIN
resources/icons/exclamation_mark_.png
Normal file
|
After Width: | Height: | Size: 1 KiB |
BIN
resources/icons/lambda.png
Normal file
|
After Width: | Height: | Size: 913 B |
BIN
resources/icons/lambda_.png
Normal file
|
After Width: | Height: | Size: 422 B |
BIN
resources/icons/left_half_circle.png
Normal file
|
After Width: | Height: | Size: 518 B |
BIN
resources/icons/object.png
Normal file
|
After Width: | Height: | Size: 1,017 B |
BIN
resources/icons/one_layer_lock_off.png
Normal file
|
After Width: | Height: | Size: 577 B |
BIN
resources/icons/one_layer_lock_on.png
Normal file
|
After Width: | Height: | Size: 528 B |
BIN
resources/icons/one_layer_unlock_off.png
Normal file
|
After Width: | Height: | Size: 508 B |
BIN
resources/icons/one_layer_unlock_on.png
Normal file
|
After Width: | Height: | Size: 483 B |
BIN
resources/icons/right_half_circle.png
Normal file
|
After Width: | Height: | Size: 521 B |
BIN
resources/icons/split.png
Normal file
|
After Width: | Height: | Size: 1,021 B |
BIN
resources/icons/toolbar.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
resources/icons/up_half_circle.png
Normal file
|
After Width: | Height: | Size: 517 B |
|
|
@ -207,6 +207,8 @@ add_library(libslic3r_gui STATIC
|
||||||
${LIBDIR}/slic3r/GUI/GLGizmo.cpp
|
${LIBDIR}/slic3r/GUI/GLGizmo.cpp
|
||||||
${LIBDIR}/slic3r/GUI/GLTexture.hpp
|
${LIBDIR}/slic3r/GUI/GLTexture.hpp
|
||||||
${LIBDIR}/slic3r/GUI/GLTexture.cpp
|
${LIBDIR}/slic3r/GUI/GLTexture.cpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GLToolbar.hpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GLToolbar.cpp
|
||||||
${LIBDIR}/slic3r/GUI/Preferences.cpp
|
${LIBDIR}/slic3r/GUI/Preferences.cpp
|
||||||
${LIBDIR}/slic3r/GUI/Preferences.hpp
|
${LIBDIR}/slic3r/GUI/Preferences.hpp
|
||||||
${LIBDIR}/slic3r/GUI/Preset.cpp
|
${LIBDIR}/slic3r/GUI/Preset.cpp
|
||||||
|
|
@ -217,6 +219,10 @@ add_library(libslic3r_gui STATIC
|
||||||
${LIBDIR}/slic3r/GUI/PresetHints.hpp
|
${LIBDIR}/slic3r/GUI/PresetHints.hpp
|
||||||
${LIBDIR}/slic3r/GUI/GUI.cpp
|
${LIBDIR}/slic3r/GUI/GUI.cpp
|
||||||
${LIBDIR}/slic3r/GUI/GUI.hpp
|
${LIBDIR}/slic3r/GUI/GUI.hpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GUI_ObjectParts.cpp
|
||||||
|
${LIBDIR}/slic3r/GUI/GUI_ObjectParts.hpp
|
||||||
|
${LIBDIR}/slic3r/GUI/LambdaObjectDialog.cpp
|
||||||
|
${LIBDIR}/slic3r/GUI/LambdaObjectDialog.hpp
|
||||||
${LIBDIR}/slic3r/GUI/Tab.cpp
|
${LIBDIR}/slic3r/GUI/Tab.cpp
|
||||||
${LIBDIR}/slic3r/GUI/Tab.hpp
|
${LIBDIR}/slic3r/GUI/Tab.hpp
|
||||||
${LIBDIR}/slic3r/GUI/TabIface.cpp
|
${LIBDIR}/slic3r/GUI/TabIface.cpp
|
||||||
|
|
@ -259,8 +265,14 @@ add_library(libslic3r_gui STATIC
|
||||||
${LIBDIR}/slic3r/Utils/Http.hpp
|
${LIBDIR}/slic3r/Utils/Http.hpp
|
||||||
${LIBDIR}/slic3r/Utils/FixModelByWin10.cpp
|
${LIBDIR}/slic3r/Utils/FixModelByWin10.cpp
|
||||||
${LIBDIR}/slic3r/Utils/FixModelByWin10.hpp
|
${LIBDIR}/slic3r/Utils/FixModelByWin10.hpp
|
||||||
|
${LIBDIR}/slic3r/Utils/PrintHostSendDialog.cpp
|
||||||
|
${LIBDIR}/slic3r/Utils/PrintHostSendDialog.hpp
|
||||||
${LIBDIR}/slic3r/Utils/OctoPrint.cpp
|
${LIBDIR}/slic3r/Utils/OctoPrint.cpp
|
||||||
${LIBDIR}/slic3r/Utils/OctoPrint.hpp
|
${LIBDIR}/slic3r/Utils/OctoPrint.hpp
|
||||||
|
${LIBDIR}/slic3r/Utils/Duet.cpp
|
||||||
|
${LIBDIR}/slic3r/Utils/Duet.hpp
|
||||||
|
${LIBDIR}/slic3r/Utils/PrintHost.cpp
|
||||||
|
${LIBDIR}/slic3r/Utils/PrintHost.hpp
|
||||||
${LIBDIR}/slic3r/Utils/Bonjour.cpp
|
${LIBDIR}/slic3r/Utils/Bonjour.cpp
|
||||||
${LIBDIR}/slic3r/Utils/Bonjour.hpp
|
${LIBDIR}/slic3r/Utils/Bonjour.hpp
|
||||||
${LIBDIR}/slic3r/Utils/PresetUpdater.cpp
|
${LIBDIR}/slic3r/Utils/PresetUpdater.cpp
|
||||||
|
|
@ -464,7 +476,7 @@ set(XS_XSP_FILES
|
||||||
${XSP_DIR}/Surface.xsp
|
${XSP_DIR}/Surface.xsp
|
||||||
${XSP_DIR}/SurfaceCollection.xsp
|
${XSP_DIR}/SurfaceCollection.xsp
|
||||||
${XSP_DIR}/TriangleMesh.xsp
|
${XSP_DIR}/TriangleMesh.xsp
|
||||||
${XSP_DIR}/Utils_OctoPrint.xsp
|
${XSP_DIR}/Utils_PrintHost.xsp
|
||||||
${XSP_DIR}/Utils_PresetUpdater.xsp
|
${XSP_DIR}/Utils_PresetUpdater.xsp
|
||||||
${XSP_DIR}/AppController.xsp
|
${XSP_DIR}/AppController.xsp
|
||||||
${XSP_DIR}/XS.xsp
|
${XSP_DIR}/XS.xsp
|
||||||
|
|
@ -513,7 +525,7 @@ if(APPLE)
|
||||||
# Ignore undefined symbols of the perl interpreter, they will be found in the caller image.
|
# Ignore undefined symbols of the perl interpreter, they will be found in the caller image.
|
||||||
target_link_libraries(XS "-undefined dynamic_lookup")
|
target_link_libraries(XS "-undefined dynamic_lookup")
|
||||||
endif()
|
endif()
|
||||||
target_link_libraries(XS libslic3r libslic3r_gui admesh miniz clipper nowide polypartition poly2tri semver avrdude)
|
target_link_libraries(XS libslic3r libslic3r_gui admesh miniz clipper nowide polypartition poly2tri semver avrdude qhull)
|
||||||
if(SLIC3R_PROFILE)
|
if(SLIC3R_PROFILE)
|
||||||
target_link_libraries(XS Shiny)
|
target_link_libraries(XS Shiny)
|
||||||
endif()
|
endif()
|
||||||
|
|
@ -602,6 +614,10 @@ endif()
|
||||||
|
|
||||||
add_subdirectory(src/avrdude)
|
add_subdirectory(src/avrdude)
|
||||||
|
|
||||||
|
add_subdirectory(src/qhull)
|
||||||
|
include_directories(${LIBDIR}/qhull/src)
|
||||||
|
message(STATUS ${LIBDIR}/qhull/src)
|
||||||
|
|
||||||
## REQUIRED packages
|
## REQUIRED packages
|
||||||
|
|
||||||
# Find and configure boost
|
# Find and configure boost
|
||||||
|
|
|
||||||
|
|
@ -33,16 +33,6 @@ use overload
|
||||||
'@{}' => sub { $_[0]->arrayref },
|
'@{}' => sub { $_[0]->arrayref },
|
||||||
'fallback' => 1;
|
'fallback' => 1;
|
||||||
|
|
||||||
package Slic3r::Point3;
|
|
||||||
use overload
|
|
||||||
'@{}' => sub { [ $_[0]->x, $_[0]->y, $_[0]->z ] }, #,
|
|
||||||
'fallback' => 1;
|
|
||||||
|
|
||||||
sub pp {
|
|
||||||
my ($self) = @_;
|
|
||||||
return [ @$self ];
|
|
||||||
}
|
|
||||||
|
|
||||||
package Slic3r::Pointf;
|
package Slic3r::Pointf;
|
||||||
use overload
|
use overload
|
||||||
'@{}' => sub { $_[0]->arrayref },
|
'@{}' => sub { $_[0]->arrayref },
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,11 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <boost/detail/endian.hpp>
|
||||||
|
|
||||||
#include "stl.h"
|
#include "stl.h"
|
||||||
|
|
||||||
|
|
||||||
static void stl_match_neighbors_exact(stl_file *stl,
|
|
||||||
stl_hash_edge *edge_a, stl_hash_edge *edge_b);
|
|
||||||
static void stl_match_neighbors_nearby(stl_file *stl,
|
static void stl_match_neighbors_nearby(stl_file *stl,
|
||||||
stl_hash_edge *edge_a, stl_hash_edge *edge_b);
|
stl_hash_edge *edge_a, stl_hash_edge *edge_b);
|
||||||
static void stl_record_neighbors(stl_file *stl,
|
static void stl_record_neighbors(stl_file *stl,
|
||||||
|
|
@ -43,7 +43,6 @@ static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge,
|
||||||
static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
|
static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
|
||||||
void (*match_neighbors)(stl_file *stl,
|
void (*match_neighbors)(stl_file *stl,
|
||||||
stl_hash_edge *edge_a, stl_hash_edge *edge_b));
|
stl_hash_edge *edge_a, stl_hash_edge *edge_b));
|
||||||
static int stl_get_hash_for_edge(int M, stl_hash_edge *edge);
|
|
||||||
static int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b);
|
static int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b);
|
||||||
static void stl_free_edges(stl_file *stl);
|
static void stl_free_edges(stl_file *stl);
|
||||||
static void stl_remove_facet(stl_file *stl, int facet_number);
|
static void stl_remove_facet(stl_file *stl, int facet_number);
|
||||||
|
|
@ -82,37 +81,20 @@ stl_check_facets_exact(stl_file *stl) {
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
facet = stl->facet_start[i];
|
facet = stl->facet_start[i];
|
||||||
// Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
|
// If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet.
|
||||||
// When using a memcmp on raw floats, those numbers report to be different.
|
if (facet.vertex[0] == facet.vertex[1] ||
|
||||||
// Unify all +0 and -0 to +0 to make the floats equal under memcmp.
|
facet.vertex[1] == facet.vertex[2] ||
|
||||||
{
|
facet.vertex[0] == facet.vertex[2]) {
|
||||||
uint32_t *f = (uint32_t*)&facet;
|
|
||||||
for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
|
|
||||||
if (*f == 0x80000000)
|
|
||||||
// Negative zero, switch to positive zero.
|
|
||||||
*f = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If any two of the three vertices are found to be exactally the same, call them degenerate and remove the facet. */
|
|
||||||
if( !memcmp(&facet.vertex[0], &facet.vertex[1],
|
|
||||||
sizeof(stl_vertex))
|
|
||||||
|| !memcmp(&facet.vertex[1], &facet.vertex[2],
|
|
||||||
sizeof(stl_vertex))
|
|
||||||
|| !memcmp(&facet.vertex[0], &facet.vertex[2],
|
|
||||||
sizeof(stl_vertex))) {
|
|
||||||
stl->stats.degenerate_facets += 1;
|
stl->stats.degenerate_facets += 1;
|
||||||
stl_remove_facet(stl, i);
|
stl_remove_facet(stl, i);
|
||||||
i--;
|
-- i;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
}
|
}
|
||||||
for(j = 0; j < 3; j++) {
|
for(j = 0; j < 3; j++) {
|
||||||
edge.facet_number = i;
|
edge.facet_number = i;
|
||||||
edge.which_edge = j;
|
edge.which_edge = j;
|
||||||
stl_load_edge_exact(stl, &edge, &facet.vertex[j],
|
stl_load_edge_exact(stl, &edge, &facet.vertex[j], &facet.vertex[(j + 1) % 3]);
|
||||||
&facet.vertex[(j + 1) % 3]);
|
insert_hash_edge(stl, edge, stl_record_neighbors);
|
||||||
|
|
||||||
insert_hash_edge(stl, edge, stl_match_neighbors_exact);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stl_free_edges(stl);
|
stl_free_edges(stl);
|
||||||
|
|
@ -131,28 +113,33 @@ stl_load_edge_exact(stl_file *stl, stl_hash_edge *edge,
|
||||||
if (stl->error) return;
|
if (stl->error) return;
|
||||||
|
|
||||||
{
|
{
|
||||||
float diff_x = ABS(a->x - b->x);
|
stl_vertex diff = (*a - *b).cwiseAbs();
|
||||||
float diff_y = ABS(a->y - b->y);
|
float max_diff = std::max(diff(0), std::max(diff(1), diff(2)));
|
||||||
float diff_z = ABS(a->z - b->z);
|
stl->stats.shortest_edge = std::min(max_diff, stl->stats.shortest_edge);
|
||||||
float max_diff = STL_MAX(diff_x, diff_y);
|
|
||||||
max_diff = STL_MAX(diff_z, max_diff);
|
|
||||||
stl->stats.shortest_edge = STL_MIN(max_diff, stl->stats.shortest_edge);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure identical vertex ordering of equal edges.
|
// Ensure identical vertex ordering of equal edges.
|
||||||
// This method is numerically robust.
|
// This method is numerically robust.
|
||||||
if ((a->x != b->x) ?
|
if (stl_vertex_lower(*a, *b)) {
|
||||||
(a->x < b->x) :
|
|
||||||
((a->y != b->y) ?
|
|
||||||
(a->y < b->y) :
|
|
||||||
(a->z < b->z))) {
|
|
||||||
memcpy(&edge->key[0], a, sizeof(stl_vertex));
|
|
||||||
memcpy(&edge->key[3], b, sizeof(stl_vertex));
|
|
||||||
} else {
|
} else {
|
||||||
memcpy(&edge->key[0], b, sizeof(stl_vertex));
|
std::swap(a, b);
|
||||||
memcpy(&edge->key[3], a, sizeof(stl_vertex));
|
|
||||||
edge->which_edge += 3; /* this edge is loaded backwards */
|
edge->which_edge += 3; /* this edge is loaded backwards */
|
||||||
}
|
}
|
||||||
|
memcpy(&edge->key[0], a->data(), sizeof(stl_vertex));
|
||||||
|
memcpy(&edge->key[sizeof(stl_vertex)], b->data(), sizeof(stl_vertex));
|
||||||
|
// Switch negative zeros to positive zeros, so memcmp will consider them to be equal.
|
||||||
|
for (size_t i = 0; i < 6; ++ i) {
|
||||||
|
unsigned char *p = edge->key + i * 4;
|
||||||
|
#ifdef BOOST_LITTLE_ENDIAN
|
||||||
|
if (p[0] == 0 && p[1] == 0 && p[2] == 0 && p[3] == 0x80)
|
||||||
|
// Negative zero, switch to positive zero.
|
||||||
|
p[3] = 0;
|
||||||
|
#else /* BOOST_LITTLE_ENDIAN */
|
||||||
|
if (p[0] == 0x80 && p[1] == 0 && p[2] == 0 && p[3] == 0)
|
||||||
|
// Negative zero, switch to positive zero.
|
||||||
|
p[0] = 0;
|
||||||
|
#endif /* BOOST_LITTLE_ENDIAN */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -188,21 +175,17 @@ stl_initialize_facet_check_exact(stl_file *stl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void insert_hash_edge(stl_file *stl, stl_hash_edge edge,
|
||||||
insert_hash_edge(stl_file *stl, stl_hash_edge edge,
|
|
||||||
void (*match_neighbors)(stl_file *stl,
|
void (*match_neighbors)(stl_file *stl,
|
||||||
stl_hash_edge *edge_a, stl_hash_edge *edge_b)) {
|
stl_hash_edge *edge_a, stl_hash_edge *edge_b))
|
||||||
stl_hash_edge *link;
|
{
|
||||||
stl_hash_edge *new_edge;
|
|
||||||
stl_hash_edge *temp;
|
|
||||||
int chain_number;
|
|
||||||
|
|
||||||
if (stl->error) return;
|
if (stl->error) return;
|
||||||
|
|
||||||
chain_number = stl_get_hash_for_edge(stl->M, &edge);
|
int chain_number = edge.hash(stl->M);
|
||||||
|
stl_hash_edge *link = stl->heads[chain_number];
|
||||||
link = stl->heads[chain_number];
|
|
||||||
|
|
||||||
|
stl_hash_edge *new_edge;
|
||||||
|
stl_hash_edge *temp;
|
||||||
if(link == stl->tail) {
|
if(link == stl->tail) {
|
||||||
/* This list doesn't have any edges currently in it. Add this one. */
|
/* This list doesn't have any edges currently in it. Add this one. */
|
||||||
new_edge = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
|
new_edge = (stl_hash_edge*)malloc(sizeof(stl_hash_edge));
|
||||||
|
|
@ -252,30 +235,17 @@ insert_hash_edge(stl_file *stl, stl_hash_edge edge,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return 1 if the edges are not matched.
|
||||||
static int
|
static inline int stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b)
|
||||||
stl_get_hash_for_edge(int M, stl_hash_edge *edge) {
|
{
|
||||||
return ((edge->key[0] / 23 + edge->key[1] / 19 + edge->key[2] / 17
|
// Don't match edges of the same facet
|
||||||
+ edge->key[3] /13 + edge->key[4] / 11 + edge->key[5] / 7 ) % M);
|
return (edge_a->facet_number == edge_b->facet_number) || (*edge_a != *edge_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
void stl_check_facets_nearby(stl_file *stl, float tolerance)
|
||||||
stl_compare_function(stl_hash_edge *edge_a, stl_hash_edge *edge_b) {
|
{
|
||||||
if(edge_a->facet_number == edge_b->facet_number) {
|
if (stl->error)
|
||||||
return 1; /* Don't match edges of the same facet */
|
return;
|
||||||
} else {
|
|
||||||
return memcmp(edge_a, edge_b, SIZEOF_EDGE_SORT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
stl_check_facets_nearby(stl_file *stl, float tolerance) {
|
|
||||||
stl_hash_edge edge[3];
|
|
||||||
stl_facet facet;
|
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
|
|
||||||
if (stl->error) return;
|
|
||||||
|
|
||||||
if( (stl->stats.connected_facets_1_edge == stl->stats.number_of_facets)
|
if( (stl->stats.connected_facets_1_edge == stl->stats.number_of_facets)
|
||||||
&& (stl->stats.connected_facets_2_edge == stl->stats.number_of_facets)
|
&& (stl->stats.connected_facets_2_edge == stl->stats.number_of_facets)
|
||||||
|
|
@ -286,27 +256,19 @@ stl_check_facets_nearby(stl_file *stl, float tolerance) {
|
||||||
|
|
||||||
stl_initialize_facet_check_nearby(stl);
|
stl_initialize_facet_check_nearby(stl);
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for (int i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||||
facet = stl->facet_start[i];
|
//FIXME is the copy necessary?
|
||||||
// Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
|
stl_facet facet = stl->facet_start[i];
|
||||||
// When using a memcmp on raw floats, those numbers report to be different.
|
for (int j = 0; j < 3; j++) {
|
||||||
// Unify all +0 and -0 to +0 to make the floats equal under memcmp.
|
|
||||||
{
|
|
||||||
uint32_t *f = (uint32_t*)&facet;
|
|
||||||
for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
|
|
||||||
if (*f == 0x80000000)
|
|
||||||
// Negative zero, switch to positive zero.
|
|
||||||
*f = 0;
|
|
||||||
}
|
|
||||||
for(j = 0; j < 3; j++) {
|
|
||||||
if(stl->neighbors_start[i].neighbor[j] == -1) {
|
if(stl->neighbors_start[i].neighbor[j] == -1) {
|
||||||
edge[j].facet_number = i;
|
stl_hash_edge edge;
|
||||||
edge[j].which_edge = j;
|
edge.facet_number = i;
|
||||||
if(stl_load_edge_nearby(stl, &edge[j], &facet.vertex[j],
|
edge.which_edge = j;
|
||||||
|
if(stl_load_edge_nearby(stl, &edge, &facet.vertex[j],
|
||||||
&facet.vertex[(j + 1) % 3],
|
&facet.vertex[(j + 1) % 3],
|
||||||
tolerance)) {
|
tolerance)) {
|
||||||
/* only insert edges that have different keys */
|
/* only insert edges that have different keys */
|
||||||
insert_hash_edge(stl, edge[j], stl_match_neighbors_nearby);
|
insert_hash_edge(stl, edge, stl_match_neighbors_nearby);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -315,27 +277,17 @@ stl_check_facets_nearby(stl_file *stl, float tolerance) {
|
||||||
stl_free_edges(stl);
|
stl_free_edges(stl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge, stl_vertex *a, stl_vertex *b, float tolerance)
|
||||||
stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge,
|
{
|
||||||
stl_vertex *a, stl_vertex *b, float tolerance) {
|
|
||||||
// Index of a grid cell spaced by tolerance.
|
// Index of a grid cell spaced by tolerance.
|
||||||
uint32_t vertex1[3] = {
|
typedef Eigen::Matrix<int32_t, 3, 1, Eigen::DontAlign> Vec3i;
|
||||||
(uint32_t)((a->x - stl->stats.min.x) / tolerance),
|
Vec3i vertex1 = (*a / tolerance).cast<int32_t>();
|
||||||
(uint32_t)((a->y - stl->stats.min.y) / tolerance),
|
Vec3i vertex2 = (*b / tolerance).cast<int32_t>();
|
||||||
(uint32_t)((a->z - stl->stats.min.z) / tolerance)
|
static_assert(sizeof(Vec3i) == 12, "size of Vec3i incorrect");
|
||||||
};
|
|
||||||
uint32_t vertex2[3] = {
|
|
||||||
(uint32_t)((b->x - stl->stats.min.x) / tolerance),
|
|
||||||
(uint32_t)((b->y - stl->stats.min.y) / tolerance),
|
|
||||||
(uint32_t)((b->z - stl->stats.min.z) / tolerance)
|
|
||||||
};
|
|
||||||
|
|
||||||
if( (vertex1[0] == vertex2[0])
|
if (vertex1 == vertex2)
|
||||||
&& (vertex1[1] == vertex2[1])
|
// Both vertices hash to the same value
|
||||||
&& (vertex1[2] == vertex2[2])) {
|
|
||||||
/* Both vertices hash to the same value */
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure identical vertex ordering of edges, which vertices land into equal grid cells.
|
// Ensure identical vertex ordering of edges, which vertices land into equal grid cells.
|
||||||
// This method is numerically robust.
|
// This method is numerically robust.
|
||||||
|
|
@ -344,30 +296,27 @@ stl_load_edge_nearby(stl_file *stl, stl_hash_edge *edge,
|
||||||
((vertex1[1] != vertex2[1]) ?
|
((vertex1[1] != vertex2[1]) ?
|
||||||
(vertex1[1] < vertex2[1]) :
|
(vertex1[1] < vertex2[1]) :
|
||||||
(vertex1[2] < vertex2[2]))) {
|
(vertex1[2] < vertex2[2]))) {
|
||||||
memcpy(&edge->key[0], vertex1, sizeof(stl_vertex));
|
memcpy(&edge->key[0], vertex1.data(), sizeof(stl_vertex));
|
||||||
memcpy(&edge->key[3], vertex2, sizeof(stl_vertex));
|
memcpy(&edge->key[sizeof(stl_vertex)], vertex2.data(), sizeof(stl_vertex));
|
||||||
} else {
|
} else {
|
||||||
memcpy(&edge->key[0], vertex2, sizeof(stl_vertex));
|
memcpy(&edge->key[0], vertex2.data(), sizeof(stl_vertex));
|
||||||
memcpy(&edge->key[3], vertex1, sizeof(stl_vertex));
|
memcpy(&edge->key[sizeof(stl_vertex)], vertex1.data(), sizeof(stl_vertex));
|
||||||
edge->which_edge += 3; /* this edge is loaded backwards */
|
edge->which_edge += 3; /* this edge is loaded backwards */
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void stl_free_edges(stl_file *stl)
|
||||||
stl_free_edges(stl_file *stl) {
|
{
|
||||||
int i;
|
if (stl->error)
|
||||||
stl_hash_edge *temp;
|
return;
|
||||||
|
|
||||||
if (stl->error) return;
|
|
||||||
|
|
||||||
if(stl->stats.malloced != stl->stats.freed) {
|
if(stl->stats.malloced != stl->stats.freed) {
|
||||||
for(i = 0; i < stl->M; i++) {
|
for (int i = 0; i < stl->M; i++) {
|
||||||
for(temp = stl->heads[i]; stl->heads[i] != stl->tail;
|
for (stl_hash_edge *temp = stl->heads[i]; stl->heads[i] != stl->tail; temp = stl->heads[i]) {
|
||||||
temp = stl->heads[i]) {
|
|
||||||
stl->heads[i] = stl->heads[i]->next;
|
stl->heads[i] = stl->heads[i]->next;
|
||||||
free(temp);
|
free(temp);
|
||||||
stl->stats.freed++;
|
++ stl->stats.freed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -375,8 +324,8 @@ stl_free_edges(stl_file *stl) {
|
||||||
free(stl->tail);
|
free(stl->tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void stl_initialize_facet_check_nearby(stl_file *stl)
|
||||||
stl_initialize_facet_check_nearby(stl_file *stl) {
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (stl->error) return;
|
if (stl->error) return;
|
||||||
|
|
@ -467,16 +416,8 @@ stl_record_neighbors(stl_file *stl,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void stl_match_neighbors_nearby(stl_file *stl, stl_hash_edge *edge_a, stl_hash_edge *edge_b)
|
||||||
stl_match_neighbors_exact(stl_file *stl,
|
{
|
||||||
stl_hash_edge *edge_a, stl_hash_edge *edge_b) {
|
|
||||||
if (stl->error) return;
|
|
||||||
stl_record_neighbors(stl, edge_a, edge_b);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
stl_match_neighbors_nearby(stl_file *stl,
|
|
||||||
stl_hash_edge *edge_a, stl_hash_edge *edge_b) {
|
|
||||||
int facet1;
|
int facet1;
|
||||||
int facet2;
|
int facet2;
|
||||||
int vertex1;
|
int vertex1;
|
||||||
|
|
@ -517,9 +458,7 @@ stl_match_neighbors_nearby(stl_file *stl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void stl_change_vertices(stl_file *stl, int facet_num, int vnot, stl_vertex new_vertex) {
|
||||||
stl_change_vertices(stl_file *stl, int facet_num, int vnot,
|
|
||||||
stl_vertex new_vertex) {
|
|
||||||
int first_facet;
|
int first_facet;
|
||||||
int direction;
|
int direction;
|
||||||
int next_edge;
|
int next_edge;
|
||||||
|
|
@ -551,30 +490,30 @@ stl_change_vertices(stl_file *stl, int facet_num, int vnot,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
if (stl->facet_start[facet_num].vertex[pivot_vertex].x == new_vertex.x &&
|
if (stl->facet_start[facet_num].vertex[pivot_vertex](0) == new_vertex(0) &&
|
||||||
stl->facet_start[facet_num].vertex[pivot_vertex].y == new_vertex.y &&
|
stl->facet_start[facet_num].vertex[pivot_vertex](1) == new_vertex(1) &&
|
||||||
stl->facet_start[facet_num].vertex[pivot_vertex].z == new_vertex.z)
|
stl->facet_start[facet_num].vertex[pivot_vertex](2) == new_vertex(2))
|
||||||
printf("Changing vertex %f,%f,%f: Same !!!\r\n",
|
printf("Changing vertex %f,%f,%f: Same !!!\r\n",
|
||||||
new_vertex.x, new_vertex.y, new_vertex.z);
|
new_vertex(0), new_vertex(1), new_vertex(2));
|
||||||
else {
|
else {
|
||||||
if (stl->facet_start[facet_num].vertex[pivot_vertex].x != new_vertex.x)
|
if (stl->facet_start[facet_num].vertex[pivot_vertex](0) != new_vertex(0))
|
||||||
printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
|
printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
|
||||||
stl->facet_start[facet_num].vertex[pivot_vertex].x,
|
stl->facet_start[facet_num].vertex[pivot_vertex](0),
|
||||||
*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex].x),
|
*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](0)),
|
||||||
new_vertex.x,
|
new_vertex(0),
|
||||||
*reinterpret_cast<const int*>(&new_vertex.x));
|
*reinterpret_cast<const int*>(&new_vertex(0)));
|
||||||
if (stl->facet_start[facet_num].vertex[pivot_vertex].y != new_vertex.y)
|
if (stl->facet_start[facet_num].vertex[pivot_vertex](1) != new_vertex(1))
|
||||||
printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
|
printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
|
||||||
stl->facet_start[facet_num].vertex[pivot_vertex].y,
|
stl->facet_start[facet_num].vertex[pivot_vertex](1),
|
||||||
*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex].y),
|
*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](1)),
|
||||||
new_vertex.y,
|
new_vertex(1),
|
||||||
*reinterpret_cast<const int*>(&new_vertex.y));
|
*reinterpret_cast<const int*>(&new_vertex(1)));
|
||||||
if (stl->facet_start[facet_num].vertex[pivot_vertex].z != new_vertex.z)
|
if (stl->facet_start[facet_num].vertex[pivot_vertex](2) != new_vertex(2))
|
||||||
printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
|
printf("Changing coordinate x, vertex %e (0x%08x) to %e(0x%08x)\r\n",
|
||||||
stl->facet_start[facet_num].vertex[pivot_vertex].z,
|
stl->facet_start[facet_num].vertex[pivot_vertex](2),
|
||||||
*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex].z),
|
*reinterpret_cast<const int*>(&stl->facet_start[facet_num].vertex[pivot_vertex](2)),
|
||||||
new_vertex.z,
|
new_vertex(2),
|
||||||
*reinterpret_cast<const int*>(&new_vertex.z));
|
*reinterpret_cast<const int*>(&new_vertex(2)));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex;
|
stl->facet_start[facet_num].vertex[pivot_vertex] = new_vertex;
|
||||||
|
|
@ -595,7 +534,6 @@ Try using a smaller tolerance or don't do a nearby check\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
|
stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
|
||||||
stl_hash_edge *edge_b, int *facet1, int *vertex1,
|
stl_hash_edge *edge_b, int *facet1, int *vertex1,
|
||||||
|
|
@ -622,11 +560,10 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
|
||||||
v1b = (edge_b->which_edge + 1) % 3;
|
v1b = (edge_b->which_edge + 1) % 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Of the first pair, which vertex, if any, should be changed */
|
// Of the first pair, which vertex, if any, should be changed
|
||||||
if(!memcmp(&stl->facet_start[edge_a->facet_number].vertex[v1a],
|
if(stl->facet_start[edge_a->facet_number].vertex[v1a] ==
|
||||||
&stl->facet_start[edge_b->facet_number].vertex[v1b],
|
stl->facet_start[edge_b->facet_number].vertex[v1b]) {
|
||||||
sizeof(stl_vertex))) {
|
// These facets are already equal. No need to change.
|
||||||
/* These facets are already equal. No need to change. */
|
|
||||||
*facet1 = -1;
|
*facet1 = -1;
|
||||||
} else {
|
} else {
|
||||||
if( (stl->neighbors_start[edge_a->facet_number].neighbor[v1a] == -1)
|
if( (stl->neighbors_start[edge_a->facet_number].neighbor[v1a] == -1)
|
||||||
|
|
@ -644,10 +581,9 @@ stl_which_vertices_to_change(stl_file *stl, stl_hash_edge *edge_a,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Of the second pair, which vertex, if any, should be changed */
|
/* Of the second pair, which vertex, if any, should be changed */
|
||||||
if(!memcmp(&stl->facet_start[edge_a->facet_number].vertex[v2a],
|
if(stl->facet_start[edge_a->facet_number].vertex[v2a] ==
|
||||||
&stl->facet_start[edge_b->facet_number].vertex[v2b],
|
stl->facet_start[edge_b->facet_number].vertex[v2b]) {
|
||||||
sizeof(stl_vertex))) {
|
// These facets are already equal. No need to change.
|
||||||
/* These facets are already equal. No need to change. */
|
|
||||||
*facet2 = -1;
|
*facet2 = -1;
|
||||||
} else {
|
} else {
|
||||||
if( (stl->neighbors_start[edge_a->facet_number].neighbor[v2a] == -1)
|
if( (stl->neighbors_start[edge_a->facet_number].neighbor[v2a] == -1)
|
||||||
|
|
@ -718,40 +654,35 @@ in stl_remove_facet: neighbor = %d numfacets = %d this is wrong\n",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void stl_remove_unconnected_facets(stl_file *stl)
|
||||||
stl_remove_unconnected_facets(stl_file *stl) {
|
{
|
||||||
/* A couple of things need to be done here. One is to remove any */
|
/* A couple of things need to be done here. One is to remove any */
|
||||||
/* completely unconnected facets (0 edges connected) since these are */
|
/* completely unconnected facets (0 edges connected) since these are */
|
||||||
/* useless and could be completely wrong. The second thing that needs to */
|
/* useless and could be completely wrong. The second thing that needs to */
|
||||||
/* be done is to remove any degenerate facets that were created during */
|
/* be done is to remove any degenerate facets that were created during */
|
||||||
/* stl_check_facets_nearby(). */
|
/* stl_check_facets_nearby(). */
|
||||||
|
if (stl->error)
|
||||||
|
return;
|
||||||
|
|
||||||
int i;
|
// remove degenerate facets
|
||||||
|
for (int i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||||
if (stl->error) return;
|
if(stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[1] ||
|
||||||
|
stl->facet_start[i].vertex[0] == stl->facet_start[i].vertex[2] ||
|
||||||
/* remove degenerate facets */
|
stl->facet_start[i].vertex[1] == stl->facet_start[i].vertex[2]) {
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
|
||||||
if( !memcmp(&stl->facet_start[i].vertex[0],
|
|
||||||
&stl->facet_start[i].vertex[1], sizeof(stl_vertex))
|
|
||||||
|| !memcmp(&stl->facet_start[i].vertex[1],
|
|
||||||
&stl->facet_start[i].vertex[2], sizeof(stl_vertex))
|
|
||||||
|| !memcmp(&stl->facet_start[i].vertex[0],
|
|
||||||
&stl->facet_start[i].vertex[2], sizeof(stl_vertex))) {
|
|
||||||
stl_remove_degenerate(stl, i);
|
stl_remove_degenerate(stl, i);
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(stl->stats.connected_facets_1_edge < stl->stats.number_of_facets) {
|
if(stl->stats.connected_facets_1_edge < stl->stats.number_of_facets) {
|
||||||
/* remove completely unconnected facets */
|
// remove completely unconnected facets
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for (int i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
if( (stl->neighbors_start[i].neighbor[0] == -1)
|
if (stl->neighbors_start[i].neighbor[0] == -1 &&
|
||||||
&& (stl->neighbors_start[i].neighbor[1] == -1)
|
stl->neighbors_start[i].neighbor[1] == -1 &&
|
||||||
&& (stl->neighbors_start[i].neighbor[2] == -1)) {
|
stl->neighbors_start[i].neighbor[2] == -1) {
|
||||||
/* This facet is completely unconnected. Remove it. */
|
// This facet is completely unconnected. Remove it.
|
||||||
stl_remove_facet(stl, i);
|
stl_remove_facet(stl, i);
|
||||||
i--;
|
-- i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -771,30 +702,24 @@ stl_remove_degenerate(stl_file *stl, int facet) {
|
||||||
|
|
||||||
if (stl->error) return;
|
if (stl->error) return;
|
||||||
|
|
||||||
if( !memcmp(&stl->facet_start[facet].vertex[0],
|
if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1] &&
|
||||||
&stl->facet_start[facet].vertex[1], sizeof(stl_vertex))
|
stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
|
||||||
&& !memcmp(&stl->facet_start[facet].vertex[1],
|
|
||||||
&stl->facet_start[facet].vertex[2], sizeof(stl_vertex))) {
|
|
||||||
/* all 3 vertices are equal. Just remove the facet. I don't think*/
|
/* all 3 vertices are equal. Just remove the facet. I don't think*/
|
||||||
/* this is really possible, but just in case... */
|
/* this is really possible, but just in case... */
|
||||||
printf("removing a facet in stl_remove_degenerate\n");
|
printf("removing a facet in stl_remove_degenerate\n");
|
||||||
|
|
||||||
stl_remove_facet(stl, facet);
|
stl_remove_facet(stl, facet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!memcmp(&stl->facet_start[facet].vertex[0],
|
if (stl->facet_start[facet].vertex[0] == stl->facet_start[facet].vertex[1]) {
|
||||||
&stl->facet_start[facet].vertex[1], sizeof(stl_vertex))) {
|
|
||||||
edge1 = 1;
|
edge1 = 1;
|
||||||
edge2 = 2;
|
edge2 = 2;
|
||||||
edge3 = 0;
|
edge3 = 0;
|
||||||
} else if(!memcmp(&stl->facet_start[facet].vertex[1],
|
} else if (stl->facet_start[facet].vertex[1] == stl->facet_start[facet].vertex[2]) {
|
||||||
&stl->facet_start[facet].vertex[2], sizeof(stl_vertex))) {
|
|
||||||
edge1 = 0;
|
edge1 = 0;
|
||||||
edge2 = 2;
|
edge2 = 2;
|
||||||
edge3 = 1;
|
edge3 = 1;
|
||||||
} else if(!memcmp(&stl->facet_start[facet].vertex[2],
|
} else if (stl->facet_start[facet].vertex[2] == stl->facet_start[facet].vertex[0]) {
|
||||||
&stl->facet_start[facet].vertex[0], sizeof(stl_vertex))) {
|
|
||||||
edge1 = 0;
|
edge1 = 0;
|
||||||
edge2 = 1;
|
edge2 = 1;
|
||||||
edge3 = 2;
|
edge3 = 2;
|
||||||
|
|
@ -883,7 +808,7 @@ stl_fill_holes(stl_file *stl) {
|
||||||
stl_load_edge_exact(stl, &edge, &facet.vertex[j],
|
stl_load_edge_exact(stl, &edge, &facet.vertex[j],
|
||||||
&facet.vertex[(j + 1) % 3]);
|
&facet.vertex[(j + 1) % 3]);
|
||||||
|
|
||||||
insert_hash_edge(stl, edge, stl_match_neighbors_exact);
|
insert_hash_edge(stl, edge, stl_record_neighbors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -939,7 +864,7 @@ stl_fill_holes(stl_file *stl) {
|
||||||
stl_load_edge_exact(stl, &edge, &new_facet.vertex[k],
|
stl_load_edge_exact(stl, &edge, &new_facet.vertex[k],
|
||||||
&new_facet.vertex[(k + 1) % 3]);
|
&new_facet.vertex[(k + 1) % 3]);
|
||||||
|
|
||||||
insert_hash_edge(stl, edge, stl_match_neighbors_exact);
|
insert_hash_edge(stl, edge, stl_record_neighbors);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -977,9 +902,7 @@ stl_add_facet(stl_file *stl, stl_facet *new_facet) {
|
||||||
stl->facet_start[stl->stats.number_of_facets] = *new_facet;
|
stl->facet_start[stl->stats.number_of_facets] = *new_facet;
|
||||||
|
|
||||||
/* note that the normal vector is not set here, just initialized to 0 */
|
/* note that the normal vector is not set here, just initialized to 0 */
|
||||||
stl->facet_start[stl->stats.number_of_facets].normal.x = 0.0;
|
stl->facet_start[stl->stats.number_of_facets].normal = stl_normal::Zero();
|
||||||
stl->facet_start[stl->stats.number_of_facets].normal.y = 0.0;
|
|
||||||
stl->facet_start[stl->stats.number_of_facets].normal.z = 0.0;
|
|
||||||
|
|
||||||
stl->neighbors_start[stl->stats.number_of_facets].neighbor[0] = -1;
|
stl->neighbors_start[stl->stats.number_of_facets].neighbor[0] = -1;
|
||||||
stl->neighbors_start[stl->stats.number_of_facets].neighbor[1] = -1;
|
stl->neighbors_start[stl->stats.number_of_facets].neighbor[1] = -1;
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,6 @@
|
||||||
|
|
||||||
#include "stl.h"
|
#include "stl.h"
|
||||||
|
|
||||||
static void stl_reverse_vector(float v[]) {
|
|
||||||
v[0] *= -1;
|
|
||||||
v[1] *= -1;
|
|
||||||
v[2] *= -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag);
|
static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_flag);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -228,102 +222,52 @@ static int stl_check_normal_vector(stl_file *stl, int facet_num, int normal_fix_
|
||||||
/* Returns 2 if the normal is not within tolerance and backwards */
|
/* Returns 2 if the normal is not within tolerance and backwards */
|
||||||
/* Returns 4 if the status is unknown. */
|
/* Returns 4 if the status is unknown. */
|
||||||
|
|
||||||
float normal[3];
|
|
||||||
float test_norm[3];
|
|
||||||
stl_facet *facet;
|
stl_facet *facet;
|
||||||
|
|
||||||
facet = &stl->facet_start[facet_num];
|
facet = &stl->facet_start[facet_num];
|
||||||
|
|
||||||
|
stl_normal normal;
|
||||||
stl_calculate_normal(normal, facet);
|
stl_calculate_normal(normal, facet);
|
||||||
stl_normalize_vector(normal);
|
stl_normalize_vector(normal);
|
||||||
|
stl_normal normal_dif = (normal - facet->normal).cwiseAbs();
|
||||||
|
|
||||||
if( (ABS(normal[0] - facet->normal.x) < 0.001)
|
const float eps = 0.001f;
|
||||||
&& (ABS(normal[1] - facet->normal.y) < 0.001)
|
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
|
||||||
&& (ABS(normal[2] - facet->normal.z) < 0.001)) {
|
|
||||||
/* It is not really necessary to change the values here */
|
/* It is not really necessary to change the values here */
|
||||||
/* but just for consistency, I will. */
|
/* but just for consistency, I will. */
|
||||||
facet->normal.x = normal[0];
|
facet->normal = normal;
|
||||||
facet->normal.y = normal[1];
|
|
||||||
facet->normal.z = normal[2];
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
test_norm[0] = facet->normal.x;
|
stl_normal test_norm = facet->normal;
|
||||||
test_norm[1] = facet->normal.y;
|
|
||||||
test_norm[2] = facet->normal.z;
|
|
||||||
|
|
||||||
stl_normalize_vector(test_norm);
|
stl_normalize_vector(test_norm);
|
||||||
if( (ABS(normal[0] - test_norm[0]) < 0.001)
|
normal_dif = (normal - test_norm).cwiseAbs();
|
||||||
&& (ABS(normal[1] - test_norm[1]) < 0.001)
|
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
|
||||||
&& (ABS(normal[2] - test_norm[2]) < 0.001)) {
|
|
||||||
if(normal_fix_flag) {
|
if(normal_fix_flag) {
|
||||||
facet->normal.x = normal[0];
|
facet->normal = normal;
|
||||||
facet->normal.y = normal[1];
|
|
||||||
facet->normal.z = normal[2];
|
|
||||||
stl->stats.normals_fixed += 1;
|
stl->stats.normals_fixed += 1;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
stl_reverse_vector(test_norm);
|
test_norm *= -1.f;
|
||||||
if( (ABS(normal[0] - test_norm[0]) < 0.001)
|
normal_dif = (normal - test_norm).cwiseAbs();
|
||||||
&& (ABS(normal[1] - test_norm[1]) < 0.001)
|
if (normal_dif(0) < eps && normal_dif(1) < eps && normal_dif(2) < eps) {
|
||||||
&& (ABS(normal[2] - test_norm[2]) < 0.001)) {
|
// Facet is backwards.
|
||||||
/* Facet is backwards. */
|
|
||||||
if(normal_fix_flag) {
|
if(normal_fix_flag) {
|
||||||
facet->normal.x = normal[0];
|
facet->normal = normal;
|
||||||
facet->normal.y = normal[1];
|
|
||||||
facet->normal.z = normal[2];
|
|
||||||
stl->stats.normals_fixed += 1;
|
stl->stats.normals_fixed += 1;
|
||||||
}
|
}
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
if(normal_fix_flag) {
|
if(normal_fix_flag) {
|
||||||
facet->normal.x = normal[0];
|
facet->normal = normal;
|
||||||
facet->normal.y = normal[1];
|
|
||||||
facet->normal.z = normal[2];
|
|
||||||
stl->stats.normals_fixed += 1;
|
stl->stats.normals_fixed += 1;
|
||||||
}
|
}
|
||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stl_calculate_normal(float normal[], stl_facet *facet) {
|
void stl_fix_normal_values(stl_file *stl) {
|
||||||
float v1[3] = {
|
|
||||||
facet->vertex[1].x - facet->vertex[0].x,
|
|
||||||
facet->vertex[1].y - facet->vertex[0].y,
|
|
||||||
facet->vertex[1].z - facet->vertex[0].z
|
|
||||||
};
|
|
||||||
float v2[3] = {
|
|
||||||
facet->vertex[2].x - facet->vertex[0].x,
|
|
||||||
facet->vertex[2].y - facet->vertex[0].y,
|
|
||||||
facet->vertex[2].z - facet->vertex[0].z
|
|
||||||
};
|
|
||||||
normal[0] = (float)((double)v1[1] * (double)v2[2]) - ((double)v1[2] * (double)v2[1]);
|
|
||||||
normal[1] = (float)((double)v1[2] * (double)v2[0]) - ((double)v1[0] * (double)v2[2]);
|
|
||||||
normal[2] = (float)((double)v1[0] * (double)v2[1]) - ((double)v1[1] * (double)v2[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void stl_normalize_vector(float v[]) {
|
|
||||||
double length;
|
|
||||||
double factor;
|
|
||||||
float min_normal_length;
|
|
||||||
|
|
||||||
length = sqrt((double)v[0] * (double)v[0] + (double)v[1] * (double)v[1] + (double)v[2] * (double)v[2]);
|
|
||||||
min_normal_length = 0.000000000001;
|
|
||||||
if(length < min_normal_length) {
|
|
||||||
v[0] = 0.0;
|
|
||||||
v[1] = 0.0;
|
|
||||||
v[2] = 0.0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
factor = 1.0 / length;
|
|
||||||
v[0] *= factor;
|
|
||||||
v[1] *= factor;
|
|
||||||
v[2] *= factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
stl_fix_normal_values(stl_file *stl) {
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (stl->error) return;
|
if (stl->error) return;
|
||||||
|
|
@ -333,20 +277,16 @@ stl_fix_normal_values(stl_file *stl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void stl_reverse_all_facets(stl_file *stl)
|
||||||
stl_reverse_all_facets(stl_file *stl) {
|
{
|
||||||
int i;
|
if (stl->error)
|
||||||
float normal[3];
|
return;
|
||||||
|
|
||||||
if (stl->error) return;
|
stl_normal normal;
|
||||||
|
for(int i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
|
||||||
stl_reverse_facet(stl, i);
|
stl_reverse_facet(stl, i);
|
||||||
stl_calculate_normal(normal, &stl->facet_start[i]);
|
stl_calculate_normal(normal, &stl->facet_start[i]);
|
||||||
stl_normalize_vector(normal);
|
stl_normalize_vector(normal);
|
||||||
stl->facet_start[i].normal.x = normal[0];
|
stl->facet_start[i].normal = normal;
|
||||||
stl->facet_start[i].normal.y = normal[1];
|
|
||||||
stl->facet_start[i].normal.z = normal[2];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,7 +169,7 @@ stl_write_off(stl_file *stl, char *file) {
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.shared_vertices; i++) {
|
for(i = 0; i < stl->stats.shared_vertices; i++) {
|
||||||
fprintf(fp, "\t%f %f %f\n",
|
fprintf(fp, "\t%f %f %f\n",
|
||||||
stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z);
|
stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
|
||||||
}
|
}
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0],
|
fprintf(fp, "\t3 %d %d %d\n", stl->v_indices[i].vertex[0],
|
||||||
|
|
@ -216,10 +216,10 @@ stl_write_vrml(stl_file *stl, char *file) {
|
||||||
|
|
||||||
for(i = 0; i < (stl->stats.shared_vertices - 1); i++) {
|
for(i = 0; i < (stl->stats.shared_vertices - 1); i++) {
|
||||||
fprintf(fp, "\t\t\t\t%f %f %f,\n",
|
fprintf(fp, "\t\t\t\t%f %f %f,\n",
|
||||||
stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z);
|
stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
|
||||||
}
|
}
|
||||||
fprintf(fp, "\t\t\t\t%f %f %f]\n",
|
fprintf(fp, "\t\t\t\t%f %f %f]\n",
|
||||||
stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z);
|
stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
|
||||||
fprintf(fp, "\t\t}\n");
|
fprintf(fp, "\t\t}\n");
|
||||||
fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
|
fprintf(fp, "\t\tDEF STLTriangles IndexedFaceSet {\n");
|
||||||
fprintf(fp, "\t\t\tcoordIndex [\n");
|
fprintf(fp, "\t\t\tcoordIndex [\n");
|
||||||
|
|
@ -254,7 +254,7 @@ void stl_write_obj (stl_file *stl, char *file) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < stl->stats.shared_vertices; i++) {
|
for (i = 0; i < stl->stats.shared_vertices; i++) {
|
||||||
fprintf(fp, "v %f %f %f\n", stl->v_shared[i].x, stl->v_shared[i].y, stl->v_shared[i].z);
|
fprintf(fp, "v %f %f %f\n", stl->v_shared[i](0), stl->v_shared[i](1), stl->v_shared[i](2));
|
||||||
}
|
}
|
||||||
for (i = 0; i < stl->stats.number_of_facets; i++) {
|
for (i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1);
|
fprintf(fp, "f %d %d %d\n", stl->v_indices[i].vertex[0]+1, stl->v_indices[i].vertex[1]+1, stl->v_indices[i].vertex[2]+1);
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#define STL_MAX(A,B) ((A)>(B)? (A):(B))
|
#include <Eigen/Geometry>
|
||||||
#define STL_MIN(A,B) ((A)<(B)? (A):(B))
|
|
||||||
#define ABS(X) ((X) < 0 ? -(X) : (X))
|
|
||||||
|
|
||||||
// Size of the binary STL header, free form.
|
// Size of the binary STL header, free form.
|
||||||
#define LABEL_SIZE 80
|
#define LABEL_SIZE 80
|
||||||
|
|
@ -39,31 +37,16 @@
|
||||||
#define HEADER_SIZE 84
|
#define HEADER_SIZE 84
|
||||||
#define STL_MIN_FILE_SIZE 284
|
#define STL_MIN_FILE_SIZE 284
|
||||||
#define ASCII_LINES_PER_FACET 7
|
#define ASCII_LINES_PER_FACET 7
|
||||||
// Comparing an edge by memcmp, 2x3x4 bytes = 24
|
|
||||||
#define SIZEOF_EDGE_SORT 24
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float x;
|
|
||||||
float y;
|
|
||||||
float z;
|
|
||||||
} stl_vertex;
|
|
||||||
|
|
||||||
|
typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_vertex;
|
||||||
|
typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> stl_normal;
|
||||||
static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
|
static_assert(sizeof(stl_vertex) == 12, "size of stl_vertex incorrect");
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
float x;
|
|
||||||
float y;
|
|
||||||
float z;
|
|
||||||
} stl_normal;
|
|
||||||
|
|
||||||
static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
|
static_assert(sizeof(stl_normal) == 12, "size of stl_normal incorrect");
|
||||||
|
|
||||||
typedef char stl_extra[2];
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
stl_normal normal;
|
stl_normal normal;
|
||||||
stl_vertex vertex[3];
|
stl_vertex vertex[3];
|
||||||
stl_extra extra;
|
char extra[2];
|
||||||
} stl_facet;
|
} stl_facet;
|
||||||
#define SIZEOF_STL_FACET 50
|
#define SIZEOF_STL_FACET 50
|
||||||
|
|
||||||
|
|
@ -81,8 +64,12 @@ typedef struct {
|
||||||
} stl_edge;
|
} stl_edge;
|
||||||
|
|
||||||
typedef struct stl_hash_edge {
|
typedef struct stl_hash_edge {
|
||||||
// Key of a hash edge: 2x binary copy of a floating point vertex.
|
// Key of a hash edge: sorted vertices of the edge.
|
||||||
uint32_t key[6];
|
unsigned char key[2 * sizeof(stl_vertex)];
|
||||||
|
// Compare two keys.
|
||||||
|
bool operator==(const stl_hash_edge &rhs) { return memcmp(key, rhs.key, sizeof(key)) == 0; }
|
||||||
|
bool operator!=(const stl_hash_edge &rhs) { return ! (*this == rhs); }
|
||||||
|
int hash(int M) const { return ((key[0] / 23 + key[1] / 19 + key[2] / 17 + key[3] /13 + key[4] / 11 + key[5] / 7 ) % M); }
|
||||||
// Index of a facet owning this edge.
|
// Index of a facet owning this edge.
|
||||||
int facet_number;
|
int facet_number;
|
||||||
// Index of this edge inside the facet with an index of facet_number.
|
// Index of this edge inside the facet with an index of facet_number.
|
||||||
|
|
@ -91,8 +78,6 @@ typedef struct stl_hash_edge {
|
||||||
struct stl_hash_edge *next;
|
struct stl_hash_edge *next;
|
||||||
} stl_hash_edge;
|
} stl_hash_edge;
|
||||||
|
|
||||||
static_assert(offsetof(stl_hash_edge, facet_number) == SIZEOF_EDGE_SORT, "size of stl_hash_edge.key incorrect");
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// Index of a neighbor facet.
|
// Index of a neighbor facet.
|
||||||
int neighbor[3];
|
int neighbor[3];
|
||||||
|
|
@ -179,8 +164,8 @@ extern void stl_fix_normal_values(stl_file *stl);
|
||||||
extern void stl_reverse_all_facets(stl_file *stl);
|
extern void stl_reverse_all_facets(stl_file *stl);
|
||||||
extern void stl_translate(stl_file *stl, float x, float y, float z);
|
extern void stl_translate(stl_file *stl, float x, float y, float z);
|
||||||
extern void stl_translate_relative(stl_file *stl, float x, float y, float z);
|
extern void stl_translate_relative(stl_file *stl, float x, float y, float z);
|
||||||
extern void stl_scale_versor(stl_file *stl, float versor[3]);
|
extern void stl_scale_versor(stl_file *stl, const stl_vertex &versor);
|
||||||
extern void stl_scale(stl_file *stl, float factor);
|
inline void stl_scale(stl_file *stl, float factor) { stl_scale_versor(stl, stl_vertex(factor, factor, factor)); }
|
||||||
extern void stl_rotate_x(stl_file *stl, float angle);
|
extern void stl_rotate_x(stl_file *stl, float angle);
|
||||||
extern void stl_rotate_y(stl_file *stl, float angle);
|
extern void stl_rotate_y(stl_file *stl, float angle);
|
||||||
extern void stl_rotate_z(stl_file *stl, float angle);
|
extern void stl_rotate_z(stl_file *stl, float angle);
|
||||||
|
|
@ -195,8 +180,20 @@ extern void stl_write_obj(stl_file *stl, char *file);
|
||||||
extern void stl_write_off(stl_file *stl, char *file);
|
extern void stl_write_off(stl_file *stl, char *file);
|
||||||
extern void stl_write_dxf(stl_file *stl, char *file, char *label);
|
extern void stl_write_dxf(stl_file *stl, char *file, char *label);
|
||||||
extern void stl_write_vrml(stl_file *stl, char *file);
|
extern void stl_write_vrml(stl_file *stl, char *file);
|
||||||
extern void stl_calculate_normal(float normal[], stl_facet *facet);
|
inline void stl_calculate_normal(stl_normal &normal, stl_facet *facet) {
|
||||||
extern void stl_normalize_vector(float v[]);
|
normal = (facet->vertex[1] - facet->vertex[0]).cross(facet->vertex[2] - facet->vertex[0]);
|
||||||
|
}
|
||||||
|
inline void stl_normalize_vector(stl_normal &normal) {
|
||||||
|
double length = normal.cast<double>().norm();
|
||||||
|
if (length < 0.000000000001)
|
||||||
|
normal = stl_normal::Zero();
|
||||||
|
else
|
||||||
|
normal *= (1.0 / length);
|
||||||
|
}
|
||||||
|
inline bool stl_vertex_lower(const stl_vertex &a, const stl_vertex &b) {
|
||||||
|
return (a(0) != b(0)) ? (a(0) < b(0)) :
|
||||||
|
((a(1) != b(1)) ? (a(1) < b(1)) : (a(2) < b(2)));
|
||||||
|
}
|
||||||
extern void stl_calculate_volume(stl_file *stl);
|
extern void stl_calculate_volume(stl_file *stl);
|
||||||
|
|
||||||
extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag);
|
extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int tolerance_flag, float tolerance, int increment_flag, float increment, int nearby_flag, int iterations, int remove_unconnected_flag, int fill_holes_flag, int normal_directions_flag, int normal_values_flag, int reverse_all_flag, int verbose_flag);
|
||||||
|
|
@ -204,8 +201,8 @@ extern void stl_repair(stl_file *stl, int fixall_flag, int exact_flag, int toler
|
||||||
extern void stl_initialize(stl_file *stl);
|
extern void stl_initialize(stl_file *stl);
|
||||||
extern void stl_count_facets(stl_file *stl, const char *file);
|
extern void stl_count_facets(stl_file *stl, const char *file);
|
||||||
extern void stl_allocate(stl_file *stl);
|
extern void stl_allocate(stl_file *stl);
|
||||||
extern void stl_read(stl_file *stl, int first_facet, int first);
|
extern void stl_read(stl_file *stl, int first_facet, bool first);
|
||||||
extern void stl_facet_stats(stl_file *stl, stl_facet facet, int first);
|
extern void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first);
|
||||||
extern void stl_reallocate(stl_file *stl);
|
extern void stl_reallocate(stl_file *stl);
|
||||||
extern void stl_add_facet(stl_file *stl, stl_facet *new_facet);
|
extern void stl_add_facet(stl_file *stl, stl_facet *new_facet);
|
||||||
extern void stl_get_size(stl_file *stl);
|
extern void stl_get_size(stl_file *stl);
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,9 @@ stl_print_edges(stl_file *stl, FILE *file) {
|
||||||
for(i = 0; i < edges_allocated; i++) {
|
for(i = 0; i < edges_allocated; i++) {
|
||||||
fprintf(file, "%d, %f, %f, %f, %f, %f, %f\n",
|
fprintf(file, "%d, %f, %f, %f, %f, %f, %f\n",
|
||||||
stl->edge_start[i].facet_number,
|
stl->edge_start[i].facet_number,
|
||||||
stl->edge_start[i].p1.x, stl->edge_start[i].p1.y,
|
stl->edge_start[i].p1(0), stl->edge_start[i].p1(1),
|
||||||
stl->edge_start[i].p1.z, stl->edge_start[i].p2.x,
|
stl->edge_start[i].p1(2), stl->edge_start[i].p2(0),
|
||||||
stl->edge_start[i].p2.y, stl->edge_start[i].p2.z);
|
stl->edge_start[i].p2(1), stl->edge_start[i].p2(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -75,11 +75,11 @@ File type : ASCII STL file\n");
|
||||||
Header : %s\n", stl->stats.header);
|
Header : %s\n", stl->stats.header);
|
||||||
fprintf(file, "============== Size ==============\n");
|
fprintf(file, "============== Size ==============\n");
|
||||||
fprintf(file, "Min X = % f, Max X = % f\n",
|
fprintf(file, "Min X = % f, Max X = % f\n",
|
||||||
stl->stats.min.x, stl->stats.max.x);
|
stl->stats.min(0), stl->stats.max(0));
|
||||||
fprintf(file, "Min Y = % f, Max Y = % f\n",
|
fprintf(file, "Min Y = % f, Max Y = % f\n",
|
||||||
stl->stats.min.y, stl->stats.max.y);
|
stl->stats.min(1), stl->stats.max(1));
|
||||||
fprintf(file, "Min Z = % f, Max Z = % f\n",
|
fprintf(file, "Min Z = % f, Max Z = % f\n",
|
||||||
stl->stats.min.z, stl->stats.max.z);
|
stl->stats.min(2), stl->stats.max(2));
|
||||||
|
|
||||||
fprintf(file, "\
|
fprintf(file, "\
|
||||||
========= Facet Status ========== Original ============ Final ====\n");
|
========= Facet Status ========== Original ============ Final ====\n");
|
||||||
|
|
@ -149,18 +149,18 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) {
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
fprintf(fp, " facet normal % .8E % .8E % .8E\n",
|
fprintf(fp, " facet normal % .8E % .8E % .8E\n",
|
||||||
stl->facet_start[i].normal.x, stl->facet_start[i].normal.y,
|
stl->facet_start[i].normal(0), stl->facet_start[i].normal(1),
|
||||||
stl->facet_start[i].normal.z);
|
stl->facet_start[i].normal(2));
|
||||||
fprintf(fp, " outer loop\n");
|
fprintf(fp, " outer loop\n");
|
||||||
fprintf(fp, " vertex % .8E % .8E % .8E\n",
|
fprintf(fp, " vertex % .8E % .8E % .8E\n",
|
||||||
stl->facet_start[i].vertex[0].x, stl->facet_start[i].vertex[0].y,
|
stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
|
||||||
stl->facet_start[i].vertex[0].z);
|
stl->facet_start[i].vertex[0](2));
|
||||||
fprintf(fp, " vertex % .8E % .8E % .8E\n",
|
fprintf(fp, " vertex % .8E % .8E % .8E\n",
|
||||||
stl->facet_start[i].vertex[1].x, stl->facet_start[i].vertex[1].y,
|
stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
|
||||||
stl->facet_start[i].vertex[1].z);
|
stl->facet_start[i].vertex[1](2));
|
||||||
fprintf(fp, " vertex % .8E % .8E % .8E\n",
|
fprintf(fp, " vertex % .8E % .8E % .8E\n",
|
||||||
stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y,
|
stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
|
||||||
stl->facet_start[i].vertex[2].z);
|
stl->facet_start[i].vertex[2](2));
|
||||||
fprintf(fp, " endloop\n");
|
fprintf(fp, " endloop\n");
|
||||||
fprintf(fp, " endfacet\n");
|
fprintf(fp, " endfacet\n");
|
||||||
}
|
}
|
||||||
|
|
@ -264,9 +264,9 @@ void
|
||||||
stl_write_vertex(stl_file *stl, int facet, int vertex) {
|
stl_write_vertex(stl_file *stl, int facet, int vertex) {
|
||||||
if (stl->error) return;
|
if (stl->error) return;
|
||||||
printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
|
printf(" vertex %d/%d % .8E % .8E % .8E\n", vertex, facet,
|
||||||
stl->facet_start[facet].vertex[vertex].x,
|
stl->facet_start[facet].vertex[vertex](0),
|
||||||
stl->facet_start[facet].vertex[vertex].y,
|
stl->facet_start[facet].vertex[vertex](1),
|
||||||
stl->facet_start[facet].vertex[vertex].z);
|
stl->facet_start[facet].vertex[vertex](2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -309,10 +309,10 @@ stl_write_quad_object(stl_file *stl, char *file) {
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
char *error_msg;
|
char *error_msg;
|
||||||
stl_vertex connect_color;
|
stl_vertex connect_color = stl_vertex::Zero();
|
||||||
stl_vertex uncon_1_color;
|
stl_vertex uncon_1_color = stl_vertex::Zero();
|
||||||
stl_vertex uncon_2_color;
|
stl_vertex uncon_2_color = stl_vertex::Zero();
|
||||||
stl_vertex uncon_3_color;
|
stl_vertex uncon_3_color = stl_vertex::Zero();
|
||||||
stl_vertex color;
|
stl_vertex color;
|
||||||
|
|
||||||
if (stl->error) return;
|
if (stl->error) return;
|
||||||
|
|
@ -330,19 +330,6 @@ stl_write_quad_object(stl_file *stl, char *file) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
connect_color.x = 0.0;
|
|
||||||
connect_color.y = 0.0;
|
|
||||||
connect_color.z = 1.0;
|
|
||||||
uncon_1_color.x = 0.0;
|
|
||||||
uncon_1_color.y = 1.0;
|
|
||||||
uncon_1_color.z = 0.0;
|
|
||||||
uncon_2_color.x = 1.0;
|
|
||||||
uncon_2_color.y = 1.0;
|
|
||||||
uncon_2_color.z = 1.0;
|
|
||||||
uncon_3_color.x = 1.0;
|
|
||||||
uncon_3_color.y = 0.0;
|
|
||||||
uncon_3_color.z = 0.0;
|
|
||||||
|
|
||||||
fprintf(fp, "CQUAD\n");
|
fprintf(fp, "CQUAD\n");
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
j = ((stl->neighbors_start[i].neighbor[0] == -1) +
|
j = ((stl->neighbors_start[i].neighbor[0] == -1) +
|
||||||
|
|
@ -358,21 +345,21 @@ stl_write_quad_object(stl_file *stl, char *file) {
|
||||||
color = uncon_3_color;
|
color = uncon_3_color;
|
||||||
}
|
}
|
||||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
||||||
stl->facet_start[i].vertex[0].x,
|
stl->facet_start[i].vertex[0](0),
|
||||||
stl->facet_start[i].vertex[0].y,
|
stl->facet_start[i].vertex[0](1),
|
||||||
stl->facet_start[i].vertex[0].z, color.x, color.y, color.z);
|
stl->facet_start[i].vertex[0](2), color(0), color(1), color(2));
|
||||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
||||||
stl->facet_start[i].vertex[1].x,
|
stl->facet_start[i].vertex[1](0),
|
||||||
stl->facet_start[i].vertex[1].y,
|
stl->facet_start[i].vertex[1](1),
|
||||||
stl->facet_start[i].vertex[1].z, color.x, color.y, color.z);
|
stl->facet_start[i].vertex[1](2), color(0), color(1), color(2));
|
||||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
||||||
stl->facet_start[i].vertex[2].x,
|
stl->facet_start[i].vertex[2](0),
|
||||||
stl->facet_start[i].vertex[2].y,
|
stl->facet_start[i].vertex[2](1),
|
||||||
stl->facet_start[i].vertex[2].z, color.x, color.y, color.z);
|
stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
|
||||||
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
fprintf(fp, "%f %f %f %1.1f %1.1f %1.1f 1\n",
|
||||||
stl->facet_start[i].vertex[2].x,
|
stl->facet_start[i].vertex[2](0),
|
||||||
stl->facet_start[i].vertex[2].y,
|
stl->facet_start[i].vertex[2](1),
|
||||||
stl->facet_start[i].vertex[2].z, color.x, color.y, color.z);
|
stl->facet_start[i].vertex[2](2), color(0), color(1), color(2));
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
@ -409,17 +396,17 @@ stl_write_dxf(stl_file *stl, char *file, char *label) {
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
fprintf(fp, "0\n3DFACE\n8\n0\n");
|
fprintf(fp, "0\n3DFACE\n8\n0\n");
|
||||||
fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n",
|
fprintf(fp, "10\n%f\n20\n%f\n30\n%f\n",
|
||||||
stl->facet_start[i].vertex[0].x, stl->facet_start[i].vertex[0].y,
|
stl->facet_start[i].vertex[0](0), stl->facet_start[i].vertex[0](1),
|
||||||
stl->facet_start[i].vertex[0].z);
|
stl->facet_start[i].vertex[0](2));
|
||||||
fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n",
|
fprintf(fp, "11\n%f\n21\n%f\n31\n%f\n",
|
||||||
stl->facet_start[i].vertex[1].x, stl->facet_start[i].vertex[1].y,
|
stl->facet_start[i].vertex[1](0), stl->facet_start[i].vertex[1](1),
|
||||||
stl->facet_start[i].vertex[1].z);
|
stl->facet_start[i].vertex[1](2));
|
||||||
fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n",
|
fprintf(fp, "12\n%f\n22\n%f\n32\n%f\n",
|
||||||
stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y,
|
stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
|
||||||
stl->facet_start[i].vertex[2].z);
|
stl->facet_start[i].vertex[2](2));
|
||||||
fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n",
|
fprintf(fp, "13\n%f\n23\n%f\n33\n%f\n",
|
||||||
stl->facet_start[i].vertex[2].x, stl->facet_start[i].vertex[2].y,
|
stl->facet_start[i].vertex[2](0), stl->facet_start[i].vertex[2](1),
|
||||||
stl->facet_start[i].vertex[2].z);
|
stl->facet_start[i].vertex[2](2));
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, "0\nENDSEC\n0\nEOF\n");
|
fprintf(fp, "0\nENDSEC\n0\nEOF\n");
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ stl_open(stl_file *stl, const char *file) {
|
||||||
stl_initialize(stl);
|
stl_initialize(stl);
|
||||||
stl_count_facets(stl, file);
|
stl_count_facets(stl, file);
|
||||||
stl_allocate(stl);
|
stl_allocate(stl);
|
||||||
stl_read(stl, 0, 1);
|
stl_read(stl, 0, true);
|
||||||
if (!stl->error) fclose(stl->fp);
|
if (!stl->error) fclose(stl->fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,7 +227,7 @@ stl_open_merge(stl_file *stl, char *file_to_merge) {
|
||||||
Start at num_facets_so_far, the index to the first unused facet. Also say
|
Start at num_facets_so_far, the index to the first unused facet. Also say
|
||||||
that this isn't our first time so we should augment stats like min and max
|
that this isn't our first time so we should augment stats like min and max
|
||||||
instead of erasing them. */
|
instead of erasing them. */
|
||||||
stl_read(stl, num_facets_so_far, 0);
|
stl_read(stl, num_facets_so_far, false);
|
||||||
|
|
||||||
/* Restore the stl information we overwrote (for stl_read) so that it still accurately
|
/* Restore the stl information we overwrote (for stl_read) so that it still accurately
|
||||||
reflects the subject part: */
|
reflects the subject part: */
|
||||||
|
|
@ -255,8 +255,7 @@ stl_reallocate(stl_file *stl) {
|
||||||
/* Reads the contents of the file pointed to by stl->fp into the stl structure,
|
/* Reads the contents of the file pointed to by stl->fp into the stl structure,
|
||||||
starting at facet first_facet. The second argument says if it's our first
|
starting at facet first_facet. The second argument says if it's our first
|
||||||
time running this for the stl and therefore we should reset our max and min stats. */
|
time running this for the stl and therefore we should reset our max and min stats. */
|
||||||
void
|
void stl_read(stl_file *stl, int first_facet, bool first) {
|
||||||
stl_read(stl_file *stl, int first_facet, int first) {
|
|
||||||
stl_facet facet;
|
stl_facet facet;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
|
@ -294,11 +293,11 @@ stl_read(stl_file *stl, int first_facet, int first) {
|
||||||
assert(res_normal == 3);
|
assert(res_normal == 3);
|
||||||
int res_outer_loop = fscanf(stl->fp, " outer loop");
|
int res_outer_loop = fscanf(stl->fp, " outer loop");
|
||||||
assert(res_outer_loop == 0);
|
assert(res_outer_loop == 0);
|
||||||
int res_vertex1 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[0].x, &facet.vertex[0].y, &facet.vertex[0].z);
|
int res_vertex1 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
|
||||||
assert(res_vertex1 == 3);
|
assert(res_vertex1 == 3);
|
||||||
int res_vertex2 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[1].x, &facet.vertex[1].y, &facet.vertex[1].z);
|
int res_vertex2 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
|
||||||
assert(res_vertex2 == 3);
|
assert(res_vertex2 == 3);
|
||||||
int res_vertex3 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[2].x, &facet.vertex[2].y, &facet.vertex[2].z);
|
int res_vertex3 = fscanf(stl->fp, " vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
|
||||||
assert(res_vertex3 == 3);
|
assert(res_vertex3 == 3);
|
||||||
int res_endloop = fscanf(stl->fp, " endloop");
|
int res_endloop = fscanf(stl->fp, " endloop");
|
||||||
assert(res_endloop == 0);
|
assert(res_endloop == 0);
|
||||||
|
|
@ -311,9 +310,9 @@ stl_read(stl_file *stl, int first_facet, int first) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
|
// The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
|
||||||
if (sscanf(normal_buf[0], "%f", &facet.normal.x) != 1 ||
|
if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
|
||||||
sscanf(normal_buf[1], "%f", &facet.normal.y) != 1 ||
|
sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
|
||||||
sscanf(normal_buf[2], "%f", &facet.normal.z) != 1) {
|
sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
|
||||||
// Normal was mangled. Maybe denormals or "not a number" were stored?
|
// Normal was mangled. Maybe denormals or "not a number" were stored?
|
||||||
// Just reset the normal and silently ignore it.
|
// Just reset the normal and silently ignore it.
|
||||||
memset(&facet.normal, 0, sizeof(facet.normal));
|
memset(&facet.normal, 0, sizeof(facet.normal));
|
||||||
|
|
@ -326,104 +325,45 @@ stl_read(stl_file *stl, int first_facet, int first) {
|
||||||
// It may be worth to round these numbers to zero during loading to reduce the number of errors reported
|
// It may be worth to round these numbers to zero during loading to reduce the number of errors reported
|
||||||
// during the STL import.
|
// during the STL import.
|
||||||
for (size_t j = 0; j < 3; ++ j) {
|
for (size_t j = 0; j < 3; ++ j) {
|
||||||
if (facet.vertex[j].x > -1e-12f && facet.vertex[j].x < 1e-12f)
|
if (facet.vertex[j](0) > -1e-12f && facet.vertex[j](0) < 1e-12f)
|
||||||
printf("stl_read: facet %d.x = %e\r\n", j, facet.vertex[j].x);
|
printf("stl_read: facet %d(0) = %e\r\n", j, facet.vertex[j](0));
|
||||||
if (facet.vertex[j].y > -1e-12f && facet.vertex[j].y < 1e-12f)
|
if (facet.vertex[j](1) > -1e-12f && facet.vertex[j](1) < 1e-12f)
|
||||||
printf("stl_read: facet %d.y = %e\r\n", j, facet.vertex[j].y);
|
printf("stl_read: facet %d(1) = %e\r\n", j, facet.vertex[j](1));
|
||||||
if (facet.vertex[j].z > -1e-12f && facet.vertex[j].z < 1e-12f)
|
if (facet.vertex[j](2) > -1e-12f && facet.vertex[j](2) < 1e-12f)
|
||||||
printf("stl_read: facet %d.z = %e\r\n", j, facet.vertex[j].z);
|
printf("stl_read: facet %d(2) = %e\r\n", j, facet.vertex[j](2));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 1
|
|
||||||
{
|
|
||||||
// Positive and negative zeros are possible in the floats, which are considered equal by the FP unit.
|
|
||||||
// When using a memcmp on raw floats, those numbers report to be different.
|
|
||||||
// Unify all +0 and -0 to +0 to make the floats equal under memcmp.
|
|
||||||
uint32_t *f = (uint32_t*)&facet;
|
|
||||||
for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
|
|
||||||
if (*f == 0x80000000)
|
|
||||||
// Negative zero, switch to positive zero.
|
|
||||||
*f = 0;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
// Due to the nature of the floating point numbers, close to zero values may be represented with singificantly higher precision
|
|
||||||
// than the rest of the vertices. Round them to zero.
|
|
||||||
float *f = (float*)&facet;
|
|
||||||
for (int j = 0; j < 12; ++ j, ++ f) // 3x vertex + normal: 4x3 = 12 floats
|
|
||||||
if (*f > -1e-12f && *f < 1e-12f)
|
|
||||||
// Negative zero, switch to positive zero.
|
|
||||||
*f = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
/* Write the facet into memory. */
|
/* Write the facet into memory. */
|
||||||
memcpy(stl->facet_start+i, &facet, SIZEOF_STL_FACET);
|
stl->facet_start[i] = facet;
|
||||||
stl_facet_stats(stl, facet, first);
|
stl_facet_stats(stl, facet, first);
|
||||||
first = 0;
|
|
||||||
}
|
}
|
||||||
stl->stats.size.x = stl->stats.max.x - stl->stats.min.x;
|
stl->stats.size = stl->stats.max - stl->stats.min;
|
||||||
stl->stats.size.y = stl->stats.max.y - stl->stats.min.y;
|
stl->stats.bounding_diameter = stl->stats.size.norm();
|
||||||
stl->stats.size.z = stl->stats.max.z - stl->stats.min.z;
|
|
||||||
stl->stats.bounding_diameter = sqrt(
|
|
||||||
stl->stats.size.x * stl->stats.size.x +
|
|
||||||
stl->stats.size.y * stl->stats.size.y +
|
|
||||||
stl->stats.size.z * stl->stats.size.z
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void stl_facet_stats(stl_file *stl, stl_facet facet, bool &first)
|
||||||
stl_facet_stats(stl_file *stl, stl_facet facet, int first) {
|
{
|
||||||
float diff_x;
|
if (stl->error)
|
||||||
float diff_y;
|
return;
|
||||||
float diff_z;
|
|
||||||
float max_diff;
|
|
||||||
|
|
||||||
if (stl->error) return;
|
// While we are going through all of the facets, let's find the
|
||||||
|
// maximum and minimum values for x, y, and z
|
||||||
|
|
||||||
/* while we are going through all of the facets, let's find the */
|
|
||||||
/* maximum and minimum values for x, y, and z */
|
|
||||||
|
|
||||||
/* Initialize the max and min values the first time through*/
|
|
||||||
if (first) {
|
if (first) {
|
||||||
stl->stats.max.x = facet.vertex[0].x;
|
// Initialize the max and min values the first time through
|
||||||
stl->stats.min.x = facet.vertex[0].x;
|
stl->stats.min = facet.vertex[0];
|
||||||
stl->stats.max.y = facet.vertex[0].y;
|
stl->stats.max = facet.vertex[0];
|
||||||
stl->stats.min.y = facet.vertex[0].y;
|
stl_vertex diff = (facet.vertex[1] - facet.vertex[0]).cwiseAbs();
|
||||||
stl->stats.max.z = facet.vertex[0].z;
|
stl->stats.shortest_edge = std::max(diff(0), std::max(diff(1), diff(2)));
|
||||||
stl->stats.min.z = facet.vertex[0].z;
|
first = false;
|
||||||
|
|
||||||
diff_x = ABS(facet.vertex[0].x - facet.vertex[1].x);
|
|
||||||
diff_y = ABS(facet.vertex[0].y - facet.vertex[1].y);
|
|
||||||
diff_z = ABS(facet.vertex[0].z - facet.vertex[1].z);
|
|
||||||
max_diff = STL_MAX(diff_x, diff_y);
|
|
||||||
max_diff = STL_MAX(diff_z, max_diff);
|
|
||||||
stl->stats.shortest_edge = max_diff;
|
|
||||||
|
|
||||||
first = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* now find the max and min values */
|
// Now find the max and min values.
|
||||||
stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[0].x);
|
for (size_t i = 0; i < 3; ++ i) {
|
||||||
stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[0].x);
|
stl->stats.min = stl->stats.min.cwiseMin(facet.vertex[i]);
|
||||||
stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[0].y);
|
stl->stats.max = stl->stats.max.cwiseMax(facet.vertex[i]);
|
||||||
stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[0].y);
|
}
|
||||||
stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[0].z);
|
|
||||||
stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[0].z);
|
|
||||||
|
|
||||||
stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[1].x);
|
|
||||||
stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[1].x);
|
|
||||||
stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[1].y);
|
|
||||||
stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[1].y);
|
|
||||||
stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[1].z);
|
|
||||||
stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[1].z);
|
|
||||||
|
|
||||||
stl->stats.max.x = STL_MAX(stl->stats.max.x, facet.vertex[2].x);
|
|
||||||
stl->stats.min.x = STL_MIN(stl->stats.min.x, facet.vertex[2].x);
|
|
||||||
stl->stats.max.y = STL_MAX(stl->stats.max.y, facet.vertex[2].y);
|
|
||||||
stl->stats.min.y = STL_MIN(stl->stats.min.y, facet.vertex[2].y);
|
|
||||||
stl->stats.max.z = STL_MAX(stl->stats.max.z, facet.vertex[2].z);
|
|
||||||
stl->stats.min.z = STL_MIN(stl->stats.min.z, facet.vertex[2].z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ stl_verify_neighbors(stl_file *stl) {
|
||||||
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
|
edge_b.p1 = stl->facet_start[neighbor].vertex[(vnot + 1) % 3];
|
||||||
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
|
edge_b.p2 = stl->facet_start[neighbor].vertex[(vnot + 2) % 3];
|
||||||
}
|
}
|
||||||
if(memcmp(&edge_a, &edge_b, SIZEOF_EDGE_SORT) != 0) {
|
if (edge_a.p1 != edge_b.p1 || edge_a.p2 != edge_b.p2) {
|
||||||
/* These edges should match but they don't. Print results. */
|
/* These edges should match but they don't. Print results. */
|
||||||
printf("edge %d of facet %d doesn't match edge %d of facet %d\n",
|
printf("edge %d of facet %d doesn't match edge %d of facet %d\n",
|
||||||
j, i, vnot + 1, neighbor);
|
j, i, vnot + 1, neighbor);
|
||||||
|
|
@ -73,114 +73,67 @@ stl_verify_neighbors(stl_file *stl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void stl_translate(stl_file *stl, float x, float y, float z)
|
||||||
stl_translate(stl_file *stl, float x, float y, float z) {
|
{
|
||||||
int i;
|
if (stl->error)
|
||||||
int j;
|
return;
|
||||||
|
|
||||||
if (stl->error) return;
|
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
|
||||||
for(j = 0; j < 3; j++) {
|
|
||||||
stl->facet_start[i].vertex[j].x -= (stl->stats.min.x - x);
|
|
||||||
stl->facet_start[i].vertex[j].y -= (stl->stats.min.y - y);
|
|
||||||
stl->facet_start[i].vertex[j].z -= (stl->stats.min.z - z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stl->stats.max.x -= (stl->stats.min.x - x);
|
|
||||||
stl->stats.max.y -= (stl->stats.min.y - y);
|
|
||||||
stl->stats.max.z -= (stl->stats.min.z - z);
|
|
||||||
stl->stats.min.x = x;
|
|
||||||
stl->stats.min.y = y;
|
|
||||||
stl->stats.min.z = z;
|
|
||||||
|
|
||||||
|
stl_vertex new_min(x, y, z);
|
||||||
|
stl_vertex shift = new_min - stl->stats.min;
|
||||||
|
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||||
|
for (int j = 0; j < 3; ++ j)
|
||||||
|
stl->facet_start[i].vertex[j] += shift;
|
||||||
|
stl->stats.min = new_min;
|
||||||
|
stl->stats.max += shift;
|
||||||
stl_invalidate_shared_vertices(stl);
|
stl_invalidate_shared_vertices(stl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Translates the stl by x,y,z, relatively from wherever it is currently */
|
/* Translates the stl by x,y,z, relatively from wherever it is currently */
|
||||||
void
|
void stl_translate_relative(stl_file *stl, float x, float y, float z)
|
||||||
stl_translate_relative(stl_file *stl, float x, float y, float z) {
|
{
|
||||||
int i;
|
if (stl->error)
|
||||||
int j;
|
return;
|
||||||
|
|
||||||
if (stl->error) return;
|
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
|
||||||
for(j = 0; j < 3; j++) {
|
|
||||||
stl->facet_start[i].vertex[j].x += x;
|
|
||||||
stl->facet_start[i].vertex[j].y += y;
|
|
||||||
stl->facet_start[i].vertex[j].z += z;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stl->stats.min.x += x;
|
|
||||||
stl->stats.min.y += y;
|
|
||||||
stl->stats.min.z += z;
|
|
||||||
stl->stats.max.x += x;
|
|
||||||
stl->stats.max.y += y;
|
|
||||||
stl->stats.max.z += z;
|
|
||||||
|
|
||||||
|
stl_vertex shift(x, y, z);
|
||||||
|
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||||
|
for (int j = 0; j < 3; ++ j)
|
||||||
|
stl->facet_start[i].vertex[j] += shift;
|
||||||
|
stl->stats.min += shift;
|
||||||
|
stl->stats.max += shift;
|
||||||
stl_invalidate_shared_vertices(stl);
|
stl_invalidate_shared_vertices(stl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void stl_scale_versor(stl_file *stl, const stl_vertex &versor)
|
||||||
stl_scale_versor(stl_file *stl, float versor[3]) {
|
{
|
||||||
int i;
|
if (stl->error)
|
||||||
int j;
|
return;
|
||||||
|
|
||||||
if (stl->error) return;
|
|
||||||
|
|
||||||
/* scale extents */
|
|
||||||
stl->stats.min.x *= versor[0];
|
|
||||||
stl->stats.min.y *= versor[1];
|
|
||||||
stl->stats.min.z *= versor[2];
|
|
||||||
stl->stats.max.x *= versor[0];
|
|
||||||
stl->stats.max.y *= versor[1];
|
|
||||||
stl->stats.max.z *= versor[2];
|
|
||||||
|
|
||||||
/* scale size */
|
|
||||||
stl->stats.size.x *= versor[0];
|
|
||||||
stl->stats.size.y *= versor[1];
|
|
||||||
stl->stats.size.z *= versor[2];
|
|
||||||
|
|
||||||
/* scale volume */
|
|
||||||
if (stl->stats.volume > 0.0) {
|
|
||||||
stl->stats.volume *= (versor[0] * versor[1] * versor[2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
|
||||||
for(j = 0; j < 3; j++) {
|
|
||||||
stl->facet_start[i].vertex[j].x *= versor[0];
|
|
||||||
stl->facet_start[i].vertex[j].y *= versor[1];
|
|
||||||
stl->facet_start[i].vertex[j].z *= versor[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Scale extents.
|
||||||
|
auto s = versor.array();
|
||||||
|
stl->stats.min.array() *= s;
|
||||||
|
stl->stats.max.array() *= s;
|
||||||
|
// Scale size.
|
||||||
|
stl->stats.size.array() *= s;
|
||||||
|
// Scale volume.
|
||||||
|
if (stl->stats.volume > 0.0)
|
||||||
|
stl->stats.volume *= versor(0) * versor(1) * versor(2);
|
||||||
|
// Scale the mesh.
|
||||||
|
for (int i = 0; i < stl->stats.number_of_facets; ++ i)
|
||||||
|
for (int j = 0; j < 3; ++ j)
|
||||||
|
stl->facet_start[i].vertex[j].array() *= s;
|
||||||
stl_invalidate_shared_vertices(stl);
|
stl_invalidate_shared_vertices(stl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void calculate_normals(stl_file *stl)
|
||||||
stl_scale(stl_file *stl, float factor) {
|
{
|
||||||
float versor[3];
|
if (stl->error)
|
||||||
|
return;
|
||||||
if (stl->error) return;
|
|
||||||
|
|
||||||
versor[0] = factor;
|
|
||||||
versor[1] = factor;
|
|
||||||
versor[2] = factor;
|
|
||||||
stl_scale_versor(stl, versor);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void calculate_normals(stl_file *stl) {
|
|
||||||
float normal[3];
|
|
||||||
|
|
||||||
if (stl->error) return;
|
|
||||||
|
|
||||||
|
stl_normal normal;
|
||||||
for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
|
for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
stl_calculate_normal(normal, &stl->facet_start[i]);
|
stl_calculate_normal(normal, &stl->facet_start[i]);
|
||||||
stl_normalize_vector(normal);
|
stl_normalize_vector(normal);
|
||||||
stl->facet_start[i].normal.x = normal[0];
|
stl->facet_start[i].normal = normal;
|
||||||
stl->facet_start[i].normal.y = normal[1];
|
|
||||||
stl->facet_start[i].normal.z = normal[2];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -193,9 +146,9 @@ void stl_transform(stl_file *stl, float *trafo3x4) {
|
||||||
for (i_vertex = 0; i_vertex < 3; ++ i_vertex) {
|
for (i_vertex = 0; i_vertex < 3; ++ i_vertex) {
|
||||||
stl_vertex &v_dst = vertices[i_vertex];
|
stl_vertex &v_dst = vertices[i_vertex];
|
||||||
stl_vertex v_src = v_dst;
|
stl_vertex v_src = v_dst;
|
||||||
v_dst.x = trafo3x4[0] * v_src.x + trafo3x4[1] * v_src.y + trafo3x4[2] * v_src.z + trafo3x4[3];
|
v_dst(0) = trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3];
|
||||||
v_dst.y = trafo3x4[4] * v_src.x + trafo3x4[5] * v_src.y + trafo3x4[6] * v_src.z + trafo3x4[7];
|
v_dst(1) = trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7];
|
||||||
v_dst.z = trafo3x4[8] * v_src.x + trafo3x4[9] * v_src.y + trafo3x4[10] * v_src.z + trafo3x4[11];
|
v_dst(2) = trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stl_get_size(stl);
|
stl_get_size(stl);
|
||||||
|
|
@ -214,8 +167,8 @@ stl_rotate_x(stl_file *stl, float angle) {
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
for(j = 0; j < 3; j++) {
|
for(j = 0; j < 3; j++) {
|
||||||
stl_rotate(&stl->facet_start[i].vertex[j].y,
|
stl_rotate(&stl->facet_start[i].vertex[j](1),
|
||||||
&stl->facet_start[i].vertex[j].z, c, s);
|
&stl->facet_start[i].vertex[j](2), c, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stl_get_size(stl);
|
stl_get_size(stl);
|
||||||
|
|
@ -234,8 +187,8 @@ stl_rotate_y(stl_file *stl, float angle) {
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
for(j = 0; j < 3; j++) {
|
for(j = 0; j < 3; j++) {
|
||||||
stl_rotate(&stl->facet_start[i].vertex[j].z,
|
stl_rotate(&stl->facet_start[i].vertex[j](2),
|
||||||
&stl->facet_start[i].vertex[j].x, c, s);
|
&stl->facet_start[i].vertex[j](0), c, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stl_get_size(stl);
|
stl_get_size(stl);
|
||||||
|
|
@ -254,8 +207,8 @@ stl_rotate_z(stl_file *stl, float angle) {
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
for(j = 0; j < 3; j++) {
|
for(j = 0; j < 3; j++) {
|
||||||
stl_rotate(&stl->facet_start[i].vertex[j].x,
|
stl_rotate(&stl->facet_start[i].vertex[j](0),
|
||||||
&stl->facet_start[i].vertex[j].y, c, s);
|
&stl->facet_start[i].vertex[j](1), c, s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stl_get_size(stl);
|
stl_get_size(stl);
|
||||||
|
|
@ -272,142 +225,98 @@ stl_rotate(float *x, float *y, const double c, const double s) {
|
||||||
*y = float(s * xold + c * yold);
|
*y = float(s * xold + c * yold);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void
|
void stl_get_size(stl_file *stl)
|
||||||
stl_get_size(stl_file *stl) {
|
{
|
||||||
int i;
|
if (stl->error || stl->stats.number_of_facets == 0)
|
||||||
int j;
|
return;
|
||||||
|
stl->stats.min = stl->facet_start[0].vertex[0];
|
||||||
if (stl->error) return;
|
stl->stats.max = stl->stats.min;
|
||||||
if (stl->stats.number_of_facets == 0) return;
|
for (int i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||||
|
const stl_facet &face = stl->facet_start[i];
|
||||||
stl->stats.min.x = stl->facet_start[0].vertex[0].x;
|
for (int j = 0; j < 3; ++ j) {
|
||||||
stl->stats.min.y = stl->facet_start[0].vertex[0].y;
|
stl->stats.min = stl->stats.min.cwiseMin(face.vertex[j]);
|
||||||
stl->stats.min.z = stl->facet_start[0].vertex[0].z;
|
stl->stats.max = stl->stats.max.cwiseMax(face.vertex[j]);
|
||||||
stl->stats.max.x = stl->facet_start[0].vertex[0].x;
|
|
||||||
stl->stats.max.y = stl->facet_start[0].vertex[0].y;
|
|
||||||
stl->stats.max.z = stl->facet_start[0].vertex[0].z;
|
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
|
||||||
for(j = 0; j < 3; j++) {
|
|
||||||
stl->stats.min.x = STL_MIN(stl->stats.min.x,
|
|
||||||
stl->facet_start[i].vertex[j].x);
|
|
||||||
stl->stats.min.y = STL_MIN(stl->stats.min.y,
|
|
||||||
stl->facet_start[i].vertex[j].y);
|
|
||||||
stl->stats.min.z = STL_MIN(stl->stats.min.z,
|
|
||||||
stl->facet_start[i].vertex[j].z);
|
|
||||||
stl->stats.max.x = STL_MAX(stl->stats.max.x,
|
|
||||||
stl->facet_start[i].vertex[j].x);
|
|
||||||
stl->stats.max.y = STL_MAX(stl->stats.max.y,
|
|
||||||
stl->facet_start[i].vertex[j].y);
|
|
||||||
stl->stats.max.z = STL_MAX(stl->stats.max.z,
|
|
||||||
stl->facet_start[i].vertex[j].z);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stl->stats.size.x = stl->stats.max.x - stl->stats.min.x;
|
stl->stats.size = stl->stats.max - stl->stats.min;
|
||||||
stl->stats.size.y = stl->stats.max.y - stl->stats.min.y;
|
stl->stats.bounding_diameter = stl->stats.size.norm();
|
||||||
stl->stats.size.z = stl->stats.max.z - stl->stats.min.z;
|
|
||||||
stl->stats.bounding_diameter = sqrt(
|
|
||||||
stl->stats.size.x * stl->stats.size.x +
|
|
||||||
stl->stats.size.y * stl->stats.size.y +
|
|
||||||
stl->stats.size.z * stl->stats.size.z
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void stl_mirror_xy(stl_file *stl)
|
||||||
stl_mirror_xy(stl_file *stl) {
|
{
|
||||||
int i;
|
if (stl->error)
|
||||||
int j;
|
return;
|
||||||
float temp_size;
|
|
||||||
|
|
||||||
if (stl->error) return;
|
for(int i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
|
for(int j = 0; j < 3; j++) {
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
stl->facet_start[i].vertex[j](2) *= -1.0;
|
||||||
for(j = 0; j < 3; j++) {
|
|
||||||
stl->facet_start[i].vertex[j].z *= -1.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
temp_size = stl->stats.min.z;
|
float temp_size = stl->stats.min(2);
|
||||||
stl->stats.min.z = stl->stats.max.z;
|
stl->stats.min(2) = stl->stats.max(2);
|
||||||
stl->stats.max.z = temp_size;
|
stl->stats.max(2) = temp_size;
|
||||||
stl->stats.min.z *= -1.0;
|
stl->stats.min(2) *= -1.0;
|
||||||
stl->stats.max.z *= -1.0;
|
stl->stats.max(2) *= -1.0;
|
||||||
stl_reverse_all_facets(stl);
|
stl_reverse_all_facets(stl);
|
||||||
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void stl_mirror_yz(stl_file *stl)
|
||||||
stl_mirror_yz(stl_file *stl) {
|
{
|
||||||
int i;
|
|
||||||
int j;
|
|
||||||
float temp_size;
|
|
||||||
|
|
||||||
if (stl->error) return;
|
if (stl->error) return;
|
||||||
|
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
for (int i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
for(j = 0; j < 3; j++) {
|
for (int j = 0; j < 3; j++) {
|
||||||
stl->facet_start[i].vertex[j].x *= -1.0;
|
stl->facet_start[i].vertex[j](0) *= -1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
temp_size = stl->stats.min.x;
|
float temp_size = stl->stats.min(0);
|
||||||
stl->stats.min.x = stl->stats.max.x;
|
stl->stats.min(0) = stl->stats.max(0);
|
||||||
stl->stats.max.x = temp_size;
|
stl->stats.max(0) = temp_size;
|
||||||
stl->stats.min.x *= -1.0;
|
stl->stats.min(0) *= -1.0;
|
||||||
stl->stats.max.x *= -1.0;
|
stl->stats.max(0) *= -1.0;
|
||||||
stl_reverse_all_facets(stl);
|
stl_reverse_all_facets(stl);
|
||||||
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void stl_mirror_xz(stl_file *stl)
|
||||||
stl_mirror_xz(stl_file *stl) {
|
{
|
||||||
int i;
|
if (stl->error)
|
||||||
int j;
|
return;
|
||||||
float temp_size;
|
|
||||||
|
|
||||||
if (stl->error) return;
|
for (int i = 0; i < stl->stats.number_of_facets; i++) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
for(i = 0; i < stl->stats.number_of_facets; i++) {
|
stl->facet_start[i].vertex[j](1) *= -1.0;
|
||||||
for(j = 0; j < 3; j++) {
|
|
||||||
stl->facet_start[i].vertex[j].y *= -1.0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
temp_size = stl->stats.min.y;
|
float temp_size = stl->stats.min(1);
|
||||||
stl->stats.min.y = stl->stats.max.y;
|
stl->stats.min(1) = stl->stats.max(1);
|
||||||
stl->stats.max.y = temp_size;
|
stl->stats.max(1) = temp_size;
|
||||||
stl->stats.min.y *= -1.0;
|
stl->stats.min(1) *= -1.0;
|
||||||
stl->stats.max.y *= -1.0;
|
stl->stats.max(1) *= -1.0;
|
||||||
stl_reverse_all_facets(stl);
|
stl_reverse_all_facets(stl);
|
||||||
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
stl->stats.facets_reversed -= stl->stats.number_of_facets; /* for not altering stats */
|
||||||
}
|
}
|
||||||
|
|
||||||
static float get_volume(stl_file *stl) {
|
static float get_volume(stl_file *stl)
|
||||||
stl_vertex p0;
|
{
|
||||||
stl_vertex p;
|
if (stl->error)
|
||||||
stl_normal n;
|
return 0;
|
||||||
float height;
|
|
||||||
float area;
|
|
||||||
float volume = 0.0;
|
|
||||||
|
|
||||||
if (stl->error) return 0;
|
// Choose a point, any point as the reference.
|
||||||
|
stl_vertex p0 = stl->facet_start[0].vertex[0];
|
||||||
/* Choose a point, any point as the reference */
|
float volume = 0.f;
|
||||||
p0.x = stl->facet_start[0].vertex[0].x;
|
for(uint32_t i = 0; i < stl->stats.number_of_facets; ++ i) {
|
||||||
p0.y = stl->facet_start[0].vertex[0].y;
|
// Do dot product to get distance from point to plane.
|
||||||
p0.z = stl->facet_start[0].vertex[0].z;
|
float height = stl->facet_start[i].normal.dot(stl->facet_start[i].vertex[0] - p0);
|
||||||
|
float area = get_area(&stl->facet_start[i]);
|
||||||
for(uint32_t i = 0; i < stl->stats.number_of_facets; i++) {
|
|
||||||
p.x = stl->facet_start[i].vertex[0].x - p0.x;
|
|
||||||
p.y = stl->facet_start[i].vertex[0].y - p0.y;
|
|
||||||
p.z = stl->facet_start[i].vertex[0].z - p0.z;
|
|
||||||
/* Do dot product to get distance from point to plane */
|
|
||||||
n = stl->facet_start[i].normal;
|
|
||||||
height = (n.x * p.x) + (n.y * p.y) + (n.z * p.z);
|
|
||||||
area = get_area(&stl->facet_start[i]);
|
|
||||||
volume += (area * height) / 3.0f;
|
volume += (area * height) / 3.0f;
|
||||||
}
|
}
|
||||||
return volume;
|
return volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stl_calculate_volume(stl_file *stl) {
|
void stl_calculate_volume(stl_file *stl)
|
||||||
|
{
|
||||||
if (stl->error) return;
|
if (stl->error) return;
|
||||||
stl->stats.volume = get_volume(stl);
|
stl->stats.volume = get_volume(stl);
|
||||||
if(stl->stats.volume < 0.0) {
|
if(stl->stats.volume < 0.0) {
|
||||||
|
|
@ -416,35 +325,32 @@ void stl_calculate_volume(stl_file *stl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static float get_area(stl_facet *facet) {
|
static float get_area(stl_facet *facet)
|
||||||
double cross[3][3];
|
{
|
||||||
float sum[3];
|
|
||||||
float n[3];
|
|
||||||
float area;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
/* cast to double before calculating cross product because large coordinates
|
/* cast to double before calculating cross product because large coordinates
|
||||||
can result in overflowing product
|
can result in overflowing product
|
||||||
(bad area is responsible for bad volume and bad facets reversal) */
|
(bad area is responsible for bad volume and bad facets reversal) */
|
||||||
for(i = 0; i < 3; i++) {
|
double cross[3][3];
|
||||||
cross[i][0]=(((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].z) -
|
for (int i = 0; i < 3; i++) {
|
||||||
((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].y));
|
cross[i][0]=(((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](2)) -
|
||||||
cross[i][1]=(((double)facet->vertex[i].z * (double)facet->vertex[(i + 1) % 3].x) -
|
((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](1)));
|
||||||
((double)facet->vertex[i].x * (double)facet->vertex[(i + 1) % 3].z));
|
cross[i][1]=(((double)facet->vertex[i](2) * (double)facet->vertex[(i + 1) % 3](0)) -
|
||||||
cross[i][2]=(((double)facet->vertex[i].x * (double)facet->vertex[(i + 1) % 3].y) -
|
((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](2)));
|
||||||
((double)facet->vertex[i].y * (double)facet->vertex[(i + 1) % 3].x));
|
cross[i][2]=(((double)facet->vertex[i](0) * (double)facet->vertex[(i + 1) % 3](1)) -
|
||||||
|
((double)facet->vertex[i](1) * (double)facet->vertex[(i + 1) % 3](0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
sum[0] = cross[0][0] + cross[1][0] + cross[2][0];
|
stl_normal sum;
|
||||||
sum[1] = cross[0][1] + cross[1][1] + cross[2][1];
|
sum(0) = cross[0][0] + cross[1][0] + cross[2][0];
|
||||||
sum[2] = cross[0][2] + cross[1][2] + cross[2][2];
|
sum(1) = cross[0][1] + cross[1][1] + cross[2][1];
|
||||||
|
sum(2) = cross[0][2] + cross[1][2] + cross[2][2];
|
||||||
|
|
||||||
/* This should already be done. But just in case, let's do it again */
|
// This should already be done. But just in case, let's do it again.
|
||||||
|
//FIXME this is questionable. the "sum" normal should be accurate, while the normal "n" may be calculated with a low accuracy.
|
||||||
|
stl_normal n;
|
||||||
stl_calculate_normal(n, facet);
|
stl_calculate_normal(n, facet);
|
||||||
stl_normalize_vector(n);
|
stl_normalize_vector(n);
|
||||||
|
return 0.5f * n.dot(sum);
|
||||||
area = 0.5 * (n[0] * sum[0] + n[1] * sum[1] + n[2] * sum[2]);
|
|
||||||
return area;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stl_repair(stl_file *stl,
|
void stl_repair(stl_file *stl,
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
template BoundingBoxBase<Point>::BoundingBoxBase(const std::vector<Point> &points);
|
template BoundingBoxBase<Point>::BoundingBoxBase(const std::vector<Point> &points);
|
||||||
template BoundingBoxBase<Pointf>::BoundingBoxBase(const std::vector<Pointf> &points);
|
template BoundingBoxBase<Vec2d>::BoundingBoxBase(const std::vector<Vec2d> &points);
|
||||||
|
|
||||||
template BoundingBox3Base<Pointf3>::BoundingBox3Base(const std::vector<Pointf3> &points);
|
template BoundingBox3Base<Vec3d>::BoundingBox3Base(const std::vector<Vec3d> &points);
|
||||||
|
|
||||||
BoundingBox::BoundingBox(const Lines &lines)
|
BoundingBox::BoundingBox(const Lines &lines)
|
||||||
{
|
{
|
||||||
|
|
@ -22,8 +22,7 @@ BoundingBox::BoundingBox(const Lines &lines)
|
||||||
*this = BoundingBox(points);
|
*this = BoundingBox(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void BoundingBox::polygon(Polygon* polygon) const
|
||||||
BoundingBox::polygon(Polygon* polygon) const
|
|
||||||
{
|
{
|
||||||
polygon->points.clear();
|
polygon->points.clear();
|
||||||
polygon->points.resize(4);
|
polygon->points.resize(4);
|
||||||
|
|
@ -37,8 +36,7 @@ BoundingBox::polygon(Polygon* polygon) const
|
||||||
polygon->points[3](1) = this->max(1);
|
polygon->points[3](1) = this->max(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Polygon
|
Polygon BoundingBox::polygon() const
|
||||||
BoundingBox::polygon() const
|
|
||||||
{
|
{
|
||||||
Polygon p;
|
Polygon p;
|
||||||
this->polygon(&p);
|
this->polygon(&p);
|
||||||
|
|
@ -72,24 +70,23 @@ BoundingBoxBase<PointClass>::scale(double factor)
|
||||||
this->max *= factor;
|
this->max *= factor;
|
||||||
}
|
}
|
||||||
template void BoundingBoxBase<Point>::scale(double factor);
|
template void BoundingBoxBase<Point>::scale(double factor);
|
||||||
template void BoundingBoxBase<Pointf>::scale(double factor);
|
template void BoundingBoxBase<Vec2d>::scale(double factor);
|
||||||
template void BoundingBoxBase<Pointf3>::scale(double factor);
|
template void BoundingBoxBase<Vec3d>::scale(double factor);
|
||||||
|
|
||||||
template <class PointClass> void
|
template <class PointClass> void
|
||||||
BoundingBoxBase<PointClass>::merge(const PointClass &point)
|
BoundingBoxBase<PointClass>::merge(const PointClass &point)
|
||||||
{
|
{
|
||||||
if (this->defined) {
|
if (this->defined) {
|
||||||
this->min(0) = std::min(point(0), this->min(0));
|
this->min = this->min.cwiseMin(point);
|
||||||
this->min(1) = std::min(point(1), this->min(1));
|
this->max = this->max.cwiseMax(point);
|
||||||
this->max(0) = std::max(point(0), this->max(0));
|
|
||||||
this->max(1) = std::max(point(1), this->max(1));
|
|
||||||
} else {
|
} else {
|
||||||
this->min = this->max = point;
|
this->min = point;
|
||||||
|
this->max = point;
|
||||||
this->defined = true;
|
this->defined = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template void BoundingBoxBase<Point>::merge(const Point &point);
|
template void BoundingBoxBase<Point>::merge(const Point &point);
|
||||||
template void BoundingBoxBase<Pointf>::merge(const Pointf &point);
|
template void BoundingBoxBase<Vec2d>::merge(const Vec2d &point);
|
||||||
|
|
||||||
template <class PointClass> void
|
template <class PointClass> void
|
||||||
BoundingBoxBase<PointClass>::merge(const std::vector<PointClass> &points)
|
BoundingBoxBase<PointClass>::merge(const std::vector<PointClass> &points)
|
||||||
|
|
@ -97,7 +94,7 @@ BoundingBoxBase<PointClass>::merge(const std::vector<PointClass> &points)
|
||||||
this->merge(BoundingBoxBase(points));
|
this->merge(BoundingBoxBase(points));
|
||||||
}
|
}
|
||||||
template void BoundingBoxBase<Point>::merge(const Points &points);
|
template void BoundingBoxBase<Point>::merge(const Points &points);
|
||||||
template void BoundingBoxBase<Pointf>::merge(const Pointfs &points);
|
template void BoundingBoxBase<Vec2d>::merge(const Pointfs &points);
|
||||||
|
|
||||||
template <class PointClass> void
|
template <class PointClass> void
|
||||||
BoundingBoxBase<PointClass>::merge(const BoundingBoxBase<PointClass> &bb)
|
BoundingBoxBase<PointClass>::merge(const BoundingBoxBase<PointClass> &bb)
|
||||||
|
|
@ -105,10 +102,8 @@ BoundingBoxBase<PointClass>::merge(const BoundingBoxBase<PointClass> &bb)
|
||||||
assert(bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1));
|
assert(bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1));
|
||||||
if (bb.defined) {
|
if (bb.defined) {
|
||||||
if (this->defined) {
|
if (this->defined) {
|
||||||
this->min(0) = std::min(bb.min(0), this->min(0));
|
this->min = this->min.cwiseMin(bb.min);
|
||||||
this->min(1) = std::min(bb.min(1), this->min(1));
|
this->max = this->max.cwiseMax(bb.max);
|
||||||
this->max(0) = std::max(bb.max(0), this->max(0));
|
|
||||||
this->max(1) = std::max(bb.max(1), this->max(1));
|
|
||||||
} else {
|
} else {
|
||||||
this->min = bb.min;
|
this->min = bb.min;
|
||||||
this->max = bb.max;
|
this->max = bb.max;
|
||||||
|
|
@ -117,25 +112,28 @@ BoundingBoxBase<PointClass>::merge(const BoundingBoxBase<PointClass> &bb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template void BoundingBoxBase<Point>::merge(const BoundingBoxBase<Point> &bb);
|
template void BoundingBoxBase<Point>::merge(const BoundingBoxBase<Point> &bb);
|
||||||
template void BoundingBoxBase<Pointf>::merge(const BoundingBoxBase<Pointf> &bb);
|
template void BoundingBoxBase<Vec2d>::merge(const BoundingBoxBase<Vec2d> &bb);
|
||||||
|
|
||||||
template <class PointClass> void
|
template <class PointClass> void
|
||||||
BoundingBox3Base<PointClass>::merge(const PointClass &point)
|
BoundingBox3Base<PointClass>::merge(const PointClass &point)
|
||||||
{
|
{
|
||||||
if (this->defined) {
|
if (this->defined) {
|
||||||
this->min(2) = std::min(point(2), this->min(2));
|
this->min = this->min.cwiseMin(point);
|
||||||
this->max(2) = std::max(point(2), this->max(2));
|
this->max = this->max.cwiseMax(point);
|
||||||
|
} else {
|
||||||
|
this->min = point;
|
||||||
|
this->max = point;
|
||||||
|
this->defined = true;
|
||||||
}
|
}
|
||||||
BoundingBoxBase<PointClass>::merge(point);
|
|
||||||
}
|
}
|
||||||
template void BoundingBox3Base<Pointf3>::merge(const Pointf3 &point);
|
template void BoundingBox3Base<Vec3d>::merge(const Vec3d &point);
|
||||||
|
|
||||||
template <class PointClass> void
|
template <class PointClass> void
|
||||||
BoundingBox3Base<PointClass>::merge(const std::vector<PointClass> &points)
|
BoundingBox3Base<PointClass>::merge(const std::vector<PointClass> &points)
|
||||||
{
|
{
|
||||||
this->merge(BoundingBox3Base(points));
|
this->merge(BoundingBox3Base(points));
|
||||||
}
|
}
|
||||||
template void BoundingBox3Base<Pointf3>::merge(const Pointf3s &points);
|
template void BoundingBox3Base<Vec3d>::merge(const Pointf3s &points);
|
||||||
|
|
||||||
template <class PointClass> void
|
template <class PointClass> void
|
||||||
BoundingBox3Base<PointClass>::merge(const BoundingBox3Base<PointClass> &bb)
|
BoundingBox3Base<PointClass>::merge(const BoundingBox3Base<PointClass> &bb)
|
||||||
|
|
@ -143,13 +141,16 @@ BoundingBox3Base<PointClass>::merge(const BoundingBox3Base<PointClass> &bb)
|
||||||
assert(bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1) || bb.min(2) >= bb.max(2));
|
assert(bb.defined || bb.min(0) >= bb.max(0) || bb.min(1) >= bb.max(1) || bb.min(2) >= bb.max(2));
|
||||||
if (bb.defined) {
|
if (bb.defined) {
|
||||||
if (this->defined) {
|
if (this->defined) {
|
||||||
this->min(2) = std::min(bb.min(2), this->min(2));
|
this->min = this->min.cwiseMin(bb.min);
|
||||||
this->max(2) = std::max(bb.max(2), this->max(2));
|
this->max = this->max.cwiseMax(bb.max);
|
||||||
|
} else {
|
||||||
|
this->min = bb.min;
|
||||||
|
this->max = bb.max;
|
||||||
|
this->defined = true;
|
||||||
}
|
}
|
||||||
BoundingBoxBase<PointClass>::merge(bb);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
template void BoundingBox3Base<Pointf3>::merge(const BoundingBox3Base<Pointf3> &bb);
|
template void BoundingBox3Base<Vec3d>::merge(const BoundingBox3Base<Vec3d> &bb);
|
||||||
|
|
||||||
template <class PointClass> PointClass
|
template <class PointClass> PointClass
|
||||||
BoundingBoxBase<PointClass>::size() const
|
BoundingBoxBase<PointClass>::size() const
|
||||||
|
|
@ -157,14 +158,14 @@ BoundingBoxBase<PointClass>::size() const
|
||||||
return PointClass(this->max(0) - this->min(0), this->max(1) - this->min(1));
|
return PointClass(this->max(0) - this->min(0), this->max(1) - this->min(1));
|
||||||
}
|
}
|
||||||
template Point BoundingBoxBase<Point>::size() const;
|
template Point BoundingBoxBase<Point>::size() const;
|
||||||
template Pointf BoundingBoxBase<Pointf>::size() const;
|
template Vec2d BoundingBoxBase<Vec2d>::size() const;
|
||||||
|
|
||||||
template <class PointClass> PointClass
|
template <class PointClass> PointClass
|
||||||
BoundingBox3Base<PointClass>::size() const
|
BoundingBox3Base<PointClass>::size() const
|
||||||
{
|
{
|
||||||
return PointClass(this->max(0) - this->min(0), this->max(1) - this->min(1), this->max(2) - this->min(2));
|
return PointClass(this->max(0) - this->min(0), this->max(1) - this->min(1), this->max(2) - this->min(2));
|
||||||
}
|
}
|
||||||
template Pointf3 BoundingBox3Base<Pointf3>::size() const;
|
template Vec3d BoundingBox3Base<Vec3d>::size() const;
|
||||||
|
|
||||||
template <class PointClass> double BoundingBoxBase<PointClass>::radius() const
|
template <class PointClass> double BoundingBoxBase<PointClass>::radius() const
|
||||||
{
|
{
|
||||||
|
|
@ -174,7 +175,7 @@ template <class PointClass> double BoundingBoxBase<PointClass>::radius() const
|
||||||
return 0.5 * sqrt(x*x+y*y);
|
return 0.5 * sqrt(x*x+y*y);
|
||||||
}
|
}
|
||||||
template double BoundingBoxBase<Point>::radius() const;
|
template double BoundingBoxBase<Point>::radius() const;
|
||||||
template double BoundingBoxBase<Pointf>::radius() const;
|
template double BoundingBoxBase<Vec2d>::radius() const;
|
||||||
|
|
||||||
template <class PointClass> double BoundingBox3Base<PointClass>::radius() const
|
template <class PointClass> double BoundingBox3Base<PointClass>::radius() const
|
||||||
{
|
{
|
||||||
|
|
@ -183,7 +184,7 @@ template <class PointClass> double BoundingBox3Base<PointClass>::radius() const
|
||||||
double z = this->max(2) - this->min(2);
|
double z = this->max(2) - this->min(2);
|
||||||
return 0.5 * sqrt(x*x+y*y+z*z);
|
return 0.5 * sqrt(x*x+y*y+z*z);
|
||||||
}
|
}
|
||||||
template double BoundingBox3Base<Pointf3>::radius() const;
|
template double BoundingBox3Base<Vec3d>::radius() const;
|
||||||
|
|
||||||
template <class PointClass> void
|
template <class PointClass> void
|
||||||
BoundingBoxBase<PointClass>::offset(coordf_t delta)
|
BoundingBoxBase<PointClass>::offset(coordf_t delta)
|
||||||
|
|
@ -193,7 +194,7 @@ BoundingBoxBase<PointClass>::offset(coordf_t delta)
|
||||||
this->max += v;
|
this->max += v;
|
||||||
}
|
}
|
||||||
template void BoundingBoxBase<Point>::offset(coordf_t delta);
|
template void BoundingBoxBase<Point>::offset(coordf_t delta);
|
||||||
template void BoundingBoxBase<Pointf>::offset(coordf_t delta);
|
template void BoundingBoxBase<Vec2d>::offset(coordf_t delta);
|
||||||
|
|
||||||
template <class PointClass> void
|
template <class PointClass> void
|
||||||
BoundingBox3Base<PointClass>::offset(coordf_t delta)
|
BoundingBox3Base<PointClass>::offset(coordf_t delta)
|
||||||
|
|
@ -202,29 +203,22 @@ BoundingBox3Base<PointClass>::offset(coordf_t delta)
|
||||||
this->min -= v;
|
this->min -= v;
|
||||||
this->max += v;
|
this->max += v;
|
||||||
}
|
}
|
||||||
template void BoundingBox3Base<Pointf3>::offset(coordf_t delta);
|
template void BoundingBox3Base<Vec3d>::offset(coordf_t delta);
|
||||||
|
|
||||||
template <class PointClass> PointClass
|
template <class PointClass> PointClass
|
||||||
BoundingBoxBase<PointClass>::center() const
|
BoundingBoxBase<PointClass>::center() const
|
||||||
{
|
{
|
||||||
return PointClass(
|
return (this->min + this->max) / 2;
|
||||||
(this->max(0) + this->min(0))/2,
|
|
||||||
(this->max(1) + this->min(1))/2
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
template Point BoundingBoxBase<Point>::center() const;
|
template Point BoundingBoxBase<Point>::center() const;
|
||||||
template Pointf BoundingBoxBase<Pointf>::center() const;
|
template Vec2d BoundingBoxBase<Vec2d>::center() const;
|
||||||
|
|
||||||
template <class PointClass> PointClass
|
template <class PointClass> PointClass
|
||||||
BoundingBox3Base<PointClass>::center() const
|
BoundingBox3Base<PointClass>::center() const
|
||||||
{
|
{
|
||||||
return PointClass(
|
return (this->min + this->max) / 2;
|
||||||
(this->max(0) + this->min(0))/2,
|
|
||||||
(this->max(1) + this->min(1))/2,
|
|
||||||
(this->max(2) + this->min(2))/2
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
template Pointf3 BoundingBox3Base<Pointf3>::center() const;
|
template Vec3d BoundingBox3Base<Vec3d>::center() const;
|
||||||
|
|
||||||
template <class PointClass> coordf_t
|
template <class PointClass> coordf_t
|
||||||
BoundingBox3Base<PointClass>::max_size() const
|
BoundingBox3Base<PointClass>::max_size() const
|
||||||
|
|
@ -232,7 +226,7 @@ BoundingBox3Base<PointClass>::max_size() const
|
||||||
PointClass s = size();
|
PointClass s = size();
|
||||||
return std::max(s(0), std::max(s(1), s(2)));
|
return std::max(s(0), std::max(s(1), s(2)));
|
||||||
}
|
}
|
||||||
template coordf_t BoundingBox3Base<Pointf3>::max_size() const;
|
template coordf_t BoundingBox3Base<Vec3d>::max_size() const;
|
||||||
|
|
||||||
// Align a coordinate to a grid. The coordinate may be negative,
|
// Align a coordinate to a grid. The coordinate may be negative,
|
||||||
// the aligned value will never be bigger than the original one.
|
// the aligned value will never be bigger than the original one.
|
||||||
|
|
@ -255,39 +249,35 @@ void BoundingBox::align_to_grid(const coord_t cell_size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBoxf3 BoundingBoxf3::transformed(const Transform3f& matrix) const
|
BoundingBoxf3 BoundingBoxf3::transformed(const Transform3d& matrix) const
|
||||||
{
|
{
|
||||||
Eigen::Matrix<float, 3, 8, Eigen::DontAlign> vertices;
|
typedef Eigen::Matrix<double, 3, 8, Eigen::DontAlign> Vertices;
|
||||||
|
|
||||||
vertices(0, 0) = (float)min(0); vertices(1, 0) = (float)min(1); vertices(2, 0) = (float)min(2);
|
Vertices src_vertices;
|
||||||
vertices(0, 1) = (float)max(0); vertices(1, 1) = (float)min(1); vertices(2, 1) = (float)min(2);
|
src_vertices(0, 0) = min(0); src_vertices(1, 0) = min(1); src_vertices(2, 0) = min(2);
|
||||||
vertices(0, 2) = (float)max(0); vertices(1, 2) = (float)max(1); vertices(2, 2) = (float)min(2);
|
src_vertices(0, 1) = max(0); src_vertices(1, 1) = min(1); src_vertices(2, 1) = min(2);
|
||||||
vertices(0, 3) = (float)min(0); vertices(1, 3) = (float)max(1); vertices(2, 3) = (float)min(2);
|
src_vertices(0, 2) = max(0); src_vertices(1, 2) = max(1); src_vertices(2, 2) = min(2);
|
||||||
vertices(0, 4) = (float)min(0); vertices(1, 4) = (float)min(1); vertices(2, 4) = (float)max(2);
|
src_vertices(0, 3) = min(0); src_vertices(1, 3) = max(1); src_vertices(2, 3) = min(2);
|
||||||
vertices(0, 5) = (float)max(0); vertices(1, 5) = (float)min(1); vertices(2, 5) = (float)max(2);
|
src_vertices(0, 4) = min(0); src_vertices(1, 4) = min(1); src_vertices(2, 4) = max(2);
|
||||||
vertices(0, 6) = (float)max(0); vertices(1, 6) = (float)max(1); vertices(2, 6) = (float)max(2);
|
src_vertices(0, 5) = max(0); src_vertices(1, 5) = min(1); src_vertices(2, 5) = max(2);
|
||||||
vertices(0, 7) = (float)min(0); vertices(1, 7) = (float)max(1); vertices(2, 7) = (float)max(2);
|
src_vertices(0, 6) = max(0); src_vertices(1, 6) = max(1); src_vertices(2, 6) = max(2);
|
||||||
|
src_vertices(0, 7) = min(0); src_vertices(1, 7) = max(1); src_vertices(2, 7) = max(2);
|
||||||
|
|
||||||
Eigen::Matrix<float, 3, 8, Eigen::DontAlign> transf_vertices = matrix * vertices.colwise().homogeneous();
|
Vertices dst_vertices = matrix * src_vertices.colwise().homogeneous();
|
||||||
|
|
||||||
float min_x = transf_vertices(0, 0);
|
Vec3d v_min(dst_vertices(0, 0), dst_vertices(1, 0), dst_vertices(2, 0));
|
||||||
float max_x = transf_vertices(0, 0);
|
Vec3d v_max = v_min;
|
||||||
float min_y = transf_vertices(1, 0);
|
|
||||||
float max_y = transf_vertices(1, 0);
|
|
||||||
float min_z = transf_vertices(2, 0);
|
|
||||||
float max_z = transf_vertices(2, 0);
|
|
||||||
|
|
||||||
for (int i = 1; i < 8; ++i)
|
for (int i = 1; i < 8; ++i)
|
||||||
{
|
{
|
||||||
min_x = std::min(min_x, transf_vertices(0, i));
|
for (int j = 0; j < 3; ++j)
|
||||||
max_x = std::max(max_x, transf_vertices(0, i));
|
{
|
||||||
min_y = std::min(min_y, transf_vertices(1, i));
|
v_min(j) = std::min(v_min(j), dst_vertices(j, i));
|
||||||
max_y = std::max(max_y, transf_vertices(1, i));
|
v_max(j) = std::max(v_max(j), dst_vertices(j, i));
|
||||||
min_z = std::min(min_z, transf_vertices(2, i));
|
}
|
||||||
max_z = std::max(max_z, transf_vertices(2, i));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return BoundingBoxf3(Pointf3((coordf_t)min_x, (coordf_t)min_y, (coordf_t)min_z), Pointf3((coordf_t)max_x, (coordf_t)max_y, (coordf_t)max_z));
|
return BoundingBoxf3(v_min, v_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,6 @@
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
typedef Point Size;
|
|
||||||
typedef Point3 Size3;
|
|
||||||
typedef Pointf Sizef;
|
|
||||||
typedef Pointf3 Sizef3;
|
|
||||||
|
|
||||||
template <class PointClass>
|
template <class PointClass>
|
||||||
class BoundingBoxBase
|
class BoundingBoxBase
|
||||||
{
|
{
|
||||||
|
|
@ -20,23 +15,20 @@ public:
|
||||||
PointClass max;
|
PointClass max;
|
||||||
bool defined;
|
bool defined;
|
||||||
|
|
||||||
BoundingBoxBase() : defined(false) {};
|
BoundingBoxBase() : defined(false), min(PointClass::Zero()), max(PointClass::Zero()) {}
|
||||||
BoundingBoxBase(const PointClass &pmin, const PointClass &pmax) :
|
BoundingBoxBase(const PointClass &pmin, const PointClass &pmax) :
|
||||||
min(pmin), max(pmax), defined(pmin(0) < pmax(0) && pmin(1) < pmax(1)) {}
|
min(pmin), max(pmax), defined(pmin(0) < pmax(0) && pmin(1) < pmax(1)) {}
|
||||||
BoundingBoxBase(const std::vector<PointClass>& points)
|
BoundingBoxBase(const std::vector<PointClass>& points) : min(PointClass::Zero()), max(PointClass::Zero())
|
||||||
{
|
{
|
||||||
if (points.empty())
|
if (points.empty())
|
||||||
CONFESS("Empty point set supplied to BoundingBoxBase constructor");
|
CONFESS("Empty point set supplied to BoundingBoxBase constructor");
|
||||||
|
|
||||||
typename std::vector<PointClass>::const_iterator it = points.begin();
|
typename std::vector<PointClass>::const_iterator it = points.begin();
|
||||||
this->min(0) = this->max(0) = (*it)(0);
|
this->min = *it;
|
||||||
this->min(1) = this->max(1) = (*it)(1);
|
this->max = *it;
|
||||||
for (++it; it != points.end(); ++it)
|
for (++ it; it != points.end(); ++ it) {
|
||||||
{
|
this->min = this->min.cwiseMin(*it);
|
||||||
this->min(0) = std::min((*it)(0), this->min(0));
|
this->max = this->max.cwiseMax(*it);
|
||||||
this->min(1) = std::min((*it)(1), this->min(1));
|
|
||||||
this->max(0) = std::max((*it)(0), this->max(0));
|
|
||||||
this->max(1) = std::max((*it)(1), this->max(1));
|
|
||||||
}
|
}
|
||||||
this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1));
|
this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1));
|
||||||
}
|
}
|
||||||
|
|
@ -47,7 +39,7 @@ public:
|
||||||
PointClass size() const;
|
PointClass size() const;
|
||||||
double radius() const;
|
double radius() const;
|
||||||
void translate(coordf_t x, coordf_t y) { assert(this->defined); PointClass v(x, y); this->min += v; this->max += v; }
|
void translate(coordf_t x, coordf_t y) { assert(this->defined); PointClass v(x, y); this->min += v; this->max += v; }
|
||||||
void translate(const Pointf &v) { this->min += v; this->max += v; }
|
void translate(const Vec2d &v) { this->min += v; this->max += v; }
|
||||||
void offset(coordf_t delta);
|
void offset(coordf_t delta);
|
||||||
PointClass center() const;
|
PointClass center() const;
|
||||||
bool contains(const PointClass &point) const {
|
bool contains(const PointClass &point) const {
|
||||||
|
|
@ -71,19 +63,17 @@ public:
|
||||||
BoundingBoxBase<PointClass>(pmin, pmax)
|
BoundingBoxBase<PointClass>(pmin, pmax)
|
||||||
{ if (pmin(2) >= pmax(2)) BoundingBoxBase<PointClass>::defined = false; }
|
{ if (pmin(2) >= pmax(2)) BoundingBoxBase<PointClass>::defined = false; }
|
||||||
BoundingBox3Base(const std::vector<PointClass>& points)
|
BoundingBox3Base(const std::vector<PointClass>& points)
|
||||||
: BoundingBoxBase<PointClass>(points)
|
|
||||||
{
|
{
|
||||||
if (points.empty())
|
if (points.empty())
|
||||||
CONFESS("Empty point set supplied to BoundingBox3Base constructor");
|
CONFESS("Empty point set supplied to BoundingBox3Base constructor");
|
||||||
|
|
||||||
typename std::vector<PointClass>::const_iterator it = points.begin();
|
typename std::vector<PointClass>::const_iterator it = points.begin();
|
||||||
this->min(2) = this->max(2) = (*it)(2);
|
this->min = *it;
|
||||||
for (++it; it != points.end(); ++it)
|
this->max = *it;
|
||||||
{
|
for (++ it; it != points.end(); ++ it) {
|
||||||
this->min(2) = std::min((*it)(2), this->min(2));
|
this->min = this->min.cwiseMin(*it);
|
||||||
this->max(2) = std::max((*it)(2), this->max(2));
|
this->max = this->max.cwiseMax(*it);
|
||||||
}
|
}
|
||||||
this->defined &= (this->min(2) < this->max(2));
|
this->defined = (this->min(0) < this->max(0)) && (this->min(1) < this->max(1)) && (this->min(2) < this->max(2));
|
||||||
}
|
}
|
||||||
void merge(const PointClass &point);
|
void merge(const PointClass &point);
|
||||||
void merge(const std::vector<PointClass> &points);
|
void merge(const std::vector<PointClass> &points);
|
||||||
|
|
@ -91,7 +81,7 @@ public:
|
||||||
PointClass size() const;
|
PointClass size() const;
|
||||||
double radius() const;
|
double radius() const;
|
||||||
void translate(coordf_t x, coordf_t y, coordf_t z) { assert(this->defined); PointClass v(x, y, z); this->min += v; this->max += v; }
|
void translate(coordf_t x, coordf_t y, coordf_t z) { assert(this->defined); PointClass v(x, y, z); this->min += v; this->max += v; }
|
||||||
void translate(const Pointf3 &v) { this->min += v; this->max += v; }
|
void translate(const Vec3d &v) { this->min += v; this->max += v; }
|
||||||
void offset(coordf_t delta);
|
void offset(coordf_t delta);
|
||||||
PointClass center() const;
|
PointClass center() const;
|
||||||
coordf_t max_size() const;
|
coordf_t max_size() const;
|
||||||
|
|
@ -130,30 +120,30 @@ public:
|
||||||
friend BoundingBox get_extents_rotated(const Points &points, double angle);
|
friend BoundingBox get_extents_rotated(const Points &points, double angle);
|
||||||
};
|
};
|
||||||
|
|
||||||
class BoundingBox3 : public BoundingBox3Base<Point3>
|
class BoundingBox3 : public BoundingBox3Base<Vec3crd>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BoundingBox3() : BoundingBox3Base<Point3>() {};
|
BoundingBox3() : BoundingBox3Base<Vec3crd>() {};
|
||||||
BoundingBox3(const Point3 &pmin, const Point3 &pmax) : BoundingBox3Base<Point3>(pmin, pmax) {};
|
BoundingBox3(const Vec3crd &pmin, const Vec3crd &pmax) : BoundingBox3Base<Vec3crd>(pmin, pmax) {};
|
||||||
BoundingBox3(const Points3& points) : BoundingBox3Base<Point3>(points) {};
|
BoundingBox3(const Points3& points) : BoundingBox3Base<Vec3crd>(points) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
class BoundingBoxf : public BoundingBoxBase<Pointf>
|
class BoundingBoxf : public BoundingBoxBase<Vec2d>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BoundingBoxf() : BoundingBoxBase<Pointf>() {};
|
BoundingBoxf() : BoundingBoxBase<Vec2d>() {};
|
||||||
BoundingBoxf(const Pointf &pmin, const Pointf &pmax) : BoundingBoxBase<Pointf>(pmin, pmax) {};
|
BoundingBoxf(const Vec2d &pmin, const Vec2d &pmax) : BoundingBoxBase<Vec2d>(pmin, pmax) {};
|
||||||
BoundingBoxf(const std::vector<Pointf> &points) : BoundingBoxBase<Pointf>(points) {};
|
BoundingBoxf(const std::vector<Vec2d> &points) : BoundingBoxBase<Vec2d>(points) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
class BoundingBoxf3 : public BoundingBox3Base<Pointf3>
|
class BoundingBoxf3 : public BoundingBox3Base<Vec3d>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BoundingBoxf3() : BoundingBox3Base<Pointf3>() {};
|
BoundingBoxf3() : BoundingBox3Base<Vec3d>() {};
|
||||||
BoundingBoxf3(const Pointf3 &pmin, const Pointf3 &pmax) : BoundingBox3Base<Pointf3>(pmin, pmax) {};
|
BoundingBoxf3(const Vec3d &pmin, const Vec3d &pmax) : BoundingBox3Base<Vec3d>(pmin, pmax) {};
|
||||||
BoundingBoxf3(const std::vector<Pointf3> &points) : BoundingBox3Base<Pointf3>(points) {};
|
BoundingBoxf3(const std::vector<Vec3d> &points) : BoundingBox3Base<Vec3d>(points) {};
|
||||||
|
|
||||||
BoundingBoxf3 transformed(const Transform3f& matrix) const;
|
BoundingBoxf3 transformed(const Transform3d& matrix) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename VT>
|
template<typename VT>
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,9 @@ enum ConfigOptionType {
|
||||||
coPercents = coPercent + coVectorType,
|
coPercents = coPercent + coVectorType,
|
||||||
// a fraction or an absolute value
|
// a fraction or an absolute value
|
||||||
coFloatOrPercent = 5,
|
coFloatOrPercent = 5,
|
||||||
// single 2d point. Currently not used.
|
// single 2d point (Point2f). Currently not used.
|
||||||
coPoint = 6,
|
coPoint = 6,
|
||||||
// vector of 2d points. Currently used for the definition of the print bed and for the extruder offsets.
|
// vector of 2d points (Point2f). Currently used for the definition of the print bed and for the extruder offsets.
|
||||||
coPoints = coPoint + coVectorType,
|
coPoints = coPoint + coVectorType,
|
||||||
// single boolean value
|
// single boolean value
|
||||||
coBool = 7,
|
coBool = 7,
|
||||||
|
|
@ -622,11 +622,11 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConfigOptionPoint : public ConfigOptionSingle<Pointf>
|
class ConfigOptionPoint : public ConfigOptionSingle<Vec2d>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConfigOptionPoint() : ConfigOptionSingle<Pointf>(Pointf(0,0)) {}
|
ConfigOptionPoint() : ConfigOptionSingle<Vec2d>(Vec2d(0,0)) {}
|
||||||
explicit ConfigOptionPoint(const Pointf &value) : ConfigOptionSingle<Pointf>(value) {}
|
explicit ConfigOptionPoint(const Vec2d &value) : ConfigOptionSingle<Vec2d>(value) {}
|
||||||
|
|
||||||
static ConfigOptionType static_type() { return coPoint; }
|
static ConfigOptionType static_type() { return coPoint; }
|
||||||
ConfigOptionType type() const override { return static_type(); }
|
ConfigOptionType type() const override { return static_type(); }
|
||||||
|
|
@ -652,13 +652,13 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConfigOptionPoints : public ConfigOptionVector<Pointf>
|
class ConfigOptionPoints : public ConfigOptionVector<Vec2d>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ConfigOptionPoints() : ConfigOptionVector<Pointf>() {}
|
ConfigOptionPoints() : ConfigOptionVector<Vec2d>() {}
|
||||||
explicit ConfigOptionPoints(size_t n, const Pointf &value) : ConfigOptionVector<Pointf>(n, value) {}
|
explicit ConfigOptionPoints(size_t n, const Vec2d &value) : ConfigOptionVector<Vec2d>(n, value) {}
|
||||||
explicit ConfigOptionPoints(std::initializer_list<Pointf> il) : ConfigOptionVector<Pointf>(std::move(il)) {}
|
explicit ConfigOptionPoints(std::initializer_list<Vec2d> il) : ConfigOptionVector<Vec2d>(std::move(il)) {}
|
||||||
explicit ConfigOptionPoints(const std::vector<Pointf> &values) : ConfigOptionVector<Pointf>(values) {}
|
explicit ConfigOptionPoints(const std::vector<Vec2d> &values) : ConfigOptionVector<Vec2d>(values) {}
|
||||||
|
|
||||||
static ConfigOptionType static_type() { return coPoints; }
|
static ConfigOptionType static_type() { return coPoints; }
|
||||||
ConfigOptionType type() const override { return static_type(); }
|
ConfigOptionType type() const override { return static_type(); }
|
||||||
|
|
@ -696,7 +696,7 @@ public:
|
||||||
std::istringstream is(str);
|
std::istringstream is(str);
|
||||||
std::string point_str;
|
std::string point_str;
|
||||||
while (std::getline(is, point_str, ',')) {
|
while (std::getline(is, point_str, ',')) {
|
||||||
Pointf point;
|
Vec2d point(Vec2d::Zero());
|
||||||
std::istringstream iss(point_str);
|
std::istringstream iss(point_str);
|
||||||
std::string coord_str;
|
std::string coord_str;
|
||||||
if (std::getline(iss, coord_str, 'x')) {
|
if (std::getline(iss, coord_str, 'x')) {
|
||||||
|
|
@ -821,12 +821,7 @@ public:
|
||||||
bool deserialize(const std::string &str, bool append = false) override
|
bool deserialize(const std::string &str, bool append = false) override
|
||||||
{
|
{
|
||||||
UNUSED(append);
|
UNUSED(append);
|
||||||
const t_config_enum_values &enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
|
return from_string(str, this->value);
|
||||||
auto it = enum_keys_map.find(str);
|
|
||||||
if (it == enum_keys_map.end())
|
|
||||||
return false;
|
|
||||||
this->value = static_cast<T>(it->second);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool has(T value)
|
static bool has(T value)
|
||||||
|
|
@ -838,7 +833,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map from an enum name to an enum integer value.
|
// Map from an enum name to an enum integer value.
|
||||||
static t_config_enum_names& get_enum_names()
|
static const t_config_enum_names& get_enum_names()
|
||||||
{
|
{
|
||||||
static t_config_enum_names names;
|
static t_config_enum_names names;
|
||||||
if (names.empty()) {
|
if (names.empty()) {
|
||||||
|
|
@ -855,7 +850,17 @@ public:
|
||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
// Map from an enum name to an enum integer value.
|
// Map from an enum name to an enum integer value.
|
||||||
static t_config_enum_values& get_enum_values();
|
static const t_config_enum_values& get_enum_values();
|
||||||
|
|
||||||
|
static bool from_string(const std::string &str, T &value)
|
||||||
|
{
|
||||||
|
const t_config_enum_values &enum_keys_map = ConfigOptionEnum<T>::get_enum_values();
|
||||||
|
auto it = enum_keys_map.find(str);
|
||||||
|
if (it == enum_keys_map.end())
|
||||||
|
return false;
|
||||||
|
value = static_cast<T>(it->second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generic enum configuration value.
|
// Generic enum configuration value.
|
||||||
|
|
@ -900,7 +905,7 @@ public:
|
||||||
// What type? bool, int, string etc.
|
// What type? bool, int, string etc.
|
||||||
ConfigOptionType type = coNone;
|
ConfigOptionType type = coNone;
|
||||||
// Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
|
// Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
|
||||||
ConfigOption *default_value = nullptr;
|
const ConfigOption *default_value = nullptr;
|
||||||
|
|
||||||
// Usually empty.
|
// Usually empty.
|
||||||
// Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection,
|
// Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection,
|
||||||
|
|
@ -958,7 +963,7 @@ public:
|
||||||
std::vector<std::string> enum_labels;
|
std::vector<std::string> enum_labels;
|
||||||
// For enums (when type == coEnum). Maps enum_values to enums.
|
// For enums (when type == coEnum). Maps enum_values to enums.
|
||||||
// Initialized by ConfigOptionEnum<xxx>::get_enum_values()
|
// Initialized by ConfigOptionEnum<xxx>::get_enum_values()
|
||||||
t_config_enum_values *enum_keys_map = nullptr;
|
const t_config_enum_values *enum_keys_map = nullptr;
|
||||||
|
|
||||||
bool has_enum_value(const std::string &value) const {
|
bool has_enum_value(const std::string &value) const {
|
||||||
for (const std::string &v : enum_values)
|
for (const std::string &v : enum_values)
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ public:
|
||||||
// Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
|
// Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm.
|
||||||
double min_mm3_per_mm() const { return this->mm3_per_mm; }
|
double min_mm3_per_mm() const { return this->mm3_per_mm; }
|
||||||
Polyline as_polyline() const { return this->polyline; }
|
Polyline as_polyline() const { return this->polyline; }
|
||||||
virtual double total_volume() const { return mm3_per_mm * unscale(length()); }
|
virtual double total_volume() const { return mm3_per_mm * unscale<double>(length()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const;
|
void _inflate_collection(const Polylines &polylines, ExtrusionEntityCollection* collection) const;
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ static std::vector<coordf_t> perpendPoints(const coordf_t offset, const size_t b
|
||||||
// components that are outside these limits are set to the limits.
|
// components that are outside these limits are set to the limits.
|
||||||
static inline void trim(Pointfs &pts, coordf_t minX, coordf_t minY, coordf_t maxX, coordf_t maxY)
|
static inline void trim(Pointfs &pts, coordf_t minX, coordf_t minY, coordf_t maxX, coordf_t maxY)
|
||||||
{
|
{
|
||||||
for (Pointf &pt : pts) {
|
for (Vec2d &pt : pts) {
|
||||||
pt(0) = clamp(minX, maxX, pt(0));
|
pt(0) = clamp(minX, maxX, pt(0));
|
||||||
pt(1) = clamp(minY, maxY, pt(1));
|
pt(1) = clamp(minY, maxY, pt(1));
|
||||||
}
|
}
|
||||||
|
|
@ -66,7 +66,7 @@ static inline Pointfs zip(const std::vector<coordf_t> &x, const std::vector<coor
|
||||||
Pointfs out;
|
Pointfs out;
|
||||||
out.reserve(x.size());
|
out.reserve(x.size());
|
||||||
for (size_t i = 0; i < x.size(); ++ i)
|
for (size_t i = 0; i < x.size(); ++ i)
|
||||||
out.push_back(Pointf(x[i], y[i]));
|
out.push_back(Vec2d(x[i], y[i]));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ void FillConcentric::_fill_surface_single(
|
||||||
|
|
||||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||||
distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
|
distance = this->_adjust_solid_spacing(bounding_box.size()(0), distance);
|
||||||
this->spacing = unscale(distance);
|
this->spacing = unscale<double>(distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
Polygons loops = (Polygons)expolygon;
|
Polygons loops = (Polygons)expolygon;
|
||||||
|
|
|
||||||
|
|
@ -30,15 +30,15 @@ static inline double f(double x, double z_sin, double z_cos, bool vertical, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline Polyline make_wave(
|
static inline Polyline make_wave(
|
||||||
const std::vector<Pointf>& one_period, double width, double height, double offset, double scaleFactor,
|
const std::vector<Vec2d>& one_period, double width, double height, double offset, double scaleFactor,
|
||||||
double z_cos, double z_sin, bool vertical)
|
double z_cos, double z_sin, bool vertical)
|
||||||
{
|
{
|
||||||
std::vector<Pointf> points = one_period;
|
std::vector<Vec2d> points = one_period;
|
||||||
double period = points.back()(0);
|
double period = points.back()(0);
|
||||||
points.pop_back();
|
points.pop_back();
|
||||||
int n = points.size();
|
int n = points.size();
|
||||||
do {
|
do {
|
||||||
points.emplace_back(Pointf(points[points.size()-n](0) + period, points[points.size()-n](1)));
|
points.emplace_back(Vec2d(points[points.size()-n](0) + period, points[points.size()-n](1)));
|
||||||
} while (points.back()(0) < width);
|
} while (points.back()(0) < width);
|
||||||
points.back()(0) = width;
|
points.back()(0) = width;
|
||||||
|
|
||||||
|
|
@ -55,14 +55,14 @@ static inline Polyline make_wave(
|
||||||
return polyline;
|
return polyline;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::vector<Pointf> make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip)
|
static std::vector<Vec2d> make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip)
|
||||||
{
|
{
|
||||||
std::vector<Pointf> points;
|
std::vector<Vec2d> points;
|
||||||
double dx = M_PI_4; // very coarse spacing to begin with
|
double dx = M_PI_4; // very coarse spacing to begin with
|
||||||
double limit = std::min(2*M_PI, width);
|
double limit = std::min(2*M_PI, width);
|
||||||
for (double x = 0.; x < limit + EPSILON; x += dx) { // so the last point is there too
|
for (double x = 0.; x < limit + EPSILON; x += dx) { // so the last point is there too
|
||||||
x = std::min(x, limit);
|
x = std::min(x, limit);
|
||||||
points.emplace_back(Pointf(x,f(x, z_sin,z_cos, vertical, flip)));
|
points.emplace_back(Vec2d(x,f(x, z_sin,z_cos, vertical, flip)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we will check all internal points and in case some are too far from the line connecting its neighbours,
|
// now we will check all internal points and in case some are too far from the line connecting its neighbours,
|
||||||
|
|
@ -71,17 +71,19 @@ static std::vector<Pointf> make_one_period(double width, double scaleFactor, dou
|
||||||
for (unsigned int i=1;i<points.size()-1;++i) {
|
for (unsigned int i=1;i<points.size()-1;++i) {
|
||||||
auto& lp = points[i-1]; // left point
|
auto& lp = points[i-1]; // left point
|
||||||
auto& tp = points[i]; // this point
|
auto& tp = points[i]; // this point
|
||||||
|
Vec2d lrv = tp - lp;
|
||||||
auto& rp = points[i+1]; // right point
|
auto& rp = points[i+1]; // right point
|
||||||
// calculate distance of the point to the line:
|
// calculate distance of the point to the line:
|
||||||
double dist_mm = unscale(scaleFactor * std::abs( (rp(1) - lp(1))*tp(0) + (lp(0) - rp(0))*tp(1) + (rp(0)*lp(1) - rp(1)*lp(0)) ) / std::hypot((rp(1) - lp(1)),(lp(0) - rp(0))));
|
double dist_mm = unscale<double>(scaleFactor) * std::abs(cross2(rp, lp) - cross2(rp - lp, tp)) / lrv.norm();
|
||||||
|
|
||||||
if (dist_mm > tolerance) { // if the difference from straight line is more than this
|
if (dist_mm > tolerance) { // if the difference from straight line is more than this
|
||||||
double x = 0.5f * (points[i-1](0) + points[i](0));
|
double x = 0.5f * (points[i-1](0) + points[i](0));
|
||||||
points.emplace_back(Pointf(x, f(x, z_sin, z_cos, vertical, flip)));
|
points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip)));
|
||||||
x = 0.5f * (points[i+1](0) + points[i](0));
|
x = 0.5f * (points[i+1](0) + points[i](0));
|
||||||
points.emplace_back(Pointf(x, f(x, z_sin, z_cos, vertical, flip)));
|
points.emplace_back(Vec2d(x, f(x, z_sin, z_cos, vertical, flip)));
|
||||||
std::sort(points.begin(), points.end()); // we added the points to the end, but need them all in order
|
// we added the points to the end, but need them all in order
|
||||||
--i; // decrement i so we also check the first newly added point
|
std::sort(points.begin(), points.end(), [](const Vec2d &lhs, const Vec2d &rhs){ return lhs < rhs; });
|
||||||
|
// decrement i so we also check the first newly added point
|
||||||
|
--i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return points;
|
return points;
|
||||||
|
|
@ -107,7 +109,7 @@ static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double
|
||||||
std::swap(width,height);
|
std::swap(width,height);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Pointf> one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time
|
std::vector<Vec2d> one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time
|
||||||
Polylines result;
|
Polylines result;
|
||||||
|
|
||||||
for (double y0 = lower_bound; y0 < upper_bound+EPSILON; y0 += 2*M_PI) // creates odd polylines
|
for (double y0 = lower_bound; y0 < upper_bound+EPSILON; y0 += 2*M_PI) // creates odd polylines
|
||||||
|
|
|
||||||
|
|
@ -86,12 +86,12 @@ Pointfs FillArchimedeanChords::_generate(coord_t min_x, coord_t min_y, coord_t m
|
||||||
coordf_t r = 1;
|
coordf_t r = 1;
|
||||||
Pointfs out;
|
Pointfs out;
|
||||||
//FIXME Vojtech: If used as a solid infill, there is a gap left at the center.
|
//FIXME Vojtech: If used as a solid infill, there is a gap left at the center.
|
||||||
out.push_back(Pointf(0, 0));
|
out.push_back(Vec2d(0, 0));
|
||||||
out.push_back(Pointf(1, 0));
|
out.push_back(Vec2d(1, 0));
|
||||||
while (r < rmax) {
|
while (r < rmax) {
|
||||||
theta += 1. / r;
|
theta += 1. / r;
|
||||||
r = a + b * theta;
|
r = a + b * theta;
|
||||||
out.push_back(Pointf(r * cos(theta), r * sin(theta)));
|
out.push_back(Vec2d(r * cos(theta), r * sin(theta)));
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
@ -162,7 +162,7 @@ Pointfs FillHilbertCurve::_generate(coord_t min_x, coord_t min_y, coord_t max_x,
|
||||||
line.reserve(sz2);
|
line.reserve(sz2);
|
||||||
for (size_t i = 0; i < sz2; ++ i) {
|
for (size_t i = 0; i < sz2; ++ i) {
|
||||||
Point p = hilbert_n_to_xy(i);
|
Point p = hilbert_n_to_xy(i);
|
||||||
line.push_back(Pointf(p(0) + min_x, p(1) + min_y));
|
line.push_back(Vec2d(p(0) + min_x, p(1) + min_y));
|
||||||
}
|
}
|
||||||
return line;
|
return line;
|
||||||
}
|
}
|
||||||
|
|
@ -175,27 +175,27 @@ Pointfs FillOctagramSpiral::_generate(coord_t min_x, coord_t min_y, coord_t max_
|
||||||
coordf_t r = 0;
|
coordf_t r = 0;
|
||||||
coordf_t r_inc = sqrt(2.);
|
coordf_t r_inc = sqrt(2.);
|
||||||
Pointfs out;
|
Pointfs out;
|
||||||
out.push_back(Pointf(0, 0));
|
out.push_back(Vec2d(0, 0));
|
||||||
while (r < rmax) {
|
while (r < rmax) {
|
||||||
r += r_inc;
|
r += r_inc;
|
||||||
coordf_t rx = r / sqrt(2.);
|
coordf_t rx = r / sqrt(2.);
|
||||||
coordf_t r2 = r + rx;
|
coordf_t r2 = r + rx;
|
||||||
out.push_back(Pointf( r, 0.));
|
out.push_back(Vec2d( r, 0.));
|
||||||
out.push_back(Pointf( r2, rx));
|
out.push_back(Vec2d( r2, rx));
|
||||||
out.push_back(Pointf( rx, rx));
|
out.push_back(Vec2d( rx, rx));
|
||||||
out.push_back(Pointf( rx, r2));
|
out.push_back(Vec2d( rx, r2));
|
||||||
out.push_back(Pointf(0., r));
|
out.push_back(Vec2d(0., r));
|
||||||
out.push_back(Pointf(-rx, r2));
|
out.push_back(Vec2d(-rx, r2));
|
||||||
out.push_back(Pointf(-rx, rx));
|
out.push_back(Vec2d(-rx, rx));
|
||||||
out.push_back(Pointf(-r2, rx));
|
out.push_back(Vec2d(-r2, rx));
|
||||||
out.push_back(Pointf(-r, 0.));
|
out.push_back(Vec2d(-r, 0.));
|
||||||
out.push_back(Pointf(-r2, -rx));
|
out.push_back(Vec2d(-r2, -rx));
|
||||||
out.push_back(Pointf(-rx, -rx));
|
out.push_back(Vec2d(-rx, -rx));
|
||||||
out.push_back(Pointf(-rx, -r2));
|
out.push_back(Vec2d(-rx, -r2));
|
||||||
out.push_back(Pointf(0., -r));
|
out.push_back(Vec2d(0., -r));
|
||||||
out.push_back(Pointf( rx, -r2));
|
out.push_back(Vec2d( rx, -r2));
|
||||||
out.push_back(Pointf( rx, -rx));
|
out.push_back(Vec2d( rx, -rx));
|
||||||
out.push_back(Pointf( r2+r_inc, -rx));
|
out.push_back(Vec2d( r2+r_inc, -rx));
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ void FillRectilinear::_fill_surface_single(
|
||||||
// define flow spacing according to requested density
|
// define flow spacing according to requested density
|
||||||
if (params.density > 0.9999f && !params.dont_adjust) {
|
if (params.density > 0.9999f && !params.dont_adjust) {
|
||||||
this->_line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), this->_line_spacing);
|
this->_line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), this->_line_spacing);
|
||||||
this->spacing = unscale(this->_line_spacing);
|
this->spacing = unscale<double>(this->_line_spacing);
|
||||||
} else {
|
} else {
|
||||||
// extend bounding box so that our pattern will be aligned with other layers
|
// extend bounding box so that our pattern will be aligned with other layers
|
||||||
// Transform the reference point to the rotated coordinate system.
|
// Transform the reference point to the rotated coordinate system.
|
||||||
|
|
|
||||||
|
|
@ -792,7 +792,7 @@ bool FillRectilinear2::fill_surface_by_lines(const Surface *surface, const FillP
|
||||||
// define flow spacing according to requested density
|
// define flow spacing according to requested density
|
||||||
if (params.full_infill() && !params.dont_adjust) {
|
if (params.full_infill() && !params.dont_adjust) {
|
||||||
line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), line_spacing);
|
line_spacing = this->_adjust_solid_spacing(bounding_box.size()(0), line_spacing);
|
||||||
this->spacing = unscale(line_spacing);
|
this->spacing = unscale<double>(line_spacing);
|
||||||
} else {
|
} else {
|
||||||
// extend bounding box so that our pattern will be aligned with other layers
|
// extend bounding box so that our pattern will be aligned with other layers
|
||||||
// Transform the reference point to the rotated coordinate system.
|
// Transform the reference point to the rotated coordinate system.
|
||||||
|
|
|
||||||
|
|
@ -217,11 +217,11 @@ Point SegmentIntersection::pos() const
|
||||||
const Point &seg_start = poly.points[(this->iSegment == 0) ? poly.points.size() - 1 : this->iSegment - 1];
|
const Point &seg_start = poly.points[(this->iSegment == 0) ? poly.points.size() - 1 : this->iSegment - 1];
|
||||||
const Point &seg_end = poly.points[this->iSegment];
|
const Point &seg_end = poly.points[this->iSegment];
|
||||||
// Point, vector of the segment.
|
// Point, vector of the segment.
|
||||||
const Pointf p1(seg_start.cast<coordf_t>());
|
const Vec2d p1(seg_start.cast<coordf_t>());
|
||||||
const Pointf v1((seg_end - seg_start).cast<coordf_t>());
|
const Vec2d v1((seg_end - seg_start).cast<coordf_t>());
|
||||||
// Point, vector of this hatching line.
|
// Point, vector of this hatching line.
|
||||||
const Pointf p2(line->pos.cast<coordf_t>());
|
const Vec2d p2(line->pos.cast<coordf_t>());
|
||||||
const Pointf v2(line->dir.cast<coordf_t>());
|
const Vec2d v2(line->dir.cast<coordf_t>());
|
||||||
// Intersect the two rays.
|
// Intersect the two rays.
|
||||||
double denom = v1(0) * v2(1) - v2(0) * v1(1);
|
double denom = v1(0) * v2(1) - v2(0) * v1(1);
|
||||||
Point out;
|
Point out;
|
||||||
|
|
@ -391,7 +391,7 @@ static bool prepare_infill_hatching_segments(
|
||||||
// Full infill, adjust the line spacing to fit an integer number of lines.
|
// Full infill, adjust the line spacing to fit an integer number of lines.
|
||||||
out.line_spacing = Fill::_adjust_solid_spacing(bounding_box.size()(0), line_spacing);
|
out.line_spacing = Fill::_adjust_solid_spacing(bounding_box.size()(0), line_spacing);
|
||||||
// Report back the adjusted line spacing.
|
// Report back the adjusted line spacing.
|
||||||
fill_dir_params.spacing = float(unscale(line_spacing));
|
fill_dir_params.spacing = unscale<double>(line_spacing);
|
||||||
} else {
|
} else {
|
||||||
// Extend bounding box so that our pattern will be aligned with the other layers.
|
// Extend bounding box so that our pattern will be aligned with the other layers.
|
||||||
// Transform the reference point to the rotated coordinate system.
|
// Transform the reference point to the rotated coordinate system.
|
||||||
|
|
|
||||||
|
|
@ -1485,12 +1485,13 @@ namespace Slic3r {
|
||||||
stl_facet& facet = stl.facet_start[i];
|
stl_facet& facet = stl.facet_start[i];
|
||||||
for (unsigned int v = 0; v < 3; ++v)
|
for (unsigned int v = 0; v < 3; ++v)
|
||||||
{
|
{
|
||||||
::memcpy((void*)&facet.vertex[v].x, (const void*)&geometry.vertices[geometry.triangles[src_start_id + ii + v] * 3], 3 * sizeof(float));
|
::memcpy(facet.vertex[v].data(), (const void*)&geometry.vertices[geometry.triangles[src_start_id + ii + v] * 3], 3 * sizeof(float));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stl_get_size(&stl);
|
stl_get_size(&stl);
|
||||||
volume->mesh.repair();
|
volume->mesh.repair();
|
||||||
|
volume->calculate_convex_hull();
|
||||||
|
|
||||||
// apply volume's name and config data
|
// apply volume's name and config data
|
||||||
for (const Metadata& metadata : volume_data.metadata)
|
for (const Metadata& metadata : volume_data.metadata)
|
||||||
|
|
@ -1844,9 +1845,9 @@ namespace Slic3r {
|
||||||
for (int i = 0; i < stl.stats.shared_vertices; ++i)
|
for (int i = 0; i < stl.stats.shared_vertices; ++i)
|
||||||
{
|
{
|
||||||
stream << " <" << VERTEX_TAG << " ";
|
stream << " <" << VERTEX_TAG << " ";
|
||||||
stream << "x=\"" << stl.v_shared[i].x << "\" ";
|
stream << "x=\"" << stl.v_shared[i](0) << "\" ";
|
||||||
stream << "y=\"" << stl.v_shared[i].y << "\" ";
|
stream << "y=\"" << stl.v_shared[i](1) << "\" ";
|
||||||
stream << "z=\"" << stl.v_shared[i].z << "\" />\n";
|
stream << "z=\"" << stl.v_shared[i](2) << "\" />\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -402,10 +402,11 @@ void AMFParserContext::endElement(const char * /* name */)
|
||||||
for (size_t i = 0; i < m_volume_facets.size();) {
|
for (size_t i = 0; i < m_volume_facets.size();) {
|
||||||
stl_facet &facet = stl.facet_start[i/3];
|
stl_facet &facet = stl.facet_start[i/3];
|
||||||
for (unsigned int v = 0; v < 3; ++ v)
|
for (unsigned int v = 0; v < 3; ++ v)
|
||||||
memcpy(&facet.vertex[v].x, &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float));
|
memcpy(facet.vertex[v].data(), &m_object_vertices[m_volume_facets[i ++] * 3], 3 * sizeof(float));
|
||||||
}
|
}
|
||||||
stl_get_size(&stl);
|
stl_get_size(&stl);
|
||||||
m_volume->mesh.repair();
|
m_volume->mesh.repair();
|
||||||
|
m_volume->calculate_convex_hull();
|
||||||
m_volume_facets.clear();
|
m_volume_facets.clear();
|
||||||
m_volume = nullptr;
|
m_volume = nullptr;
|
||||||
break;
|
break;
|
||||||
|
|
@ -760,9 +761,9 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c
|
||||||
for (size_t i = 0; i < stl.stats.shared_vertices; ++ i) {
|
for (size_t i = 0; i < stl.stats.shared_vertices; ++ i) {
|
||||||
stream << " <vertex>\n";
|
stream << " <vertex>\n";
|
||||||
stream << " <coordinates>\n";
|
stream << " <coordinates>\n";
|
||||||
stream << " <x>" << stl.v_shared[i].x << "</x>\n";
|
stream << " <x>" << stl.v_shared[i](0) << "</x>\n";
|
||||||
stream << " <y>" << stl.v_shared[i].y << "</y>\n";
|
stream << " <y>" << stl.v_shared[i](1) << "</y>\n";
|
||||||
stream << " <z>" << stl.v_shared[i].z << "</z>\n";
|
stream << " <z>" << stl.v_shared[i](2) << "</z>\n";
|
||||||
stream << " </coordinates>\n";
|
stream << " </coordinates>\n";
|
||||||
stream << " </vertex>\n";
|
stream << " </vertex>\n";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,14 +57,14 @@ bool load_obj(const char *path, Model *model, const char *object_name_in)
|
||||||
continue;
|
continue;
|
||||||
stl_facet &facet = stl.facet_start[i_face ++];
|
stl_facet &facet = stl.facet_start[i_face ++];
|
||||||
size_t num_normals = 0;
|
size_t num_normals = 0;
|
||||||
stl_normal normal = { 0.f };
|
stl_normal normal(stl_normal::Zero());
|
||||||
for (unsigned int v = 0; v < 3; ++ v) {
|
for (unsigned int v = 0; v < 3; ++ v) {
|
||||||
const ObjParser::ObjVertex &vertex = data.vertices[i++];
|
const ObjParser::ObjVertex &vertex = data.vertices[i++];
|
||||||
memcpy(&facet.vertex[v].x, &data.coordinates[vertex.coordIdx*4], 3 * sizeof(float));
|
memcpy(facet.vertex[v].data(), &data.coordinates[vertex.coordIdx*4], 3 * sizeof(float));
|
||||||
if (vertex.normalIdx != -1) {
|
if (vertex.normalIdx != -1) {
|
||||||
normal.x += data.normals[vertex.normalIdx*3];
|
normal(0) += data.normals[vertex.normalIdx*3];
|
||||||
normal.y += data.normals[vertex.normalIdx*3+1];
|
normal(1) += data.normals[vertex.normalIdx*3+1];
|
||||||
normal.z += data.normals[vertex.normalIdx*3+2];
|
normal(2) += data.normals[vertex.normalIdx*3+2];
|
||||||
++ num_normals;
|
++ num_normals;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -74,33 +74,27 @@ bool load_obj(const char *path, Model *model, const char *object_name_in)
|
||||||
facet2.vertex[0] = facet.vertex[0];
|
facet2.vertex[0] = facet.vertex[0];
|
||||||
facet2.vertex[1] = facet.vertex[2];
|
facet2.vertex[1] = facet.vertex[2];
|
||||||
const ObjParser::ObjVertex &vertex = data.vertices[i++];
|
const ObjParser::ObjVertex &vertex = data.vertices[i++];
|
||||||
memcpy(&facet2.vertex[2].x, &data.coordinates[vertex.coordIdx * 4], 3 * sizeof(float));
|
memcpy(facet2.vertex[2].data(), &data.coordinates[vertex.coordIdx * 4], 3 * sizeof(float));
|
||||||
if (vertex.normalIdx != -1) {
|
if (vertex.normalIdx != -1) {
|
||||||
normal.x += data.normals[vertex.normalIdx*3];
|
normal(0) += data.normals[vertex.normalIdx*3];
|
||||||
normal.y += data.normals[vertex.normalIdx*3+1];
|
normal(1) += data.normals[vertex.normalIdx*3+1];
|
||||||
normal.z += data.normals[vertex.normalIdx*3+2];
|
normal(2) += data.normals[vertex.normalIdx*3+2];
|
||||||
++ num_normals;
|
++ num_normals;
|
||||||
}
|
}
|
||||||
if (num_normals == 4) {
|
if (num_normals == 4) {
|
||||||
// Normalize an average normal of a quad.
|
// Normalize an average normal of a quad.
|
||||||
float len = sqrt(facet.normal.x*facet.normal.x + facet.normal.y*facet.normal.y + facet.normal.z*facet.normal.z);
|
float len = facet.normal.norm();
|
||||||
if (len > EPSILON) {
|
if (len > EPSILON) {
|
||||||
normal.x /= len;
|
normal /= len;
|
||||||
normal.y /= len;
|
|
||||||
normal.z /= len;
|
|
||||||
facet.normal = normal;
|
facet.normal = normal;
|
||||||
facet2.normal = normal;
|
facet2.normal = normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (num_normals == 3) {
|
} else if (num_normals == 3) {
|
||||||
// Normalize an average normal of a triangle.
|
// Normalize an average normal of a triangle.
|
||||||
float len = sqrt(facet.normal.x*facet.normal.x + facet.normal.y*facet.normal.y + facet.normal.z*facet.normal.z);
|
float len = facet.normal.norm();
|
||||||
if (len > EPSILON) {
|
if (len > EPSILON)
|
||||||
normal.x /= len;
|
facet.normal = normal / len;
|
||||||
normal.y /= len;
|
|
||||||
normal.z /= len;
|
|
||||||
facet.normal = normal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stl_get_size(&stl);
|
stl_get_size(&stl);
|
||||||
|
|
|
||||||
|
|
@ -166,7 +166,7 @@ bool load_prus(const char *path, Model *model)
|
||||||
float trafo[3][4] = { 0 };
|
float trafo[3][4] = { 0 };
|
||||||
double instance_rotation = 0.;
|
double instance_rotation = 0.;
|
||||||
double instance_scaling_factor = 1.f;
|
double instance_scaling_factor = 1.f;
|
||||||
Pointf instance_offset(0., 0.);
|
Vec2d instance_offset(0., 0.);
|
||||||
bool trafo_set = false;
|
bool trafo_set = false;
|
||||||
unsigned int group_id = (unsigned int)-1;
|
unsigned int group_id = (unsigned int)-1;
|
||||||
unsigned int extruder_id = (unsigned int)-1;
|
unsigned int extruder_id = (unsigned int)-1;
|
||||||
|
|
@ -260,8 +260,8 @@ bool load_prus(const char *path, Model *model)
|
||||||
mesh.repair();
|
mesh.repair();
|
||||||
// Transform the model.
|
// Transform the model.
|
||||||
stl_transform(&stl, &trafo[0][0]);
|
stl_transform(&stl, &trafo[0][0]);
|
||||||
if (std::abs(stl.stats.min.z) < EPSILON)
|
if (std::abs(stl.stats.min(2)) < EPSILON)
|
||||||
stl.stats.min.z = 0.;
|
stl.stats.min(2) = 0.;
|
||||||
// Add a mesh to a model.
|
// Add a mesh to a model.
|
||||||
if (mesh.facets_count() > 0)
|
if (mesh.facets_count() > 0)
|
||||||
mesh_valid = true;
|
mesh_valid = true;
|
||||||
|
|
@ -309,11 +309,11 @@ bool load_prus(const char *path, Model *model)
|
||||||
assert(res_normal == 3);
|
assert(res_normal == 3);
|
||||||
int res_outer_loop = line_reader.next_line_scanf(" outer loop");
|
int res_outer_loop = line_reader.next_line_scanf(" outer loop");
|
||||||
assert(res_outer_loop == 0);
|
assert(res_outer_loop == 0);
|
||||||
int res_vertex1 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[0].x, &facet.vertex[0].y, &facet.vertex[0].z);
|
int res_vertex1 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[0](0), &facet.vertex[0](1), &facet.vertex[0](2));
|
||||||
assert(res_vertex1 == 3);
|
assert(res_vertex1 == 3);
|
||||||
int res_vertex2 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[1].x, &facet.vertex[1].y, &facet.vertex[1].z);
|
int res_vertex2 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[1](0), &facet.vertex[1](1), &facet.vertex[1](2));
|
||||||
assert(res_vertex2 == 3);
|
assert(res_vertex2 == 3);
|
||||||
int res_vertex3 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[2].x, &facet.vertex[2].y, &facet.vertex[2].z);
|
int res_vertex3 = line_reader.next_line_scanf(" vertex %f %f %f", &facet.vertex[2](0), &facet.vertex[2](1), &facet.vertex[2](2));
|
||||||
assert(res_vertex3 == 3);
|
assert(res_vertex3 == 3);
|
||||||
int res_endloop = line_reader.next_line_scanf(" endloop");
|
int res_endloop = line_reader.next_line_scanf(" endloop");
|
||||||
assert(res_endloop == 0);
|
assert(res_endloop == 0);
|
||||||
|
|
@ -324,9 +324,9 @@ bool load_prus(const char *path, Model *model)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
|
// The facet normal has been parsed as a single string as to workaround for not a numbers in the normal definition.
|
||||||
if (sscanf(normal_buf[0], "%f", &facet.normal.x) != 1 ||
|
if (sscanf(normal_buf[0], "%f", &facet.normal(0)) != 1 ||
|
||||||
sscanf(normal_buf[1], "%f", &facet.normal.y) != 1 ||
|
sscanf(normal_buf[1], "%f", &facet.normal(1)) != 1 ||
|
||||||
sscanf(normal_buf[2], "%f", &facet.normal.z) != 1) {
|
sscanf(normal_buf[2], "%f", &facet.normal(2)) != 1) {
|
||||||
// Normal was mangled. Maybe denormals or "not a number" were stored?
|
// Normal was mangled. Maybe denormals or "not a number" were stored?
|
||||||
// Just reset the normal and silently ignore it.
|
// Just reset the normal and silently ignore it.
|
||||||
memset(&facet.normal, 0, sizeof(facet.normal));
|
memset(&facet.normal, 0, sizeof(facet.normal));
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,7 @@ std::string OozePrevention::pre_toolchange(GCode &gcodegen)
|
||||||
// move to the nearest standby point
|
// move to the nearest standby point
|
||||||
if (!this->standby_points.empty()) {
|
if (!this->standby_points.empty()) {
|
||||||
// get current position in print coordinates
|
// get current position in print coordinates
|
||||||
Pointf3 writer_pos = gcodegen.writer().get_position();
|
Vec3d writer_pos = gcodegen.writer().get_position();
|
||||||
Point pos = Point::new_scale(writer_pos(0), writer_pos(1));
|
Point pos = Point::new_scale(writer_pos(0), writer_pos(1));
|
||||||
|
|
||||||
// find standby point
|
// find standby point
|
||||||
|
|
@ -74,7 +74,7 @@ std::string OozePrevention::pre_toolchange(GCode &gcodegen)
|
||||||
/* We don't call gcodegen.travel_to() because we don't need retraction (it was already
|
/* We don't call gcodegen.travel_to() because we don't need retraction (it was already
|
||||||
triggered by the caller) nor avoid_crossing_perimeters and also because the coordinates
|
triggered by the caller) nor avoid_crossing_perimeters and also because the coordinates
|
||||||
of the destination point must not be transformed by origin nor current extruder offset. */
|
of the destination point must not be transformed by origin nor current extruder offset. */
|
||||||
gcode += gcodegen.writer().travel_to_xy(Pointf::new_unscale(standby_point),
|
gcode += gcodegen.writer().travel_to_xy(unscale(standby_point),
|
||||||
"move to standby position");
|
"move to standby position");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -207,7 +207,7 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T
|
||||||
check_add_eol(gcode);
|
check_add_eol(gcode);
|
||||||
}
|
}
|
||||||
// A phony move to the end position at the wipe tower.
|
// A phony move to the end position at the wipe tower.
|
||||||
gcodegen.writer().travel_to_xy(Pointf(end_pos.x, end_pos.y));
|
gcodegen.writer().travel_to_xy(Vec2d(end_pos.x, end_pos.y));
|
||||||
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos));
|
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, end_pos));
|
||||||
|
|
||||||
// Prepare a future wipe.
|
// Prepare a future wipe.
|
||||||
|
|
@ -293,7 +293,7 @@ std::string WipeTowerIntegration::prime(GCode &gcodegen)
|
||||||
gcodegen.writer().toolchange(current_extruder_id);
|
gcodegen.writer().toolchange(current_extruder_id);
|
||||||
gcodegen.placeholder_parser().set("current_extruder", current_extruder_id);
|
gcodegen.placeholder_parser().set("current_extruder", current_extruder_id);
|
||||||
// A phony move to the end position at the wipe tower.
|
// A phony move to the end position at the wipe tower.
|
||||||
gcodegen.writer().travel_to_xy(Pointf(m_priming.end_pos.x, m_priming.end_pos.y));
|
gcodegen.writer().travel_to_xy(Vec2d(m_priming.end_pos.x, m_priming.end_pos.y));
|
||||||
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, m_priming.end_pos));
|
gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, m_priming.end_pos));
|
||||||
// Prepare a future wipe.
|
// Prepare a future wipe.
|
||||||
gcodegen.m_wipe.path.points.clear();
|
gcodegen.m_wipe.path.points.clear();
|
||||||
|
|
@ -783,7 +783,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||||
Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points);
|
Polygon outer_skirt = Slic3r::Geometry::convex_hull(skirt_points);
|
||||||
Polygons skirts;
|
Polygons skirts;
|
||||||
for (unsigned int extruder_id : print.extruders()) {
|
for (unsigned int extruder_id : print.extruders()) {
|
||||||
const Pointf &extruder_offset = print.config.extruder_offset.get_at(extruder_id);
|
const Vec2d &extruder_offset = print.config.extruder_offset.get_at(extruder_id);
|
||||||
Polygon s(outer_skirt);
|
Polygon s(outer_skirt);
|
||||||
s.translate(Point::new_scale(- extruder_offset(0), - extruder_offset(1)));
|
s.translate(Point::new_scale(- extruder_offset(0), - extruder_offset(1)));
|
||||||
skirts.emplace_back(std::move(s));
|
skirts.emplace_back(std::move(s));
|
||||||
|
|
@ -831,7 +831,7 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data)
|
||||||
final_extruder_id = tool_ordering.last_extruder();
|
final_extruder_id = tool_ordering.last_extruder();
|
||||||
assert(final_extruder_id != (unsigned int)-1);
|
assert(final_extruder_id != (unsigned int)-1);
|
||||||
}
|
}
|
||||||
this->set_origin(unscale(copy(0)), unscale(copy(1)));
|
this->set_origin(unscale(copy));
|
||||||
if (finished_objects > 0) {
|
if (finished_objects > 0) {
|
||||||
// Move to the origin position for the copy we're going to print.
|
// Move to the origin position for the copy we're going to print.
|
||||||
// This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
|
// This happens before Z goes down to layer 0 again, so that no collision happens hopefully.
|
||||||
|
|
@ -1547,7 +1547,7 @@ void GCode::process_layer(
|
||||||
if (m_last_obj_copy != this_object_copy)
|
if (m_last_obj_copy != this_object_copy)
|
||||||
m_avoid_crossing_perimeters.use_external_mp_once = true;
|
m_avoid_crossing_perimeters.use_external_mp_once = true;
|
||||||
m_last_obj_copy = this_object_copy;
|
m_last_obj_copy = this_object_copy;
|
||||||
this->set_origin(unscale(copy(0)), unscale(copy(1)));
|
this->set_origin(unscale(copy));
|
||||||
if (object_by_extruder.support != nullptr && !print_wipe_extrusions) {
|
if (object_by_extruder.support != nullptr && !print_wipe_extrusions) {
|
||||||
m_layer = layers[layer_id].support_layer;
|
m_layer = layers[layer_id].support_layer;
|
||||||
gcode += this->extrude_support(
|
gcode += this->extrude_support(
|
||||||
|
|
@ -1632,7 +1632,7 @@ void GCode::set_extruders(const std::vector<unsigned int> &extruder_ids)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCode::set_origin(const Pointf &pointf)
|
void GCode::set_origin(const Vec2d &pointf)
|
||||||
{
|
{
|
||||||
// if origin increases (goes towards right), last_pos decreases because it goes towards left
|
// if origin increases (goes towards right), last_pos decreases because it goes towards left
|
||||||
const Point translate(
|
const Point translate(
|
||||||
|
|
@ -2618,24 +2618,21 @@ std::string GCode::set_extruder(unsigned int extruder_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert a model-space scaled point into G-code coordinates
|
// convert a model-space scaled point into G-code coordinates
|
||||||
Pointf GCode::point_to_gcode(const Point &point) const
|
Vec2d GCode::point_to_gcode(const Point &point) const
|
||||||
{
|
{
|
||||||
Pointf extruder_offset = EXTRUDER_CONFIG(extruder_offset);
|
Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
|
||||||
return Pointf(
|
return unscale(point) + m_origin - extruder_offset;
|
||||||
unscale(point(0)) + m_origin(0) - extruder_offset(0),
|
|
||||||
unscale(point(1)) + m_origin(1) - extruder_offset(1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert a model-space scaled point into G-code coordinates
|
// convert a model-space scaled point into G-code coordinates
|
||||||
Point GCode::gcode_to_point(const Pointf &point) const
|
Point GCode::gcode_to_point(const Vec2d &point) const
|
||||||
{
|
{
|
||||||
Pointf extruder_offset = EXTRUDER_CONFIG(extruder_offset);
|
Vec2d extruder_offset = EXTRUDER_CONFIG(extruder_offset);
|
||||||
return Point(
|
return Point(
|
||||||
scale_(point(0) - m_origin(0) + extruder_offset(0)),
|
scale_(point(0) - m_origin(0) + extruder_offset(0)),
|
||||||
scale_(point(1) - m_origin(1) + extruder_offset(1)));
|
scale_(point(1) - m_origin(1) + extruder_offset(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
|
// Goes through by_region std::vector and returns reference to a subvector of entities, that are to be printed
|
||||||
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
|
// during infill/perimeter wiping, or normally (depends on wiping_entities parameter)
|
||||||
// Returns a reference to member to avoid copying.
|
// Returns a reference to member to avoid copying.
|
||||||
|
|
|
||||||
|
|
@ -125,6 +125,7 @@ private:
|
||||||
class GCode {
|
class GCode {
|
||||||
public:
|
public:
|
||||||
GCode() :
|
GCode() :
|
||||||
|
m_origin(Vec2d::Zero()),
|
||||||
m_enable_loop_clipping(true),
|
m_enable_loop_clipping(true),
|
||||||
m_enable_cooling_markers(false),
|
m_enable_cooling_markers(false),
|
||||||
m_enable_extrusion_role_markers(false),
|
m_enable_extrusion_role_markers(false),
|
||||||
|
|
@ -152,12 +153,12 @@ public:
|
||||||
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
|
void do_export(Print *print, const char *path, GCodePreviewData *preview_data = nullptr);
|
||||||
|
|
||||||
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
// Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests.
|
||||||
const Pointf& origin() const { return m_origin; }
|
const Vec2d& origin() const { return m_origin; }
|
||||||
void set_origin(const Pointf &pointf);
|
void set_origin(const Vec2d &pointf);
|
||||||
void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Pointf(x, y)); }
|
void set_origin(const coordf_t x, const coordf_t y) { this->set_origin(Vec2d(x, y)); }
|
||||||
const Point& last_pos() const { return m_last_pos; }
|
const Point& last_pos() const { return m_last_pos; }
|
||||||
Pointf point_to_gcode(const Point &point) const;
|
Vec2d point_to_gcode(const Point &point) const;
|
||||||
Point gcode_to_point(const Pointf &point) const;
|
Point gcode_to_point(const Vec2d &point) const;
|
||||||
const FullPrintConfig &config() const { return m_config; }
|
const FullPrintConfig &config() const { return m_config; }
|
||||||
const Layer* layer() const { return m_layer; }
|
const Layer* layer() const { return m_layer; }
|
||||||
GCodeWriter& writer() { return m_writer; }
|
GCodeWriter& writer() { return m_writer; }
|
||||||
|
|
@ -258,7 +259,7 @@ protected:
|
||||||
/* Origin of print coordinates expressed in unscaled G-code coordinates.
|
/* Origin of print coordinates expressed in unscaled G-code coordinates.
|
||||||
This affects the input arguments supplied to the extrude*() and travel_to()
|
This affects the input arguments supplied to the extrude*() and travel_to()
|
||||||
methods. */
|
methods. */
|
||||||
Pointf m_origin;
|
Vec2d m_origin;
|
||||||
FullPrintConfig m_config;
|
FullPrintConfig m_config;
|
||||||
GCodeWriter m_writer;
|
GCodeWriter m_writer;
|
||||||
PlaceholderParser m_placeholder_parser;
|
PlaceholderParser m_placeholder_parser;
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ static const float MMMIN_TO_MMSEC = 1.0f / 60.0f;
|
||||||
static const float INCHES_TO_MM = 25.4f;
|
static const float INCHES_TO_MM = 25.4f;
|
||||||
static const float DEFAULT_FEEDRATE = 0.0f;
|
static const float DEFAULT_FEEDRATE = 0.0f;
|
||||||
static const unsigned int DEFAULT_EXTRUDER_ID = 0;
|
static const unsigned int DEFAULT_EXTRUDER_ID = 0;
|
||||||
static const Slic3r::Pointf3 DEFAULT_START_POSITION = Slic3r::Pointf3(0.0f, 0.0f, 0.0f);
|
static const Slic3r::Vec3d DEFAULT_START_POSITION = Slic3r::Vec3d(0.0f, 0.0f, 0.0f);
|
||||||
static const float DEFAULT_START_EXTRUSION = 0.0f;
|
static const float DEFAULT_START_EXTRUSION = 0.0f;
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
@ -71,7 +71,7 @@ bool GCodeAnalyzer::Metadata::operator != (const GCodeAnalyzer::Metadata& other)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder)
|
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder)
|
||||||
: type(type)
|
: type(type)
|
||||||
, data(extrusion_role, extruder_id, mm3_per_mm, width, height, feedrate)
|
, data(extrusion_role, extruder_id, mm3_per_mm, width, height, feedrate)
|
||||||
, start_position(start_position)
|
, start_position(start_position)
|
||||||
|
|
@ -80,7 +80,7 @@ GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusi
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder)
|
GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder)
|
||||||
: type(type)
|
: type(type)
|
||||||
, data(data)
|
, data(data)
|
||||||
, start_position(start_position)
|
, start_position(start_position)
|
||||||
|
|
@ -587,12 +587,12 @@ void GCodeAnalyzer::_reset_axes_position()
|
||||||
::memset((void*)m_state.position, 0, Num_Axis * sizeof(float));
|
::memset((void*)m_state.position, 0, Num_Axis * sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeAnalyzer::_set_start_position(const Pointf3& position)
|
void GCodeAnalyzer::_set_start_position(const Vec3d& position)
|
||||||
{
|
{
|
||||||
m_state.start_position = position;
|
m_state.start_position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Pointf3& GCodeAnalyzer::_get_start_position() const
|
const Vec3d& GCodeAnalyzer::_get_start_position() const
|
||||||
{
|
{
|
||||||
return m_state.start_position;
|
return m_state.start_position;
|
||||||
}
|
}
|
||||||
|
|
@ -612,9 +612,9 @@ float GCodeAnalyzer::_get_delta_extrusion() const
|
||||||
return _get_axis_position(E) - m_state.start_extrusion;
|
return _get_axis_position(E) - m_state.start_extrusion;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pointf3 GCodeAnalyzer::_get_end_position() const
|
Vec3d GCodeAnalyzer::_get_end_position() const
|
||||||
{
|
{
|
||||||
return Pointf3(m_state.position[X], m_state.position[Y], m_state.position[Z]);
|
return Vec3d(m_state.position[X], m_state.position[Y], m_state.position[Z]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type)
|
void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type)
|
||||||
|
|
@ -673,7 +673,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
|
||||||
Metadata data;
|
Metadata data;
|
||||||
float z = FLT_MAX;
|
float z = FLT_MAX;
|
||||||
Polyline polyline;
|
Polyline polyline;
|
||||||
Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX);
|
Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||||
float volumetric_rate = FLT_MAX;
|
float volumetric_rate = FLT_MAX;
|
||||||
GCodePreviewData::Range height_range;
|
GCodePreviewData::Range height_range;
|
||||||
GCodePreviewData::Range width_range;
|
GCodePreviewData::Range width_range;
|
||||||
|
|
@ -742,7 +742,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Polyline3 polyline;
|
Polyline3 polyline;
|
||||||
Pointf3 position(FLT_MAX, FLT_MAX, FLT_MAX);
|
Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||||
GCodePreviewData::Travel::EType type = GCodePreviewData::Travel::Num_Types;
|
GCodePreviewData::Travel::EType type = GCodePreviewData::Travel::Num_Types;
|
||||||
GCodePreviewData::Travel::Polyline::EDirection direction = GCodePreviewData::Travel::Polyline::Num_Directions;
|
GCodePreviewData::Travel::Polyline::EDirection direction = GCodePreviewData::Travel::Polyline::Num_Directions;
|
||||||
float feedrate = FLT_MAX;
|
float feedrate = FLT_MAX;
|
||||||
|
|
@ -768,12 +768,12 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data)
|
||||||
polyline = Polyline3();
|
polyline = Polyline3();
|
||||||
|
|
||||||
// add both vertices of the move
|
// add both vertices of the move
|
||||||
polyline.append(Point3(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())));
|
polyline.append(Vec3crd(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z())));
|
||||||
polyline.append(Point3(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z())));
|
polyline.append(Vec3crd(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z())));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// append end vertex of the move to current polyline
|
// append end vertex of the move to current polyline
|
||||||
polyline.append(Point3(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z())));
|
polyline.append(Vec3crd(scale_(move.end_position.x()), scale_(move.end_position.y()), scale_(move.end_position.z())));
|
||||||
|
|
||||||
// update current values
|
// update current values
|
||||||
position = move.end_position;
|
position = move.end_position;
|
||||||
|
|
@ -804,7 +804,7 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da
|
||||||
for (const GCodeMove& move : retraction_moves->second)
|
for (const GCodeMove& move : retraction_moves->second)
|
||||||
{
|
{
|
||||||
// store position
|
// store position
|
||||||
Point3 position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
|
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
|
||||||
preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height);
|
preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -818,7 +818,7 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_
|
||||||
for (const GCodeMove& move : unretraction_moves->second)
|
for (const GCodeMove& move : unretraction_moves->second)
|
||||||
{
|
{
|
||||||
// store position
|
// store position
|
||||||
Point3 position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
|
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
|
||||||
preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height);
|
preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,12 +75,12 @@ public:
|
||||||
|
|
||||||
EType type;
|
EType type;
|
||||||
Metadata data;
|
Metadata data;
|
||||||
Pointf3 start_position;
|
Vec3d start_position;
|
||||||
Pointf3 end_position;
|
Vec3d end_position;
|
||||||
float delta_extruder;
|
float delta_extruder;
|
||||||
|
|
||||||
GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder);
|
GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder);
|
||||||
GCodeMove(EType type, const Metadata& data, const Pointf3& start_position, const Pointf3& end_position, float delta_extruder);
|
GCodeMove(EType type, const Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<GCodeMove> GCodeMovesList;
|
typedef std::vector<GCodeMove> GCodeMovesList;
|
||||||
|
|
@ -93,7 +93,7 @@ private:
|
||||||
EPositioningType global_positioning_type;
|
EPositioningType global_positioning_type;
|
||||||
EPositioningType e_local_positioning_type;
|
EPositioningType e_local_positioning_type;
|
||||||
Metadata data;
|
Metadata data;
|
||||||
Pointf3 start_position;
|
Vec3d start_position = Vec3d::Zero();
|
||||||
float start_extrusion;
|
float start_extrusion;
|
||||||
float position[Num_Axis];
|
float position[Num_Axis];
|
||||||
};
|
};
|
||||||
|
|
@ -206,15 +206,15 @@ private:
|
||||||
// Sets axes position to zero
|
// Sets axes position to zero
|
||||||
void _reset_axes_position();
|
void _reset_axes_position();
|
||||||
|
|
||||||
void _set_start_position(const Pointf3& position);
|
void _set_start_position(const Vec3d& position);
|
||||||
const Pointf3& _get_start_position() const;
|
const Vec3d& _get_start_position() const;
|
||||||
|
|
||||||
void _set_start_extrusion(float extrusion);
|
void _set_start_extrusion(float extrusion);
|
||||||
float _get_start_extrusion() const;
|
float _get_start_extrusion() const;
|
||||||
float _get_delta_extrusion() const;
|
float _get_delta_extrusion() const;
|
||||||
|
|
||||||
// Returns current xyz position (from m_state.position[])
|
// Returns current xyz position (from m_state.position[])
|
||||||
Pointf3 _get_end_position() const;
|
Vec3d _get_end_position() const;
|
||||||
|
|
||||||
// Adds a new move with the given data
|
// Adds a new move with the given data
|
||||||
void _store_move(GCodeMove::EType type);
|
void _store_move(GCodeMove::EType type);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ CoolingBuffer::CoolingBuffer(GCode &gcodegen) : m_gcodegen(gcodegen), m_current_
|
||||||
void CoolingBuffer::reset()
|
void CoolingBuffer::reset()
|
||||||
{
|
{
|
||||||
m_current_pos.assign(5, 0.f);
|
m_current_pos.assign(5, 0.f);
|
||||||
Pointf3 pos = m_gcodegen.writer().get_position();
|
Vec3d pos = m_gcodegen.writer().get_position();
|
||||||
m_current_pos[0] = float(pos(0));
|
m_current_pos[0] = float(pos(0));
|
||||||
m_current_pos[1] = float(pos(1));
|
m_current_pos[1] = float(pos(1));
|
||||||
m_current_pos[2] = float(pos(2));
|
m_current_pos[2] = float(pos(2));
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ void GCodePreviewData::Travel::set_default()
|
||||||
|
|
||||||
const GCodePreviewData::Color GCodePreviewData::Retraction::Default_Color = GCodePreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f);
|
const GCodePreviewData::Color GCodePreviewData::Retraction::Default_Color = GCodePreviewData::Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
|
||||||
GCodePreviewData::Retraction::Position::Position(const Point3& position, float width, float height)
|
GCodePreviewData::Retraction::Position::Position(const Vec3crd& position, float width, float height)
|
||||||
: position(position)
|
: position(position)
|
||||||
, width(width)
|
, width(width)
|
||||||
, height(height)
|
, height(height)
|
||||||
|
|
|
||||||
|
|
@ -151,11 +151,11 @@ public:
|
||||||
|
|
||||||
struct Position
|
struct Position
|
||||||
{
|
{
|
||||||
Point3 position;
|
Vec3crd position;
|
||||||
float width;
|
float width;
|
||||||
float height;
|
float height;
|
||||||
|
|
||||||
Position(const Point3& position, float width, float height);
|
Position(const Vec3crd& position, float width, float height);
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Position> PositionsList;
|
typedef std::vector<Position> PositionsList;
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionPath &extrusio
|
||||||
BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width));
|
BoundingBox bbox = extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width));
|
||||||
BoundingBoxf bboxf;
|
BoundingBoxf bboxf;
|
||||||
if (! empty(bbox)) {
|
if (! empty(bbox)) {
|
||||||
bboxf.min = Pointf::new_unscale(bbox.min);
|
bboxf.min = unscale(bbox.min);
|
||||||
bboxf.max = Pointf::new_unscale(bbox.max);
|
bboxf.max = unscale(bbox.max);
|
||||||
bboxf.defined = true;
|
bboxf.defined = true;
|
||||||
}
|
}
|
||||||
return bboxf;
|
return bboxf;
|
||||||
|
|
@ -46,8 +46,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionLoop &extrusio
|
||||||
bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
|
bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
|
||||||
BoundingBoxf bboxf;
|
BoundingBoxf bboxf;
|
||||||
if (! empty(bbox)) {
|
if (! empty(bbox)) {
|
||||||
bboxf.min = Pointf::new_unscale(bbox.min);
|
bboxf.min = unscale(bbox.min);
|
||||||
bboxf.max = Pointf::new_unscale(bbox.max);
|
bboxf.max = unscale(bbox.max);
|
||||||
bboxf.defined = true;
|
bboxf.defined = true;
|
||||||
}
|
}
|
||||||
return bboxf;
|
return bboxf;
|
||||||
|
|
@ -60,8 +60,8 @@ static inline BoundingBoxf extrusionentity_extents(const ExtrusionMultiPath &ext
|
||||||
bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
|
bbox.merge(extrusion_polyline_extents(extrusion_path.polyline, scale_(0.5 * extrusion_path.width)));
|
||||||
BoundingBoxf bboxf;
|
BoundingBoxf bboxf;
|
||||||
if (! empty(bbox)) {
|
if (! empty(bbox)) {
|
||||||
bboxf.min = Pointf::new_unscale(bbox.min);
|
bboxf.min = unscale(bbox.min);
|
||||||
bboxf.max = Pointf::new_unscale(bbox.max);
|
bboxf.max = unscale(bbox.max);
|
||||||
bboxf.defined = true;
|
bboxf.defined = true;
|
||||||
}
|
}
|
||||||
return bboxf;
|
return bboxf;
|
||||||
|
|
@ -123,7 +123,7 @@ BoundingBoxf get_print_object_extrusions_extents(const PrintObject &print_object
|
||||||
bbox_this.merge(extrusionentity_extents(extrusion_entity));
|
bbox_this.merge(extrusionentity_extents(extrusion_entity));
|
||||||
for (const Point &offset : print_object._shifted_copies) {
|
for (const Point &offset : print_object._shifted_copies) {
|
||||||
BoundingBoxf bbox_translated(bbox_this);
|
BoundingBoxf bbox_translated(bbox_this);
|
||||||
bbox_translated.translate(Pointf::new_unscale(offset));
|
bbox_translated.translate(unscale(offset));
|
||||||
bbox.merge(bbox_translated);
|
bbox.merge(bbox_translated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -136,8 +136,9 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_
|
||||||
{
|
{
|
||||||
// Wipe tower extrusions are saved as if the tower was at the origin with no rotation
|
// Wipe tower extrusions are saved as if the tower was at the origin with no rotation
|
||||||
// We need to get position and angle of the wipe tower to transform them to actual position.
|
// We need to get position and angle of the wipe tower to transform them to actual position.
|
||||||
Pointf wipe_tower_pos(print.config.wipe_tower_x.value, print.config.wipe_tower_y.value);
|
Transform2d trafo =
|
||||||
float wipe_tower_angle = print.config.wipe_tower_rotation_angle.value;
|
Eigen::Translation2d(print.config.wipe_tower_x.value, print.config.wipe_tower_y.value) *
|
||||||
|
Eigen::Rotation2Dd(print.config.wipe_tower_rotation_angle.value);
|
||||||
|
|
||||||
BoundingBoxf bbox;
|
BoundingBoxf bbox;
|
||||||
for (const std::vector<WipeTower::ToolChangeResult> &tool_changes : print.m_wipe_tower_tool_changes) {
|
for (const std::vector<WipeTower::ToolChangeResult> &tool_changes : print.m_wipe_tower_tool_changes) {
|
||||||
|
|
@ -147,19 +148,11 @@ BoundingBoxf get_wipe_tower_extrusions_extents(const Print &print, const coordf_
|
||||||
for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
|
for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
|
||||||
const WipeTower::Extrusion &e = tcr.extrusions[i];
|
const WipeTower::Extrusion &e = tcr.extrusions[i];
|
||||||
if (e.width > 0) {
|
if (e.width > 0) {
|
||||||
Pointf p1((&e - 1)->pos.x, (&e - 1)->pos.y);
|
Vec2d delta = 0.5 * Vec2d(e.width, e.width);
|
||||||
Pointf p2(e.pos.x, e.pos.y);
|
Vec2d p1 = trafo * Vec2d((&e - 1)->pos.x, (&e - 1)->pos.y);
|
||||||
p1.rotate(wipe_tower_angle);
|
Vec2d p2 = trafo * Vec2d(e.pos.x, e.pos.y);
|
||||||
p1 += wipe_tower_pos;
|
bbox.merge(p1.cwiseMin(p2) - delta);
|
||||||
p2.rotate(wipe_tower_angle);
|
bbox.merge(p1.cwiseMax(p2) + delta);
|
||||||
p2 += wipe_tower_pos;
|
|
||||||
|
|
||||||
bbox.merge(p1);
|
|
||||||
coordf_t radius = 0.5 * e.width;
|
|
||||||
bbox.min(0) = std::min(bbox.min(0), std::min(p1(0), p2(0)) - radius);
|
|
||||||
bbox.min(1) = std::min(bbox.min(1), std::min(p1(1), p2(1)) - radius);
|
|
||||||
bbox.max(0) = std::max(bbox.max(0), std::max(p1(0), p2(0)) + radius);
|
|
||||||
bbox.max(1) = std::max(bbox.max(1), std::max(p1(1), p2(1)) + radius);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -176,8 +169,8 @@ BoundingBoxf get_wipe_tower_priming_extrusions_extents(const Print &print)
|
||||||
for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
|
for (size_t i = 1; i < tcr.extrusions.size(); ++ i) {
|
||||||
const WipeTower::Extrusion &e = tcr.extrusions[i];
|
const WipeTower::Extrusion &e = tcr.extrusions[i];
|
||||||
if (e.width > 0) {
|
if (e.width > 0) {
|
||||||
Pointf p1((&e - 1)->pos.x, (&e - 1)->pos.y);
|
Vec2d p1((&e - 1)->pos.x, (&e - 1)->pos.y);
|
||||||
Pointf p2(e.pos.x, e.pos.y);
|
Vec2d p2(e.pos.x, e.pos.y);
|
||||||
bbox.merge(p1);
|
bbox.merge(p1);
|
||||||
coordf_t radius = 0.5 * e.width;
|
coordf_t radius = 0.5 * e.width;
|
||||||
bbox.min(0) = std::min(bbox.min(0), std::min(p1(0), p2(0)) - radius);
|
bbox.min(0) = std::min(bbox.min(0), std::min(p1(0), p2(0)) - radius);
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,7 @@ std::string GCodeWriter::set_speed(double F, const std::string &comment, const s
|
||||||
return gcode.str();
|
return gcode.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GCodeWriter::travel_to_xy(const Pointf &point, const std::string &comment)
|
std::string GCodeWriter::travel_to_xy(const Vec2d &point, const std::string &comment)
|
||||||
{
|
{
|
||||||
m_pos(0) = point(0);
|
m_pos(0) = point(0);
|
||||||
m_pos(1) = point(1);
|
m_pos(1) = point(1);
|
||||||
|
|
@ -290,7 +290,7 @@ std::string GCodeWriter::travel_to_xy(const Pointf &point, const std::string &co
|
||||||
return gcode.str();
|
return gcode.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GCodeWriter::travel_to_xyz(const Pointf3 &point, const std::string &comment)
|
std::string GCodeWriter::travel_to_xyz(const Vec3d &point, const std::string &comment)
|
||||||
{
|
{
|
||||||
/* If target Z is lower than current Z but higher than nominal Z we
|
/* If target Z is lower than current Z but higher than nominal Z we
|
||||||
don't perform the Z move but we only move in the XY plane and
|
don't perform the Z move but we only move in the XY plane and
|
||||||
|
|
@ -299,7 +299,7 @@ std::string GCodeWriter::travel_to_xyz(const Pointf3 &point, const std::string &
|
||||||
if (!this->will_move_z(point(2))) {
|
if (!this->will_move_z(point(2))) {
|
||||||
double nominal_z = m_pos(2) - m_lifted;
|
double nominal_z = m_pos(2) - m_lifted;
|
||||||
m_lifted = m_lifted - (point(2) - nominal_z);
|
m_lifted = m_lifted - (point(2) - nominal_z);
|
||||||
return this->travel_to_xy(point.xy());
|
return this->travel_to_xy(to_2d(point));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In all the other cases, we perform an actual XYZ move and cancel
|
/* In all the other cases, we perform an actual XYZ move and cancel
|
||||||
|
|
@ -358,7 +358,7 @@ bool GCodeWriter::will_move_z(double z) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GCodeWriter::extrude_to_xy(const Pointf &point, double dE, const std::string &comment)
|
std::string GCodeWriter::extrude_to_xy(const Vec2d &point, double dE, const std::string &comment)
|
||||||
{
|
{
|
||||||
m_pos(0) = point(0);
|
m_pos(0) = point(0);
|
||||||
m_pos(1) = point(1);
|
m_pos(1) = point(1);
|
||||||
|
|
@ -373,7 +373,7 @@ std::string GCodeWriter::extrude_to_xy(const Pointf &point, double dE, const std
|
||||||
return gcode.str();
|
return gcode.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GCodeWriter::extrude_to_xyz(const Pointf3 &point, double dE, const std::string &comment)
|
std::string GCodeWriter::extrude_to_xyz(const Vec3d &point, double dE, const std::string &comment)
|
||||||
{
|
{
|
||||||
m_pos = point;
|
m_pos = point;
|
||||||
m_lifted = 0;
|
m_lifted = 0;
|
||||||
|
|
|
||||||
|
|
@ -55,18 +55,18 @@ public:
|
||||||
std::string toolchange_prefix() const;
|
std::string toolchange_prefix() const;
|
||||||
std::string toolchange(unsigned int extruder_id);
|
std::string toolchange(unsigned int extruder_id);
|
||||||
std::string set_speed(double F, const std::string &comment = std::string(), const std::string &cooling_marker = std::string()) const;
|
std::string set_speed(double F, const std::string &comment = std::string(), const std::string &cooling_marker = std::string()) const;
|
||||||
std::string travel_to_xy(const Pointf &point, const std::string &comment = std::string());
|
std::string travel_to_xy(const Vec2d &point, const std::string &comment = std::string());
|
||||||
std::string travel_to_xyz(const Pointf3 &point, const std::string &comment = std::string());
|
std::string travel_to_xyz(const Vec3d &point, const std::string &comment = std::string());
|
||||||
std::string travel_to_z(double z, const std::string &comment = std::string());
|
std::string travel_to_z(double z, const std::string &comment = std::string());
|
||||||
bool will_move_z(double z) const;
|
bool will_move_z(double z) const;
|
||||||
std::string extrude_to_xy(const Pointf &point, double dE, const std::string &comment = std::string());
|
std::string extrude_to_xy(const Vec2d &point, double dE, const std::string &comment = std::string());
|
||||||
std::string extrude_to_xyz(const Pointf3 &point, double dE, const std::string &comment = std::string());
|
std::string extrude_to_xyz(const Vec3d &point, double dE, const std::string &comment = std::string());
|
||||||
std::string retract(bool before_wipe = false);
|
std::string retract(bool before_wipe = false);
|
||||||
std::string retract_for_toolchange(bool before_wipe = false);
|
std::string retract_for_toolchange(bool before_wipe = false);
|
||||||
std::string unretract();
|
std::string unretract();
|
||||||
std::string lift();
|
std::string lift();
|
||||||
std::string unlift();
|
std::string unlift();
|
||||||
Pointf3 get_position() const { return m_pos; }
|
Vec3d get_position() const { return m_pos; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<Extruder> m_extruders;
|
std::vector<Extruder> m_extruders;
|
||||||
|
|
@ -81,7 +81,7 @@ private:
|
||||||
unsigned int m_last_bed_temperature;
|
unsigned int m_last_bed_temperature;
|
||||||
bool m_last_bed_temperature_reached;
|
bool m_last_bed_temperature_reached;
|
||||||
double m_lifted;
|
double m_lifted;
|
||||||
Pointf3 m_pos;
|
Vec3d m_pos = Vec3d::Zero();
|
||||||
|
|
||||||
std::string _travel_to_z(double z, const std::string &comment);
|
std::string _travel_to_z(double z, const std::string &comment);
|
||||||
std::string _retract(double length, double restart_extra, const std::string &comment);
|
std::string _retract(double length, double restart_extra, const std::string &comment);
|
||||||
|
|
|
||||||
|
|
@ -345,7 +345,7 @@ linint(double value, double oldmin, double oldmax, double newmin, double newmax)
|
||||||
// If the points have the same weight, sort them lexicographically by their positions.
|
// If the points have the same weight, sort them lexicographically by their positions.
|
||||||
struct ArrangeItem {
|
struct ArrangeItem {
|
||||||
ArrangeItem() {}
|
ArrangeItem() {}
|
||||||
Pointf pos;
|
Vec2d pos;
|
||||||
coordf_t weight;
|
coordf_t weight;
|
||||||
bool operator<(const ArrangeItem &other) const {
|
bool operator<(const ArrangeItem &other) const {
|
||||||
return weight < other.weight ||
|
return weight < other.weight ||
|
||||||
|
|
@ -353,17 +353,17 @@ struct ArrangeItem {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Pointfs arrange(size_t num_parts, const Pointf &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box)
|
Pointfs arrange(size_t num_parts, const Vec2d &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box)
|
||||||
{
|
{
|
||||||
// Use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm.
|
// Use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm.
|
||||||
const Pointf cell_size(part_size(0) + gap, part_size(1) + gap);
|
const Vec2d cell_size(part_size(0) + gap, part_size(1) + gap);
|
||||||
|
|
||||||
const BoundingBoxf bed_bbox = (bed_bounding_box != NULL && bed_bounding_box->defined) ?
|
const BoundingBoxf bed_bbox = (bed_bounding_box != NULL && bed_bounding_box->defined) ?
|
||||||
*bed_bounding_box :
|
*bed_bounding_box :
|
||||||
// Bogus bed size, large enough not to trigger the unsufficient bed size error.
|
// Bogus bed size, large enough not to trigger the unsufficient bed size error.
|
||||||
BoundingBoxf(
|
BoundingBoxf(
|
||||||
Pointf(0, 0),
|
Vec2d(0, 0),
|
||||||
Pointf(cell_size(0) * num_parts, cell_size(1) * num_parts));
|
Vec2d(cell_size(0) * num_parts, cell_size(1) * num_parts));
|
||||||
|
|
||||||
// This is how many cells we have available into which to put parts.
|
// This is how many cells we have available into which to put parts.
|
||||||
size_t cellw = size_t(floor((bed_bbox.size()(0) + gap) / cell_size(0)));
|
size_t cellw = size_t(floor((bed_bbox.size()(0) + gap) / cell_size(0)));
|
||||||
|
|
@ -372,8 +372,8 @@ Pointfs arrange(size_t num_parts, const Pointf &part_size, coordf_t gap, const B
|
||||||
CONFESS(PRINTF_ZU " parts won't fit in your print area!\n", num_parts);
|
CONFESS(PRINTF_ZU " parts won't fit in your print area!\n", num_parts);
|
||||||
|
|
||||||
// Get a bounding box of cellw x cellh cells, centered at the center of the bed.
|
// Get a bounding box of cellw x cellh cells, centered at the center of the bed.
|
||||||
Pointf cells_size(cellw * cell_size(0) - gap, cellh * cell_size(1) - gap);
|
Vec2d cells_size(cellw * cell_size(0) - gap, cellh * cell_size(1) - gap);
|
||||||
Pointf cells_offset(bed_bbox.center() - 0.5 * cells_size);
|
Vec2d cells_offset(bed_bbox.center() - 0.5 * cells_size);
|
||||||
BoundingBoxf cells_bb(cells_offset, cells_size + cells_offset);
|
BoundingBoxf cells_bb(cells_offset, cells_size + cells_offset);
|
||||||
|
|
||||||
// List of cells, sorted by distance from center.
|
// List of cells, sorted by distance from center.
|
||||||
|
|
@ -405,35 +405,35 @@ Pointfs arrange(size_t num_parts, const Pointf &part_size, coordf_t gap, const B
|
||||||
Pointfs positions;
|
Pointfs positions;
|
||||||
positions.reserve(num_parts);
|
positions.reserve(num_parts);
|
||||||
for (std::vector<ArrangeItem>::const_iterator it = cellsorder.begin(); it != cellsorder.end(); ++ it)
|
for (std::vector<ArrangeItem>::const_iterator it = cellsorder.begin(); it != cellsorder.end(); ++ it)
|
||||||
positions.push_back(Pointf(it->pos(0) - 0.5 * part_size(0), it->pos(1) - 0.5 * part_size(1)));
|
positions.push_back(Vec2d(it->pos(0) - 0.5 * part_size(0), it->pos(1) - 0.5 * part_size(1)));
|
||||||
return positions;
|
return positions;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
class ArrangeItem {
|
class ArrangeItem {
|
||||||
public:
|
public:
|
||||||
Pointf pos;
|
Vec2d pos = Vec2d::Zero();
|
||||||
size_t index_x, index_y;
|
size_t index_x, index_y;
|
||||||
coordf_t dist;
|
coordf_t dist;
|
||||||
};
|
};
|
||||||
class ArrangeItemIndex {
|
class ArrangeItemIndex {
|
||||||
public:
|
public:
|
||||||
coordf_t index;
|
coordf_t index;
|
||||||
ArrangeItem item;
|
ArrangeItem item;
|
||||||
ArrangeItemIndex(coordf_t _index, ArrangeItem _item) : index(_index), item(_item) {};
|
ArrangeItemIndex(coordf_t _index, ArrangeItem _item) : index(_index), item(_item) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
bool
|
||||||
arrange(size_t total_parts, const Pointf &part_size, coordf_t dist, const BoundingBoxf* bb, Pointfs &positions)
|
arrange(size_t total_parts, const Vec2d &part_size, coordf_t dist, const BoundingBoxf* bb, Pointfs &positions)
|
||||||
{
|
{
|
||||||
positions.clear();
|
positions.clear();
|
||||||
|
|
||||||
Pointf part = part_size;
|
Vec2d part = part_size;
|
||||||
|
|
||||||
// use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm
|
// use actual part size (the largest) plus separation distance (half on each side) in spacing algorithm
|
||||||
part(0) += dist;
|
part(0) += dist;
|
||||||
part(1) += dist;
|
part(1) += dist;
|
||||||
|
|
||||||
Pointf area;
|
Vec2d area(Vec2d::Zero());
|
||||||
if (bb != NULL && bb->defined) {
|
if (bb != NULL && bb->defined) {
|
||||||
area = bb->size();
|
area = bb->size();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -449,11 +449,11 @@ arrange(size_t total_parts, const Pointf &part_size, coordf_t dist, const Boundi
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// total space used by cells
|
// total space used by cells
|
||||||
Pointf cells(cellw * part(0), cellh * part(1));
|
Vec2d cells(cellw * part(0), cellh * part(1));
|
||||||
|
|
||||||
// bounding box of total space used by cells
|
// bounding box of total space used by cells
|
||||||
BoundingBoxf cells_bb;
|
BoundingBoxf cells_bb;
|
||||||
cells_bb.merge(Pointf(0,0)); // min
|
cells_bb.merge(Vec2d(0,0)); // min
|
||||||
cells_bb.merge(cells); // max
|
cells_bb.merge(cells); // max
|
||||||
|
|
||||||
// center bounding box to area
|
// center bounding box to area
|
||||||
|
|
@ -533,7 +533,7 @@ arrange(size_t total_parts, const Pointf &part_size, coordf_t dist, const Boundi
|
||||||
coordf_t cx = c.item.index_x - lx;
|
coordf_t cx = c.item.index_x - lx;
|
||||||
coordf_t cy = c.item.index_y - ty;
|
coordf_t cy = c.item.index_y - ty;
|
||||||
|
|
||||||
positions.push_back(Pointf(cx * part(0), cy * part(1)));
|
positions.push_back(Vec2d(cx * part(0), cy * part(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bb != NULL && bb->defined) {
|
if (bb != NULL && bb->defined) {
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ static inline bool is_ccw(const Polygon &poly)
|
||||||
return o == ORIENTATION_CCW;
|
return o == ORIENTATION_CCW;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool ray_ray_intersection(const Pointf &p1, const Vectorf &v1, const Pointf &p2, const Vectorf &v2, Pointf &res)
|
inline bool ray_ray_intersection(const Vec2d &p1, const Vec2d &v1, const Vec2d &p2, const Vec2d &v2, Vec2d &res)
|
||||||
{
|
{
|
||||||
double denom = v1(0) * v2(1) - v2(0) * v1(1);
|
double denom = v1(0) * v2(1) - v2(0) * v1(1);
|
||||||
if (std::abs(denom) < EPSILON)
|
if (std::abs(denom) < EPSILON)
|
||||||
|
|
@ -77,7 +77,7 @@ inline bool ray_ray_intersection(const Pointf &p1, const Vectorf &v1, const Poin
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool segment_segment_intersection(const Pointf &p1, const Vectorf &v1, const Pointf &p2, const Vectorf &v2, Pointf &res)
|
inline bool segment_segment_intersection(const Vec2d &p1, const Vec2d &v1, const Vec2d &p2, const Vec2d &v2, Vec2d &res)
|
||||||
{
|
{
|
||||||
double denom = v1(0) * v2(1) - v2(0) * v1(1);
|
double denom = v1(0) * v2(1) - v2(0) * v1(1);
|
||||||
if (std::abs(denom) < EPSILON)
|
if (std::abs(denom) < EPSILON)
|
||||||
|
|
@ -123,7 +123,7 @@ void simplify_polygons(const Polygons &polygons, double tolerance, Polygons* ret
|
||||||
double linint(double value, double oldmin, double oldmax, double newmin, double newmax);
|
double linint(double value, double oldmin, double oldmax, double newmin, double newmax);
|
||||||
bool arrange(
|
bool arrange(
|
||||||
// input
|
// input
|
||||||
size_t num_parts, const Pointf &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box,
|
size_t num_parts, const Vec2d &part_size, coordf_t gap, const BoundingBoxf* bed_bounding_box,
|
||||||
// output
|
// output
|
||||||
Pointfs &positions);
|
Pointfs &positions);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,11 +97,11 @@ bool Line::intersection(const Line &l2, Point *intersection) const
|
||||||
return false; // not intersecting
|
return false; // not intersecting
|
||||||
}
|
}
|
||||||
|
|
||||||
Pointf3 Linef3::intersect_plane(double z) const
|
Vec3d Linef3::intersect_plane(double z) const
|
||||||
{
|
{
|
||||||
auto v = (this->b - this->a).cast<double>();
|
auto v = (this->b - this->a).cast<double>();
|
||||||
double t = (z - this->a(2)) / v(2);
|
double t = (z - this->a(2)) / v(2);
|
||||||
return Pointf3(this->a(0) + v(0) * t, this->a(1) + v(1) * t, z);
|
return Vec3d(this->a(0) + v(0) * t, this->a(1) + v(1) * t, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class Line
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Line() {}
|
Line() {}
|
||||||
explicit Line(Point _a, Point _b): a(_a), b(_b) {}
|
Line(const Point& _a, const Point& _b) : a(_a), b(_b) {}
|
||||||
explicit operator Lines() const { Lines lines; lines.emplace_back(*this); return lines; }
|
explicit operator Lines() const { Lines lines; lines.emplace_back(*this); return lines; }
|
||||||
void scale(double factor) { this->a *= factor; this->b *= factor; }
|
void scale(double factor) { this->a *= factor; this->b *= factor; }
|
||||||
void translate(double x, double y) { Vector v(x, y); this->a += v; this->b += v; }
|
void translate(double x, double y) { Vector v(x, y); this->a += v; this->b += v; }
|
||||||
|
|
@ -49,45 +49,49 @@ class ThickLine : public Line
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ThickLine() : a_width(0), b_width(0) {}
|
ThickLine() : a_width(0), b_width(0) {}
|
||||||
ThickLine(Point a, Point b) : Line(a, b), a_width(0), b_width(0) {}
|
ThickLine(const Point& a, const Point& b) : Line(a, b), a_width(0), b_width(0) {}
|
||||||
ThickLine(Point a, Point b, double wa, double wb) : Line(a, b), a_width(wa), b_width(wb) {}
|
ThickLine(const Point& a, const Point& b, double wa, double wb) : Line(a, b), a_width(wa), b_width(wb) {}
|
||||||
|
|
||||||
coordf_t a_width, b_width;
|
double a_width, b_width;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Line3
|
class Line3
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Line3() {}
|
Line3() : a(Vec3crd::Zero()), b(Vec3crd::Zero()) {}
|
||||||
Line3(const Point3& _a, const Point3& _b) : a(_a), b(_b) {}
|
Line3(const Vec3crd& _a, const Vec3crd& _b) : a(_a), b(_b) {}
|
||||||
|
|
||||||
double length() const { return (this->a - this->b).cast<double>().norm(); }
|
double length() const { return (this->a - this->b).cast<double>().norm(); }
|
||||||
Vector3 vector() const { return this->b - this->a; }
|
Vec3crd vector() const { return this->b - this->a; }
|
||||||
|
|
||||||
Point3 a;
|
Vec3crd a;
|
||||||
Point3 b;
|
Vec3crd b;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Linef
|
class Linef
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Linef() {}
|
Linef() : a(Vec2d::Zero()), b(Vec2d::Zero()) {}
|
||||||
explicit Linef(Pointf _a, Pointf _b): a(_a), b(_b) {}
|
Linef(const Vec2d& _a, const Vec2d& _b) : a(_a), b(_b) {}
|
||||||
|
|
||||||
Pointf a;
|
Vec2d a;
|
||||||
Pointf b;
|
Vec2d b;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Linef3
|
class Linef3
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Linef3() {}
|
Linef3() : a(Vec3d::Zero()), b(Vec3d::Zero()) {}
|
||||||
explicit Linef3(Pointf3 _a, Pointf3 _b): a(_a), b(_b) {}
|
Linef3(const Vec3d& _a, const Vec3d& _b) : a(_a), b(_b) {}
|
||||||
Pointf3 intersect_plane(double z) const;
|
|
||||||
void scale(double factor) { this->a *= factor; this->b *= factor; }
|
|
||||||
|
|
||||||
Pointf3 a;
|
Vec3d intersect_plane(double z) const;
|
||||||
Pointf3 b;
|
void scale(double factor) { this->a *= factor; this->b *= factor; }
|
||||||
|
Vec3d vector() const { return this->b - this->a; }
|
||||||
|
Vec3d unit_vector() const { return (length() == 0.0) ? Vec3d::Zero() : vector().normalized(); }
|
||||||
|
double length() const { return vector().norm(); }
|
||||||
|
|
||||||
|
Vec3d a;
|
||||||
|
Vec3d b;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
|
||||||
|
|
@ -235,15 +235,7 @@ BoundingBoxf3 Model::bounding_box() const
|
||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBoxf3 Model::transformed_bounding_box() const
|
void Model::center_instances_around_point(const Vec2d &point)
|
||||||
{
|
|
||||||
BoundingBoxf3 bb;
|
|
||||||
for (const ModelObject* obj : this->objects)
|
|
||||||
bb.merge(obj->tight_bounding_box(false));
|
|
||||||
return bb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Model::center_instances_around_point(const Pointf &point)
|
|
||||||
{
|
{
|
||||||
// BoundingBoxf3 bb = this->bounding_box();
|
// BoundingBoxf3 bb = this->bounding_box();
|
||||||
BoundingBoxf3 bb;
|
BoundingBoxf3 bb;
|
||||||
|
|
@ -251,7 +243,7 @@ void Model::center_instances_around_point(const Pointf &point)
|
||||||
for (size_t i = 0; i < o->instances.size(); ++ i)
|
for (size_t i = 0; i < o->instances.size(); ++ i)
|
||||||
bb.merge(o->instance_bounding_box(i, false));
|
bb.merge(o->instance_bounding_box(i, false));
|
||||||
|
|
||||||
Pointf shift = point - 0.5 * bb.size().xy() - bb.min.xy();
|
Vec2d shift = point - 0.5 * to_2d(bb.size()) - to_2d(bb.min);
|
||||||
for (ModelObject *o : this->objects) {
|
for (ModelObject *o : this->objects) {
|
||||||
for (ModelInstance *i : o->instances)
|
for (ModelInstance *i : o->instances)
|
||||||
i->offset += shift;
|
i->offset += shift;
|
||||||
|
|
@ -309,8 +301,8 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
|
||||||
for (size_t i = 0; i < o->instances.size(); ++ i) {
|
for (size_t i = 0; i < o->instances.size(); ++ i) {
|
||||||
// an accurate snug bounding box around the transformed mesh.
|
// an accurate snug bounding box around the transformed mesh.
|
||||||
BoundingBoxf3 bbox(o->instance_bounding_box(i, true));
|
BoundingBoxf3 bbox(o->instance_bounding_box(i, true));
|
||||||
instance_sizes.push_back(bbox.size().xy());
|
instance_sizes.emplace_back(to_2d(bbox.size()));
|
||||||
instance_centers.push_back(bbox.center().xy());
|
instance_centers.emplace_back(to_2d(bbox.center()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Pointfs positions;
|
Pointfs positions;
|
||||||
|
|
@ -332,7 +324,7 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb)
|
||||||
// Duplicate the entire model preserving instance relative positions.
|
// Duplicate the entire model preserving instance relative positions.
|
||||||
void Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb)
|
void Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb)
|
||||||
{
|
{
|
||||||
Pointfs model_sizes(copies_num-1, this->bounding_box().size().xy());
|
Pointfs model_sizes(copies_num-1, to_2d(this->bounding_box().size()));
|
||||||
Pointfs positions;
|
Pointfs positions;
|
||||||
if (! _arrange(model_sizes, dist, bb, positions))
|
if (! _arrange(model_sizes, dist, bb, positions))
|
||||||
CONFESS("Cannot duplicate part as the resulting objects would not fit on the print bed.\n");
|
CONFESS("Cannot duplicate part as the resulting objects would not fit on the print bed.\n");
|
||||||
|
|
@ -343,7 +335,7 @@ void Model::duplicate(size_t copies_num, coordf_t dist, const BoundingBoxf* bb)
|
||||||
// make a copy of the pointers in order to avoid recursion when appending their copies
|
// make a copy of the pointers in order to avoid recursion when appending their copies
|
||||||
ModelInstancePtrs instances = o->instances;
|
ModelInstancePtrs instances = o->instances;
|
||||||
for (const ModelInstance *i : instances) {
|
for (const ModelInstance *i : instances) {
|
||||||
for (const Pointf &pos : positions) {
|
for (const Vec2d &pos : positions) {
|
||||||
ModelInstance *instance = o->add_instance(*i);
|
ModelInstance *instance = o->add_instance(*i);
|
||||||
instance->offset += pos;
|
instance->offset += pos;
|
||||||
}
|
}
|
||||||
|
|
@ -375,7 +367,7 @@ void Model::duplicate_objects_grid(size_t x, size_t y, coordf_t dist)
|
||||||
ModelObject* object = this->objects.front();
|
ModelObject* object = this->objects.front();
|
||||||
object->clear_instances();
|
object->clear_instances();
|
||||||
|
|
||||||
Sizef3 size = object->bounding_box().size();
|
Vec3d size = object->bounding_box().size();
|
||||||
|
|
||||||
for (size_t x_copy = 1; x_copy <= x; ++x_copy) {
|
for (size_t x_copy = 1; x_copy <= x; ++x_copy) {
|
||||||
for (size_t y_copy = 1; y_copy <= y; ++y_copy) {
|
for (size_t y_copy = 1; y_copy <= y; ++y_copy) {
|
||||||
|
|
@ -621,54 +613,6 @@ const BoundingBoxf3& ModelObject::bounding_box() const
|
||||||
return m_bounding_box;
|
return m_bounding_box;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBoxf3 ModelObject::tight_bounding_box(bool include_modifiers) const
|
|
||||||
{
|
|
||||||
BoundingBoxf3 bb;
|
|
||||||
|
|
||||||
for (const ModelVolume* vol : this->volumes)
|
|
||||||
{
|
|
||||||
if (include_modifiers || !vol->modifier)
|
|
||||||
{
|
|
||||||
for (const ModelInstance* inst : this->instances)
|
|
||||||
{
|
|
||||||
double c = cos(inst->rotation);
|
|
||||||
double s = sin(inst->rotation);
|
|
||||||
|
|
||||||
for (int f = 0; f < vol->mesh.stl.stats.number_of_facets; ++f)
|
|
||||||
{
|
|
||||||
const stl_facet& facet = vol->mesh.stl.facet_start[f];
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
{
|
|
||||||
// original point
|
|
||||||
const stl_vertex& v = facet.vertex[i];
|
|
||||||
Pointf3 p((double)v.x, (double)v.y, (double)v.z);
|
|
||||||
|
|
||||||
// scale
|
|
||||||
p(0) *= inst->scaling_factor;
|
|
||||||
p(1) *= inst->scaling_factor;
|
|
||||||
p(2) *= inst->scaling_factor;
|
|
||||||
|
|
||||||
// rotate Z
|
|
||||||
double x = p(0);
|
|
||||||
double y = p(1);
|
|
||||||
p(0) = c * x - s * y;
|
|
||||||
p(1) = s * x + c * y;
|
|
||||||
|
|
||||||
// translate
|
|
||||||
p(0) += inst->offset(0);
|
|
||||||
p(1) += inst->offset(1);
|
|
||||||
|
|
||||||
bb.merge(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bb;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A mesh containing all transformed instances of this object.
|
// A mesh containing all transformed instances of this object.
|
||||||
TriangleMesh ModelObject::mesh() const
|
TriangleMesh ModelObject::mesh() const
|
||||||
{
|
{
|
||||||
|
|
@ -726,24 +670,22 @@ void ModelObject::center_around_origin()
|
||||||
if (! v->modifier)
|
if (! v->modifier)
|
||||||
bb.merge(v->mesh.bounding_box());
|
bb.merge(v->mesh.bounding_box());
|
||||||
|
|
||||||
// first align to origin on XYZ
|
// First align to origin on XYZ, then center it on XY.
|
||||||
Vectorf3 vector(-bb.min(0), -bb.min(1), -bb.min(2));
|
Vec3d size = bb.size();
|
||||||
|
size(2) = 0.;
|
||||||
|
Vec3d shift3 = - bb.min - 0.5 * size;
|
||||||
|
// Unaligned vector, for the Rotation2D to work on Visual Studio 2013.
|
||||||
|
Eigen::Vector2d shift2 = to_2d(shift3);
|
||||||
|
|
||||||
// then center it on XY
|
this->translate(shift3);
|
||||||
Sizef3 size = bb.size();
|
this->origin_translation += shift3;
|
||||||
vector(0) -= size(0)/2;
|
|
||||||
vector(1) -= size(1)/2;
|
|
||||||
|
|
||||||
this->translate(vector);
|
|
||||||
this->origin_translation += vector;
|
|
||||||
|
|
||||||
if (!this->instances.empty()) {
|
if (!this->instances.empty()) {
|
||||||
for (ModelInstance *i : this->instances) {
|
for (ModelInstance *i : this->instances) {
|
||||||
// apply rotation and scaling to vector as well before translating instance,
|
// apply rotation and scaling to vector as well before translating instance,
|
||||||
// in order to leave final position unaltered
|
// in order to leave final position unaltered
|
||||||
Vectorf v = - vector.xy();
|
Eigen::Rotation2Dd rot(i->rotation);
|
||||||
v.rotate(i->rotation);
|
i->offset -= rot * shift2 * i->scaling_factor;
|
||||||
i->offset += v * i->scaling_factor;
|
|
||||||
}
|
}
|
||||||
this->invalidate_bounding_box();
|
this->invalidate_bounding_box();
|
||||||
}
|
}
|
||||||
|
|
@ -752,39 +694,38 @@ void ModelObject::center_around_origin()
|
||||||
void ModelObject::translate(coordf_t x, coordf_t y, coordf_t z)
|
void ModelObject::translate(coordf_t x, coordf_t y, coordf_t z)
|
||||||
{
|
{
|
||||||
for (ModelVolume *v : this->volumes)
|
for (ModelVolume *v : this->volumes)
|
||||||
|
{
|
||||||
v->mesh.translate(float(x), float(y), float(z));
|
v->mesh.translate(float(x), float(y), float(z));
|
||||||
|
v->m_convex_hull.translate(float(x), float(y), float(z));
|
||||||
|
}
|
||||||
|
|
||||||
if (m_bounding_box_valid)
|
if (m_bounding_box_valid)
|
||||||
m_bounding_box.translate(x, y, z);
|
m_bounding_box.translate(x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelObject::scale(const Pointf3 &versor)
|
void ModelObject::scale(const Vec3d &versor)
|
||||||
{
|
{
|
||||||
for (ModelVolume *v : this->volumes)
|
for (ModelVolume *v : this->volumes)
|
||||||
|
{
|
||||||
v->mesh.scale(versor);
|
v->mesh.scale(versor);
|
||||||
|
v->m_convex_hull.scale(versor);
|
||||||
|
}
|
||||||
// reset origin translation since it doesn't make sense anymore
|
// reset origin translation since it doesn't make sense anymore
|
||||||
this->origin_translation = Pointf3(0,0,0);
|
this->origin_translation = Vec3d::Zero();
|
||||||
this->invalidate_bounding_box();
|
this->invalidate_bounding_box();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelObject::rotate(float angle, const Axis &axis)
|
void ModelObject::rotate(float angle, const Axis &axis)
|
||||||
{
|
{
|
||||||
float min_z = FLT_MAX;
|
|
||||||
for (ModelVolume *v : this->volumes)
|
for (ModelVolume *v : this->volumes)
|
||||||
{
|
{
|
||||||
v->mesh.rotate(angle, axis);
|
v->mesh.rotate(angle, axis);
|
||||||
min_z = std::min(min_z, v->mesh.stl.stats.min.z);
|
v->m_convex_hull.rotate(angle, axis);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (min_z != 0.0f)
|
center_around_origin();
|
||||||
{
|
|
||||||
// translate the object so that its minimum z lays on the bed
|
|
||||||
for (ModelVolume *v : this->volumes)
|
|
||||||
{
|
|
||||||
v->mesh.translate(0.0f, 0.0f, -min_z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this->origin_translation = Pointf3(0, 0, 0);
|
this->origin_translation = Vec3d::Zero();
|
||||||
this->invalidate_bounding_box();
|
this->invalidate_bounding_box();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -796,17 +737,22 @@ void ModelObject::transform(const float* matrix3x4)
|
||||||
for (ModelVolume* v : volumes)
|
for (ModelVolume* v : volumes)
|
||||||
{
|
{
|
||||||
v->mesh.transform(matrix3x4);
|
v->mesh.transform(matrix3x4);
|
||||||
|
v->m_convex_hull.transform(matrix3x4);
|
||||||
}
|
}
|
||||||
|
|
||||||
origin_translation = Pointf3(0.0, 0.0, 0.0);
|
this->origin_translation = Vec3d::Zero();
|
||||||
invalidate_bounding_box();
|
this->invalidate_bounding_box();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelObject::mirror(const Axis &axis)
|
void ModelObject::mirror(const Axis &axis)
|
||||||
{
|
{
|
||||||
for (ModelVolume *v : this->volumes)
|
for (ModelVolume *v : this->volumes)
|
||||||
|
{
|
||||||
v->mesh.mirror(axis);
|
v->mesh.mirror(axis);
|
||||||
this->origin_translation = Pointf3(0,0,0);
|
v->m_convex_hull.mirror(axis);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->origin_translation = Vec3d::Zero();
|
||||||
this->invalidate_bounding_box();
|
this->invalidate_bounding_box();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -910,45 +856,18 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
||||||
|
|
||||||
void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
|
void ModelObject::check_instances_print_volume_state(const BoundingBoxf3& print_volume)
|
||||||
{
|
{
|
||||||
for (ModelVolume* vol : this->volumes)
|
for (const ModelVolume* vol : this->volumes)
|
||||||
{
|
{
|
||||||
if (!vol->modifier)
|
if (!vol->modifier)
|
||||||
{
|
{
|
||||||
for (ModelInstance* inst : this->instances)
|
for (ModelInstance* inst : this->instances)
|
||||||
{
|
{
|
||||||
BoundingBoxf3 bb;
|
Transform3d m = Transform3d::Identity();
|
||||||
|
m.translate(Vec3d(inst->offset(0), inst->offset(1), 0.0));
|
||||||
|
m.rotate(Eigen::AngleAxisd(inst->rotation, Vec3d::UnitZ()));
|
||||||
|
m.scale(inst->scaling_factor);
|
||||||
|
|
||||||
double c = cos(inst->rotation);
|
BoundingBoxf3 bb = vol->get_convex_hull().transformed_bounding_box(m);
|
||||||
double s = sin(inst->rotation);
|
|
||||||
|
|
||||||
for (int f = 0; f < vol->mesh.stl.stats.number_of_facets; ++f)
|
|
||||||
{
|
|
||||||
const stl_facet& facet = vol->mesh.stl.facet_start[f];
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; ++i)
|
|
||||||
{
|
|
||||||
// original point
|
|
||||||
const stl_vertex& v = facet.vertex[i];
|
|
||||||
Pointf3 p((double)v.x, (double)v.y, (double)v.z);
|
|
||||||
|
|
||||||
// scale
|
|
||||||
p(0) *= inst->scaling_factor;
|
|
||||||
p(1) *= inst->scaling_factor;
|
|
||||||
p(2) *= inst->scaling_factor;
|
|
||||||
|
|
||||||
// rotate Z
|
|
||||||
double x = p(0);
|
|
||||||
double y = p(1);
|
|
||||||
p(0) = c * x - s * y;
|
|
||||||
p(1) = s * x + c * y;
|
|
||||||
|
|
||||||
// translate
|
|
||||||
p(0) += inst->offset(0);
|
|
||||||
p(1) += inst->offset(1);
|
|
||||||
|
|
||||||
bb.merge(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (print_volume.contains(bb))
|
if (print_volume.contains(bb))
|
||||||
inst->print_volume_state = ModelInstance::PVS_Inside;
|
inst->print_volume_state = ModelInstance::PVS_Inside;
|
||||||
|
|
@ -970,7 +889,7 @@ void ModelObject::print_info() const
|
||||||
TriangleMesh mesh = this->raw_mesh();
|
TriangleMesh mesh = this->raw_mesh();
|
||||||
mesh.check_topology();
|
mesh.check_topology();
|
||||||
BoundingBoxf3 bb = mesh.bounding_box();
|
BoundingBoxf3 bb = mesh.bounding_box();
|
||||||
Sizef3 size = bb.size();
|
Vec3d size = bb.size();
|
||||||
cout << "size_x = " << size(0) << endl;
|
cout << "size_x = " << size(0) << endl;
|
||||||
cout << "size_y = " << size(1) << endl;
|
cout << "size_y = " << size(1) << endl;
|
||||||
cout << "size_z = " << size(2) << endl;
|
cout << "size_z = " << size(2) << endl;
|
||||||
|
|
@ -1031,6 +950,16 @@ ModelMaterial* ModelVolume::assign_unique_material()
|
||||||
return model->add_material(this->_material_id);
|
return model->add_material(this->_material_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ModelVolume::calculate_convex_hull()
|
||||||
|
{
|
||||||
|
m_convex_hull = mesh.convex_hull_3d();
|
||||||
|
}
|
||||||
|
|
||||||
|
const TriangleMesh& ModelVolume::get_convex_hull() const
|
||||||
|
{
|
||||||
|
return m_convex_hull;
|
||||||
|
}
|
||||||
|
|
||||||
// Split this volume, append the result to the object owning this volume.
|
// Split this volume, append the result to the object owning this volume.
|
||||||
// Return the number of volumes created from this one.
|
// Return the number of volumes created from this one.
|
||||||
// This is useful to assign different materials to different volumes of an object.
|
// This is useful to assign different materials to different volumes of an object.
|
||||||
|
|
@ -1082,30 +1011,20 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes
|
||||||
for (int i = 0; i < mesh->stl.stats.number_of_facets; ++ i) {
|
for (int i = 0; i < mesh->stl.stats.number_of_facets; ++ i) {
|
||||||
const stl_facet &facet = mesh->stl.facet_start[i];
|
const stl_facet &facet = mesh->stl.facet_start[i];
|
||||||
for (int j = 0; j < 3; ++ j) {
|
for (int j = 0; j < 3; ++ j) {
|
||||||
stl_vertex v = facet.vertex[j];
|
const stl_vertex &v = facet.vertex[j];
|
||||||
double xold = v.x;
|
bbox.merge(Vec3d(c * v(0) - s * v(1), s * v(0) + c * v(1), v(2)));
|
||||||
double yold = v.y;
|
|
||||||
v.x = float(c * xold - s * yold);
|
|
||||||
v.y = float(s * xold + c * yold);
|
|
||||||
bbox.merge(Pointf3(v.x, v.y, v.z));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (! empty(bbox)) {
|
if (! empty(bbox)) {
|
||||||
// Scale the bounding box uniformly.
|
// Scale the bounding box uniformly.
|
||||||
if (std::abs(this->scaling_factor - 1.) > EPSILON) {
|
if (std::abs(this->scaling_factor - 1.) > EPSILON) {
|
||||||
bbox.min(0) *= float(this->scaling_factor);
|
bbox.min *= this->scaling_factor;
|
||||||
bbox.min(1) *= float(this->scaling_factor);
|
bbox.max *= this->scaling_factor;
|
||||||
bbox.min(2) *= float(this->scaling_factor);
|
|
||||||
bbox.max(0) *= float(this->scaling_factor);
|
|
||||||
bbox.max(1) *= float(this->scaling_factor);
|
|
||||||
bbox.max(2) *= float(this->scaling_factor);
|
|
||||||
}
|
}
|
||||||
// Translate the bounding box.
|
// Translate the bounding box.
|
||||||
if (! dont_translate) {
|
if (! dont_translate) {
|
||||||
bbox.min(0) += float(this->offset(0));
|
Eigen::Map<Vec2d>(bbox.min.data()) += this->offset;
|
||||||
bbox.min(1) += float(this->offset(1));
|
Eigen::Map<Vec2d>(bbox.max.data()) += this->offset;
|
||||||
bbox.max(0) += float(this->offset(0));
|
|
||||||
bbox.max(1) += float(this->offset(1));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bbox;
|
return bbox;
|
||||||
|
|
@ -1113,10 +1032,11 @@ BoundingBoxf3 ModelInstance::transform_mesh_bounding_box(const TriangleMesh* mes
|
||||||
|
|
||||||
BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
|
BoundingBoxf3 ModelInstance::transform_bounding_box(const BoundingBoxf3 &bbox, bool dont_translate) const
|
||||||
{
|
{
|
||||||
auto matrix = Transform3f::Identity();
|
Transform3d matrix = Transform3d::Identity();
|
||||||
if (!dont_translate)
|
if (!dont_translate)
|
||||||
matrix.translate(Vec3f((float)offset(0), (float)offset(1), 0.0f));
|
matrix.translate(Vec3d(offset(0), offset(1), 0.0));
|
||||||
matrix.rotate(Eigen::AngleAxisf(rotation, Vec3f::UnitZ()));
|
|
||||||
|
matrix.rotate(Eigen::AngleAxisd(rotation, Vec3d::UnitZ()));
|
||||||
matrix.scale(scaling_factor);
|
matrix.scale(scaling_factor);
|
||||||
return bbox.transformed(matrix);
|
return bbox.transformed(matrix);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ public:
|
||||||
center_around_origin() method. Callers might want to apply the same translation
|
center_around_origin() method. Callers might want to apply the same translation
|
||||||
to new volumes before adding them to this object in order to preserve alignment
|
to new volumes before adding them to this object in order to preserve alignment
|
||||||
when user expects that. */
|
when user expects that. */
|
||||||
Pointf3 origin_translation;
|
Vec3d origin_translation;
|
||||||
|
|
||||||
Model* get_model() const { return m_model; };
|
Model* get_model() const { return m_model; };
|
||||||
|
|
||||||
|
|
@ -105,9 +105,6 @@ public:
|
||||||
// This bounding box is being cached.
|
// This bounding box is being cached.
|
||||||
const BoundingBoxf3& bounding_box() const;
|
const BoundingBoxf3& bounding_box() const;
|
||||||
void invalidate_bounding_box() { m_bounding_box_valid = false; }
|
void invalidate_bounding_box() { m_bounding_box_valid = false; }
|
||||||
// Returns a snug bounding box of the transformed instances.
|
|
||||||
// This bounding box is not being cached.
|
|
||||||
BoundingBoxf3 tight_bounding_box(bool include_modifiers) const;
|
|
||||||
|
|
||||||
// A mesh containing all transformed instances of this object.
|
// A mesh containing all transformed instances of this object.
|
||||||
TriangleMesh mesh() const;
|
TriangleMesh mesh() const;
|
||||||
|
|
@ -120,9 +117,9 @@ public:
|
||||||
// A snug bounding box around the transformed non-modifier object volumes.
|
// A snug bounding box around the transformed non-modifier object volumes.
|
||||||
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
|
BoundingBoxf3 instance_bounding_box(size_t instance_idx, bool dont_translate = false) const;
|
||||||
void center_around_origin();
|
void center_around_origin();
|
||||||
void translate(const Vectorf3 &vector) { this->translate(vector(0), vector(1), vector(2)); }
|
void translate(const Vec3d &vector) { this->translate(vector(0), vector(1), vector(2)); }
|
||||||
void translate(coordf_t x, coordf_t y, coordf_t z);
|
void translate(coordf_t x, coordf_t y, coordf_t z);
|
||||||
void scale(const Pointf3 &versor);
|
void scale(const Vec3d &versor);
|
||||||
void rotate(float angle, const Axis &axis);
|
void rotate(float angle, const Axis &axis);
|
||||||
void transform(const float* matrix3x4);
|
void transform(const float* matrix3x4);
|
||||||
void mirror(const Axis &axis);
|
void mirror(const Axis &axis);
|
||||||
|
|
@ -138,7 +135,7 @@ public:
|
||||||
void print_info() const;
|
void print_info() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), m_bounding_box_valid(false) {}
|
ModelObject(Model *model) : layer_height_profile_valid(false), m_model(model), origin_translation(Vec3d::Zero()), m_bounding_box_valid(false) {}
|
||||||
ModelObject(Model *model, const ModelObject &other, bool copy_volumes = true);
|
ModelObject(Model *model, const ModelObject &other, bool copy_volumes = true);
|
||||||
ModelObject& operator= (ModelObject other);
|
ModelObject& operator= (ModelObject other);
|
||||||
void swap(ModelObject &other);
|
void swap(ModelObject &other);
|
||||||
|
|
@ -157,6 +154,10 @@ private:
|
||||||
class ModelVolume
|
class ModelVolume
|
||||||
{
|
{
|
||||||
friend class ModelObject;
|
friend class ModelObject;
|
||||||
|
|
||||||
|
// The convex hull of this model's mesh.
|
||||||
|
TriangleMesh m_convex_hull;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::string name;
|
std::string name;
|
||||||
// The triangular model.
|
// The triangular model.
|
||||||
|
|
@ -180,19 +181,32 @@ public:
|
||||||
|
|
||||||
ModelMaterial* assign_unique_material();
|
ModelMaterial* assign_unique_material();
|
||||||
|
|
||||||
|
void calculate_convex_hull();
|
||||||
|
const TriangleMesh& get_convex_hull() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Parent object owning this ModelVolume.
|
// Parent object owning this ModelVolume.
|
||||||
ModelObject* object;
|
ModelObject* object;
|
||||||
t_model_material_id _material_id;
|
t_model_material_id _material_id;
|
||||||
|
|
||||||
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), modifier(false), object(object) {}
|
ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), modifier(false), object(object)
|
||||||
ModelVolume(ModelObject *object, TriangleMesh &&mesh) : mesh(std::move(mesh)), modifier(false), object(object) {}
|
{
|
||||||
|
if (mesh.stl.stats.number_of_facets > 1)
|
||||||
|
calculate_convex_hull();
|
||||||
|
}
|
||||||
|
ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) : mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), modifier(false), object(object) {}
|
||||||
ModelVolume(ModelObject *object, const ModelVolume &other) :
|
ModelVolume(ModelObject *object, const ModelVolume &other) :
|
||||||
name(other.name), mesh(other.mesh), config(other.config), modifier(other.modifier), object(object)
|
name(other.name), mesh(other.mesh), m_convex_hull(other.m_convex_hull), config(other.config), modifier(other.modifier), object(object)
|
||||||
{ this->material_id(other.material_id()); }
|
{
|
||||||
|
this->material_id(other.material_id());
|
||||||
|
}
|
||||||
ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) :
|
ModelVolume(ModelObject *object, const ModelVolume &other, const TriangleMesh &&mesh) :
|
||||||
name(other.name), mesh(std::move(mesh)), config(other.config), modifier(other.modifier), object(object)
|
name(other.name), mesh(std::move(mesh)), config(other.config), modifier(other.modifier), object(object)
|
||||||
{ this->material_id(other.material_id()); }
|
{
|
||||||
|
this->material_id(other.material_id());
|
||||||
|
if (mesh.stl.stats.number_of_facets > 1)
|
||||||
|
calculate_convex_hull();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A single instance of a ModelObject.
|
// A single instance of a ModelObject.
|
||||||
|
|
@ -213,7 +227,7 @@ public:
|
||||||
// Transform3d transform;
|
// Transform3d transform;
|
||||||
double rotation; // Rotation around the Z axis, in radians around mesh center point
|
double rotation; // Rotation around the Z axis, in radians around mesh center point
|
||||||
double scaling_factor;
|
double scaling_factor;
|
||||||
Pointf offset; // in unscaled coordinates
|
Vec2d offset; // in unscaled coordinates
|
||||||
|
|
||||||
// flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state())
|
// flag showing the position of this instance with respect to the print volume (set by Print::validate() using ModelObject::check_instances_print_volume_state())
|
||||||
EPrintVolumeState print_volume_state;
|
EPrintVolumeState print_volume_state;
|
||||||
|
|
@ -235,7 +249,7 @@ private:
|
||||||
// Parent object, owning this instance.
|
// Parent object, owning this instance.
|
||||||
ModelObject* object;
|
ModelObject* object;
|
||||||
|
|
||||||
ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), object(object), print_volume_state(PVS_Inside) {}
|
ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), offset(Vec2d::Zero()), object(object), print_volume_state(PVS_Inside) {}
|
||||||
ModelInstance(ModelObject *object, const ModelInstance &other) :
|
ModelInstance(ModelObject *object, const ModelInstance &other) :
|
||||||
rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object), print_volume_state(PVS_Inside) {}
|
rotation(other.rotation), scaling_factor(other.scaling_factor), offset(other.offset), object(object), print_volume_state(PVS_Inside) {}
|
||||||
};
|
};
|
||||||
|
|
@ -286,9 +300,7 @@ public:
|
||||||
bool add_default_instances();
|
bool add_default_instances();
|
||||||
// Returns approximate axis aligned bounding box of this model
|
// Returns approximate axis aligned bounding box of this model
|
||||||
BoundingBoxf3 bounding_box() const;
|
BoundingBoxf3 bounding_box() const;
|
||||||
// Returns tight axis aligned bounding box of this model
|
void center_instances_around_point(const Vec2d &point);
|
||||||
BoundingBoxf3 transformed_bounding_box() const;
|
|
||||||
void center_instances_around_point(const Pointf &point);
|
|
||||||
void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
|
void translate(coordf_t x, coordf_t y, coordf_t z) { for (ModelObject *o : this->objects) o->translate(x, y, z); }
|
||||||
TriangleMesh mesh() const;
|
TriangleMesh mesh() const;
|
||||||
bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL);
|
bool arrange_objects(coordf_t dist, const BoundingBoxf* bb = NULL);
|
||||||
|
|
|
||||||
|
|
@ -468,7 +468,7 @@ void applyResult(
|
||||||
// appropriately
|
// appropriately
|
||||||
auto off = item.translation();
|
auto off = item.translation();
|
||||||
Radians rot = item.rotation();
|
Radians rot = item.rotation();
|
||||||
Pointf foff(off.X*SCALING_FACTOR + batch_offset,
|
Vec2d foff(off.X*SCALING_FACTOR + batch_offset,
|
||||||
off.Y*SCALING_FACTOR);
|
off.Y*SCALING_FACTOR);
|
||||||
|
|
||||||
// write the tranformation data into the model instance
|
// write the tranformation data into the model instance
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ MultiPoint::_douglas_peucker(const Points &points, const double tolerance)
|
||||||
|
|
||||||
void MultiPoint3::translate(double x, double y)
|
void MultiPoint3::translate(double x, double y)
|
||||||
{
|
{
|
||||||
for (Point3 &p : points) {
|
for (Vec3crd &p : points) {
|
||||||
p(0) += x;
|
p(0) += x;
|
||||||
p(1) += y;
|
p(1) += y;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@ class MultiPoint3
|
||||||
public:
|
public:
|
||||||
Points3 points;
|
Points3 points;
|
||||||
|
|
||||||
void append(const Point3& point) { this->points.push_back(point); }
|
void append(const Vec3crd& point) { this->points.push_back(point); }
|
||||||
|
|
||||||
void translate(double x, double y);
|
void translate(double x, double y);
|
||||||
void translate(const Point& vector);
|
void translate(const Point& vector);
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ void PerimeterGenerator::process()
|
||||||
perimeter_spacing / 2;
|
perimeter_spacing / 2;
|
||||||
// only apply infill overlap if we actually have one perimeter
|
// only apply infill overlap if we actually have one perimeter
|
||||||
if (inset > 0)
|
if (inset > 0)
|
||||||
inset -= scale_(this->config->get_abs_value("infill_overlap", unscale(inset + solid_infill_spacing / 2)));
|
inset -= scale_(this->config->get_abs_value("infill_overlap", unscale<double>(inset + solid_infill_spacing / 2)));
|
||||||
// simplify infill contours according to resolution
|
// simplify infill contours according to resolution
|
||||||
Polygons pp;
|
Polygons pp;
|
||||||
for (ExPolygon &ex : last)
|
for (ExPolygon &ex : last)
|
||||||
|
|
@ -420,7 +420,7 @@ static inline ExtrusionPaths thick_polyline_to_extrusion_paths(const ThickPolyli
|
||||||
path.polyline.append(line.b);
|
path.polyline.append(line.b);
|
||||||
// Convert from spacing to extrusion width based on the extrusion model
|
// Convert from spacing to extrusion width based on the extrusion model
|
||||||
// of a square extrusion ended with semi circles.
|
// of a square extrusion ended with semi circles.
|
||||||
flow.width = unscale(w) + flow.height * (1. - 0.25 * PI);
|
flow.width = unscale<float>(w) + flow.height * (1. - 0.25 * PI);
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
printf(" filling %f gap\n", flow.width);
|
printf(" filling %f gap\n", flow.width);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -148,33 +148,11 @@ Point Point::projection_onto(const Line &line) const
|
||||||
return ((line.a - *this).cast<double>().squaredNorm() < (line.b - *this).cast<double>().squaredNorm()) ? line.a : line.b;
|
return ((line.a - *this).cast<double>().squaredNorm() < (line.b - *this).cast<double>().squaredNorm()) ? line.a : line.b;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream &stm, const Pointf &pointf)
|
std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf)
|
||||||
{
|
{
|
||||||
return stm << pointf(0) << "," << pointf(1);
|
return stm << pointf(0) << "," << pointf(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pointf::rotate(double angle)
|
|
||||||
{
|
|
||||||
double cur_x = (*this)(0);
|
|
||||||
double cur_y = (*this)(1);
|
|
||||||
double s = ::sin(angle);
|
|
||||||
double c = ::cos(angle);
|
|
||||||
(*this)(0) = c * cur_x - s * cur_y;
|
|
||||||
(*this)(1) = c * cur_y + s * cur_x;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Pointf::rotate(double angle, const Pointf ¢er)
|
|
||||||
{
|
|
||||||
double cur_x = (*this)(0);
|
|
||||||
double cur_y = (*this)(1);
|
|
||||||
double s = ::sin(angle);
|
|
||||||
double c = ::cos(angle);
|
|
||||||
double dx = cur_x - center(0);
|
|
||||||
double dy = cur_y - center(1);
|
|
||||||
(*this)(0) = center(0) + c * dx - s * dy;
|
|
||||||
(*this)(1) = center(1) + c * dy + s * dx;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace int128 {
|
namespace int128 {
|
||||||
|
|
||||||
int orient(const Vec2crd &p1, const Vec2crd &p2, const Vec2crd &p3)
|
int orient(const Vec2crd &p1, const Vec2crd &p2, const Vec2crd &p3)
|
||||||
|
|
|
||||||
|
|
@ -16,19 +16,7 @@ namespace Slic3r {
|
||||||
class Line;
|
class Line;
|
||||||
class MultiPoint;
|
class MultiPoint;
|
||||||
class Point;
|
class Point;
|
||||||
class Point3;
|
|
||||||
class Pointf;
|
|
||||||
class Pointf3;
|
|
||||||
typedef Point Vector;
|
typedef Point Vector;
|
||||||
typedef Point3 Vector3;
|
|
||||||
typedef Pointf Vectorf;
|
|
||||||
typedef Pointf3 Vectorf3;
|
|
||||||
typedef std::vector<Point> Points;
|
|
||||||
typedef std::vector<Point*> PointPtrs;
|
|
||||||
typedef std::vector<const Point*> PointConstPtrs;
|
|
||||||
typedef std::vector<Point3> Points3;
|
|
||||||
typedef std::vector<Pointf> Pointfs;
|
|
||||||
typedef std::vector<Pointf3> Pointf3s;
|
|
||||||
|
|
||||||
// Eigen types, to replace the Slic3r's own types in the future.
|
// Eigen types, to replace the Slic3r's own types in the future.
|
||||||
// Vector types with a fixed point coordinate base type.
|
// Vector types with a fixed point coordinate base type.
|
||||||
|
|
@ -43,16 +31,37 @@ typedef Eigen::Matrix<float, 3, 1, Eigen::DontAlign> Vec3f;
|
||||||
typedef Eigen::Matrix<double, 2, 1, Eigen::DontAlign> Vec2d;
|
typedef Eigen::Matrix<double, 2, 1, Eigen::DontAlign> Vec2d;
|
||||||
typedef Eigen::Matrix<double, 3, 1, Eigen::DontAlign> Vec3d;
|
typedef Eigen::Matrix<double, 3, 1, Eigen::DontAlign> Vec3d;
|
||||||
|
|
||||||
|
typedef std::vector<Point> Points;
|
||||||
|
typedef std::vector<Point*> PointPtrs;
|
||||||
|
typedef std::vector<const Point*> PointConstPtrs;
|
||||||
|
typedef std::vector<Vec3crd> Points3;
|
||||||
|
typedef std::vector<Vec2d> Pointfs;
|
||||||
|
typedef std::vector<Vec3d> Pointf3s;
|
||||||
|
|
||||||
typedef Eigen::Transform<float, 2, Eigen::Affine, Eigen::DontAlign> Transform2f;
|
typedef Eigen::Transform<float, 2, Eigen::Affine, Eigen::DontAlign> Transform2f;
|
||||||
typedef Eigen::Transform<double, 2, Eigen::Affine, Eigen::DontAlign> Transform2d;
|
typedef Eigen::Transform<double, 2, Eigen::Affine, Eigen::DontAlign> Transform2d;
|
||||||
typedef Eigen::Transform<float, 3, Eigen::Affine, Eigen::DontAlign> Transform3f;
|
typedef Eigen::Transform<float, 3, Eigen::Affine, Eigen::DontAlign> Transform3f;
|
||||||
typedef Eigen::Transform<double, 3, Eigen::Affine, Eigen::DontAlign> Transform3d;
|
typedef Eigen::Transform<double, 3, Eigen::Affine, Eigen::DontAlign> Transform3d;
|
||||||
|
|
||||||
|
inline bool operator<(const Vec2d &lhs, const Vec2d &rhs) { return lhs(0) < rhs(0) || (lhs(0) == rhs(0) && lhs(1) < rhs(1)); }
|
||||||
|
|
||||||
inline int64_t cross2(const Vec2i64 &v1, const Vec2i64 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
inline int64_t cross2(const Vec2i64 &v1, const Vec2i64 &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||||
inline coord_t cross2(const Vec2crd &v1, const Vec2crd &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
inline coord_t cross2(const Vec2crd &v1, const Vec2crd &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||||
inline float cross2(const Vec2f &v1, const Vec2f &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
inline float cross2(const Vec2f &v1, const Vec2f &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||||
inline double cross2(const Vec2d &v1, const Vec2d &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
inline double cross2(const Vec2d &v1, const Vec2d &v2) { return v1(0) * v2(1) - v1(1) * v2(0); }
|
||||||
|
|
||||||
|
inline Vec2crd to_2d(const Vec3crd &pt3) { return Vec2crd(pt3(0), pt3(1)); }
|
||||||
|
inline Vec2i64 to_2d(const Vec3i64 &pt3) { return Vec2i64(pt3(0), pt3(1)); }
|
||||||
|
inline Vec2f to_2d(const Vec3f &pt3) { return Vec2f (pt3(0), pt3(1)); }
|
||||||
|
inline Vec2d to_2d(const Vec3d &pt3) { return Vec2d (pt3(0), pt3(1)); }
|
||||||
|
|
||||||
|
inline Vec2d unscale(coord_t x, coord_t y) { return Vec2d(unscale<double>(x), unscale<double>(y)); }
|
||||||
|
inline Vec2d unscale(const Vec2crd &pt) { return Vec2d(unscale<double>(pt(0)), unscale<double>(pt(1))); }
|
||||||
|
inline Vec2d unscale(const Vec2d &pt) { return Vec2d(unscale<double>(pt(0)), unscale<double>(pt(1))); }
|
||||||
|
inline Vec3d unscale(coord_t x, coord_t y, coord_t z) { return Vec3d(unscale<double>(x), unscale<double>(y), unscale<double>(z)); }
|
||||||
|
inline Vec3d unscale(const Vec3crd &pt) { return Vec3d(unscale<double>(pt(0)), unscale<double>(pt(1)), unscale<double>(pt(2))); }
|
||||||
|
inline Vec3d unscale(const Vec3d &pt) { return Vec3d(unscale<double>(pt(0)), unscale<double>(pt(1)), unscale<double>(pt(2))); }
|
||||||
|
|
||||||
inline std::string to_string(const Vec2crd &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + "]"; }
|
inline std::string to_string(const Vec2crd &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + "]"; }
|
||||||
inline std::string to_string(const Vec2d &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + "]"; }
|
inline std::string to_string(const Vec2d &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + "]"; }
|
||||||
inline std::string to_string(const Vec3crd &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + ", " + std::to_string(pt(2)) + "]"; }
|
inline std::string to_string(const Vec3crd &pt) { return std::string("[") + std::to_string(pt(0)) + ", " + std::to_string(pt(1)) + ", " + std::to_string(pt(2)) + "]"; }
|
||||||
|
|
@ -210,81 +219,7 @@ private:
|
||||||
coord_t m_grid_log2;
|
coord_t m_grid_log2;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Point3 : public Vec3crd
|
std::ostream& operator<<(std::ostream &stm, const Vec2d &pointf);
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef coord_t coord_type;
|
|
||||||
|
|
||||||
explicit Point3() { (*this)(0) = (*this)(1) = (*this)(2) = 0; }
|
|
||||||
explicit Point3(coord_t x, coord_t y, coord_t z) { (*this)(0) = x; (*this)(1) = y; (*this)(2) = z; }
|
|
||||||
// This constructor allows you to construct Point3 from Eigen expressions
|
|
||||||
template<typename OtherDerived>
|
|
||||||
Point3(const Eigen::MatrixBase<OtherDerived> &other) : Vec3crd(other) {}
|
|
||||||
static Point3 new_scale(coordf_t x, coordf_t y, coordf_t z) { return Point3(coord_t(scale_(x)), coord_t(scale_(y)), coord_t(scale_(z))); }
|
|
||||||
|
|
||||||
// This method allows you to assign Eigen expressions to MyVectorType
|
|
||||||
template<typename OtherDerived>
|
|
||||||
Point3& operator=(const Eigen::MatrixBase<OtherDerived> &other)
|
|
||||||
{
|
|
||||||
this->Vec3crd::operator=(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Point xy() const { return Point((*this)(0), (*this)(1)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream &stm, const Pointf &pointf);
|
|
||||||
|
|
||||||
class Pointf : public Vec2d
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef coordf_t coord_type;
|
|
||||||
|
|
||||||
explicit Pointf() { (*this)(0) = (*this)(1) = 0.; }
|
|
||||||
explicit Pointf(coordf_t x, coordf_t y) { (*this)(0) = x; (*this)(1) = y; }
|
|
||||||
// This constructor allows you to construct Pointf from Eigen expressions
|
|
||||||
template<typename OtherDerived>
|
|
||||||
Pointf(const Eigen::MatrixBase<OtherDerived> &other) : Vec2d(other) {}
|
|
||||||
static Pointf new_unscale(coord_t x, coord_t y) { return Pointf(unscale(x), unscale(y)); }
|
|
||||||
static Pointf new_unscale(const Point &p) { return Pointf(unscale(p(0)), unscale(p(1))); }
|
|
||||||
|
|
||||||
// This method allows you to assign Eigen expressions to MyVectorType
|
|
||||||
template<typename OtherDerived>
|
|
||||||
Pointf& operator=(const Eigen::MatrixBase<OtherDerived> &other)
|
|
||||||
{
|
|
||||||
this->Vec2d::operator=(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rotate(double angle);
|
|
||||||
void rotate(double angle, const Pointf ¢er);
|
|
||||||
|
|
||||||
bool operator< (const Pointf& rhs) const { return (*this)(0) < rhs(0) || ((*this)(0) == rhs(0) && (*this)(1) < rhs(1)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class Pointf3 : public Vec3d
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef coordf_t coord_type;
|
|
||||||
|
|
||||||
explicit Pointf3() { (*this)(0) = (*this)(1) = (*this)(2) = 0.; }
|
|
||||||
explicit Pointf3(coordf_t x, coordf_t y, coordf_t z) { (*this)(0) = x; (*this)(1) = y; (*this)(2) = z; }
|
|
||||||
// This constructor allows you to construct Pointf from Eigen expressions
|
|
||||||
template<typename OtherDerived>
|
|
||||||
Pointf3(const Eigen::MatrixBase<OtherDerived> &other) : Vec3d(other) {}
|
|
||||||
static Pointf3 new_unscale(coord_t x, coord_t y, coord_t z) { return Pointf3(unscale(x), unscale(y), unscale(z)); }
|
|
||||||
static Pointf3 new_unscale(const Point3& p) { return Pointf3(unscale(p(0)), unscale(p(1)), unscale(p(2))); }
|
|
||||||
|
|
||||||
// This method allows you to assign Eigen expressions to MyVectorType
|
|
||||||
template<typename OtherDerived>
|
|
||||||
Pointf3& operator=(const Eigen::MatrixBase<OtherDerived> &other)
|
|
||||||
{
|
|
||||||
this->Vec3d::operator=(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pointf xy() const { return Pointf((*this)(0), (*this)(1)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -297,10 +297,10 @@ Point Polygon::point_projection(const Point &point) const
|
||||||
dmin = d;
|
dmin = d;
|
||||||
proj = pt1;
|
proj = pt1;
|
||||||
}
|
}
|
||||||
Pointf v1(coordf_t(pt1(0) - pt0(0)), coordf_t(pt1(1) - pt0(1)));
|
Vec2d v1(coordf_t(pt1(0) - pt0(0)), coordf_t(pt1(1) - pt0(1)));
|
||||||
coordf_t div = v1.squaredNorm();
|
coordf_t div = v1.squaredNorm();
|
||||||
if (div > 0.) {
|
if (div > 0.) {
|
||||||
Pointf v2(coordf_t(point(0) - pt0(0)), coordf_t(point(1) - pt0(1)));
|
Vec2d v2(coordf_t(point(0) - pt0(0)), coordf_t(point(1) - pt0(1)));
|
||||||
coordf_t t = v1.dot(v2) / div;
|
coordf_t t = v1.dot(v2) / div;
|
||||||
if (t > 0. && t < 1.) {
|
if (t > 0. && t < 1.) {
|
||||||
Point foot(coord_t(floor(coordf_t(pt0(0)) + t * v1(0) + 0.5)), coord_t(floor(coordf_t(pt0(1)) + t * v1(1) + 0.5)));
|
Point foot(coord_t(floor(coordf_t(pt0(0)) + t * v1(0) + 0.5)), coord_t(floor(coordf_t(pt0(1)) + t * v1(1) + 0.5)));
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,12 @@ public:
|
||||||
explicit Polygon(const Points &points): MultiPoint(points) {}
|
explicit Polygon(const Points &points): MultiPoint(points) {}
|
||||||
Polygon(const Polygon &other) : MultiPoint(other.points) {}
|
Polygon(const Polygon &other) : MultiPoint(other.points) {}
|
||||||
Polygon(Polygon &&other) : MultiPoint(std::move(other.points)) {}
|
Polygon(Polygon &&other) : MultiPoint(std::move(other.points)) {}
|
||||||
static Polygon new_scale(std::vector<Pointf> points) {
|
static Polygon new_scale(const std::vector<Vec2d> &points) {
|
||||||
Points int_points;
|
Polygon pgn;
|
||||||
for (auto pt : points)
|
pgn.points.reserve(points.size());
|
||||||
int_points.push_back(Point::new_scale(pt(0), pt(1)));
|
for (const Vec2d &pt : points)
|
||||||
return Polygon(int_points);
|
pgn.points.emplace_back(Point::new_scale(pt(0), pt(1)));
|
||||||
|
return pgn;
|
||||||
}
|
}
|
||||||
Polygon& operator=(const Polygon &other) { points = other.points; return *this; }
|
Polygon& operator=(const Polygon &other) { points = other.points; return *this; }
|
||||||
Polygon& operator=(Polygon &&other) { points = std::move(other.points); return *this; }
|
Polygon& operator=(Polygon &&other) { points = std::move(other.points); return *this; }
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,11 @@ public:
|
||||||
explicit Polyline(const Point &p1, const Point &p2) { points.reserve(2); points.emplace_back(p1); points.emplace_back(p2); }
|
explicit Polyline(const Point &p1, const Point &p2) { points.reserve(2); points.emplace_back(p1); points.emplace_back(p2); }
|
||||||
Polyline& operator=(const Polyline &other) { points = other.points; return *this; }
|
Polyline& operator=(const Polyline &other) { points = other.points; return *this; }
|
||||||
Polyline& operator=(Polyline &&other) { points = std::move(other.points); return *this; }
|
Polyline& operator=(Polyline &&other) { points = std::move(other.points); return *this; }
|
||||||
static Polyline new_scale(std::vector<Pointf> points) {
|
static Polyline new_scale(const std::vector<Vec2d> &points) {
|
||||||
Polyline pl;
|
Polyline pl;
|
||||||
Points int_points;
|
pl.points.reserve(points.size());
|
||||||
for (auto pt : points)
|
for (const Vec2d &pt : points)
|
||||||
int_points.push_back(Point::new_scale(pt(0), pt(1)));
|
pl.points.emplace_back(Point::new_scale(pt(0), pt(1)));
|
||||||
pl.append(int_points);
|
|
||||||
return pl;
|
return pl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -540,7 +540,7 @@ bool Print::has_skirt() const
|
||||||
std::string Print::validate() const
|
std::string Print::validate() const
|
||||||
{
|
{
|
||||||
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.bed_shape.values));
|
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(config.bed_shape.values));
|
||||||
BoundingBoxf3 print_volume(Pointf3(unscale(bed_box_2D.min(0)), unscale(bed_box_2D.min(1)), 0.0), Pointf3(unscale(bed_box_2D.max(0)), unscale(bed_box_2D.max(1)), config.max_print_height));
|
BoundingBoxf3 print_volume(unscale(bed_box_2D.min(0), bed_box_2D.min(1), 0.0), unscale(bed_box_2D.max(0), bed_box_2D.max(1), scale_(config.max_print_height)));
|
||||||
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
|
// Allow the objects to protrude below the print bed, only the part of the object above the print bed will be sliced.
|
||||||
print_volume.min(2) = -1e10;
|
print_volume.min(2) = -1e10;
|
||||||
unsigned int printable_count = 0;
|
unsigned int printable_count = 0;
|
||||||
|
|
@ -728,7 +728,7 @@ BoundingBox Print::bounding_box() const
|
||||||
for (const PrintObject *object : this->objects)
|
for (const PrintObject *object : this->objects)
|
||||||
for (Point copy : object->_shifted_copies) {
|
for (Point copy : object->_shifted_copies) {
|
||||||
bb.merge(copy);
|
bb.merge(copy);
|
||||||
copy += object->size.xy();
|
copy += to_2d(object->size);
|
||||||
bb.merge(copy);
|
bb.merge(copy);
|
||||||
}
|
}
|
||||||
return bb;
|
return bb;
|
||||||
|
|
@ -971,7 +971,7 @@ void Print::_make_skirt()
|
||||||
this->skirt.append(eloop);
|
this->skirt.append(eloop);
|
||||||
if (this->config.min_skirt_length.value > 0) {
|
if (this->config.min_skirt_length.value > 0) {
|
||||||
// The skirt length is limited. Sum the total amount of filament length extruded, in mm.
|
// The skirt length is limited. Sum the total amount of filament length extruded, in mm.
|
||||||
extruded_length[extruder_idx] += unscale(loop.length()) * extruders_e_per_mm[extruder_idx];
|
extruded_length[extruder_idx] += unscale<double>(loop.length()) * extruders_e_per_mm[extruder_idx];
|
||||||
if (extruded_length[extruder_idx] < this->config.min_skirt_length.value) {
|
if (extruded_length[extruder_idx] < this->config.min_skirt_length.value) {
|
||||||
// Not extruded enough yet with the current extruder. Add another loop.
|
// Not extruded enough yet with the current extruder. Add another loop.
|
||||||
if (i == 1)
|
if (i == 1)
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ public:
|
||||||
// so that next call to make_perimeters() performs a union() before computing loops
|
// so that next call to make_perimeters() performs a union() before computing loops
|
||||||
bool typed_slices;
|
bool typed_slices;
|
||||||
|
|
||||||
Point3 size; // XYZ in scaled coordinates
|
Vec3crd size; // XYZ in scaled coordinates
|
||||||
|
|
||||||
// scaled coordinates to add to copies (to compensate for the alignment
|
// scaled coordinates to add to copies (to compensate for the alignment
|
||||||
// operated when creating the object but still preserving a coherent API
|
// operated when creating the object but still preserving a coherent API
|
||||||
|
|
@ -138,13 +138,13 @@ public:
|
||||||
const ModelObject* model_object() const { return this->_model_object; }
|
const ModelObject* model_object() const { return this->_model_object; }
|
||||||
|
|
||||||
const Points& copies() const { return this->_copies; }
|
const Points& copies() const { return this->_copies; }
|
||||||
bool add_copy(const Pointf &point);
|
bool add_copy(const Vec2d &point);
|
||||||
bool delete_last_copy();
|
bool delete_last_copy();
|
||||||
bool delete_all_copies() { return this->set_copies(Points()); }
|
bool delete_all_copies() { return this->set_copies(Points()); }
|
||||||
bool set_copies(const Points &points);
|
bool set_copies(const Points &points);
|
||||||
bool reload_model_instances();
|
bool reload_model_instances();
|
||||||
// since the object is aligned to origin, bounding box coincides with size
|
// since the object is aligned to origin, bounding box coincides with size
|
||||||
BoundingBox bounding_box() const { return BoundingBox(Point(0,0), this->size.xy()); }
|
BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); }
|
||||||
|
|
||||||
// adds region_id, too, if necessary
|
// adds region_id, too, if necessary
|
||||||
void add_region_volume(unsigned int region_id, int volume_id) {
|
void add_region_volume(unsigned int region_id, int volume_id) {
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,50 @@ namespace Slic3r {
|
||||||
|
|
||||||
PrintConfigDef::PrintConfigDef()
|
PrintConfigDef::PrintConfigDef()
|
||||||
{
|
{
|
||||||
t_optiondef_map &Options = this->options;
|
this->init_common_params();
|
||||||
|
this->init_fff_params();
|
||||||
|
this->init_sla_params();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintConfigDef::init_common_params()
|
||||||
|
{
|
||||||
|
t_optiondef_map &Options = this->options;
|
||||||
|
ConfigOptionDef* def;
|
||||||
|
|
||||||
|
def = this->add("printer_technology", coEnum);
|
||||||
|
def->label = L("Printer technology");
|
||||||
|
def->tooltip = L("Printer technology");
|
||||||
|
def->cli = "printer-technology=s";
|
||||||
|
def->enum_keys_map = &ConfigOptionEnum<PrinterTechnology>::get_enum_values();
|
||||||
|
def->enum_values.push_back("FFF");
|
||||||
|
def->enum_values.push_back("SLA");
|
||||||
|
def->default_value = new ConfigOptionEnum<PrinterTechnology>(ptFFF);
|
||||||
|
|
||||||
|
def = this->add("bed_shape", coPoints);
|
||||||
|
def->label = L("Bed shape");
|
||||||
|
def->default_value = new ConfigOptionPoints{ Vec2d(0, 0), Vec2d(200, 0), Vec2d(200, 200), Vec2d(0, 200) };
|
||||||
|
|
||||||
|
def = this->add("layer_height", coFloat);
|
||||||
|
def->label = L("Layer height");
|
||||||
|
def->category = L("Layers and Perimeters");
|
||||||
|
def->tooltip = L("This setting controls the height (and thus the total number) of the slices/layers. "
|
||||||
|
"Thinner layers give better accuracy but take more time to print.");
|
||||||
|
def->sidetext = L("mm");
|
||||||
|
def->cli = "layer-height=f";
|
||||||
|
def->min = 0;
|
||||||
|
def->default_value = new ConfigOptionFloat(0.3);
|
||||||
|
|
||||||
|
def = this->add("max_print_height", coFloat);
|
||||||
|
def->label = L("Max print height");
|
||||||
|
def->tooltip = L("Set this to the maximum height that can be reached by your extruder while printing.");
|
||||||
|
def->sidetext = L("mm");
|
||||||
|
def->cli = "max-print-height=f";
|
||||||
|
def->default_value = new ConfigOptionFloat(200.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrintConfigDef::init_fff_params()
|
||||||
|
{
|
||||||
|
t_optiondef_map &Options = this->options;
|
||||||
ConfigOptionDef* def;
|
ConfigOptionDef* def;
|
||||||
|
|
||||||
// Maximum extruder temperature, bumped to 1500 to support printing of glass.
|
// Maximum extruder temperature, bumped to 1500 to support printing of glass.
|
||||||
|
|
@ -33,10 +75,6 @@ PrintConfigDef::PrintConfigDef()
|
||||||
def->cli = "avoid-crossing-perimeters!";
|
def->cli = "avoid-crossing-perimeters!";
|
||||||
def->default_value = new ConfigOptionBool(false);
|
def->default_value = new ConfigOptionBool(false);
|
||||||
|
|
||||||
def = this->add("bed_shape", coPoints);
|
|
||||||
def->label = L("Bed shape");
|
|
||||||
def->default_value = new ConfigOptionPoints { Pointf(0,0), Pointf(200,0), Pointf(200,200), Pointf(0,200) };
|
|
||||||
|
|
||||||
def = this->add("bed_temperature", coInts);
|
def = this->add("bed_temperature", coInts);
|
||||||
def->label = L("Other layers");
|
def->label = L("Other layers");
|
||||||
def->tooltip = L("Bed temperature for layers after the first one. "
|
def->tooltip = L("Bed temperature for layers after the first one. "
|
||||||
|
|
@ -392,7 +430,7 @@ PrintConfigDef::PrintConfigDef()
|
||||||
"from the XY coordinate).");
|
"from the XY coordinate).");
|
||||||
def->sidetext = L("mm");
|
def->sidetext = L("mm");
|
||||||
def->cli = "extruder-offset=s@";
|
def->cli = "extruder-offset=s@";
|
||||||
def->default_value = new ConfigOptionPoints { Pointf(0,0) };
|
def->default_value = new ConfigOptionPoints { Vec2d(0,0) };
|
||||||
|
|
||||||
def = this->add("extrusion_axis", coString);
|
def = this->add("extrusion_axis", coString);
|
||||||
def->label = L("Extrusion axis");
|
def->label = L("Extrusion axis");
|
||||||
|
|
@ -906,16 +944,6 @@ PrintConfigDef::PrintConfigDef()
|
||||||
def->height = 50;
|
def->height = 50;
|
||||||
def->default_value = new ConfigOptionString("");
|
def->default_value = new ConfigOptionString("");
|
||||||
|
|
||||||
def = this->add("layer_height", coFloat);
|
|
||||||
def->label = L("Layer height");
|
|
||||||
def->category = L("Layers and Perimeters");
|
|
||||||
def->tooltip = L("This setting controls the height (and thus the total number) of the slices/layers. "
|
|
||||||
"Thinner layers give better accuracy but take more time to print.");
|
|
||||||
def->sidetext = L("mm");
|
|
||||||
def->cli = "layer-height=f";
|
|
||||||
def->min = 0;
|
|
||||||
def->default_value = new ConfigOptionFloat(0.3);
|
|
||||||
|
|
||||||
def = this->add("remaining_times", coBool);
|
def = this->add("remaining_times", coBool);
|
||||||
def->label = L("Supports remaining times");
|
def->label = L("Supports remaining times");
|
||||||
def->tooltip = L("Emit M73 P[percent printed] R[remaining time in minutes] at 1 minute"
|
def->tooltip = L("Emit M73 P[percent printed] R[remaining time in minutes] at 1 minute"
|
||||||
|
|
@ -1036,13 +1064,6 @@ PrintConfigDef::PrintConfigDef()
|
||||||
def->min = 0;
|
def->min = 0;
|
||||||
def->default_value = new ConfigOptionFloats { 0. };
|
def->default_value = new ConfigOptionFloats { 0. };
|
||||||
|
|
||||||
def = this->add("max_print_height", coFloat);
|
|
||||||
def->label = L("Max print height");
|
|
||||||
def->tooltip = L("Set this to the maximum height that can be reached by your extruder while printing.");
|
|
||||||
def->sidetext = L("mm");
|
|
||||||
def->cli = "max-print-height=f";
|
|
||||||
def->default_value = new ConfigOptionFloat(200.0);
|
|
||||||
|
|
||||||
def = this->add("max_print_speed", coFloat);
|
def = this->add("max_print_speed", coFloat);
|
||||||
def->label = L("Max print speed");
|
def->label = L("Max print speed");
|
||||||
def->tooltip = L("When setting other speed settings to 0 Slic3r will autocalculate the optimal speed "
|
def->tooltip = L("When setting other speed settings to 0 Slic3r will autocalculate the optimal speed "
|
||||||
|
|
@ -1137,25 +1158,37 @@ PrintConfigDef::PrintConfigDef()
|
||||||
def->cli = "nozzle-diameter=f@";
|
def->cli = "nozzle-diameter=f@";
|
||||||
def->default_value = new ConfigOptionFloats { 0.5 };
|
def->default_value = new ConfigOptionFloats { 0.5 };
|
||||||
|
|
||||||
def = this->add("octoprint_apikey", coString);
|
def = this->add("host_type", coEnum);
|
||||||
def->label = L("API Key");
|
def->label = L("Host Type");
|
||||||
def->tooltip = L("Slic3r can upload G-code files to OctoPrint. This field should contain "
|
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field must contain "
|
||||||
"the API Key required for authentication.");
|
"the kind of the host.");
|
||||||
def->cli = "octoprint-apikey=s";
|
def->cli = "host-type=s";
|
||||||
|
def->enum_keys_map = &ConfigOptionEnum<PrintHostType>::get_enum_values();
|
||||||
|
def->enum_values.push_back("octoprint");
|
||||||
|
def->enum_values.push_back("duet");
|
||||||
|
def->enum_labels.push_back("OctoPrint");
|
||||||
|
def->enum_labels.push_back("Duet");
|
||||||
|
def->default_value = new ConfigOptionEnum<PrintHostType>(htOctoPrint);
|
||||||
|
|
||||||
|
def = this->add("printhost_apikey", coString);
|
||||||
|
def->label = L("API Key / Password");
|
||||||
|
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
|
||||||
|
"the API Key or the password required for authentication.");
|
||||||
|
def->cli = "printhost-apikey=s";
|
||||||
def->default_value = new ConfigOptionString("");
|
def->default_value = new ConfigOptionString("");
|
||||||
|
|
||||||
def = this->add("octoprint_cafile", coString);
|
def = this->add("printhost_cafile", coString);
|
||||||
def->label = "HTTPS CA file";
|
def->label = "HTTPS CA file";
|
||||||
def->tooltip = "Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. "
|
def->tooltip = "Custom CA certificate file can be specified for HTTPS OctoPrint connections, in crt/pem format. "
|
||||||
"If left blank, the default OS CA certificate repository is used.";
|
"If left blank, the default OS CA certificate repository is used.";
|
||||||
def->cli = "octoprint-cafile=s";
|
def->cli = "printhost-cafile=s";
|
||||||
def->default_value = new ConfigOptionString("");
|
def->default_value = new ConfigOptionString("");
|
||||||
|
|
||||||
def = this->add("octoprint_host", coString);
|
def = this->add("print_host", coString);
|
||||||
def->label = L("Hostname, IP or URL");
|
def->label = L("Hostname, IP or URL");
|
||||||
def->tooltip = L("Slic3r can upload G-code files to OctoPrint. This field should contain "
|
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
|
||||||
"the hostname, IP address or URL of the OctoPrint instance.");
|
"the hostname, IP address or URL of the printer host instance.");
|
||||||
def->cli = "octoprint-host=s";
|
def->cli = "print-host=s";
|
||||||
def->default_value = new ConfigOptionString("");
|
def->default_value = new ConfigOptionString("");
|
||||||
|
|
||||||
def = this->add("only_retract_when_crossing_perimeters", coBool);
|
def = this->add("only_retract_when_crossing_perimeters", coBool);
|
||||||
|
|
@ -2121,6 +2154,103 @@ PrintConfigDef::PrintConfigDef()
|
||||||
def->default_value = new ConfigOptionFloat(35.);
|
def->default_value = new ConfigOptionFloat(35.);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrintConfigDef::init_sla_params()
|
||||||
|
{
|
||||||
|
t_optiondef_map &Options = this->options;
|
||||||
|
ConfigOptionDef* def;
|
||||||
|
|
||||||
|
// SLA Printer settings
|
||||||
|
def = this->add("display_width", coFloat);
|
||||||
|
def->label = L("Display width");
|
||||||
|
def->tooltip = L("Width of the display");
|
||||||
|
def->cli = "display-width=f";
|
||||||
|
def->min = 1;
|
||||||
|
def->default_value = new ConfigOptionFloat(150.);
|
||||||
|
|
||||||
|
def = this->add("display_height", coFloat);
|
||||||
|
def->label = L("Display height");
|
||||||
|
def->tooltip = L("Height of the display");
|
||||||
|
def->cli = "display-height=f";
|
||||||
|
def->min = 1;
|
||||||
|
def->default_value = new ConfigOptionFloat(100.);
|
||||||
|
|
||||||
|
def = this->add("display_pixels_x", coInt);
|
||||||
|
def->full_label = L("Number of pixels in");
|
||||||
|
def->label = ("X");
|
||||||
|
def->tooltip = L("Number of pixels in X");
|
||||||
|
def->cli = "display-pixels-x=i";
|
||||||
|
def->min = 100;
|
||||||
|
def->default_value = new ConfigOptionInt(2000);
|
||||||
|
|
||||||
|
def = this->add("display_pixels_y", coInt);
|
||||||
|
def->label = ("Y");
|
||||||
|
def->tooltip = L("Number of pixels in Y");
|
||||||
|
def->cli = "display-pixels-y=i";
|
||||||
|
def->min = 100;
|
||||||
|
def->default_value = new ConfigOptionInt(1000);
|
||||||
|
|
||||||
|
def = this->add("printer_correction", coFloats);
|
||||||
|
def->full_label = L("Printer scaling correction");
|
||||||
|
def->tooltip = L("Printer scaling correction");
|
||||||
|
def->min = 0;
|
||||||
|
def->default_value = new ConfigOptionFloats( { 1., 1., 1. } );
|
||||||
|
|
||||||
|
// SLA Material settings.
|
||||||
|
def = this->add("initial_layer_height", coFloat);
|
||||||
|
def->label = L("Initial layer height");
|
||||||
|
def->tooltip = L("Initial layer height");
|
||||||
|
def->sidetext = L("mm");
|
||||||
|
def->cli = "initial-layer-height=f";
|
||||||
|
def->min = 0;
|
||||||
|
def->default_value = new ConfigOptionFloat(0.3);
|
||||||
|
|
||||||
|
def = this->add("exposure_time", coFloat);
|
||||||
|
def->label = L("Exposure time");
|
||||||
|
def->tooltip = L("Exposure time");
|
||||||
|
def->sidetext = L("s");
|
||||||
|
def->cli = "exposure-time=f";
|
||||||
|
def->min = 0;
|
||||||
|
def->default_value = new ConfigOptionFloat(10);
|
||||||
|
|
||||||
|
def = this->add("initial_exposure_time", coFloat);
|
||||||
|
def->label = L("Initial exposure time");
|
||||||
|
def->tooltip = L("Initial exposure time");
|
||||||
|
def->sidetext = L("s");
|
||||||
|
def->cli = "initial-exposure-time=f";
|
||||||
|
def->min = 0;
|
||||||
|
def->default_value = new ConfigOptionFloat(15);
|
||||||
|
|
||||||
|
def = this->add("material_correction_printing", coFloats);
|
||||||
|
def->full_label = L("Correction for expansion when printing");
|
||||||
|
def->tooltip = L("Correction for expansion when printing");
|
||||||
|
def->min = 0;
|
||||||
|
def->default_value = new ConfigOptionFloats( { 1. , 1., 1. } );
|
||||||
|
|
||||||
|
def = this->add("material_correction_curing", coFloats);
|
||||||
|
def->full_label = L("Correction for expansion after curing");
|
||||||
|
def->tooltip = L("Correction for expansion after curing");
|
||||||
|
def->min = 0;
|
||||||
|
def->default_value = new ConfigOptionFloats( { 1. , 1., 1. } );
|
||||||
|
|
||||||
|
def = this->add("material_notes", coString);
|
||||||
|
def->label = L("SLA print material notes");
|
||||||
|
def->tooltip = L("You can put your notes regarding the SLA print material here.");
|
||||||
|
def->cli = "material-notes=s";
|
||||||
|
def->multiline = true;
|
||||||
|
def->full_width = true;
|
||||||
|
def->height = 130;
|
||||||
|
def->default_value = new ConfigOptionString("");
|
||||||
|
|
||||||
|
def = this->add("default_sla_material_profile", coString);
|
||||||
|
def->label = L("Default SLA material profile");
|
||||||
|
def->tooltip = L("Default print profile associated with the current printer profile. "
|
||||||
|
"On selection of the current printer profile, this print profile will be activated.");
|
||||||
|
def->default_value = new ConfigOptionString();
|
||||||
|
|
||||||
|
def = this->add("sla_material_settings_id", coString);
|
||||||
|
def->default_value = new ConfigOptionString("");
|
||||||
|
}
|
||||||
|
|
||||||
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
|
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
|
||||||
{
|
{
|
||||||
// handle legacy options
|
// handle legacy options
|
||||||
|
|
@ -2153,10 +2283,6 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << "0x0," << p.value(0) << "x0," << p.value(0) << "x" << p.value(1) << ",0x" << p.value(1);
|
oss << "0x0," << p.value(0) << "x0," << p.value(0) << "x" << p.value(1) << ",0x" << p.value(1);
|
||||||
value = oss.str();
|
value = oss.str();
|
||||||
// Maybe one day we will rename octoprint_host to print_host as it has been done in the upstream Slic3r.
|
|
||||||
// Commenting this out fixes github issue #869 for now.
|
|
||||||
// } else if (opt_key == "octoprint_host" && !value.empty()) {
|
|
||||||
// opt_key = "print_host";
|
|
||||||
} else if ((opt_key == "perimeter_acceleration" && value == "25")
|
} else if ((opt_key == "perimeter_acceleration" && value == "25")
|
||||||
|| (opt_key == "infill_acceleration" && value == "50")) {
|
|| (opt_key == "infill_acceleration" && value == "50")) {
|
||||||
/* For historical reasons, the world's full of configs having these very low values;
|
/* For historical reasons, the world's full of configs having these very low values;
|
||||||
|
|
@ -2167,6 +2293,12 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
||||||
} else if (opt_key == "support_material_pattern" && value == "pillars") {
|
} else if (opt_key == "support_material_pattern" && value == "pillars") {
|
||||||
// Slic3r PE does not support the pillars. They never worked well.
|
// Slic3r PE does not support the pillars. They never worked well.
|
||||||
value = "rectilinear";
|
value = "rectilinear";
|
||||||
|
} else if (opt_key == "octoprint_host") {
|
||||||
|
opt_key = "print_host";
|
||||||
|
} else if (opt_key == "octoprint_cafile") {
|
||||||
|
opt_key = "printhost_cafile";
|
||||||
|
} else if (opt_key == "octoprint_apikey") {
|
||||||
|
opt_key = "printhost_apikey";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore the following obsolete configuration keys:
|
// Ignore the following obsolete configuration keys:
|
||||||
|
|
@ -2176,9 +2308,6 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
||||||
"standby_temperature", "scale", "rotate", "duplicate", "duplicate_grid",
|
"standby_temperature", "scale", "rotate", "duplicate", "duplicate_grid",
|
||||||
"start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start",
|
"start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start",
|
||||||
"seal_position", "vibration_limit", "bed_size",
|
"seal_position", "vibration_limit", "bed_size",
|
||||||
// Maybe one day we will rename octoprint_host to print_host as it has been done in the upstream Slic3r.
|
|
||||||
// Commenting this out fixes github issue #869 for now.
|
|
||||||
// "octoprint_host",
|
|
||||||
"print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe"
|
"print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -2188,7 +2317,6 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! print_config_def.has(opt_key)) {
|
if (! print_config_def.has(opt_key)) {
|
||||||
//printf("Unknown option %s\n", opt_key.c_str());
|
|
||||||
opt_key = "";
|
opt_key = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -2446,4 +2574,8 @@ StaticPrintConfig::StaticCache<class Slic3r::PrintConfig> PrintConfig::s_c
|
||||||
StaticPrintConfig::StaticCache<class Slic3r::HostConfig> HostConfig::s_cache_HostConfig;
|
StaticPrintConfig::StaticCache<class Slic3r::HostConfig> HostConfig::s_cache_HostConfig;
|
||||||
StaticPrintConfig::StaticCache<class Slic3r::FullPrintConfig> FullPrintConfig::s_cache_FullPrintConfig;
|
StaticPrintConfig::StaticCache<class Slic3r::FullPrintConfig> FullPrintConfig::s_cache_FullPrintConfig;
|
||||||
|
|
||||||
|
StaticPrintConfig::StaticCache<class Slic3r::SLAMaterialConfig> SLAMaterialConfig::s_cache_SLAMaterialConfig;
|
||||||
|
StaticPrintConfig::StaticCache<class Slic3r::SLAPrinterConfig> SLAPrinterConfig::s_cache_SLAPrinterConfig;
|
||||||
|
StaticPrintConfig::StaticCache<class Slic3r::SLAFullPrintConfig> SLAFullPrintConfig::s_cache_SLAFullPrintConfig;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,23 @@
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
enum PrinterTechnology
|
||||||
|
{
|
||||||
|
// Fused Filament Fabrication
|
||||||
|
ptFFF,
|
||||||
|
// Stereolitography
|
||||||
|
ptSLA,
|
||||||
|
};
|
||||||
|
|
||||||
enum GCodeFlavor {
|
enum GCodeFlavor {
|
||||||
gcfRepRap, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlin, gcfSailfish, gcfMach3, gcfMachinekit,
|
gcfRepRap, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlin, gcfSailfish, gcfMach3, gcfMachinekit,
|
||||||
gcfSmoothie, gcfNoExtrusion,
|
gcfSmoothie, gcfNoExtrusion,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PrintHostType {
|
||||||
|
htOctoPrint, htDuet,
|
||||||
|
};
|
||||||
|
|
||||||
enum InfillPattern {
|
enum InfillPattern {
|
||||||
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
ipRectilinear, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
|
||||||
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
|
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral,
|
||||||
|
|
@ -44,7 +56,16 @@ enum FilamentType {
|
||||||
ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA
|
ftPLA, ftABS, ftPET, ftHIPS, ftFLEX, ftSCAFF, ftEDGE, ftNGEN, ftPVA
|
||||||
};
|
};
|
||||||
|
|
||||||
template<> inline t_config_enum_values& ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
|
template<> inline const t_config_enum_values& ConfigOptionEnum<PrinterTechnology>::get_enum_values() {
|
||||||
|
static t_config_enum_values keys_map;
|
||||||
|
if (keys_map.empty()) {
|
||||||
|
keys_map["FFF"] = ptFFF;
|
||||||
|
keys_map["SLA"] = ptSLA;
|
||||||
|
}
|
||||||
|
return keys_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline const t_config_enum_values& ConfigOptionEnum<GCodeFlavor>::get_enum_values() {
|
||||||
static t_config_enum_values keys_map;
|
static t_config_enum_values keys_map;
|
||||||
if (keys_map.empty()) {
|
if (keys_map.empty()) {
|
||||||
keys_map["reprap"] = gcfRepRap;
|
keys_map["reprap"] = gcfRepRap;
|
||||||
|
|
@ -61,7 +82,16 @@ template<> inline t_config_enum_values& ConfigOptionEnum<GCodeFlavor>::get_enum_
|
||||||
return keys_map;
|
return keys_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> inline t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enum_values() {
|
template<> inline const t_config_enum_values& ConfigOptionEnum<PrintHostType>::get_enum_values() {
|
||||||
|
static t_config_enum_values keys_map;
|
||||||
|
if (keys_map.empty()) {
|
||||||
|
keys_map["octoprint"] = htOctoPrint;
|
||||||
|
keys_map["duet"] = htDuet;
|
||||||
|
}
|
||||||
|
return keys_map;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enum_values() {
|
||||||
static t_config_enum_values keys_map;
|
static t_config_enum_values keys_map;
|
||||||
if (keys_map.empty()) {
|
if (keys_map.empty()) {
|
||||||
keys_map["rectilinear"] = ipRectilinear;
|
keys_map["rectilinear"] = ipRectilinear;
|
||||||
|
|
@ -81,7 +111,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enu
|
||||||
return keys_map;
|
return keys_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> inline t_config_enum_values& ConfigOptionEnum<SupportMaterialPattern>::get_enum_values() {
|
template<> inline const t_config_enum_values& ConfigOptionEnum<SupportMaterialPattern>::get_enum_values() {
|
||||||
static t_config_enum_values keys_map;
|
static t_config_enum_values keys_map;
|
||||||
if (keys_map.empty()) {
|
if (keys_map.empty()) {
|
||||||
keys_map["rectilinear"] = smpRectilinear;
|
keys_map["rectilinear"] = smpRectilinear;
|
||||||
|
|
@ -91,7 +121,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum<SupportMaterialPattern>
|
||||||
return keys_map;
|
return keys_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> inline t_config_enum_values& ConfigOptionEnum<SeamPosition>::get_enum_values() {
|
template<> inline const t_config_enum_values& ConfigOptionEnum<SeamPosition>::get_enum_values() {
|
||||||
static t_config_enum_values keys_map;
|
static t_config_enum_values keys_map;
|
||||||
if (keys_map.empty()) {
|
if (keys_map.empty()) {
|
||||||
keys_map["random"] = spRandom;
|
keys_map["random"] = spRandom;
|
||||||
|
|
@ -102,7 +132,7 @@ template<> inline t_config_enum_values& ConfigOptionEnum<SeamPosition>::get_enum
|
||||||
return keys_map;
|
return keys_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> inline t_config_enum_values& ConfigOptionEnum<FilamentType>::get_enum_values() {
|
template<> inline const t_config_enum_values& ConfigOptionEnum<FilamentType>::get_enum_values() {
|
||||||
static t_config_enum_values keys_map;
|
static t_config_enum_values keys_map;
|
||||||
if (keys_map.empty()) {
|
if (keys_map.empty()) {
|
||||||
keys_map["PLA"] = ftPLA;
|
keys_map["PLA"] = ftPLA;
|
||||||
|
|
@ -126,6 +156,11 @@ public:
|
||||||
PrintConfigDef();
|
PrintConfigDef();
|
||||||
|
|
||||||
static void handle_legacy(t_config_option_key &opt_key, std::string &value);
|
static void handle_legacy(t_config_option_key &opt_key, std::string &value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init_common_params();
|
||||||
|
void init_fff_params();
|
||||||
|
void init_sla_params();
|
||||||
};
|
};
|
||||||
|
|
||||||
// The one and only global definition of SLic3r configuration options.
|
// The one and only global definition of SLic3r configuration options.
|
||||||
|
|
@ -801,18 +836,20 @@ class HostConfig : public StaticPrintConfig
|
||||||
{
|
{
|
||||||
STATIC_PRINT_CONFIG_CACHE(HostConfig)
|
STATIC_PRINT_CONFIG_CACHE(HostConfig)
|
||||||
public:
|
public:
|
||||||
ConfigOptionString octoprint_host;
|
ConfigOptionEnum<PrintHostType> host_type;
|
||||||
ConfigOptionString octoprint_apikey;
|
ConfigOptionString print_host;
|
||||||
ConfigOptionString octoprint_cafile;
|
ConfigOptionString printhost_apikey;
|
||||||
|
ConfigOptionString printhost_cafile;
|
||||||
ConfigOptionString serial_port;
|
ConfigOptionString serial_port;
|
||||||
ConfigOptionInt serial_speed;
|
ConfigOptionInt serial_speed;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initialize(StaticCacheBase &cache, const char *base_ptr)
|
void initialize(StaticCacheBase &cache, const char *base_ptr)
|
||||||
{
|
{
|
||||||
OPT_PTR(octoprint_host);
|
OPT_PTR(host_type);
|
||||||
OPT_PTR(octoprint_apikey);
|
OPT_PTR(print_host);
|
||||||
OPT_PTR(octoprint_cafile);
|
OPT_PTR(printhost_apikey);
|
||||||
|
OPT_PTR(printhost_cafile);
|
||||||
OPT_PTR(serial_port);
|
OPT_PTR(serial_port);
|
||||||
OPT_PTR(serial_speed);
|
OPT_PTR(serial_speed);
|
||||||
}
|
}
|
||||||
|
|
@ -844,6 +881,73 @@ protected:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class SLAMaterialConfig : public StaticPrintConfig
|
||||||
|
{
|
||||||
|
STATIC_PRINT_CONFIG_CACHE(SLAMaterialConfig)
|
||||||
|
public:
|
||||||
|
ConfigOptionFloat layer_height;
|
||||||
|
ConfigOptionFloat initial_layer_height;
|
||||||
|
ConfigOptionFloat exposure_time;
|
||||||
|
ConfigOptionFloat initial_exposure_time;
|
||||||
|
ConfigOptionFloats material_correction_printing;
|
||||||
|
ConfigOptionFloats material_correction_curing;
|
||||||
|
protected:
|
||||||
|
void initialize(StaticCacheBase &cache, const char *base_ptr)
|
||||||
|
{
|
||||||
|
OPT_PTR(layer_height);
|
||||||
|
OPT_PTR(initial_layer_height);
|
||||||
|
OPT_PTR(exposure_time);
|
||||||
|
OPT_PTR(initial_exposure_time);
|
||||||
|
OPT_PTR(material_correction_printing);
|
||||||
|
OPT_PTR(material_correction_curing);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SLAPrinterConfig : public StaticPrintConfig
|
||||||
|
{
|
||||||
|
STATIC_PRINT_CONFIG_CACHE(SLAPrinterConfig)
|
||||||
|
public:
|
||||||
|
ConfigOptionEnum<PrinterTechnology> printer_technology;
|
||||||
|
ConfigOptionPoints bed_shape;
|
||||||
|
ConfigOptionFloat max_print_height;
|
||||||
|
ConfigOptionFloat display_width;
|
||||||
|
ConfigOptionFloat display_height;
|
||||||
|
ConfigOptionInt display_pixels_x;
|
||||||
|
ConfigOptionInt display_pixels_y;
|
||||||
|
ConfigOptionFloats printer_correction;
|
||||||
|
protected:
|
||||||
|
void initialize(StaticCacheBase &cache, const char *base_ptr)
|
||||||
|
{
|
||||||
|
OPT_PTR(printer_technology);
|
||||||
|
OPT_PTR(bed_shape);
|
||||||
|
OPT_PTR(max_print_height);
|
||||||
|
OPT_PTR(display_width);
|
||||||
|
OPT_PTR(display_height);
|
||||||
|
OPT_PTR(display_pixels_x);
|
||||||
|
OPT_PTR(display_pixels_y);
|
||||||
|
OPT_PTR(printer_correction);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SLAFullPrintConfig : public SLAPrinterConfig, public SLAMaterialConfig
|
||||||
|
{
|
||||||
|
STATIC_PRINT_CONFIG_CACHE_DERIVED(SLAFullPrintConfig)
|
||||||
|
SLAFullPrintConfig() : SLAPrinterConfig(0), SLAMaterialConfig(0) { initialize_cache(); *this = s_cache_SLAFullPrintConfig.defaults(); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Validate the SLAFullPrintConfig. Returns an empty string on success, otherwise an error message is returned.
|
||||||
|
// std::string validate();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Protected constructor to be called to initialize ConfigCache::m_default.
|
||||||
|
SLAFullPrintConfig(int) : SLAPrinterConfig(0), SLAMaterialConfig(0) {}
|
||||||
|
void initialize(StaticCacheBase &cache, const char *base_ptr)
|
||||||
|
{
|
||||||
|
this->SLAPrinterConfig ::initialize(cache, base_ptr);
|
||||||
|
this->SLAMaterialConfig::initialize(cache, base_ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#undef STATIC_PRINT_CONFIG_CACHE
|
#undef STATIC_PRINT_CONFIG_CACHE
|
||||||
#undef STATIC_PRINT_CONFIG_CACHE_BASE
|
#undef STATIC_PRINT_CONFIG_CACHE_BASE
|
||||||
#undef STATIC_PRINT_CONFIG_CACHE_DERIVED
|
#undef STATIC_PRINT_CONFIG_CACHE_DERIVED
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
|
||||||
typed_slices(false),
|
typed_slices(false),
|
||||||
_print(print),
|
_print(print),
|
||||||
_model_object(model_object),
|
_model_object(model_object),
|
||||||
|
size(Vec3crd::Zero()),
|
||||||
layer_height_profile_valid(false)
|
layer_height_profile_valid(false)
|
||||||
{
|
{
|
||||||
// Compute the translation to be applied to our meshes so that we work with smaller coordinates
|
// Compute the translation to be applied to our meshes so that we work with smaller coordinates
|
||||||
|
|
@ -50,8 +51,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
|
||||||
// (copies are expressed in G-code coordinates and this translation is not publicly exposed).
|
// (copies are expressed in G-code coordinates and this translation is not publicly exposed).
|
||||||
this->_copies_shift = Point::new_scale(modobj_bbox.min(0), modobj_bbox.min(1));
|
this->_copies_shift = Point::new_scale(modobj_bbox.min(0), modobj_bbox.min(1));
|
||||||
// Scale the object size and store it
|
// Scale the object size and store it
|
||||||
Pointf3 size = modobj_bbox.size();
|
this->size = (modobj_bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
|
||||||
this->size = Point3::new_scale(size(0), size(1), size(2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->reload_model_instances();
|
this->reload_model_instances();
|
||||||
|
|
@ -59,7 +59,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, const Bounding
|
||||||
this->layer_height_profile = model_object->layer_height_profile;
|
this->layer_height_profile = model_object->layer_height_profile;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PrintObject::add_copy(const Pointf &point)
|
bool PrintObject::add_copy(const Vec2d &point)
|
||||||
{
|
{
|
||||||
Points points = this->_copies;
|
Points points = this->_copies;
|
||||||
points.push_back(Point::new_scale(point(0), point(1)));
|
points.push_back(Point::new_scale(point(0), point(1)));
|
||||||
|
|
@ -1121,7 +1121,7 @@ SlicingParameters PrintObject::slicing_parameters() const
|
||||||
{
|
{
|
||||||
return SlicingParameters::create_from_config(
|
return SlicingParameters::create_from_config(
|
||||||
this->print()->config, this->config,
|
this->print()->config, this->config,
|
||||||
unscale(this->size(2)), this->print()->object_extruders());
|
unscale<double>(this->size(2)), this->print()->object_extruders());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PrintObject::update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const
|
bool PrintObject::update_layer_height_profile(std::vector<coordf_t> &layer_height_profile) const
|
||||||
|
|
@ -1335,7 +1335,7 @@ std::vector<ExPolygons> PrintObject::_slice_region(size_t region_id, const std::
|
||||||
// consider the first one
|
// consider the first one
|
||||||
this->model_object()->instances.front()->transform_mesh(&mesh, true);
|
this->model_object()->instances.front()->transform_mesh(&mesh, true);
|
||||||
// align mesh to Z = 0 (it should be already aligned actually) and apply XY shift
|
// align mesh to Z = 0 (it should be already aligned actually) and apply XY shift
|
||||||
mesh.translate(- float(unscale(this->_copies_shift(0))), - float(unscale(this->_copies_shift(1))), -float(this->model_object()->bounding_box().min(2)));
|
mesh.translate(- unscale<float>(this->_copies_shift(0)), - unscale<float>(this->_copies_shift(1)), - float(this->model_object()->bounding_box().min(2)));
|
||||||
// perform actual slicing
|
// perform actual slicing
|
||||||
TriangleMeshSlicer mslicer(&mesh);
|
TriangleMeshSlicer mslicer(&mesh);
|
||||||
mslicer.slice(z, &layers);
|
mslicer.slice(z, &layers);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <boost/nowide/cstdio.hpp>
|
#include <boost/nowide/cstdio.hpp>
|
||||||
|
|
||||||
#define COORD(x) ((float)unscale((x))*10)
|
#define COORD(x) (unscale<float>((x))*10)
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
|
@ -58,8 +58,8 @@ SVG::draw(const Line &line, std::string stroke, coordf_t stroke_width)
|
||||||
|
|
||||||
void SVG::draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coordf_t stroke_width)
|
void SVG::draw(const ThickLine &line, const std::string &fill, const std::string &stroke, coordf_t stroke_width)
|
||||||
{
|
{
|
||||||
Pointf dir(line.b(0)-line.a(0), line.b(1)-line.a(1));
|
Vec2d dir(line.b(0)-line.a(0), line.b(1)-line.a(1));
|
||||||
Pointf perp(-dir(1), dir(0));
|
Vec2d perp(-dir(1), dir(0));
|
||||||
coordf_t len = sqrt(perp(0)*perp(0) + perp(1)*perp(1));
|
coordf_t len = sqrt(perp(0)*perp(0) + perp(1)*perp(1));
|
||||||
coordf_t da = coordf_t(0.5)*line.a_width/len;
|
coordf_t da = coordf_t(0.5)*line.a_width/len;
|
||||||
coordf_t db = coordf_t(0.5)*line.b_width/len;
|
coordf_t db = coordf_t(0.5)*line.b_width/len;
|
||||||
|
|
|
||||||
|
|
@ -561,15 +561,15 @@ int generate_layer_height_texture(
|
||||||
void *data, int rows, int cols, bool level_of_detail_2nd_level)
|
void *data, int rows, int cols, bool level_of_detail_2nd_level)
|
||||||
{
|
{
|
||||||
// https://github.com/aschn/gnuplot-colorbrewer
|
// https://github.com/aschn/gnuplot-colorbrewer
|
||||||
std::vector<Point3> palette_raw;
|
std::vector<Vec3crd> palette_raw;
|
||||||
palette_raw.push_back(Point3(0x01A, 0x098, 0x050));
|
palette_raw.push_back(Vec3crd(0x01A, 0x098, 0x050));
|
||||||
palette_raw.push_back(Point3(0x066, 0x0BD, 0x063));
|
palette_raw.push_back(Vec3crd(0x066, 0x0BD, 0x063));
|
||||||
palette_raw.push_back(Point3(0x0A6, 0x0D9, 0x06A));
|
palette_raw.push_back(Vec3crd(0x0A6, 0x0D9, 0x06A));
|
||||||
palette_raw.push_back(Point3(0x0D9, 0x0F1, 0x0EB));
|
palette_raw.push_back(Vec3crd(0x0D9, 0x0F1, 0x0EB));
|
||||||
palette_raw.push_back(Point3(0x0FE, 0x0E6, 0x0EB));
|
palette_raw.push_back(Vec3crd(0x0FE, 0x0E6, 0x0EB));
|
||||||
palette_raw.push_back(Point3(0x0FD, 0x0AE, 0x061));
|
palette_raw.push_back(Vec3crd(0x0FD, 0x0AE, 0x061));
|
||||||
palette_raw.push_back(Point3(0x0F4, 0x06D, 0x043));
|
palette_raw.push_back(Vec3crd(0x0F4, 0x06D, 0x043));
|
||||||
palette_raw.push_back(Point3(0x0D7, 0x030, 0x027));
|
palette_raw.push_back(Vec3crd(0x0D7, 0x030, 0x027));
|
||||||
|
|
||||||
// Clear the main texture and the 2nd LOD level.
|
// Clear the main texture and the 2nd LOD level.
|
||||||
// memset(data, 0, rows * cols * (level_of_detail_2nd_level ? 5 : 4));
|
// memset(data, 0, rows * cols * (level_of_detail_2nd_level ? 5 : 4));
|
||||||
|
|
@ -600,14 +600,14 @@ int generate_layer_height_texture(
|
||||||
int idx1 = clamp(0, int(palette_raw.size() - 1), int(floor(idxf)));
|
int idx1 = clamp(0, int(palette_raw.size() - 1), int(floor(idxf)));
|
||||||
int idx2 = std::min(int(palette_raw.size() - 1), idx1 + 1);
|
int idx2 = std::min(int(palette_raw.size() - 1), idx1 + 1);
|
||||||
coordf_t t = idxf - coordf_t(idx1);
|
coordf_t t = idxf - coordf_t(idx1);
|
||||||
const Point3 &color1 = palette_raw[idx1];
|
const Vec3crd &color1 = palette_raw[idx1];
|
||||||
const Point3 &color2 = palette_raw[idx2];
|
const Vec3crd &color2 = palette_raw[idx2];
|
||||||
coordf_t z = cell_to_z * coordf_t(cell);
|
coordf_t z = cell_to_z * coordf_t(cell);
|
||||||
assert(z >= lo && z <= hi);
|
assert(z >= lo && z <= hi);
|
||||||
// Intensity profile to visualize the layers.
|
// Intensity profile to visualize the layers.
|
||||||
coordf_t intensity = cos(M_PI * 0.7 * (mid - z) / h);
|
coordf_t intensity = cos(M_PI * 0.7 * (mid - z) / h);
|
||||||
// Color mapping from layer height to RGB.
|
// Color mapping from layer height to RGB.
|
||||||
Pointf3 color(
|
Vec3d color(
|
||||||
intensity * lerp(coordf_t(color1(0)), coordf_t(color2(0)), t),
|
intensity * lerp(coordf_t(color1(0)), coordf_t(color2(0)), t),
|
||||||
intensity * lerp(coordf_t(color1(1)), coordf_t(color2(1)), t),
|
intensity * lerp(coordf_t(color1(1)), coordf_t(color2(1)), t),
|
||||||
intensity * lerp(coordf_t(color1(2)), coordf_t(color2(2)), t));
|
intensity * lerp(coordf_t(color1(2)), coordf_t(color2(2)), t));
|
||||||
|
|
@ -636,10 +636,10 @@ int generate_layer_height_texture(
|
||||||
int idx1 = clamp(0, int(palette_raw.size() - 1), int(floor(idxf)));
|
int idx1 = clamp(0, int(palette_raw.size() - 1), int(floor(idxf)));
|
||||||
int idx2 = std::min(int(palette_raw.size() - 1), idx1 + 1);
|
int idx2 = std::min(int(palette_raw.size() - 1), idx1 + 1);
|
||||||
coordf_t t = idxf - coordf_t(idx1);
|
coordf_t t = idxf - coordf_t(idx1);
|
||||||
const Point3 &color1 = palette_raw[idx1];
|
const Vec3crd &color1 = palette_raw[idx1];
|
||||||
const Point3 &color2 = palette_raw[idx2];
|
const Vec3crd &color2 = palette_raw[idx2];
|
||||||
// Color mapping from layer height to RGB.
|
// Color mapping from layer height to RGB.
|
||||||
Pointf3 color(
|
Vec3d color(
|
||||||
lerp(coordf_t(color1(0)), coordf_t(color2(0)), t),
|
lerp(coordf_t(color1(0)), coordf_t(color2(0)), t),
|
||||||
lerp(coordf_t(color1(1)), coordf_t(color2(1)), t),
|
lerp(coordf_t(color1(1)), coordf_t(color2(1)), t),
|
||||||
lerp(coordf_t(color1(2)), coordf_t(color2(2)), t));
|
lerp(coordf_t(color1(2)), coordf_t(color2(2)), t));
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ void SlicingAdaptive::clear()
|
||||||
std::pair<float, float> face_z_span(const stl_facet *f)
|
std::pair<float, float> face_z_span(const stl_facet *f)
|
||||||
{
|
{
|
||||||
return std::pair<float, float>(
|
return std::pair<float, float>(
|
||||||
std::min(std::min(f->vertex[0].z, f->vertex[1].z), f->vertex[2].z),
|
std::min(std::min(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2)),
|
||||||
std::max(std::max(f->vertex[0].z, f->vertex[1].z), f->vertex[2].z));
|
std::max(std::max(f->vertex[0](2), f->vertex[1](2)), f->vertex[2](2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SlicingAdaptive::prepare()
|
void SlicingAdaptive::prepare()
|
||||||
|
|
@ -40,7 +40,7 @@ void SlicingAdaptive::prepare()
|
||||||
// 3) Generate Z components of the facet normals.
|
// 3) Generate Z components of the facet normals.
|
||||||
m_face_normal_z.assign(m_faces.size(), 0.f);
|
m_face_normal_z.assign(m_faces.size(), 0.f);
|
||||||
for (size_t iface = 0; iface < m_faces.size(); ++ iface)
|
for (size_t iface = 0; iface < m_faces.size(); ++ iface)
|
||||||
m_face_normal_z[iface] = m_faces[iface]->normal.z;
|
m_face_normal_z[iface] = m_faces[iface]->normal(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet)
|
float SlicingAdaptive::cusp_height(float z, float cusp_value, int ¤t_facet)
|
||||||
|
|
|
||||||
|
|
@ -2057,8 +2057,8 @@ void LoopInterfaceProcessor::generate(MyLayerExtruded &top_contact_layer, const
|
||||||
const Point &p1 = *(it-1);
|
const Point &p1 = *(it-1);
|
||||||
const Point &p2 = *it;
|
const Point &p2 = *it;
|
||||||
// Intersection of a ray (p1, p2) with a circle placed at center_last, with radius of circle_distance.
|
// Intersection of a ray (p1, p2) with a circle placed at center_last, with radius of circle_distance.
|
||||||
const Pointf v_seg(coordf_t(p2(0)) - coordf_t(p1(0)), coordf_t(p2(1)) - coordf_t(p1(1)));
|
const Vec2d v_seg(coordf_t(p2(0)) - coordf_t(p1(0)), coordf_t(p2(1)) - coordf_t(p1(1)));
|
||||||
const Pointf v_cntr(coordf_t(p1(0) - center_last(0)), coordf_t(p1(1) - center_last(1)));
|
const Vec2d v_cntr(coordf_t(p1(0) - center_last(0)), coordf_t(p1(1) - center_last(1)));
|
||||||
coordf_t a = v_seg.squaredNorm();
|
coordf_t a = v_seg.squaredNorm();
|
||||||
coordf_t b = 2. * v_seg.dot(v_cntr);
|
coordf_t b = 2. * v_seg.dot(v_cntr);
|
||||||
coordf_t c = v_cntr.squaredNorm() - circle_distance * circle_distance;
|
coordf_t c = v_cntr.squaredNorm() - circle_distance * circle_distance;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,9 @@
|
||||||
#include "TriangleMesh.hpp"
|
#include "TriangleMesh.hpp"
|
||||||
#include "ClipperUtils.hpp"
|
#include "ClipperUtils.hpp"
|
||||||
#include "Geometry.hpp"
|
#include "Geometry.hpp"
|
||||||
|
#include "qhull/src/libqhullcpp/Qhull.h"
|
||||||
|
#include "qhull/src/libqhullcpp/QhullFacetList.h"
|
||||||
|
#include "qhull/src/libqhullcpp/QhullVertexSet.h"
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
@ -15,6 +18,8 @@
|
||||||
|
|
||||||
#include <tbb/parallel_for.h>
|
#include <tbb/parallel_for.h>
|
||||||
|
|
||||||
|
#include <Eigen/Dense>
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define DEBUG
|
#define DEBUG
|
||||||
#define _DEBUG
|
#define _DEBUG
|
||||||
|
|
@ -30,13 +35,7 @@
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
TriangleMesh::TriangleMesh()
|
TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd>& facets )
|
||||||
: repaired(false)
|
|
||||||
{
|
|
||||||
stl_initialize(&this->stl);
|
|
||||||
}
|
|
||||||
|
|
||||||
TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Point3>& facets )
|
|
||||||
: repaired(false)
|
: repaired(false)
|
||||||
{
|
{
|
||||||
stl_initialize(&this->stl);
|
stl_initialize(&this->stl);
|
||||||
|
|
@ -51,51 +50,22 @@ TriangleMesh::TriangleMesh(const Pointf3s &points, const std::vector<Point3>& fa
|
||||||
|
|
||||||
for (int i = 0; i < stl.stats.number_of_facets; i++) {
|
for (int i = 0; i < stl.stats.number_of_facets; i++) {
|
||||||
stl_facet facet;
|
stl_facet facet;
|
||||||
|
facet.vertex[0] = points[facets[i](0)].cast<float>();
|
||||||
const Pointf3& ref_f1 = points[facets[i](0)];
|
facet.vertex[1] = points[facets[i](1)].cast<float>();
|
||||||
facet.vertex[0].x = ref_f1(0);
|
facet.vertex[2] = points[facets[i](2)].cast<float>();
|
||||||
facet.vertex[0].y = ref_f1(1);
|
|
||||||
facet.vertex[0].z = ref_f1(2);
|
|
||||||
|
|
||||||
const Pointf3& ref_f2 = points[facets[i](1)];
|
|
||||||
facet.vertex[1].x = ref_f2(0);
|
|
||||||
facet.vertex[1].y = ref_f2(1);
|
|
||||||
facet.vertex[1].z = ref_f2(2);
|
|
||||||
|
|
||||||
const Pointf3& ref_f3 = points[facets[i](2)];
|
|
||||||
facet.vertex[2].x = ref_f3(0);
|
|
||||||
facet.vertex[2].y = ref_f3(1);
|
|
||||||
facet.vertex[2].z = ref_f3(2);
|
|
||||||
|
|
||||||
facet.extra[0] = 0;
|
facet.extra[0] = 0;
|
||||||
facet.extra[1] = 0;
|
facet.extra[1] = 0;
|
||||||
|
|
||||||
float normal[3];
|
stl_normal normal;
|
||||||
stl_calculate_normal(normal, &facet);
|
stl_calculate_normal(normal, &facet);
|
||||||
stl_normalize_vector(normal);
|
stl_normalize_vector(normal);
|
||||||
facet.normal.x = normal[0];
|
facet.normal = normal;
|
||||||
facet.normal.y = normal[1];
|
|
||||||
facet.normal.z = normal[2];
|
|
||||||
|
|
||||||
stl.facet_start[i] = facet;
|
stl.facet_start[i] = facet;
|
||||||
}
|
}
|
||||||
stl_get_size(&stl);
|
stl_get_size(&stl);
|
||||||
}
|
}
|
||||||
|
|
||||||
TriangleMesh::TriangleMesh(const TriangleMesh &other) :
|
|
||||||
repaired(false)
|
|
||||||
{
|
|
||||||
stl_initialize(&this->stl);
|
|
||||||
*this = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
TriangleMesh::TriangleMesh(TriangleMesh &&other) :
|
|
||||||
repaired(false)
|
|
||||||
{
|
|
||||||
stl_initialize(&this->stl);
|
|
||||||
this->swap(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
|
TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
|
||||||
{
|
{
|
||||||
stl_close(&this->stl);
|
stl_close(&this->stl);
|
||||||
|
|
@ -123,42 +93,8 @@ TriangleMesh& TriangleMesh::operator=(const TriangleMesh &other)
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
TriangleMesh& TriangleMesh::operator=(TriangleMesh &&other)
|
void TriangleMesh::repair()
|
||||||
{
|
{
|
||||||
this->swap(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TriangleMesh::swap(TriangleMesh &other)
|
|
||||||
{
|
|
||||||
std::swap(this->stl, other.stl);
|
|
||||||
std::swap(this->repaired, other.repaired);
|
|
||||||
}
|
|
||||||
|
|
||||||
TriangleMesh::~TriangleMesh() {
|
|
||||||
stl_close(&this->stl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TriangleMesh::ReadSTLFile(const char* input_file) {
|
|
||||||
stl_open(&stl, input_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TriangleMesh::write_ascii(const char* output_file)
|
|
||||||
{
|
|
||||||
stl_write_ascii(&this->stl, output_file, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TriangleMesh::write_binary(const char* output_file)
|
|
||||||
{
|
|
||||||
stl_write_binary(&this->stl, output_file, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TriangleMesh::repair() {
|
|
||||||
if (this->repaired) return;
|
if (this->repaired) return;
|
||||||
|
|
||||||
// admesh fails when repairing empty meshes
|
// admesh fails when repairing empty meshes
|
||||||
|
|
@ -255,13 +191,7 @@ void TriangleMesh::check_topology()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TriangleMesh::is_manifold() const
|
void TriangleMesh::reset_repair_stats() {
|
||||||
{
|
|
||||||
return this->stl.stats.connected_facets_3_edge == this->stl.stats.number_of_facets;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TriangleMesh::reset_repair_stats() {
|
|
||||||
this->stl.stats.degenerate_facets = 0;
|
this->stl.stats.degenerate_facets = 0;
|
||||||
this->stl.stats.edges_fixed = 0;
|
this->stl.stats.edges_fixed = 0;
|
||||||
this->stl.stats.facets_removed = 0;
|
this->stl.stats.facets_removed = 0;
|
||||||
|
|
@ -271,8 +201,7 @@ TriangleMesh::reset_repair_stats() {
|
||||||
this->stl.stats.normals_fixed = 0;
|
this->stl.stats.normals_fixed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool TriangleMesh::needed_repair() const
|
||||||
TriangleMesh::needed_repair() const
|
|
||||||
{
|
{
|
||||||
return this->stl.stats.degenerate_facets > 0
|
return this->stl.stats.degenerate_facets > 0
|
||||||
|| this->stl.stats.edges_fixed > 0
|
|| this->stl.stats.edges_fixed > 0
|
||||||
|
|
@ -282,14 +211,8 @@ TriangleMesh::needed_repair() const
|
||||||
|| this->stl.stats.backwards_edges > 0;
|
|| this->stl.stats.backwards_edges > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t
|
void TriangleMesh::WriteOBJFile(char* output_file)
|
||||||
TriangleMesh::facets_count() const
|
|
||||||
{
|
{
|
||||||
return this->stl.stats.number_of_facets;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TriangleMesh::WriteOBJFile(char* output_file) {
|
|
||||||
stl_generate_shared_vertices(&stl);
|
stl_generate_shared_vertices(&stl);
|
||||||
stl_write_obj(&stl, output_file);
|
stl_write_obj(&stl, output_file);
|
||||||
}
|
}
|
||||||
|
|
@ -300,13 +223,9 @@ void TriangleMesh::scale(float factor)
|
||||||
stl_invalidate_shared_vertices(&this->stl);
|
stl_invalidate_shared_vertices(&this->stl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriangleMesh::scale(const Pointf3 &versor)
|
void TriangleMesh::scale(const Vec3d &versor)
|
||||||
{
|
{
|
||||||
float fversor[3];
|
stl_scale_versor(&this->stl, versor.cast<float>());
|
||||||
fversor[0] = versor(0);
|
|
||||||
fversor[1] = versor(1);
|
|
||||||
fversor[2] = versor(2);
|
|
||||||
stl_scale_versor(&this->stl, fversor);
|
|
||||||
stl_invalidate_shared_vertices(&this->stl);
|
stl_invalidate_shared_vertices(&this->stl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -336,21 +255,6 @@ void TriangleMesh::rotate(float angle, const Axis &axis)
|
||||||
stl_invalidate_shared_vertices(&this->stl);
|
stl_invalidate_shared_vertices(&this->stl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriangleMesh::rotate_x(float angle)
|
|
||||||
{
|
|
||||||
this->rotate(angle, X);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TriangleMesh::rotate_y(float angle)
|
|
||||||
{
|
|
||||||
this->rotate(angle, Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TriangleMesh::rotate_z(float angle)
|
|
||||||
{
|
|
||||||
this->rotate(angle, Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TriangleMesh::mirror(const Axis &axis)
|
void TriangleMesh::mirror(const Axis &axis)
|
||||||
{
|
{
|
||||||
if (axis == X) {
|
if (axis == X) {
|
||||||
|
|
@ -363,21 +267,6 @@ void TriangleMesh::mirror(const Axis &axis)
|
||||||
stl_invalidate_shared_vertices(&this->stl);
|
stl_invalidate_shared_vertices(&this->stl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriangleMesh::mirror_x()
|
|
||||||
{
|
|
||||||
this->mirror(X);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TriangleMesh::mirror_y()
|
|
||||||
{
|
|
||||||
this->mirror(Y);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TriangleMesh::mirror_z()
|
|
||||||
{
|
|
||||||
this->mirror(Z);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TriangleMesh::transform(const float* matrix3x4)
|
void TriangleMesh::transform(const float* matrix3x4)
|
||||||
{
|
{
|
||||||
if (matrix3x4 == nullptr)
|
if (matrix3x4 == nullptr)
|
||||||
|
|
@ -390,10 +279,9 @@ void TriangleMesh::transform(const float* matrix3x4)
|
||||||
void TriangleMesh::align_to_origin()
|
void TriangleMesh::align_to_origin()
|
||||||
{
|
{
|
||||||
this->translate(
|
this->translate(
|
||||||
-(this->stl.stats.min.x),
|
- this->stl.stats.min(0),
|
||||||
-(this->stl.stats.min.y),
|
- this->stl.stats.min(1),
|
||||||
-(this->stl.stats.min.z)
|
- this->stl.stats.min(2));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TriangleMesh::rotate(double angle, Point* center)
|
void TriangleMesh::rotate(double angle, Point* center)
|
||||||
|
|
@ -476,14 +364,14 @@ size_t TriangleMesh::number_of_patches() const
|
||||||
return num_bodies;
|
return num_bodies;
|
||||||
}
|
}
|
||||||
|
|
||||||
TriangleMeshPtrs
|
TriangleMeshPtrs TriangleMesh::split() const
|
||||||
TriangleMesh::split() const
|
|
||||||
{
|
{
|
||||||
TriangleMeshPtrs meshes;
|
TriangleMeshPtrs meshes;
|
||||||
std::set<int> seen_facets;
|
std::vector<unsigned char> facet_visited(this->stl.stats.number_of_facets, false);
|
||||||
|
|
||||||
// we need neighbors
|
// we need neighbors
|
||||||
if (!this->repaired) CONFESS("split() requires repair()");
|
if (!this->repaired)
|
||||||
|
CONFESS("split() requires repair()");
|
||||||
|
|
||||||
// loop while we have remaining facets
|
// loop while we have remaining facets
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
@ -491,23 +379,24 @@ TriangleMesh::split() const
|
||||||
std::queue<int> facet_queue;
|
std::queue<int> facet_queue;
|
||||||
std::deque<int> facets;
|
std::deque<int> facets;
|
||||||
for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; facet_idx++) {
|
for (int facet_idx = 0; facet_idx < this->stl.stats.number_of_facets; facet_idx++) {
|
||||||
if (seen_facets.find(facet_idx) == seen_facets.end()) {
|
if (! facet_visited[facet_idx]) {
|
||||||
// if facet was not seen put it into queue and start searching
|
// if facet was not seen put it into queue and start searching
|
||||||
facet_queue.push(facet_idx);
|
facet_queue.push(facet_idx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (facet_queue.empty()) break;
|
if (facet_queue.empty())
|
||||||
|
break;
|
||||||
|
|
||||||
while (!facet_queue.empty()) {
|
while (! facet_queue.empty()) {
|
||||||
int facet_idx = facet_queue.front();
|
int facet_idx = facet_queue.front();
|
||||||
facet_queue.pop();
|
facet_queue.pop();
|
||||||
if (seen_facets.find(facet_idx) != seen_facets.end()) continue;
|
if (! facet_visited[facet_idx]) {
|
||||||
facets.emplace_back(facet_idx);
|
facets.emplace_back(facet_idx);
|
||||||
for (int j = 0; j <= 2; j++) {
|
for (int j = 0; j < 3; ++ j)
|
||||||
facet_queue.push(this->stl.neighbors_start[facet_idx].neighbor[j]);
|
facet_queue.push(this->stl.neighbors_start[facet_idx].neighbor[j]);
|
||||||
|
facet_visited[facet_idx] = true;
|
||||||
}
|
}
|
||||||
seen_facets.insert(facet_idx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TriangleMesh* mesh = new TriangleMesh;
|
TriangleMesh* mesh = new TriangleMesh;
|
||||||
|
|
@ -518,19 +407,17 @@ TriangleMesh::split() const
|
||||||
stl_clear_error(&mesh->stl);
|
stl_clear_error(&mesh->stl);
|
||||||
stl_allocate(&mesh->stl);
|
stl_allocate(&mesh->stl);
|
||||||
|
|
||||||
int first = 1;
|
bool first = true;
|
||||||
for (std::deque<int>::const_iterator facet = facets.begin(); facet != facets.end(); ++facet) {
|
for (std::deque<int>::const_iterator facet = facets.begin(); facet != facets.end(); ++ facet) {
|
||||||
mesh->stl.facet_start[facet - facets.begin()] = this->stl.facet_start[*facet];
|
mesh->stl.facet_start[facet - facets.begin()] = this->stl.facet_start[*facet];
|
||||||
stl_facet_stats(&mesh->stl, this->stl.facet_start[*facet], first);
|
stl_facet_stats(&mesh->stl, this->stl.facet_start[*facet], first);
|
||||||
first = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return meshes;
|
return meshes;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void TriangleMesh::merge(const TriangleMesh &mesh)
|
||||||
TriangleMesh::merge(const TriangleMesh &mesh)
|
|
||||||
{
|
{
|
||||||
// reset stats and metadata
|
// reset stats and metadata
|
||||||
int number_of_facets = this->stl.stats.number_of_facets;
|
int number_of_facets = this->stl.stats.number_of_facets;
|
||||||
|
|
@ -561,9 +448,9 @@ ExPolygons TriangleMesh::horizontal_projection() const
|
||||||
stl_facet* facet = &this->stl.facet_start[i];
|
stl_facet* facet = &this->stl.facet_start[i];
|
||||||
Polygon p;
|
Polygon p;
|
||||||
p.points.resize(3);
|
p.points.resize(3);
|
||||||
p.points[0] = Point::new_scale(facet->vertex[0].x, facet->vertex[0].y);
|
p.points[0] = Point::new_scale(facet->vertex[0](0), facet->vertex[0](1));
|
||||||
p.points[1] = Point::new_scale(facet->vertex[1].x, facet->vertex[1].y);
|
p.points[1] = Point::new_scale(facet->vertex[1](0), facet->vertex[1](1));
|
||||||
p.points[2] = Point::new_scale(facet->vertex[2].x, facet->vertex[2].y);
|
p.points[2] = Point::new_scale(facet->vertex[2](0), facet->vertex[2](1));
|
||||||
p.make_counter_clockwise(); // do this after scaling, as winding order might change while doing that
|
p.make_counter_clockwise(); // do this after scaling, as winding order might change while doing that
|
||||||
pp.emplace_back(p);
|
pp.emplace_back(p);
|
||||||
}
|
}
|
||||||
|
|
@ -578,28 +465,142 @@ Polygon TriangleMesh::convex_hull()
|
||||||
Points pp;
|
Points pp;
|
||||||
pp.reserve(this->stl.stats.shared_vertices);
|
pp.reserve(this->stl.stats.shared_vertices);
|
||||||
for (int i = 0; i < this->stl.stats.shared_vertices; ++ i) {
|
for (int i = 0; i < this->stl.stats.shared_vertices; ++ i) {
|
||||||
stl_vertex* v = &this->stl.v_shared[i];
|
const stl_vertex &v = this->stl.v_shared[i];
|
||||||
pp.emplace_back(Point::new_scale(v->x, v->y));
|
pp.emplace_back(Point::new_scale(v(0), v(1)));
|
||||||
}
|
}
|
||||||
return Slic3r::Geometry::convex_hull(pp);
|
return Slic3r::Geometry::convex_hull(pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
BoundingBoxf3
|
BoundingBoxf3 TriangleMesh::bounding_box() const
|
||||||
TriangleMesh::bounding_box() const
|
|
||||||
{
|
{
|
||||||
BoundingBoxf3 bb;
|
BoundingBoxf3 bb;
|
||||||
bb.defined = true;
|
bb.defined = true;
|
||||||
bb.min(0) = this->stl.stats.min.x;
|
bb.min = this->stl.stats.min.cast<double>();
|
||||||
bb.min(1) = this->stl.stats.min.y;
|
bb.max = this->stl.stats.max.cast<double>();
|
||||||
bb.min(2) = this->stl.stats.min.z;
|
|
||||||
bb.max(0) = this->stl.stats.max.x;
|
|
||||||
bb.max(1) = this->stl.stats.max.y;
|
|
||||||
bb.max(2) = this->stl.stats.max.z;
|
|
||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
BoundingBoxf3 TriangleMesh::transformed_bounding_box(const Transform3d& t) const
|
||||||
TriangleMesh::require_shared_vertices()
|
{
|
||||||
|
bool has_shared = (stl.v_shared != nullptr);
|
||||||
|
if (!has_shared)
|
||||||
|
stl_generate_shared_vertices(&stl);
|
||||||
|
|
||||||
|
unsigned int vertices_count = (stl.stats.shared_vertices > 0) ? (unsigned int)stl.stats.shared_vertices : 3 * (unsigned int)stl.stats.number_of_facets;
|
||||||
|
|
||||||
|
if (vertices_count == 0)
|
||||||
|
return BoundingBoxf3();
|
||||||
|
|
||||||
|
Eigen::MatrixXd src_vertices(3, vertices_count);
|
||||||
|
|
||||||
|
if (stl.stats.shared_vertices > 0)
|
||||||
|
{
|
||||||
|
stl_vertex* vertex_ptr = stl.v_shared;
|
||||||
|
for (int i = 0; i < stl.stats.shared_vertices; ++i)
|
||||||
|
{
|
||||||
|
src_vertices(0, i) = (double)(*vertex_ptr)(0);
|
||||||
|
src_vertices(1, i) = (double)(*vertex_ptr)(1);
|
||||||
|
src_vertices(2, i) = (double)(*vertex_ptr)(2);
|
||||||
|
vertex_ptr += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stl_facet* facet_ptr = stl.facet_start;
|
||||||
|
unsigned int v_id = 0;
|
||||||
|
while (facet_ptr < stl.facet_start + stl.stats.number_of_facets)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
src_vertices(0, v_id) = (double)facet_ptr->vertex[i](0);
|
||||||
|
src_vertices(1, v_id) = (double)facet_ptr->vertex[i](1);
|
||||||
|
src_vertices(2, v_id) = (double)facet_ptr->vertex[i](2);
|
||||||
|
}
|
||||||
|
facet_ptr += 1;
|
||||||
|
++v_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_shared && (stl.stats.shared_vertices > 0))
|
||||||
|
stl_invalidate_shared_vertices(&stl);
|
||||||
|
|
||||||
|
Eigen::MatrixXd dst_vertices(3, vertices_count);
|
||||||
|
dst_vertices = t * src_vertices.colwise().homogeneous();
|
||||||
|
|
||||||
|
Vec3d v_min(dst_vertices(0, 0), dst_vertices(1, 0), dst_vertices(2, 0));
|
||||||
|
Vec3d v_max = v_min;
|
||||||
|
|
||||||
|
for (int i = 1; i < vertices_count; ++i)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < 3; ++j)
|
||||||
|
{
|
||||||
|
v_min(j) = std::min(v_min(j), dst_vertices(j, i));
|
||||||
|
v_max(j) = std::max(v_max(j), dst_vertices(j, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BoundingBoxf3(v_min, v_max);
|
||||||
|
}
|
||||||
|
|
||||||
|
TriangleMesh TriangleMesh::convex_hull_3d() const
|
||||||
|
{
|
||||||
|
// Helper struct for qhull:
|
||||||
|
struct PointForQHull{
|
||||||
|
PointForQHull(float x_p, float y_p, float z_p) : x((realT)x_p), y((realT)y_p), z((realT)z_p) {}
|
||||||
|
realT x, y, z;
|
||||||
|
};
|
||||||
|
std::vector<PointForQHull> src_vertices;
|
||||||
|
|
||||||
|
// We will now fill the vector with input points for computation:
|
||||||
|
stl_facet* facet_ptr = stl.facet_start;
|
||||||
|
while (facet_ptr < stl.facet_start + stl.stats.number_of_facets)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
const stl_vertex& v = facet_ptr->vertex[i];
|
||||||
|
src_vertices.emplace_back(v(0), v(1), v(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
facet_ptr += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The qhull call:
|
||||||
|
orgQhull::Qhull qhull;
|
||||||
|
qhull.disableOutputStream(); // we want qhull to be quiet
|
||||||
|
try
|
||||||
|
{
|
||||||
|
qhull.runQhull("", 3, (int)src_vertices.size(), (const realT*)(src_vertices.data()), "Qt");
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::cout << "Unable to create convex hull" << std::endl;
|
||||||
|
return TriangleMesh();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let's collect results:
|
||||||
|
Pointf3s dst_vertices;
|
||||||
|
std::vector<Vec3crd> facets;
|
||||||
|
auto facet_list = qhull.facetList().toStdVector();
|
||||||
|
for (const orgQhull::QhullFacet& facet : facet_list)
|
||||||
|
{ // iterate through facets
|
||||||
|
orgQhull::QhullVertexSet vertices = facet.vertices();
|
||||||
|
for (int i = 0; i < 3; ++i)
|
||||||
|
{ // iterate through facet's vertices
|
||||||
|
|
||||||
|
orgQhull::QhullPoint p = vertices[i].point();
|
||||||
|
const float* coords = p.coordinates();
|
||||||
|
dst_vertices.emplace_back(coords[0], coords[1], coords[2]);
|
||||||
|
}
|
||||||
|
unsigned int size = (unsigned int)dst_vertices.size();
|
||||||
|
facets.emplace_back(size - 3, size - 2, size - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TriangleMesh output_mesh(dst_vertices, facets);
|
||||||
|
output_mesh.repair();
|
||||||
|
return output_mesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TriangleMesh::require_shared_vertices()
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - start";
|
BOOST_LOG_TRIVIAL(trace) << "TriangleMeshSlicer::require_shared_vertices - start";
|
||||||
if (!this->repaired)
|
if (!this->repaired)
|
||||||
|
|
@ -619,11 +620,8 @@ TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) :
|
||||||
facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1);
|
facets_edges.assign(_mesh->stl.stats.number_of_facets * 3, -1);
|
||||||
v_scaled_shared.assign(_mesh->stl.v_shared, _mesh->stl.v_shared + _mesh->stl.stats.shared_vertices);
|
v_scaled_shared.assign(_mesh->stl.v_shared, _mesh->stl.v_shared + _mesh->stl.stats.shared_vertices);
|
||||||
// Scale the copied vertices.
|
// Scale the copied vertices.
|
||||||
for (int i = 0; i < this->mesh->stl.stats.shared_vertices; ++ i) {
|
for (int i = 0; i < this->mesh->stl.stats.shared_vertices; ++ i)
|
||||||
this->v_scaled_shared[i].x /= float(SCALING_FACTOR);
|
this->v_scaled_shared[i] *= float(1. / SCALING_FACTOR);
|
||||||
this->v_scaled_shared[i].y /= float(SCALING_FACTOR);
|
|
||||||
this->v_scaled_shared[i].z /= float(SCALING_FACTOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a mapping from triangle edge into face.
|
// Create a mapping from triangle edge into face.
|
||||||
struct EdgeToFace {
|
struct EdgeToFace {
|
||||||
|
|
@ -697,8 +695,7 @@ TriangleMeshSlicer::TriangleMeshSlicer(TriangleMesh* _mesh) :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const
|
||||||
TriangleMeshSlicer::slice(const std::vector<float> &z, std::vector<Polygons>* layers) const
|
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::slice";
|
BOOST_LOG_TRIVIAL(debug) << "TriangleMeshSlicer::slice";
|
||||||
|
|
||||||
|
|
@ -779,14 +776,14 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin
|
||||||
const stl_facet &facet = this->mesh->stl.facet_start[facet_idx];
|
const stl_facet &facet = this->mesh->stl.facet_start[facet_idx];
|
||||||
|
|
||||||
// find facet extents
|
// find facet extents
|
||||||
const float min_z = fminf(facet.vertex[0].z, fminf(facet.vertex[1].z, facet.vertex[2].z));
|
const float min_z = fminf(facet.vertex[0](2), fminf(facet.vertex[1](2), facet.vertex[2](2)));
|
||||||
const float max_z = fmaxf(facet.vertex[0].z, fmaxf(facet.vertex[1].z, facet.vertex[2].z));
|
const float max_z = fmaxf(facet.vertex[0](2), fmaxf(facet.vertex[1](2), facet.vertex[2](2)));
|
||||||
|
|
||||||
#ifdef SLIC3R_DEBUG
|
#ifdef SLIC3R_DEBUG
|
||||||
printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx,
|
printf("\n==> FACET %d (%f,%f,%f - %f,%f,%f - %f,%f,%f):\n", facet_idx,
|
||||||
facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0].z,
|
facet.vertex[0].x, facet.vertex[0].y, facet.vertex[0](2),
|
||||||
facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1].z,
|
facet.vertex[1].x, facet.vertex[1].y, facet.vertex[1](2),
|
||||||
facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2].z);
|
facet.vertex[2].x, facet.vertex[2].y, facet.vertex[2](2));
|
||||||
printf("z: min = %.2f, max = %.2f\n", min_z, max_z);
|
printf("z: min = %.2f, max = %.2f\n", min_z, max_z);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -806,18 +803,18 @@ void TriangleMeshSlicer::_slice_do(size_t facet_idx, std::vector<IntersectionLin
|
||||||
if (il.edge_type == feHorizontal) {
|
if (il.edge_type == feHorizontal) {
|
||||||
// Insert all three edges of the face.
|
// Insert all three edges of the face.
|
||||||
const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex;
|
const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex;
|
||||||
const bool reverse = this->mesh->stl.facet_start[facet_idx].normal.z < 0;
|
const bool reverse = this->mesh->stl.facet_start[facet_idx].normal(2) < 0;
|
||||||
for (int j = 0; j < 3; ++ j) {
|
for (int j = 0; j < 3; ++ j) {
|
||||||
int a_id = vertices[j % 3];
|
int a_id = vertices[j % 3];
|
||||||
int b_id = vertices[(j+1) % 3];
|
int b_id = vertices[(j+1) % 3];
|
||||||
if (reverse)
|
if (reverse)
|
||||||
std::swap(a_id, b_id);
|
std::swap(a_id, b_id);
|
||||||
const stl_vertex *a = &this->v_scaled_shared[a_id];
|
const stl_vertex &a = this->v_scaled_shared[a_id];
|
||||||
const stl_vertex *b = &this->v_scaled_shared[b_id];
|
const stl_vertex &b = this->v_scaled_shared[b_id];
|
||||||
il.a(0) = a->x;
|
il.a(0) = a(0);
|
||||||
il.a(1) = a->y;
|
il.a(1) = a(1);
|
||||||
il.b(0) = b->x;
|
il.b(0) = b(0);
|
||||||
il.b(1) = b->y;
|
il.b(1) = b(1);
|
||||||
il.a_id = a_id;
|
il.a_id = a_id;
|
||||||
il.b_id = b_id;
|
il.b_id = b_id;
|
||||||
(*lines)[layer_idx].emplace_back(il);
|
(*lines)[layer_idx].emplace_back(il);
|
||||||
|
|
@ -863,66 +860,63 @@ bool TriangleMeshSlicer::slice_facet(
|
||||||
// Reorder vertices so that the first one is the one with lowest Z.
|
// Reorder vertices so that the first one is the one with lowest Z.
|
||||||
// This is needed to get all intersection lines in a consistent order
|
// This is needed to get all intersection lines in a consistent order
|
||||||
// (external on the right of the line)
|
// (external on the right of the line)
|
||||||
int i = (facet.vertex[1].z == min_z) ? 1 : ((facet.vertex[2].z == min_z) ? 2 : 0);
|
int i = (facet.vertex[1](2) == min_z) ? 1 : ((facet.vertex[2](2) == min_z) ? 2 : 0);
|
||||||
for (int j = i; j - i < 3; ++ j) { // loop through facet edges
|
for (int j = i; j - i < 3; ++ j) { // loop through facet edges
|
||||||
int edge_id = this->facets_edges[facet_idx * 3 + (j % 3)];
|
int edge_id = this->facets_edges[facet_idx * 3 + (j % 3)];
|
||||||
const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex;
|
const int *vertices = this->mesh->stl.v_indices[facet_idx].vertex;
|
||||||
int a_id = vertices[j % 3];
|
int a_id = vertices[j % 3];
|
||||||
int b_id = vertices[(j+1) % 3];
|
int b_id = vertices[(j+1) % 3];
|
||||||
const stl_vertex *a = &this->v_scaled_shared[a_id];
|
const stl_vertex &a = this->v_scaled_shared[a_id];
|
||||||
const stl_vertex *b = &this->v_scaled_shared[b_id];
|
const stl_vertex &b = this->v_scaled_shared[b_id];
|
||||||
|
|
||||||
// Is edge or face aligned with the cutting plane?
|
// Is edge or face aligned with the cutting plane?
|
||||||
if (a->z == slice_z && b->z == slice_z) {
|
if (a(2) == slice_z && b(2) == slice_z) {
|
||||||
// Edge is horizontal and belongs to the current layer.
|
// Edge is horizontal and belongs to the current layer.
|
||||||
const stl_vertex &v0 = this->v_scaled_shared[vertices[0]];
|
const stl_vertex &v0 = this->v_scaled_shared[vertices[0]];
|
||||||
const stl_vertex &v1 = this->v_scaled_shared[vertices[1]];
|
const stl_vertex &v1 = this->v_scaled_shared[vertices[1]];
|
||||||
const stl_vertex &v2 = this->v_scaled_shared[vertices[2]];
|
const stl_vertex &v2 = this->v_scaled_shared[vertices[2]];
|
||||||
|
bool swap = false;
|
||||||
if (min_z == max_z) {
|
if (min_z == max_z) {
|
||||||
// All three vertices are aligned with slice_z.
|
// All three vertices are aligned with slice_z.
|
||||||
line_out->edge_type = feHorizontal;
|
line_out->edge_type = feHorizontal;
|
||||||
if (this->mesh->stl.facet_start[facet_idx].normal.z < 0) {
|
if (this->mesh->stl.facet_start[facet_idx].normal(2) < 0) {
|
||||||
// If normal points downwards this is a bottom horizontal facet so we reverse its point order.
|
// If normal points downwards this is a bottom horizontal facet so we reverse its point order.
|
||||||
std::swap(a, b);
|
swap = true;
|
||||||
std::swap(a_id, b_id);
|
|
||||||
}
|
}
|
||||||
} else if (v0.z < slice_z || v1.z < slice_z || v2.z < slice_z) {
|
} else if (v0(2) < slice_z || v1(2) < slice_z || v2(2) < slice_z) {
|
||||||
// Two vertices are aligned with the cutting plane, the third vertex is below the cutting plane.
|
// Two vertices are aligned with the cutting plane, the third vertex is below the cutting plane.
|
||||||
line_out->edge_type = feTop;
|
line_out->edge_type = feTop;
|
||||||
std::swap(a, b);
|
swap = true;
|
||||||
std::swap(a_id, b_id);
|
|
||||||
} else {
|
} else {
|
||||||
// Two vertices are aligned with the cutting plane, the third vertex is above the cutting plane.
|
// Two vertices are aligned with the cutting plane, the third vertex is above the cutting plane.
|
||||||
line_out->edge_type = feBottom;
|
line_out->edge_type = feBottom;
|
||||||
}
|
}
|
||||||
line_out->a(0) = a->x;
|
line_out->a = to_2d(swap ? b : a).cast<coord_t>();
|
||||||
line_out->a(1) = a->y;
|
line_out->b = to_2d(swap ? a : b).cast<coord_t>();
|
||||||
line_out->b(0) = b->x;
|
line_out->a_id = swap ? b_id : a_id;
|
||||||
line_out->b(1) = b->y;
|
line_out->b_id = swap ? a_id : b_id;
|
||||||
line_out->a_id = a_id;
|
|
||||||
line_out->b_id = b_id;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a->z == slice_z) {
|
if (a(2) == slice_z) {
|
||||||
// Only point a alings with the cutting plane.
|
// Only point a alings with the cutting plane.
|
||||||
points_on_layer[num_points_on_layer ++] = num_points;
|
points_on_layer[num_points_on_layer ++] = num_points;
|
||||||
IntersectionPoint &point = points[num_points ++];
|
IntersectionPoint &point = points[num_points ++];
|
||||||
point(0) = a->x;
|
point(0) = a(0);
|
||||||
point(1) = a->y;
|
point(1) = a(1);
|
||||||
point.point_id = a_id;
|
point.point_id = a_id;
|
||||||
} else if (b->z == slice_z) {
|
} else if (b(2) == slice_z) {
|
||||||
// Only point b alings with the cutting plane.
|
// Only point b alings with the cutting plane.
|
||||||
points_on_layer[num_points_on_layer ++] = num_points;
|
points_on_layer[num_points_on_layer ++] = num_points;
|
||||||
IntersectionPoint &point = points[num_points ++];
|
IntersectionPoint &point = points[num_points ++];
|
||||||
point(0) = b->x;
|
point(0) = b(0);
|
||||||
point(1) = b->y;
|
point(1) = b(1);
|
||||||
point.point_id = b_id;
|
point.point_id = b_id;
|
||||||
} else if ((a->z < slice_z && b->z > slice_z) || (b->z < slice_z && a->z > slice_z)) {
|
} else if ((a(2) < slice_z && b(2) > slice_z) || (b(2) < slice_z && a(2) > slice_z)) {
|
||||||
// A general case. The face edge intersects the cutting plane. Calculate the intersection point.
|
// A general case. The face edge intersects the cutting plane. Calculate the intersection point.
|
||||||
IntersectionPoint &point = points[num_points ++];
|
IntersectionPoint &point = points[num_points ++];
|
||||||
point(0) = b->x + (a->x - b->x) * (slice_z - b->z) / (a->z - b->z);
|
point(0) = b(0) + (a(0) - b(0)) * (slice_z - b(2)) / (a(2) - b(2));
|
||||||
point(1) = b->y + (a->y - b->y) * (slice_z - b->z) / (a->z - b->z);
|
point(1) = b(1) + (a(1) - b(1)) * (slice_z - b(2)) / (a(2) - b(2));
|
||||||
point.edge_id = edge_id;
|
point.edge_id = edge_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1389,8 +1383,8 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
||||||
stl_facet* facet = &this->mesh->stl.facet_start[facet_idx];
|
stl_facet* facet = &this->mesh->stl.facet_start[facet_idx];
|
||||||
|
|
||||||
// find facet extents
|
// find facet extents
|
||||||
float min_z = std::min(facet->vertex[0].z, std::min(facet->vertex[1].z, facet->vertex[2].z));
|
float min_z = std::min(facet->vertex[0](2), std::min(facet->vertex[1](2), facet->vertex[2](2)));
|
||||||
float max_z = std::max(facet->vertex[0].z, std::max(facet->vertex[1].z, facet->vertex[2].z));
|
float max_z = std::max(facet->vertex[0](2), std::max(facet->vertex[1](2), facet->vertex[2](2)));
|
||||||
|
|
||||||
// intersect facet with cutting plane
|
// intersect facet with cutting plane
|
||||||
IntersectionLine line;
|
IntersectionLine line;
|
||||||
|
|
@ -1417,47 +1411,47 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
||||||
|
|
||||||
// look for the vertex on whose side of the slicing plane there are no other vertices
|
// look for the vertex on whose side of the slicing plane there are no other vertices
|
||||||
int isolated_vertex;
|
int isolated_vertex;
|
||||||
if ( (facet->vertex[0].z > z) == (facet->vertex[1].z > z) ) {
|
if ( (facet->vertex[0](2) > z) == (facet->vertex[1](2) > z) ) {
|
||||||
isolated_vertex = 2;
|
isolated_vertex = 2;
|
||||||
} else if ( (facet->vertex[1].z > z) == (facet->vertex[2].z > z) ) {
|
} else if ( (facet->vertex[1](2) > z) == (facet->vertex[2](2) > z) ) {
|
||||||
isolated_vertex = 0;
|
isolated_vertex = 0;
|
||||||
} else {
|
} else {
|
||||||
isolated_vertex = 1;
|
isolated_vertex = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get vertices starting from the isolated one
|
// get vertices starting from the isolated one
|
||||||
stl_vertex* v0 = &facet->vertex[isolated_vertex];
|
const stl_vertex &v0 = facet->vertex[isolated_vertex];
|
||||||
stl_vertex* v1 = &facet->vertex[(isolated_vertex+1) % 3];
|
const stl_vertex &v1 = facet->vertex[(isolated_vertex+1) % 3];
|
||||||
stl_vertex* v2 = &facet->vertex[(isolated_vertex+2) % 3];
|
const stl_vertex &v2 = facet->vertex[(isolated_vertex+2) % 3];
|
||||||
|
|
||||||
// intersect v0-v1 and v2-v0 with cutting plane and make new vertices
|
// intersect v0-v1 and v2-v0 with cutting plane and make new vertices
|
||||||
stl_vertex v0v1, v2v0;
|
stl_vertex v0v1, v2v0;
|
||||||
v0v1.x = v1->x + (v0->x - v1->x) * (z - v1->z) / (v0->z - v1->z);
|
v0v1(0) = v1(0) + (v0(0) - v1(0)) * (z - v1(2)) / (v0(2) - v1(2));
|
||||||
v0v1.y = v1->y + (v0->y - v1->y) * (z - v1->z) / (v0->z - v1->z);
|
v0v1(1) = v1(1) + (v0(1) - v1(1)) * (z - v1(2)) / (v0(2) - v1(2));
|
||||||
v0v1.z = z;
|
v0v1(2) = z;
|
||||||
v2v0.x = v2->x + (v0->x - v2->x) * (z - v2->z) / (v0->z - v2->z);
|
v2v0(0) = v2(0) + (v0(0) - v2(0)) * (z - v2(2)) / (v0(2) - v2(2));
|
||||||
v2v0.y = v2->y + (v0->y - v2->y) * (z - v2->z) / (v0->z - v2->z);
|
v2v0(1) = v2(1) + (v0(1) - v2(1)) * (z - v2(2)) / (v0(2) - v2(2));
|
||||||
v2v0.z = z;
|
v2v0(2) = z;
|
||||||
|
|
||||||
// build the triangular facet
|
// build the triangular facet
|
||||||
stl_facet triangle;
|
stl_facet triangle;
|
||||||
triangle.normal = facet->normal;
|
triangle.normal = facet->normal;
|
||||||
triangle.vertex[0] = *v0;
|
triangle.vertex[0] = v0;
|
||||||
triangle.vertex[1] = v0v1;
|
triangle.vertex[1] = v0v1;
|
||||||
triangle.vertex[2] = v2v0;
|
triangle.vertex[2] = v2v0;
|
||||||
|
|
||||||
// build the facets forming a quadrilateral on the other side
|
// build the facets forming a quadrilateral on the other side
|
||||||
stl_facet quadrilateral[2];
|
stl_facet quadrilateral[2];
|
||||||
quadrilateral[0].normal = facet->normal;
|
quadrilateral[0].normal = facet->normal;
|
||||||
quadrilateral[0].vertex[0] = *v1;
|
quadrilateral[0].vertex[0] = v1;
|
||||||
quadrilateral[0].vertex[1] = *v2;
|
quadrilateral[0].vertex[1] = v2;
|
||||||
quadrilateral[0].vertex[2] = v0v1;
|
quadrilateral[0].vertex[2] = v0v1;
|
||||||
quadrilateral[1].normal = facet->normal;
|
quadrilateral[1].normal = facet->normal;
|
||||||
quadrilateral[1].vertex[0] = *v2;
|
quadrilateral[1].vertex[0] = v2;
|
||||||
quadrilateral[1].vertex[1] = v2v0;
|
quadrilateral[1].vertex[1] = v2v0;
|
||||||
quadrilateral[1].vertex[2] = v0v1;
|
quadrilateral[1].vertex[2] = v0v1;
|
||||||
|
|
||||||
if (v0->z > z) {
|
if (v0(2) > z) {
|
||||||
if (upper != NULL) stl_add_facet(&upper->stl, &triangle);
|
if (upper != NULL) stl_add_facet(&upper->stl, &triangle);
|
||||||
if (lower != NULL) {
|
if (lower != NULL) {
|
||||||
stl_add_facet(&lower->stl, &quadrilateral[0]);
|
stl_add_facet(&lower->stl, &quadrilateral[0]);
|
||||||
|
|
@ -1489,13 +1483,11 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
||||||
Polygon p = *polygon;
|
Polygon p = *polygon;
|
||||||
p.reverse();
|
p.reverse();
|
||||||
stl_facet facet;
|
stl_facet facet;
|
||||||
facet.normal.x = 0;
|
facet.normal = stl_normal(0, 0, -1.f);
|
||||||
facet.normal.y = 0;
|
|
||||||
facet.normal.z = -1;
|
|
||||||
for (size_t i = 0; i <= 2; ++i) {
|
for (size_t i = 0; i <= 2; ++i) {
|
||||||
facet.vertex[i].x = unscale(p.points[i](0));
|
facet.vertex[i](0) = unscale<float>(p.points[i](0));
|
||||||
facet.vertex[i].y = unscale(p.points[i](1));
|
facet.vertex[i](1) = unscale<float>(p.points[i](1));
|
||||||
facet.vertex[i].z = z;
|
facet.vertex[i](2) = z;
|
||||||
}
|
}
|
||||||
stl_add_facet(&upper->stl, &facet);
|
stl_add_facet(&upper->stl, &facet);
|
||||||
}
|
}
|
||||||
|
|
@ -1515,13 +1507,11 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
||||||
// convert triangles to facets and append them to mesh
|
// convert triangles to facets and append them to mesh
|
||||||
for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) {
|
for (Polygons::const_iterator polygon = triangles.begin(); polygon != triangles.end(); ++polygon) {
|
||||||
stl_facet facet;
|
stl_facet facet;
|
||||||
facet.normal.x = 0;
|
facet.normal = stl_normal(0, 0, 1.f);
|
||||||
facet.normal.y = 0;
|
|
||||||
facet.normal.z = 1;
|
|
||||||
for (size_t i = 0; i <= 2; ++i) {
|
for (size_t i = 0; i <= 2; ++i) {
|
||||||
facet.vertex[i].x = unscale(polygon->points[i](0));
|
facet.vertex[i](0) = unscale<float>(polygon->points[i](0));
|
||||||
facet.vertex[i].y = unscale(polygon->points[i](1));
|
facet.vertex[i](1) = unscale<float>(polygon->points[i](1));
|
||||||
facet.vertex[i].z = z;
|
facet.vertex[i](2) = z;
|
||||||
}
|
}
|
||||||
stl_add_facet(&lower->stl, &facet);
|
stl_add_facet(&lower->stl, &facet);
|
||||||
}
|
}
|
||||||
|
|
@ -1534,19 +1524,19 @@ void TriangleMeshSlicer::cut(float z, TriangleMesh* upper, TriangleMesh* lower)
|
||||||
|
|
||||||
// Generate the vertex list for a cube solid of arbitrary size in X/Y/Z.
|
// Generate the vertex list for a cube solid of arbitrary size in X/Y/Z.
|
||||||
TriangleMesh make_cube(double x, double y, double z) {
|
TriangleMesh make_cube(double x, double y, double z) {
|
||||||
Pointf3 pv[8] = {
|
Vec3d pv[8] = {
|
||||||
Pointf3(x, y, 0), Pointf3(x, 0, 0), Pointf3(0, 0, 0),
|
Vec3d(x, y, 0), Vec3d(x, 0, 0), Vec3d(0, 0, 0),
|
||||||
Pointf3(0, y, 0), Pointf3(x, y, z), Pointf3(0, y, z),
|
Vec3d(0, y, 0), Vec3d(x, y, z), Vec3d(0, y, z),
|
||||||
Pointf3(0, 0, z), Pointf3(x, 0, z)
|
Vec3d(0, 0, z), Vec3d(x, 0, z)
|
||||||
};
|
};
|
||||||
Point3 fv[12] = {
|
Vec3crd fv[12] = {
|
||||||
Point3(0, 1, 2), Point3(0, 2, 3), Point3(4, 5, 6),
|
Vec3crd(0, 1, 2), Vec3crd(0, 2, 3), Vec3crd(4, 5, 6),
|
||||||
Point3(4, 6, 7), Point3(0, 4, 7), Point3(0, 7, 1),
|
Vec3crd(4, 6, 7), Vec3crd(0, 4, 7), Vec3crd(0, 7, 1),
|
||||||
Point3(1, 7, 6), Point3(1, 6, 2), Point3(2, 6, 5),
|
Vec3crd(1, 7, 6), Vec3crd(1, 6, 2), Vec3crd(2, 6, 5),
|
||||||
Point3(2, 5, 3), Point3(4, 0, 3), Point3(4, 3, 5)
|
Vec3crd(2, 5, 3), Vec3crd(4, 0, 3), Vec3crd(4, 3, 5)
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<Point3> facets(&fv[0], &fv[0]+12);
|
std::vector<Vec3crd> facets(&fv[0], &fv[0]+12);
|
||||||
Pointf3s vertices(&pv[0], &pv[0]+8);
|
Pointf3s vertices(&pv[0], &pv[0]+8);
|
||||||
|
|
||||||
TriangleMesh mesh(vertices ,facets);
|
TriangleMesh mesh(vertices ,facets);
|
||||||
|
|
@ -1558,11 +1548,11 @@ TriangleMesh make_cube(double x, double y, double z) {
|
||||||
// Default is 360 sides, angle fa is in radians.
|
// Default is 360 sides, angle fa is in radians.
|
||||||
TriangleMesh make_cylinder(double r, double h, double fa) {
|
TriangleMesh make_cylinder(double r, double h, double fa) {
|
||||||
Pointf3s vertices;
|
Pointf3s vertices;
|
||||||
std::vector<Point3> facets;
|
std::vector<Vec3crd> facets;
|
||||||
|
|
||||||
// 2 special vertices, top and bottom center, rest are relative to this
|
// 2 special vertices, top and bottom center, rest are relative to this
|
||||||
vertices.emplace_back(Pointf3(0.0, 0.0, 0.0));
|
vertices.emplace_back(Vec3d(0.0, 0.0, 0.0));
|
||||||
vertices.emplace_back(Pointf3(0.0, 0.0, h));
|
vertices.emplace_back(Vec3d(0.0, 0.0, h));
|
||||||
|
|
||||||
// adjust via rounding to get an even multiple for any provided angle.
|
// adjust via rounding to get an even multiple for any provided angle.
|
||||||
double angle = (2*PI / floor(2*PI / fa));
|
double angle = (2*PI / floor(2*PI / fa));
|
||||||
|
|
@ -1572,24 +1562,23 @@ TriangleMesh make_cylinder(double r, double h, double fa) {
|
||||||
// top and bottom.
|
// top and bottom.
|
||||||
// Special case: Last line shares 2 vertices with the first line.
|
// Special case: Last line shares 2 vertices with the first line.
|
||||||
unsigned id = vertices.size() - 1;
|
unsigned id = vertices.size() - 1;
|
||||||
vertices.emplace_back(Pointf3(sin(0) * r , cos(0) * r, 0));
|
vertices.emplace_back(Vec3d(sin(0) * r , cos(0) * r, 0));
|
||||||
vertices.emplace_back(Pointf3(sin(0) * r , cos(0) * r, h));
|
vertices.emplace_back(Vec3d(sin(0) * r , cos(0) * r, h));
|
||||||
for (double i = 0; i < 2*PI; i+=angle) {
|
for (double i = 0; i < 2*PI; i+=angle) {
|
||||||
Pointf p(0, r);
|
Vec2d p = Eigen::Rotation2Dd(i) * Eigen::Vector2d(0, r);
|
||||||
p.rotate(i);
|
vertices.emplace_back(Vec3d(p(0), p(1), 0.));
|
||||||
vertices.emplace_back(Pointf3(p(0), p(1), 0.));
|
vertices.emplace_back(Vec3d(p(0), p(1), h));
|
||||||
vertices.emplace_back(Pointf3(p(0), p(1), h));
|
|
||||||
id = vertices.size() - 1;
|
id = vertices.size() - 1;
|
||||||
facets.emplace_back(Point3( 0, id - 1, id - 3)); // top
|
facets.emplace_back(Vec3crd( 0, id - 1, id - 3)); // top
|
||||||
facets.emplace_back(Point3(id, 1, id - 2)); // bottom
|
facets.emplace_back(Vec3crd(id, 1, id - 2)); // bottom
|
||||||
facets.emplace_back(Point3(id, id - 2, id - 3)); // upper-right of side
|
facets.emplace_back(Vec3crd(id, id - 2, id - 3)); // upper-right of side
|
||||||
facets.emplace_back(Point3(id, id - 3, id - 1)); // bottom-left of side
|
facets.emplace_back(Vec3crd(id, id - 3, id - 1)); // bottom-left of side
|
||||||
}
|
}
|
||||||
// Connect the last set of vertices with the first.
|
// Connect the last set of vertices with the first.
|
||||||
facets.emplace_back(Point3( 2, 0, id - 1));
|
facets.emplace_back(Vec3crd( 2, 0, id - 1));
|
||||||
facets.emplace_back(Point3( 1, 3, id));
|
facets.emplace_back(Vec3crd( 1, 3, id));
|
||||||
facets.emplace_back(Point3(id, 3, 2));
|
facets.emplace_back(Vec3crd(id, 3, 2));
|
||||||
facets.emplace_back(Point3(id, 2, id - 1));
|
facets.emplace_back(Vec3crd(id, 2, id - 1));
|
||||||
|
|
||||||
TriangleMesh mesh(vertices, facets);
|
TriangleMesh mesh(vertices, facets);
|
||||||
return mesh;
|
return mesh;
|
||||||
|
|
@ -1600,7 +1589,7 @@ TriangleMesh make_cylinder(double r, double h, double fa) {
|
||||||
// Default angle is 1 degree.
|
// Default angle is 1 degree.
|
||||||
TriangleMesh make_sphere(double rho, double fa) {
|
TriangleMesh make_sphere(double rho, double fa) {
|
||||||
Pointf3s vertices;
|
Pointf3s vertices;
|
||||||
std::vector<Point3> facets;
|
std::vector<Vec3crd> facets;
|
||||||
|
|
||||||
// Algorithm:
|
// Algorithm:
|
||||||
// Add points one-by-one to the sphere grid and form facets using relative coordinates.
|
// Add points one-by-one to the sphere grid and form facets using relative coordinates.
|
||||||
|
|
@ -1619,17 +1608,16 @@ TriangleMesh make_sphere(double rho, double fa) {
|
||||||
|
|
||||||
// special case: first ring connects to 0,0,0
|
// special case: first ring connects to 0,0,0
|
||||||
// insert and form facets.
|
// insert and form facets.
|
||||||
vertices.emplace_back(Pointf3(0.0, 0.0, -rho));
|
vertices.emplace_back(Vec3d(0.0, 0.0, -rho));
|
||||||
size_t id = vertices.size();
|
size_t id = vertices.size();
|
||||||
for (size_t i = 0; i < ring.size(); i++) {
|
for (size_t i = 0; i < ring.size(); i++) {
|
||||||
// Fixed scaling
|
// Fixed scaling
|
||||||
const double z = -rho + increment*rho*2.0;
|
const double z = -rho + increment*rho*2.0;
|
||||||
// radius of the circle for this step.
|
// radius of the circle for this step.
|
||||||
const double r = sqrt(abs(rho*rho - z*z));
|
const double r = sqrt(abs(rho*rho - z*z));
|
||||||
Pointf b(0, r);
|
Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r);
|
||||||
b.rotate(ring[i]);
|
vertices.emplace_back(Vec3d(b(0), b(1), z));
|
||||||
vertices.emplace_back(Pointf3(b(0), b(1), z));
|
facets.emplace_back((i == 0) ? Vec3crd(1, 0, ring.size()) : Vec3crd(id, 0, id - 1));
|
||||||
facets.emplace_back((i == 0) ? Point3(1, 0, ring.size()) : Point3(id, 0, id - 1));
|
|
||||||
++ id;
|
++ id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1639,16 +1627,15 @@ TriangleMesh make_sphere(double rho, double fa) {
|
||||||
const double r = sqrt(abs(rho*rho - z*z));
|
const double r = sqrt(abs(rho*rho - z*z));
|
||||||
|
|
||||||
for (size_t i = 0; i < ring.size(); i++) {
|
for (size_t i = 0; i < ring.size(); i++) {
|
||||||
Pointf b(0, r);
|
Vec2d b = Eigen::Rotation2Dd(ring[i]) * Eigen::Vector2d(0, r);
|
||||||
b.rotate(ring[i]);
|
vertices.emplace_back(Vec3d(b(0), b(1), z));
|
||||||
vertices.emplace_back(Pointf3(b(0), b(1), z));
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
// wrap around
|
// wrap around
|
||||||
facets.emplace_back(Point3(id + ring.size() - 1 , id, id - 1));
|
facets.emplace_back(Vec3crd(id + ring.size() - 1 , id, id - 1));
|
||||||
facets.emplace_back(Point3(id, id - ring.size(), id - 1));
|
facets.emplace_back(Vec3crd(id, id - ring.size(), id - 1));
|
||||||
} else {
|
} else {
|
||||||
facets.emplace_back(Point3(id , id - ring.size(), (id - 1) - ring.size()));
|
facets.emplace_back(Vec3crd(id , id - ring.size(), (id - 1) - ring.size()));
|
||||||
facets.emplace_back(Point3(id, id - 1 - ring.size() , id - 1));
|
facets.emplace_back(Vec3crd(id, id - 1 - ring.size() , id - 1));
|
||||||
}
|
}
|
||||||
id++;
|
id++;
|
||||||
}
|
}
|
||||||
|
|
@ -1657,13 +1644,13 @@ TriangleMesh make_sphere(double rho, double fa) {
|
||||||
|
|
||||||
// special case: last ring connects to 0,0,rho*2.0
|
// special case: last ring connects to 0,0,rho*2.0
|
||||||
// only form facets.
|
// only form facets.
|
||||||
vertices.emplace_back(Pointf3(0.0, 0.0, rho));
|
vertices.emplace_back(Vec3d(0.0, 0.0, rho));
|
||||||
for (size_t i = 0; i < ring.size(); i++) {
|
for (size_t i = 0; i < ring.size(); i++) {
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
// third vertex is on the other side of the ring.
|
// third vertex is on the other side of the ring.
|
||||||
facets.emplace_back(Point3(id, id - ring.size(), id - 1));
|
facets.emplace_back(Vec3crd(id, id - ring.size(), id - 1));
|
||||||
} else {
|
} else {
|
||||||
facets.emplace_back(Point3(id, id - ring.size() + i, id - ring.size() + (i - 1)));
|
facets.emplace_back(Vec3crd(id, id - ring.size() + i, id - ring.size() + (i - 1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
id++;
|
id++;
|
||||||
|
|
|
||||||
|
|
@ -20,33 +20,33 @@ typedef std::vector<TriangleMesh*> TriangleMeshPtrs;
|
||||||
class TriangleMesh
|
class TriangleMesh
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TriangleMesh();
|
TriangleMesh() : repaired(false) { stl_initialize(&this->stl); }
|
||||||
TriangleMesh(const Pointf3s &points, const std::vector<Point3> &facets);
|
TriangleMesh(const Pointf3s &points, const std::vector<Vec3crd> &facets);
|
||||||
TriangleMesh(const TriangleMesh &other);
|
TriangleMesh(const TriangleMesh &other) : repaired(false) { stl_initialize(&this->stl); *this = other; }
|
||||||
TriangleMesh(TriangleMesh &&other);
|
TriangleMesh(TriangleMesh &&other) : repaired(false) { stl_initialize(&this->stl); this->swap(other); }
|
||||||
|
~TriangleMesh() { stl_close(&this->stl); }
|
||||||
TriangleMesh& operator=(const TriangleMesh &other);
|
TriangleMesh& operator=(const TriangleMesh &other);
|
||||||
TriangleMesh& operator=(TriangleMesh &&other);
|
TriangleMesh& operator=(TriangleMesh &&other) { this->swap(other); return *this; }
|
||||||
void swap(TriangleMesh &other);
|
void swap(TriangleMesh &other) { std::swap(this->stl, other.stl); std::swap(this->repaired, other.repaired); }
|
||||||
~TriangleMesh();
|
void ReadSTLFile(const char* input_file) { stl_open(&stl, input_file); }
|
||||||
void ReadSTLFile(const char* input_file);
|
void write_ascii(const char* output_file) { stl_write_ascii(&this->stl, output_file, ""); }
|
||||||
void write_ascii(const char* output_file);
|
void write_binary(const char* output_file) { stl_write_binary(&this->stl, output_file, ""); }
|
||||||
void write_binary(const char* output_file);
|
|
||||||
void repair();
|
void repair();
|
||||||
float volume();
|
float volume();
|
||||||
void check_topology();
|
void check_topology();
|
||||||
bool is_manifold() const;
|
bool is_manifold() const { return this->stl.stats.connected_facets_3_edge == this->stl.stats.number_of_facets; }
|
||||||
void WriteOBJFile(char* output_file);
|
void WriteOBJFile(char* output_file);
|
||||||
void scale(float factor);
|
void scale(float factor);
|
||||||
void scale(const Pointf3 &versor);
|
void scale(const Vec3d &versor);
|
||||||
void translate(float x, float y, float z);
|
void translate(float x, float y, float z);
|
||||||
void rotate(float angle, const Axis &axis);
|
void rotate(float angle, const Axis &axis);
|
||||||
void rotate_x(float angle);
|
void rotate_x(float angle) { this->rotate(angle, X); }
|
||||||
void rotate_y(float angle);
|
void rotate_y(float angle) { this->rotate(angle, Y); }
|
||||||
void rotate_z(float angle);
|
void rotate_z(float angle) { this->rotate(angle, Z); }
|
||||||
void mirror(const Axis &axis);
|
void mirror(const Axis &axis);
|
||||||
void mirror_x();
|
void mirror_x() { this->mirror(X); }
|
||||||
void mirror_y();
|
void mirror_y() { this->mirror(Y); }
|
||||||
void mirror_z();
|
void mirror_z() { this->mirror(Z); }
|
||||||
void transform(const float* matrix3x4);
|
void transform(const float* matrix3x4);
|
||||||
void align_to_origin();
|
void align_to_origin();
|
||||||
void rotate(double angle, Point* center);
|
void rotate(double angle, Point* center);
|
||||||
|
|
@ -55,9 +55,13 @@ public:
|
||||||
ExPolygons horizontal_projection() const;
|
ExPolygons horizontal_projection() const;
|
||||||
Polygon convex_hull();
|
Polygon convex_hull();
|
||||||
BoundingBoxf3 bounding_box() const;
|
BoundingBoxf3 bounding_box() const;
|
||||||
|
// Returns the bbox of this TriangleMesh transformed by the given transformation
|
||||||
|
BoundingBoxf3 transformed_bounding_box(const Transform3d& t) const;
|
||||||
|
// Returns the convex hull of this TriangleMesh
|
||||||
|
TriangleMesh convex_hull_3d() const;
|
||||||
void reset_repair_stats();
|
void reset_repair_stats();
|
||||||
bool needed_repair() const;
|
bool needed_repair() const;
|
||||||
size_t facets_count() const;
|
size_t facets_count() const { return this->stl.stats.number_of_facets; }
|
||||||
|
|
||||||
// Returns true, if there are two and more connected patches in the mesh.
|
// Returns true, if there are two and more connected patches in the mesh.
|
||||||
// Returns false, if one or zero connected patch is in the mesh.
|
// Returns false, if one or zero connected patch is in the mesh.
|
||||||
|
|
@ -66,7 +70,7 @@ public:
|
||||||
// Count disconnected triangle patches.
|
// Count disconnected triangle patches.
|
||||||
size_t number_of_patches() const;
|
size_t number_of_patches() const;
|
||||||
|
|
||||||
stl_file stl;
|
mutable stl_file stl;
|
||||||
bool repaired;
|
bool repaired;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ typedef double coordf_t;
|
||||||
//FIXME Better to use an inline function with an explicit return type.
|
//FIXME Better to use an inline function with an explicit return type.
|
||||||
//inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); }
|
//inline coord_t scale_(coordf_t v) { return coord_t(floor(v / SCALING_FACTOR + 0.5f)); }
|
||||||
#define scale_(val) ((val) / SCALING_FACTOR)
|
#define scale_(val) ((val) / SCALING_FACTOR)
|
||||||
#define unscale(val) ((val) * SCALING_FACTOR)
|
|
||||||
#define SCALED_EPSILON scale_(EPSILON)
|
#define SCALED_EPSILON scale_(EPSILON)
|
||||||
/* Implementation of CONFESS("foo"): */
|
/* Implementation of CONFESS("foo"): */
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
|
@ -102,6 +101,9 @@ inline std::string debug_out_path(const char *name, ...)
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
template<typename T, typename Q>
|
||||||
|
inline T unscale(Q v) { return T(v) * T(SCALING_FACTOR); }
|
||||||
|
|
||||||
enum Axis { X=0, Y, Z, E, F, NUM_AXES };
|
enum Axis { X=0, Y, Z, E, F, NUM_AXES };
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,8 @@ REGISTER_CLASS(BoundingBoxf, "Geometry::BoundingBoxf");
|
||||||
REGISTER_CLASS(BoundingBoxf3, "Geometry::BoundingBoxf3");
|
REGISTER_CLASS(BoundingBoxf3, "Geometry::BoundingBoxf3");
|
||||||
REGISTER_CLASS(BridgeDetector, "BridgeDetector");
|
REGISTER_CLASS(BridgeDetector, "BridgeDetector");
|
||||||
REGISTER_CLASS(Point, "Point");
|
REGISTER_CLASS(Point, "Point");
|
||||||
REGISTER_CLASS(Point3, "Point3");
|
__REGISTER_CLASS(Vec2d, "Pointf");
|
||||||
REGISTER_CLASS(Pointf, "Pointf");
|
__REGISTER_CLASS(Vec3d, "Pointf3");
|
||||||
REGISTER_CLASS(Pointf3, "Pointf3");
|
|
||||||
REGISTER_CLASS(DynamicPrintConfig, "Config");
|
REGISTER_CLASS(DynamicPrintConfig, "Config");
|
||||||
REGISTER_CLASS(StaticPrintConfig, "Config::Static");
|
REGISTER_CLASS(StaticPrintConfig, "Config::Static");
|
||||||
REGISTER_CLASS(PrintObjectConfig, "Config::PrintObject");
|
REGISTER_CLASS(PrintObjectConfig, "Config::PrintObject");
|
||||||
|
|
@ -64,9 +63,9 @@ REGISTER_CLASS(PresetCollection, "GUI::PresetCollection");
|
||||||
REGISTER_CLASS(PresetBundle, "GUI::PresetBundle");
|
REGISTER_CLASS(PresetBundle, "GUI::PresetBundle");
|
||||||
REGISTER_CLASS(TabIface, "GUI::Tab");
|
REGISTER_CLASS(TabIface, "GUI::Tab");
|
||||||
REGISTER_CLASS(PresetUpdater, "PresetUpdater");
|
REGISTER_CLASS(PresetUpdater, "PresetUpdater");
|
||||||
REGISTER_CLASS(OctoPrint, "OctoPrint");
|
|
||||||
REGISTER_CLASS(AppController, "AppController");
|
REGISTER_CLASS(AppController, "AppController");
|
||||||
REGISTER_CLASS(PrintController, "PrintController");
|
REGISTER_CLASS(PrintController, "PrintController");
|
||||||
|
REGISTER_CLASS(PrintHost, "PrintHost");
|
||||||
|
|
||||||
SV* ConfigBase__as_hash(ConfigBase* THIS)
|
SV* ConfigBase__as_hash(ConfigBase* THIS)
|
||||||
{
|
{
|
||||||
|
|
@ -133,7 +132,7 @@ SV* ConfigOption_to_SV(const ConfigOption &opt, const ConfigOptionDef &def)
|
||||||
auto optv = static_cast<const ConfigOptionPoints*>(&opt);
|
auto optv = static_cast<const ConfigOptionPoints*>(&opt);
|
||||||
AV* av = newAV();
|
AV* av = newAV();
|
||||||
av_fill(av, optv->values.size()-1);
|
av_fill(av, optv->values.size()-1);
|
||||||
for (const Pointf &v : optv->values)
|
for (const Vec2d &v : optv->values)
|
||||||
av_store(av, &v - optv->values.data(), perl_to_SV_clone_ref(v));
|
av_store(av, &v - optv->values.data(), perl_to_SV_clone_ref(v));
|
||||||
return newRV_noinc((SV*)av);
|
return newRV_noinc((SV*)av);
|
||||||
}
|
}
|
||||||
|
|
@ -263,14 +262,14 @@ bool ConfigBase__set(ConfigBase* THIS, const t_config_option_key &opt_key, SV* v
|
||||||
return from_SV_check(value, &static_cast<ConfigOptionPoint*>(opt)->value);
|
return from_SV_check(value, &static_cast<ConfigOptionPoint*>(opt)->value);
|
||||||
case coPoints:
|
case coPoints:
|
||||||
{
|
{
|
||||||
std::vector<Pointf> &values = static_cast<ConfigOptionPoints*>(opt)->values;
|
std::vector<Vec2d> &values = static_cast<ConfigOptionPoints*>(opt)->values;
|
||||||
AV* av = (AV*)SvRV(value);
|
AV* av = (AV*)SvRV(value);
|
||||||
const size_t len = av_len(av)+1;
|
const size_t len = av_len(av)+1;
|
||||||
values.clear();
|
values.clear();
|
||||||
values.reserve(len);
|
values.reserve(len);
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
SV** elem = av_fetch(av, i, 0);
|
SV** elem = av_fetch(av, i, 0);
|
||||||
Pointf point;
|
Vec2d point(Vec2d::Zero());
|
||||||
if (elem == NULL || !from_SV_check(*elem, &point)) return false;
|
if (elem == NULL || !from_SV_check(*elem, &point)) return false;
|
||||||
values.emplace_back(point);
|
values.emplace_back(point);
|
||||||
}
|
}
|
||||||
|
|
@ -509,7 +508,7 @@ void from_SV_check(SV* point_sv, Point* point)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SV* to_SV_pureperl(const Pointf* point)
|
SV* to_SV_pureperl(const Vec2d* point)
|
||||||
{
|
{
|
||||||
AV* av = newAV();
|
AV* av = newAV();
|
||||||
av_fill(av, 1);
|
av_fill(av, 1);
|
||||||
|
|
@ -518,23 +517,23 @@ SV* to_SV_pureperl(const Pointf* point)
|
||||||
return newRV_noinc((SV*)av);
|
return newRV_noinc((SV*)av);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool from_SV(SV* point_sv, Pointf* point)
|
bool from_SV(SV* point_sv, Vec2d* point)
|
||||||
{
|
{
|
||||||
AV* point_av = (AV*)SvRV(point_sv);
|
AV* point_av = (AV*)SvRV(point_sv);
|
||||||
SV* sv_x = *av_fetch(point_av, 0, 0);
|
SV* sv_x = *av_fetch(point_av, 0, 0);
|
||||||
SV* sv_y = *av_fetch(point_av, 1, 0);
|
SV* sv_y = *av_fetch(point_av, 1, 0);
|
||||||
if (!looks_like_number(sv_x) || !looks_like_number(sv_y)) return false;
|
if (!looks_like_number(sv_x) || !looks_like_number(sv_y)) return false;
|
||||||
|
|
||||||
*point = Pointf(SvNV(sv_x), SvNV(sv_y));
|
*point = Vec2d(SvNV(sv_x), SvNV(sv_y));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool from_SV_check(SV* point_sv, Pointf* point)
|
bool from_SV_check(SV* point_sv, Vec2d* point)
|
||||||
{
|
{
|
||||||
if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) {
|
if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) {
|
||||||
if (!sv_isa(point_sv, perl_class_name(point)) && !sv_isa(point_sv, perl_class_name_ref(point)))
|
if (!sv_isa(point_sv, perl_class_name(point)) && !sv_isa(point_sv, perl_class_name_ref(point)))
|
||||||
CONFESS("Not a valid %s object (got %s)", perl_class_name(point), HvNAME(SvSTASH(SvRV(point_sv))));
|
CONFESS("Not a valid %s object (got %s)", perl_class_name(point), HvNAME(SvSTASH(SvRV(point_sv))));
|
||||||
*point = *(Pointf*)SvIV((SV*)SvRV( point_sv ));
|
*point = *(Vec2d*)SvIV((SV*)SvRV( point_sv ));
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return from_SV(point_sv, point);
|
return from_SV(point_sv, point);
|
||||||
|
|
|
||||||
47
xs/src/qhull/Announce.txt
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
|
||||||
|
Qhull 2015.2 2016/01/18
|
||||||
|
|
||||||
|
http://www.qhull.org
|
||||||
|
git@github.com:qhull/qhull.git
|
||||||
|
http://www.geomview.org
|
||||||
|
|
||||||
|
Qhull computes convex hulls, Delaunay triangulations, Voronoi diagrams,
|
||||||
|
furthest-site Voronoi diagrams, and halfspace intersections about a point.
|
||||||
|
It runs in 2-d, 3-d, 4-d, or higher. It implements the Quickhull algorithm
|
||||||
|
for computing convex hulls. Qhull handles round-off errors from floating
|
||||||
|
point arithmetic. It can approximate a convex hull.
|
||||||
|
|
||||||
|
The program includes options for hull volume, facet area, partial hulls,
|
||||||
|
input transformations, randomization, tracing, multiple output formats, and
|
||||||
|
execution statistics. The program can be called from within your application.
|
||||||
|
You can view the results in 2-d, 3-d and 4-d with Geomview.
|
||||||
|
|
||||||
|
To download Qhull:
|
||||||
|
http://www.qhull.org/download
|
||||||
|
git@github.com:qhull/qhull.git
|
||||||
|
|
||||||
|
Download qhull-96.ps for:
|
||||||
|
|
||||||
|
Barber, C. B., D.P. Dobkin, and H.T. Huhdanpaa, "The
|
||||||
|
Quickhull Algorithm for Convex Hulls," ACM Trans. on
|
||||||
|
Mathematical Software, 22(4):469-483, Dec. 1996.
|
||||||
|
http://www.acm.org/pubs/citations/journals/toms/1996-22-4/p469-barber/
|
||||||
|
http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.117.405
|
||||||
|
|
||||||
|
Abstract:
|
||||||
|
|
||||||
|
The convex hull of a set of points is the smallest convex set that contains
|
||||||
|
the points. This article presents a practical convex hull algorithm that
|
||||||
|
combines the two-dimensional Quickhull Algorithm with the general dimension
|
||||||
|
Beneath-Beyond Algorithm. It is similar to the randomized, incremental
|
||||||
|
algorithms for convex hull and Delaunay triangulation. We provide empirical
|
||||||
|
evidence that the algorithm runs faster when the input contains non-extreme
|
||||||
|
points, and that it uses less memory.
|
||||||
|
|
||||||
|
Computational geometry algorithms have traditionally assumed that input sets
|
||||||
|
are well behaved. When an algorithm is implemented with floating point
|
||||||
|
arithmetic, this assumption can lead to serious errors. We briefly describe
|
||||||
|
a solution to this problem when computing the convex hull in two, three, or
|
||||||
|
four dimensions. The output is a set of "thick" facets that contain all
|
||||||
|
possible exact convex hulls of the input. A variation is effective in five
|
||||||
|
or more dimensions.
|
||||||
128
xs/src/qhull/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
|
||||||
|
# This CMake file is written specifically to integrate qhull library with Slic3rPE
|
||||||
|
# (see https://github.com/prusa3d/Slic3r for more information about the project)
|
||||||
|
#
|
||||||
|
# Only original libraries qhullstatic_r and qhullcpp are included.
|
||||||
|
# They are built as a single statically linked library.
|
||||||
|
#
|
||||||
|
# Created by modification of the original qhull CMakeLists.
|
||||||
|
# Lukas Matena (25.7.2018), lukasmatena@seznam.cz
|
||||||
|
|
||||||
|
|
||||||
|
project(qhull)
|
||||||
|
cmake_minimum_required(VERSION 2.6)
|
||||||
|
|
||||||
|
# Define qhull_VERSION in CMakeLists.txt, Makefile, qhull-exports.def, qhull_p-exports.def, qhull_r-exports.def, qhull-warn.pri
|
||||||
|
set(qhull_VERSION2 "2015.2 2016/01/18") # not used, See global.c, global_r.c, rbox.c, rbox_r.c
|
||||||
|
set(qhull_VERSION "7.2.0") # Advance every release
|
||||||
|
|
||||||
|
#include(CMakeModules/CheckLFS.cmake)
|
||||||
|
#option(WITH_LFS "Enable Large File Support" ON)
|
||||||
|
#check_lfs(WITH_LFS)
|
||||||
|
|
||||||
|
|
||||||
|
message(STATUS "qhull Version: ${qhull_VERSION} (static linking)")
|
||||||
|
|
||||||
|
|
||||||
|
set(libqhull_HEADERS
|
||||||
|
# reentrant qhull HEADERS:
|
||||||
|
src/libqhull_r/libqhull_r.h
|
||||||
|
src/libqhull_r/geom_r.h
|
||||||
|
src/libqhull_r/io_r.h
|
||||||
|
src/libqhull_r/mem_r.h
|
||||||
|
src/libqhull_r/merge_r.h
|
||||||
|
src/libqhull_r/poly_r.h
|
||||||
|
src/libqhull_r/qhull_ra.h
|
||||||
|
src/libqhull_r/qset_r.h
|
||||||
|
src/libqhull_r/random_r.h
|
||||||
|
src/libqhull_r/stat_r.h
|
||||||
|
src/libqhull_r/user_r.h
|
||||||
|
|
||||||
|
# C++ interface to reentrant Qhull HEADERS:
|
||||||
|
src/libqhullcpp/Coordinates.h
|
||||||
|
src/libqhullcpp/functionObjects.h
|
||||||
|
src/libqhullcpp/PointCoordinates.h
|
||||||
|
src/libqhullcpp/Qhull.h
|
||||||
|
src/libqhullcpp/QhullError.h
|
||||||
|
src/libqhullcpp/QhullFacet.h
|
||||||
|
src/libqhullcpp/QhullFacetList.h
|
||||||
|
src/libqhullcpp/QhullFacetSet.h
|
||||||
|
src/libqhullcpp/QhullHyperplane.h
|
||||||
|
src/libqhullcpp/QhullIterator.h
|
||||||
|
src/libqhullcpp/QhullLinkedList.h
|
||||||
|
src/libqhullcpp/QhullPoint.h
|
||||||
|
src/libqhullcpp/QhullPoints.h
|
||||||
|
src/libqhullcpp/QhullPointSet.h
|
||||||
|
src/libqhullcpp/QhullQh.h
|
||||||
|
src/libqhullcpp/QhullRidge.h
|
||||||
|
src/libqhullcpp/QhullSet.h
|
||||||
|
src/libqhullcpp/QhullSets.h
|
||||||
|
src/libqhullcpp/QhullStat.h
|
||||||
|
src/libqhullcpp/QhullVertex.h
|
||||||
|
src/libqhullcpp/QhullVertexSet.h
|
||||||
|
src/libqhullcpp/RboxPoints.h
|
||||||
|
src/libqhullcpp/RoadError.h
|
||||||
|
src/libqhullcpp/RoadLogEvent.h
|
||||||
|
src/qhulltest/RoadTest.h
|
||||||
|
)
|
||||||
|
|
||||||
|
set(libqhull_SOURCES
|
||||||
|
# reentrant qhull SOURCES:
|
||||||
|
src/libqhull_r/global_r.c
|
||||||
|
src/libqhull_r/stat_r.c
|
||||||
|
src/libqhull_r/geom2_r.c
|
||||||
|
src/libqhull_r/poly2_r.c
|
||||||
|
src/libqhull_r/merge_r.c
|
||||||
|
src/libqhull_r/libqhull_r.c
|
||||||
|
src/libqhull_r/geom_r.c
|
||||||
|
src/libqhull_r/poly_r.c
|
||||||
|
src/libqhull_r/qset_r.c
|
||||||
|
src/libqhull_r/mem_r.c
|
||||||
|
src/libqhull_r/random_r.c
|
||||||
|
src/libqhull_r/usermem_r.c
|
||||||
|
src/libqhull_r/userprintf_r.c
|
||||||
|
src/libqhull_r/io_r.c
|
||||||
|
src/libqhull_r/user_r.c
|
||||||
|
src/libqhull_r/rboxlib_r.c
|
||||||
|
src/libqhull_r/userprintf_rbox_r.c
|
||||||
|
|
||||||
|
# C++ interface to reentrant Qhull SOURCES:
|
||||||
|
src/libqhullcpp/Coordinates.cpp
|
||||||
|
src/libqhullcpp/PointCoordinates.cpp
|
||||||
|
src/libqhullcpp/Qhull.cpp
|
||||||
|
src/libqhullcpp/QhullFacet.cpp
|
||||||
|
src/libqhullcpp/QhullFacetList.cpp
|
||||||
|
src/libqhullcpp/QhullFacetSet.cpp
|
||||||
|
src/libqhullcpp/QhullHyperplane.cpp
|
||||||
|
src/libqhullcpp/QhullPoint.cpp
|
||||||
|
src/libqhullcpp/QhullPointSet.cpp
|
||||||
|
src/libqhullcpp/QhullPoints.cpp
|
||||||
|
src/libqhullcpp/QhullQh.cpp
|
||||||
|
src/libqhullcpp/QhullRidge.cpp
|
||||||
|
src/libqhullcpp/QhullSet.cpp
|
||||||
|
src/libqhullcpp/QhullStat.cpp
|
||||||
|
src/libqhullcpp/QhullVertex.cpp
|
||||||
|
src/libqhullcpp/QhullVertexSet.cpp
|
||||||
|
src/libqhullcpp/RboxPoints.cpp
|
||||||
|
src/libqhullcpp/RoadError.cpp
|
||||||
|
src/libqhullcpp/RoadLogEvent.cpp
|
||||||
|
|
||||||
|
# headers for both (libqhullr and libqhullcpp:
|
||||||
|
${libqhull_HEADERS}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
##################################################
|
||||||
|
# combined library (reentrant qhull and qhullcpp) for Slic3r:
|
||||||
|
set(qhull_STATIC qhull)
|
||||||
|
add_library(${qhull_STATIC} STATIC ${libqhull_SOURCES})
|
||||||
|
set_target_properties(${qhull_STATIC} PROPERTIES
|
||||||
|
VERSION ${qhull_VERSION})
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
target_link_libraries(${qhull_STATIC} m)
|
||||||
|
endif(UNIX)
|
||||||
|
##################################################
|
||||||
|
|
||||||
|
# LIBDIR is defined in the main xs CMake file:
|
||||||
|
target_include_directories(${qhull_STATIC} PRIVATE ${LIBDIR}/qhull/src)
|
||||||
38
xs/src/qhull/COPYING.txt
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
Qhull, Copyright (c) 1993-2015
|
||||||
|
|
||||||
|
C.B. Barber
|
||||||
|
Arlington, MA
|
||||||
|
|
||||||
|
and
|
||||||
|
|
||||||
|
The National Science and Technology Research Center for
|
||||||
|
Computation and Visualization of Geometric Structures
|
||||||
|
(The Geometry Center)
|
||||||
|
University of Minnesota
|
||||||
|
|
||||||
|
email: qhull@qhull.org
|
||||||
|
|
||||||
|
This software includes Qhull from C.B. Barber and The Geometry Center.
|
||||||
|
Qhull is copyrighted as noted above. Qhull is free software and may
|
||||||
|
be obtained via http from www.qhull.org. It may be freely copied, modified,
|
||||||
|
and redistributed under the following conditions:
|
||||||
|
|
||||||
|
1. All copyright notices must remain intact in all files.
|
||||||
|
|
||||||
|
2. A copy of this text file must be distributed along with any copies
|
||||||
|
of Qhull that you redistribute; this includes copies that you have
|
||||||
|
modified, or copies of programs or other software products that
|
||||||
|
include Qhull.
|
||||||
|
|
||||||
|
3. If you modify Qhull, you must include a notice giving the
|
||||||
|
name of the person performing the modification, the date of
|
||||||
|
modification, and the reason for such modification.
|
||||||
|
|
||||||
|
4. When distributing modified versions of Qhull, or other software
|
||||||
|
products that include Qhull, you must provide notice that the original
|
||||||
|
source code may be obtained as noted above.
|
||||||
|
|
||||||
|
5. There is no warranty or other guarantee of fitness for Qhull, it is
|
||||||
|
provided solely "as is". Bug reports or fixes may be sent to
|
||||||
|
qhull_bug@qhull.org; the authors may or may not act on them as
|
||||||
|
they desire.
|
||||||
623
xs/src/qhull/README.txt
Normal file
|
|
@ -0,0 +1,623 @@
|
||||||
|
This distribution of qhull library is only meant for interfacing qhull with Slic3rPE
|
||||||
|
(https://github.com/prusa3d/Slic3r).
|
||||||
|
|
||||||
|
The qhull source file was acquired from https://github.com/qhull/qhull at revision
|
||||||
|
f0bd8ceeb84b554d7cdde9bbfae7d3351270478c.
|
||||||
|
|
||||||
|
No changes to the qhull library were made, except for
|
||||||
|
- setting REALfloat=1 in user_r.h to enforce calculations in floats
|
||||||
|
- modifying CMakeLists.txt (the original was renamed to origCMakeLists.txt)
|
||||||
|
|
||||||
|
Many thanks to C. Bradford Barber and all contributors.
|
||||||
|
|
||||||
|
Lukas Matena (lukasmatena@seznam.cz)
|
||||||
|
25.7.2018
|
||||||
|
|
||||||
|
|
||||||
|
See original contents of the README file below.
|
||||||
|
|
||||||
|
======================================================================================
|
||||||
|
======================================================================================
|
||||||
|
======================================================================================
|
||||||
|
|
||||||
|
|
||||||
|
Name
|
||||||
|
|
||||||
|
qhull, rbox 2015.2 2016/01/18
|
||||||
|
|
||||||
|
Convex hull, Delaunay triangulation, Voronoi diagrams, Halfspace intersection
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
html/index.htm
|
||||||
|
<http://www.qhull.org/html>
|
||||||
|
|
||||||
|
Available from:
|
||||||
|
<http://www.qhull.org>
|
||||||
|
<http://www.qhull.org/download>
|
||||||
|
<http://github.com/qhull/qhull> (git@github.com:qhull/qhull.git)
|
||||||
|
|
||||||
|
News and a paper:
|
||||||
|
<http://www.qhull.org/news>
|
||||||
|
<http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.117.405>
|
||||||
|
|
||||||
|
Version 1 (simplicial only):
|
||||||
|
<http://www.qhull.org/download/qhull-1.0.tar.gz>
|
||||||
|
|
||||||
|
Purpose
|
||||||
|
|
||||||
|
Qhull is a general dimension convex hull program that reads a set
|
||||||
|
of points from stdin, and outputs the smallest convex set that contains
|
||||||
|
the points to stdout. It also generates Delaunay triangulations, Voronoi
|
||||||
|
diagrams, furthest-site Voronoi diagrams, and halfspace intersections
|
||||||
|
about a point.
|
||||||
|
|
||||||
|
Rbox is a useful tool in generating input for Qhull; it generates
|
||||||
|
hypercubes, diamonds, cones, circles, simplices, spirals,
|
||||||
|
lattices, and random points.
|
||||||
|
|
||||||
|
Qhull produces graphical output for Geomview. This helps with
|
||||||
|
understanding the output. <http://www.geomview.org>
|
||||||
|
|
||||||
|
Environment requirements
|
||||||
|
|
||||||
|
Qhull and rbox should run on all 32-bit and 64-bit computers. Use
|
||||||
|
an ANSI C or C++ compiler to compile the program. The software is
|
||||||
|
self-contained. It comes with examples and test scripts.
|
||||||
|
|
||||||
|
Qhull's C++ interface uses the STL. The C++ test program uses QTestLib
|
||||||
|
from the Qt Framework. Qhull's C++ interface may change without
|
||||||
|
notice. Eventually, it will move into the qhull shared library.
|
||||||
|
|
||||||
|
Qhull is copyrighted software. Please read COPYING.txt and REGISTER.txt
|
||||||
|
before using or distributing Qhull.
|
||||||
|
|
||||||
|
To cite Qhull, please use
|
||||||
|
|
||||||
|
Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull
|
||||||
|
algorithm for convex hulls," ACM Trans. on Mathematical Software,
|
||||||
|
22(4):469-483, Dec 1996, http://www.qhull.org.
|
||||||
|
|
||||||
|
To modify Qhull, particularly the C++ interface
|
||||||
|
|
||||||
|
Qhull is on GitHub
|
||||||
|
(http://github.com/qhull/qhull, git@github.com:qhull/qhull.git)
|
||||||
|
|
||||||
|
For internal documentation, see html/qh-code.htm
|
||||||
|
|
||||||
|
To install Qhull
|
||||||
|
|
||||||
|
Qhull is precompiled for Windows 32-bit, otherwise it needs compilation.
|
||||||
|
|
||||||
|
Qhull includes Makefiles for gcc and other targets, CMakeLists.txt for CMake,
|
||||||
|
.sln/.vcproj/.vcxproj files for Microsoft Visual Studio, and .pro files
|
||||||
|
for Qt Creator. It compiles under Windows with mingw.
|
||||||
|
|
||||||
|
Install and build instructions follow.
|
||||||
|
|
||||||
|
See the end of this document for a list of distributed files.
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Installing Qhull on Windows 10, 8, 7 (32- or 64-bit), Windows XP, and Windows NT
|
||||||
|
|
||||||
|
The zip file contains rbox.exe, qhull.exe, qconvex.exe, qdelaunay.exe,
|
||||||
|
qhalf.exe, qvoronoi.exe, testqset.exe, user_eg*.exe, documentation files,
|
||||||
|
and source files. Qhull.exe and user-eg3.exe are compiled with the reentrant
|
||||||
|
library while the other executables use the non-reentrant library.
|
||||||
|
|
||||||
|
To install Qhull:
|
||||||
|
- Unzip the files into a directory (e.g., named 'qhull')
|
||||||
|
- Click on QHULL-GO or open a command window into Qhull's bin directory.
|
||||||
|
- Test with 'rbox D4 | qhull'
|
||||||
|
|
||||||
|
To uninstall Qhull
|
||||||
|
- Delete the qhull directory
|
||||||
|
|
||||||
|
To learn about Qhull:
|
||||||
|
- Execute 'qconvex' for a synopsis and examples.
|
||||||
|
- Execute 'rbox 10 | qconvex' to compute the convex hull of 10 random points.
|
||||||
|
- Execute 'rbox 10 | qconvex i TO file' to write results to 'file'.
|
||||||
|
- Browse the documentation: qhull\html\index.htm
|
||||||
|
- If an error occurs, Windows sends the error to stdout instead of stderr.
|
||||||
|
Use 'TO xxx' to send normal output to xxx
|
||||||
|
|
||||||
|
To improve the command window
|
||||||
|
- Double-click the window bar to increase the size of the window
|
||||||
|
- Right-click the window bar
|
||||||
|
- Select Properties
|
||||||
|
- Check QuickEdit Mode
|
||||||
|
Select text with right-click or Enter
|
||||||
|
Paste text with right-click
|
||||||
|
- Change Font to Lucinda Console
|
||||||
|
- Change Layout to Screen Buffer Height 999, Window Size Height 55
|
||||||
|
- Change Colors to Screen Background White, Screen Text Black
|
||||||
|
- Click OK
|
||||||
|
- Select 'Modify shortcut that started this window', then OK
|
||||||
|
|
||||||
|
If you use qhull a lot, install a bash shell such as
|
||||||
|
MSYS (www.mingw.org/wiki/msys), Road Bash (www.qhull.org/bash),
|
||||||
|
or Cygwin (www.cygwin.com).
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Installing Qhull on Unix with gcc
|
||||||
|
|
||||||
|
To build Qhull, static libraries, shared library, and C++ interface
|
||||||
|
- Download and extract Qhull (either GitHub, .tgz file, or .zip file)
|
||||||
|
- make
|
||||||
|
- export LD_LIBRARY_PATH=$PWD/lib:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
The Makefiles may be edited for other compilers.
|
||||||
|
If 'testqset' exits with an error, qhull is broken
|
||||||
|
|
||||||
|
A simple Makefile for Qhull is in src/libqhull and src/libqhull_r.
|
||||||
|
To build the Qhull executables and libqhullstatic
|
||||||
|
- Extract Qhull from qhull...tgz or qhull...zip
|
||||||
|
- cd src/libqhull_r # cd src/libqhull
|
||||||
|
- make
|
||||||
|
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Installing Qhull with CMake 2.6 or later
|
||||||
|
|
||||||
|
See CMakeLists.txt for examples and further build instructions
|
||||||
|
|
||||||
|
To build Qhull, static libraries, shared library, and C++ interface
|
||||||
|
- Download and extract Qhull (either GitHub, .tgz file, or .zip file)
|
||||||
|
- cd build
|
||||||
|
- cmake --help # List build generators
|
||||||
|
- make -G "<generator>" .. && cmake ..
|
||||||
|
- cmake ..
|
||||||
|
- make
|
||||||
|
- make install
|
||||||
|
|
||||||
|
The ".." is important. It refers to the parent directory (i.e., qhull/)
|
||||||
|
|
||||||
|
On Windows, CMake installs to C:/Program Files/qhull. 64-bit generators
|
||||||
|
have a "Win64" tag.
|
||||||
|
|
||||||
|
If creating a qhull package, please include a pkg-config file based on build/qhull*.pc.in
|
||||||
|
|
||||||
|
If cmake fails with "No CMAKE_C_COMPILER could be found"
|
||||||
|
- cmake was not able to find the build environment specified by -G "..."
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Installing Qhull with Qt
|
||||||
|
|
||||||
|
To build Qhull, including its C++ test (qhulltest)
|
||||||
|
- Download and extract Qhull (either GitHub, .tgz file, or .zip file)
|
||||||
|
- Load src/qhull-all.pro into QtCreator
|
||||||
|
- Build
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
Working with Qhull's C++ interface
|
||||||
|
|
||||||
|
See html/qh-code.htm#cpp for calling Qhull from C++ programs
|
||||||
|
|
||||||
|
See html/qh-code.htm#reentrant for converting from Qhull-2012
|
||||||
|
|
||||||
|
Examples of using the C++ interface
|
||||||
|
user_eg3_r.cpp
|
||||||
|
qhulltest/*_test.cpp
|
||||||
|
|
||||||
|
Qhull's C++ interface is likely to change. Stay current with GitHub.
|
||||||
|
|
||||||
|
To clone Qhull's next branch from http://github.com/qhull/qhull
|
||||||
|
git init
|
||||||
|
git clone git@github.com:qhull/qhull.git
|
||||||
|
cd qhull
|
||||||
|
git checkout next
|
||||||
|
...
|
||||||
|
git pull origin next
|
||||||
|
|
||||||
|
Compile qhullcpp and libqhullstatic_r with the same compiler. Both libraries
|
||||||
|
use the C routines setjmp() and longjmp() for error handling. They must
|
||||||
|
be compiled with the same compiler.
|
||||||
|
|
||||||
|
-------------------
|
||||||
|
Calling Qhull from C programs
|
||||||
|
|
||||||
|
See html/qh-code.htm#library for calling Qhull from C programs
|
||||||
|
|
||||||
|
See html/qh-code.htm#reentrant for converting from Qhull-2012
|
||||||
|
|
||||||
|
Warning: You will need to understand Qhull's data structures and read the
|
||||||
|
code. Most users will find it easier to call Qhull as an external command.
|
||||||
|
|
||||||
|
The new, reentrant 'C' code (src/libqhull_r), passes a pointer to qhT
|
||||||
|
to most Qhull routines. This allows multiple instances of Qhull to run
|
||||||
|
at the same time. It simplifies the C++ interface.
|
||||||
|
|
||||||
|
The non-reentrant 'C' code (src/libqhull) looks unusual. It refers to
|
||||||
|
Qhull's global data structure, qhT, through a 'qh' macro (e.g., 'qh ferr').
|
||||||
|
This allows the same code to use static memory or heap memory.
|
||||||
|
If qh_QHpointer is defined, qh_qh is a pointer to an allocated qhT;
|
||||||
|
otherwise qh_qh is a global static data structure of type qhT.
|
||||||
|
|
||||||
|
------------------
|
||||||
|
Compiling Qhull with Microsoft Visual C++
|
||||||
|
|
||||||
|
To compile 32-bit Qhull with Microsoft Visual C++ 2010 and later
|
||||||
|
- Download and extract Qhull (either GitHub, .tgz file, or .zip file)
|
||||||
|
- Load solution build/qhull-32.sln
|
||||||
|
- Build target 'Win32'
|
||||||
|
- Project qhulltest requires Qt for DevStudio (http://www.qt.io)
|
||||||
|
Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/5.2.0/5.2.0/msvc2012)
|
||||||
|
If QTDIR is incorrect, precompile will fail with 'Can not locate the file specified'
|
||||||
|
|
||||||
|
To compile 64-bit Qhull with Microsoft Visual C++ 2010 and later
|
||||||
|
- 64-bit Qhull has larger data structures due to 64-bit pointers
|
||||||
|
- Download and extract Qhull (either GitHub, .tgz file, or .zip file)
|
||||||
|
- Load solution build/qhull-64.sln
|
||||||
|
- Build target 'Win32'
|
||||||
|
- Project qhulltest requires Qt for DevStudio (http://www.qt.io)
|
||||||
|
Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/5.2.0/5.2.0/msvc2012_64)
|
||||||
|
If QTDIR is incorrect, precompile will fail with 'Can not locate the file specified'
|
||||||
|
|
||||||
|
To compile Qhull with Microsoft Visual C++ 2005 (vcproj files)
|
||||||
|
- Download and extract Qhull (either GitHub, .tgz file, or .zip file)
|
||||||
|
- Load solution build/qhull.sln
|
||||||
|
- Build target 'win32' (not 'x64')
|
||||||
|
- Project qhulltest requires Qt for DevStudio (http://www.qt.io)
|
||||||
|
Set the QTDIR environment variable to your Qt directory (e.g., c:/qt/4.7.4)
|
||||||
|
If QTDIR is incorrect, precompile will fail with 'Can not locate the file specified'
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Compiling Qhull with Qt Creator
|
||||||
|
|
||||||
|
Qt (http://www.qt.io) is a C++ framework for Windows, Linux, and Macintosh
|
||||||
|
|
||||||
|
Qhull uses QTestLib to test qhull's C++ interface (see src/qhulltest/)
|
||||||
|
|
||||||
|
To compile Qhull with Qt Creator
|
||||||
|
- Download and extract Qhull (either GitHub, .tgz file, or .zip file)
|
||||||
|
- Download the Qt SDK
|
||||||
|
- Start Qt Creator
|
||||||
|
- Load src/qhull-all.pro
|
||||||
|
- Build
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Compiling Qhull with mingw on Windows
|
||||||
|
|
||||||
|
To compile Qhull with MINGW
|
||||||
|
- Download and extract Qhull (either GitHub, .tgz file, or .zip file)
|
||||||
|
- Install Road Bash (http://www.qhull.org/bash)
|
||||||
|
or install MSYS (http://www.mingw.org/wiki/msys)
|
||||||
|
- Install MINGW-w64 (http://sourceforge.net/projects/mingw-w64).
|
||||||
|
Mingw is included with Qt SDK.
|
||||||
|
- make
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Compiling Qhull with cygwin on Windows
|
||||||
|
|
||||||
|
To compile Qhull with cygwin
|
||||||
|
- Download and extract Qhull (either GitHub, .tgz file, or .zip file)
|
||||||
|
- Install cygwin (http://www.cygwin.com)
|
||||||
|
- Include packages for gcc, make, ar, and ln
|
||||||
|
- make
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Compiling from Makfile without gcc
|
||||||
|
|
||||||
|
The file, qhull-src.tgz, contains documentation and source files for
|
||||||
|
qhull and rbox.
|
||||||
|
|
||||||
|
To unpack the tgz file
|
||||||
|
- tar zxf qhull-src.tgz
|
||||||
|
- cd qhull
|
||||||
|
- Use qhull/Makefile
|
||||||
|
Simpler Makefiles are qhull/src/libqhull/Makefile and qhull/src/libqhull_r/Makefile
|
||||||
|
|
||||||
|
Compiling qhull and rbox with Makefile
|
||||||
|
- in Makefile, check the CC, CCOPTS1, PRINTMAN, and PRINTC defines
|
||||||
|
- the defaults are gcc and enscript
|
||||||
|
- CCOPTS1 should include the ANSI flag. It defines __STDC__
|
||||||
|
- in user.h, check the definitions of qh_SECticks and qh_CPUclock.
|
||||||
|
- use '#define qh_CLOCKtype 2' for timing runs longer than 1 hour
|
||||||
|
- type: make
|
||||||
|
- this builds: qhull qconvex qdelaunay qhalf qvoronoi rbox libqhull.a libqhull_r.a
|
||||||
|
- type: make doc
|
||||||
|
- this prints the man page
|
||||||
|
- See also qhull/html/index.htm
|
||||||
|
- if your compiler reports many errors, it is probably not a ANSI C compiler
|
||||||
|
- you will need to set the -ansi switch or find another compiler
|
||||||
|
- if your compiler warns about missing prototypes for fprintf() etc.
|
||||||
|
- this is ok, your compiler should have these in stdio.h
|
||||||
|
- if your compiler warns about missing prototypes for memset() etc.
|
||||||
|
- include memory.h in qhull_a.h
|
||||||
|
- if your compiler reports "global.c: storage size of 'qh_qh' isn't known"
|
||||||
|
- delete the initializer "={0}" in global.c, stat.c and mem.c
|
||||||
|
- if your compiler warns about "stat.c: improper initializer"
|
||||||
|
- this is ok, the initializer is not used
|
||||||
|
- if you have trouble building libqhull.a with 'ar'
|
||||||
|
- try 'make -f Makefile.txt qhullx'
|
||||||
|
- if the code compiles, the qhull test case will automatically execute
|
||||||
|
- if an error occurs, there's an incompatibility between machines
|
||||||
|
- If you can, try a different compiler
|
||||||
|
- You can turn off the Qhull memory manager with qh_NOmem in mem.h
|
||||||
|
- You can turn off compiler optimization (-O2 in Makefile)
|
||||||
|
- If you find the source of the problem, please let us know
|
||||||
|
- to install the programs and their man pages:
|
||||||
|
- define MANDIR and BINDIR
|
||||||
|
- type 'make install'
|
||||||
|
|
||||||
|
- if you have Geomview (www.geomview.org)
|
||||||
|
- try 'rbox 100 | qconvex G >a' and load 'a' into Geomview
|
||||||
|
- run 'q_eg' for Geomview examples of Qhull output (see qh-eg.htm)
|
||||||
|
|
||||||
|
------------------
|
||||||
|
Compiling on other machines and compilers
|
||||||
|
|
||||||
|
Qhull may compile with Borland C++ 5.0 bcc32. A Makefile is included.
|
||||||
|
Execute 'cd src/libqhull; make -f Mborland'. If you use the Borland IDE, set
|
||||||
|
the ANSI option in Options:Project:Compiler:Source:Language-compliance.
|
||||||
|
|
||||||
|
Qhull may compile with Borland C++ 4.02 for Win32 and DOS Power Pack.
|
||||||
|
Use 'cd src/libqhull; make -f Mborland -D_DPMI'. Qhull 1.0 compiles with
|
||||||
|
Borland C++ 4.02. For rbox 1.0, use "bcc32 -WX -w- -O2-e -erbox -lc rbox.c".
|
||||||
|
Use the same options for Qhull 1.0. [D. Zwick]
|
||||||
|
|
||||||
|
If you have troubles with the memory manager, you can turn it off by
|
||||||
|
defining qh_NOmem in mem.h.
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Distributed files
|
||||||
|
|
||||||
|
README.txt // Instructions for installing Qhull
|
||||||
|
REGISTER.txt // Qhull registration
|
||||||
|
COPYING.txt // Copyright notice
|
||||||
|
QHULL-GO.lnk // Windows icon for eg/qhull-go.bat
|
||||||
|
Announce.txt // Announcement
|
||||||
|
CMakeLists.txt // CMake build file (2.6 or later)
|
||||||
|
CMakeModules/CheckLFS.cmake // enables Large File Support in cmake
|
||||||
|
File_id.diz // Package descriptor
|
||||||
|
index.htm // Home page
|
||||||
|
Makefile // Makefile for gcc and other compilers
|
||||||
|
qhull*.md5sum // md5sum for all files
|
||||||
|
|
||||||
|
bin/* // Qhull executables and dll (.zip only)
|
||||||
|
build/qhull*.pc.in // pkg-config templates for qhull_r, qhull, and qhull_p
|
||||||
|
build/qhull-32.sln // 32-bit DevStudio solution and project files (2010 and later)
|
||||||
|
build/*-32.vcxproj
|
||||||
|
build/qhull-64.sln // 64-bit DevStudio solution and project files (2010 and later)
|
||||||
|
build/*-64.vcxproj
|
||||||
|
build/qhull.sln // DevStudio solution and project files (2005 and 2009)
|
||||||
|
build/*.vcproj
|
||||||
|
eg/* // Test scripts and geomview files from q_eg
|
||||||
|
html/index.htm // Manual
|
||||||
|
html/qh-faq.htm // Frequently asked questions
|
||||||
|
html/qh-get.htm // Download page
|
||||||
|
html/qhull-cpp.xml // C++ style notes as a Road FAQ (www.qhull.org/road)
|
||||||
|
src/Changes.txt // Change history for Qhull and rbox
|
||||||
|
src/qhull-all.pro // Qt project
|
||||||
|
|
||||||
|
eg/
|
||||||
|
q_eg // shell script for Geomview examples (eg.01.cube)
|
||||||
|
q_egtest // shell script for Geomview test examples
|
||||||
|
q_test // shell script to test qhull
|
||||||
|
q_test-ok.txt // output from q_test
|
||||||
|
qhulltest-ok.txt // output from qhulltest (Qt only)
|
||||||
|
make-vcproj.sh // bash shell script to create vcproj and vcxprog files
|
||||||
|
qhull-zip.sh // bash shell script for distribution files
|
||||||
|
|
||||||
|
rbox consists of (bin, html):
|
||||||
|
rbox.exe // Win32 executable (.zip only)
|
||||||
|
rbox.htm // html manual
|
||||||
|
rbox.man // Unix man page
|
||||||
|
rbox.txt
|
||||||
|
|
||||||
|
qhull consists of (bin, html):
|
||||||
|
qconvex.exe // Win32 executables and dlls (.zip download only)
|
||||||
|
qhull.exe // Built with the reentrant library (about 2% slower)
|
||||||
|
qdelaunay.exe
|
||||||
|
qhalf.exe
|
||||||
|
qvoronoi.exe
|
||||||
|
qhull_r.dll
|
||||||
|
qhull-go.bat // command window
|
||||||
|
qconvex.htm // html manual
|
||||||
|
qdelaun.htm
|
||||||
|
qdelau_f.htm
|
||||||
|
qhalf.htm
|
||||||
|
qvoronoi.htm
|
||||||
|
qvoron_f.htm
|
||||||
|
qh-eg.htm
|
||||||
|
qh-code.htm
|
||||||
|
qh-impre.htm
|
||||||
|
index.htm
|
||||||
|
qh-opt*.htm
|
||||||
|
qh-quick.htm
|
||||||
|
qh--*.gif // images for manual
|
||||||
|
normal_voronoi_knauss_oesterle.jpg
|
||||||
|
qhull.man // Unix man page
|
||||||
|
qhull.txt
|
||||||
|
|
||||||
|
bin/
|
||||||
|
msvcr80.dll // Visual C++ redistributable file (.zip download only)
|
||||||
|
|
||||||
|
src/
|
||||||
|
qhull/unix.c // Qhull and rbox applications using non-reentrant libqhullstatic.a
|
||||||
|
rbox/rbox.c
|
||||||
|
qconvex/qconvex.c
|
||||||
|
qhalf/qhalf.c
|
||||||
|
qdelaunay/qdelaunay.c
|
||||||
|
qvoronoi/qvoronoi.c
|
||||||
|
|
||||||
|
qhull/unix_r.c // Qhull and rbox applications using reentrant libqhullstatic_r.a
|
||||||
|
rbox/rbox_r.c
|
||||||
|
qconvex/qconvex_r.c // Qhull applications built with reentrant libqhull_r/Makefile
|
||||||
|
qhalf/qhalf_r.c
|
||||||
|
qdelaunay/qdelaun_r.c
|
||||||
|
qvoronoi/qvoronoi_r.c
|
||||||
|
|
||||||
|
user_eg/user_eg_r.c // example of using qhull_r.dll from a user program
|
||||||
|
user_eg2/user_eg2_r.c // example of using libqhullstatic_r.a from a user program
|
||||||
|
user_eg3/user_eg3_r.cpp // example of Qhull's C++ interface libqhullcpp with libqhullstatic_r.a
|
||||||
|
qhulltest/qhulltest.cpp // Test of Qhull's C++ interface using Qt's QTestLib
|
||||||
|
qhull-*.pri // Include files for Qt projects
|
||||||
|
testqset_r/testqset_r.c // Test of reentrant qset_r.c and mem_r.c
|
||||||
|
testqset/testqset.c // Test of non-rentrant qset.c and mem.c
|
||||||
|
|
||||||
|
|
||||||
|
src/libqhull
|
||||||
|
libqhull.pro // Qt project for non-rentrant, shared library (qhull.dll)
|
||||||
|
index.htm // design documentation for libqhull
|
||||||
|
qh-*.htm
|
||||||
|
qhull-exports.def // Export Definition file for Visual C++
|
||||||
|
Makefile // Simple gcc Makefile for qhull and libqhullstatic.a
|
||||||
|
Mborland // Makefile for Borland C++ 5.0
|
||||||
|
|
||||||
|
libqhull.h // header file for qhull
|
||||||
|
user.h // header file of user definable constants
|
||||||
|
libqhull.c // Quickhull algorithm with partitioning
|
||||||
|
user.c // user re-definable functions
|
||||||
|
usermem.c
|
||||||
|
userprintf.c
|
||||||
|
userprintf_rbox.c
|
||||||
|
|
||||||
|
qhull_a.h // include files for libqhull/*.c
|
||||||
|
geom.c // geometric routines
|
||||||
|
geom2.c
|
||||||
|
geom.h
|
||||||
|
global.c // global variables
|
||||||
|
io.c // input-output routines
|
||||||
|
io.h
|
||||||
|
mem.c // memory routines, this is stand-alone code
|
||||||
|
mem.h
|
||||||
|
merge.c // merging of non-convex facets
|
||||||
|
merge.h
|
||||||
|
poly.c // polyhedron routines
|
||||||
|
poly2.c
|
||||||
|
poly.h
|
||||||
|
qset.c // set routines, this only depends on mem.c
|
||||||
|
qset.h
|
||||||
|
random.c // utilities w/ Park & Miller's random number generator
|
||||||
|
random.h
|
||||||
|
rboxlib.c // point set generator for rbox
|
||||||
|
stat.c // statistics
|
||||||
|
stat.h
|
||||||
|
|
||||||
|
src/libqhull_r
|
||||||
|
libqhull_r.pro // Qt project for rentrant, shared library (qhull_r.dll)
|
||||||
|
index.htm // design documentation for libqhull_r
|
||||||
|
qh-*_r.htm
|
||||||
|
qhull-exports_r.def // Export Definition file for Visual C++
|
||||||
|
Makefile // Simple gcc Makefile for qhull and libqhullstatic.a
|
||||||
|
|
||||||
|
libqhull_r.h // header file for qhull
|
||||||
|
user_r.h // header file of user definable constants
|
||||||
|
libqhull_r.c // Quickhull algorithm wi_r.hpartitioning
|
||||||
|
user_r.c // user re-definable functions
|
||||||
|
usermem.c
|
||||||
|
userprintf.c
|
||||||
|
userprintf_rbox.c
|
||||||
|
qhull_ra.h // include files for libqhull/*_r.c
|
||||||
|
geom_r.c // geometric routines
|
||||||
|
geom2.c
|
||||||
|
geom_r.h
|
||||||
|
global_r.c // global variables
|
||||||
|
io_r.c // input-output routines
|
||||||
|
io_r.h
|
||||||
|
mem_r.c // memory routines, this is stand-alone code
|
||||||
|
mem.h
|
||||||
|
merge_r.c // merging of non-convex facets
|
||||||
|
merge.h
|
||||||
|
poly_r.c // polyhedron routines
|
||||||
|
poly2.c
|
||||||
|
poly_r.h
|
||||||
|
qset_r.c // set routines, this only depends on mem_r.c
|
||||||
|
qset.h
|
||||||
|
random_r.c // utilities w/ Park & Miller's random number generator
|
||||||
|
random.h
|
||||||
|
rboxlib_r.c // point set generator for rbox
|
||||||
|
stat_r.c // statistics
|
||||||
|
stat.h
|
||||||
|
|
||||||
|
src/libqhullcpp/
|
||||||
|
libqhullcpp.pro // Qt project for renentrant, static C++ library
|
||||||
|
Qhull.cpp // Calls libqhull_r.c from C++
|
||||||
|
Qhull.h
|
||||||
|
qt-qhull.cpp // Supporting methods for Qt
|
||||||
|
|
||||||
|
Coordinates.cpp // input classes
|
||||||
|
Coordinates.h
|
||||||
|
|
||||||
|
PointCoordinates.cpp
|
||||||
|
PointCoordinates.h
|
||||||
|
RboxPoints.cpp // call rboxlib.c from C++
|
||||||
|
RboxPoints.h
|
||||||
|
|
||||||
|
QhullFacet.cpp // data structure classes
|
||||||
|
QhullFacet.h
|
||||||
|
QhullHyperplane.cpp
|
||||||
|
QhullHyperplane.h
|
||||||
|
QhullPoint.cpp
|
||||||
|
QhullPoint.h
|
||||||
|
QhullQh.cpp
|
||||||
|
QhullRidge.cpp
|
||||||
|
QhullRidge.h
|
||||||
|
QhullVertex.cpp
|
||||||
|
QhullVertex.h
|
||||||
|
|
||||||
|
QhullFacetList.cpp // collection classes
|
||||||
|
QhullFacetList.h
|
||||||
|
QhullFacetSet.cpp
|
||||||
|
QhullFacetSet.h
|
||||||
|
QhullIterator.h
|
||||||
|
QhullLinkedList.h
|
||||||
|
QhullPoints.cpp
|
||||||
|
QhullPoints.h
|
||||||
|
QhullPointSet.cpp
|
||||||
|
QhullPointSet.h
|
||||||
|
QhullSet.cpp
|
||||||
|
QhullSet.h
|
||||||
|
QhullSets.h
|
||||||
|
QhullVertexSet.cpp
|
||||||
|
QhullVertexSet.h
|
||||||
|
|
||||||
|
functionObjects.h // supporting classes
|
||||||
|
QhullError.cpp
|
||||||
|
QhullError.h
|
||||||
|
QhullQh.cpp
|
||||||
|
QhullQh.h
|
||||||
|
QhullStat.cpp
|
||||||
|
QhullStat.h
|
||||||
|
RoadError.cpp // Supporting base classes
|
||||||
|
RoadError.h
|
||||||
|
RoadLogEvent.cpp
|
||||||
|
RoadLogEvent.h
|
||||||
|
usermem_r-cpp.cpp // Optional override for qh_exit() to throw an error
|
||||||
|
|
||||||
|
src/libqhullstatic/
|
||||||
|
libqhullstatic.pro // Qt project for non-reentrant, static library
|
||||||
|
|
||||||
|
src/libqhullstatic_r/
|
||||||
|
libqhullstatic_r.pro // Qt project for reentrant, static library
|
||||||
|
|
||||||
|
src/qhulltest/
|
||||||
|
qhulltest.pro // Qt project for test of C++ interface
|
||||||
|
Coordinates_test.cpp // Test of each class
|
||||||
|
PointCoordinates_test.cpp
|
||||||
|
Qhull_test.cpp
|
||||||
|
QhullFacet_test.cpp
|
||||||
|
QhullFacetList_test.cpp
|
||||||
|
QhullFacetSet_test.cpp
|
||||||
|
QhullHyperplane_test.cpp
|
||||||
|
QhullLinkedList_test.cpp
|
||||||
|
QhullPoint_test.cpp
|
||||||
|
QhullPoints_test.cpp
|
||||||
|
QhullPointSet_test.cpp
|
||||||
|
QhullRidge_test.cpp
|
||||||
|
QhullSet_test.cpp
|
||||||
|
QhullVertex_test.cpp
|
||||||
|
QhullVertexSet_test.cpp
|
||||||
|
RboxPoints_test.cpp
|
||||||
|
RoadTest.cpp // Run multiple test files with QTestLib
|
||||||
|
RoadTest.h
|
||||||
|
|
||||||
|
-----------------
|
||||||
|
Authors:
|
||||||
|
|
||||||
|
C. Bradford Barber Hannu Huhdanpaa (Version 1.0)
|
||||||
|
bradb@shore.net hannu@qhull.org
|
||||||
|
|
||||||
|
Qhull 1.0 and 2.0 were developed under NSF grants NSF/DMS-8920161
|
||||||
|
and NSF-CCR-91-15793 750-7504 at the Geometry Center and Harvard
|
||||||
|
University. If you find Qhull useful, please let us know.
|
||||||
32
xs/src/qhull/REGISTER.txt
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
Dear Qhull User
|
||||||
|
|
||||||
|
We would like to find out how you are using our software. Think of
|
||||||
|
Qhull as a new kind of shareware: you share your science and successes
|
||||||
|
with us, and we share our software and support with you.
|
||||||
|
|
||||||
|
If you use Qhull, please send us a note telling
|
||||||
|
us what you are doing with it.
|
||||||
|
|
||||||
|
We need to know:
|
||||||
|
|
||||||
|
(1) What you are working on - an abstract of your work would be
|
||||||
|
fine.
|
||||||
|
|
||||||
|
(2) How Qhull has helped you, for example, by increasing your
|
||||||
|
productivity or allowing you to do things you could not do
|
||||||
|
before. If Qhull had a direct bearing on your work, please
|
||||||
|
tell us about this.
|
||||||
|
|
||||||
|
We encourage you to cite Qhull in your publications.
|
||||||
|
|
||||||
|
To cite Qhull, please use
|
||||||
|
|
||||||
|
Barber, C.B., Dobkin, D.P., and Huhdanpaa, H.T., "The Quickhull
|
||||||
|
algorithm for convex hulls," ACM Trans. on Mathematical Software,
|
||||||
|
22(4):469-483, Dec 1996, http://www.qhull.org.
|
||||||
|
|
||||||
|
Please send e-mail to
|
||||||
|
|
||||||
|
bradb@shore.net
|
||||||
|
|
||||||
|
Thank you!
|
||||||
935
xs/src/qhull/html/index.htm
Normal file
|
|
@ -0,0 +1,935 @@
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type"
|
||||||
|
content="text/html; charset=iso-8859-1">
|
||||||
|
<meta name="GENERATOR" content="Microsoft FrontPage 2.0">
|
||||||
|
<title>Qhull manual</title>
|
||||||
|
<!-- Navigation links
|
||||||
|
NOTE -- verify all links by 'grep href=' 'grep name=' add # 'sort /+7'
|
||||||
|
index.htm
|
||||||
|
-->
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<p><a name="TOP"><b>Up:</b></a> <a
|
||||||
|
href="http://www.qhull.org">Home page</a> for Qhull<br>
|
||||||
|
<b>Up:</b><a
|
||||||
|
href="http://www.qhull.org/news">News</a> about Qhull<br>
|
||||||
|
<b>Up:</b> <a href="http://www.qhull.org/html/qh-faq.htm">FAQ</a> about Qhull<br>
|
||||||
|
<b>To:</b> <a href="#TOC">Qhull manual: Table of Contents</a>
|
||||||
|
(please wait while loading) <br>
|
||||||
|
<b>To:</b> <a href="qh-quick.htm#programs">Programs</a>
|
||||||
|
• <a href="qh-quick.htm#options">Options</a>
|
||||||
|
• <a href="qh-opto.htm#output">Output</a>
|
||||||
|
• <a href="qh-optf.htm#format">Formats</a>
|
||||||
|
• <a href="qh-optg.htm#geomview">Geomview</a>
|
||||||
|
• <a href="qh-optp.htm#print">Print</a>
|
||||||
|
• <a href="qh-optq.htm#qhull">Qhull</a>
|
||||||
|
• <a href="qh-optc.htm#prec">Precision</a>
|
||||||
|
• <a href="qh-optt.htm#trace">Trace</a>
|
||||||
|
• <a href="../src/libqhull_r/index.htm">Functions</a><br>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<!-- Main text of document -->
|
||||||
|
<h1><a
|
||||||
|
href="http://www.geom.uiuc.edu/graphics/pix/Special_Topics/Computational_Geometry/fixed.html"><img
|
||||||
|
src="qh--rand.gif" alt="[random-fixed]" align="middle"
|
||||||
|
width="100" height="100"></a> Qhull manual </h1>
|
||||||
|
|
||||||
|
<p>Qhull is a general dimension code for computing convex hulls,
|
||||||
|
Delaunay triangulations, halfspace intersections about a point, Voronoi
|
||||||
|
diagrams, furthest-site Delaunay triangulations, and
|
||||||
|
furthest-site Voronoi diagrams. These structures have
|
||||||
|
applications in science, engineering, statistics, and
|
||||||
|
mathematics. See <a
|
||||||
|
href="http://www.cs.mcgill.ca/~fukuda/soft/polyfaq/polyfaq.html">Fukuda's
|
||||||
|
introduction</a> to convex hulls, Delaunay triangulations,
|
||||||
|
Voronoi diagrams, and linear programming. For a detailed
|
||||||
|
introduction, see O'Rourke [<a href="#orou94">'94</a>], <i>Computational
|
||||||
|
Geometry in C</i>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>There are six programs. Except for rbox, they use
|
||||||
|
the same code. Each program includes instructions and examples.
|
||||||
|
<blockquote>
|
||||||
|
<ul>
|
||||||
|
<li><a href="qconvex.htm">qconvex</a> -- convex hulls
|
||||||
|
<li><a href="qdelaun.htm">qdelaunay</a> -- Delaunay triangulations and
|
||||||
|
furthest-site Delaunay triangulations
|
||||||
|
<li><a href="qhalf.htm">qhalf</a> -- halfspace intersections about a point
|
||||||
|
<li><a href="qhull.htm">qhull</a> -- all structures with additional options
|
||||||
|
<li><a href="qvoronoi.htm">qvoronoi</a> -- Voronoi diagrams and
|
||||||
|
furthest-site Voronoi diagrams
|
||||||
|
<li><a href="rbox.htm">rbox</a> -- generate point distributions for qhull
|
||||||
|
</ul>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>Qhull implements the Quickhull algorithm for computing the
|
||||||
|
convex hull. Qhull includes options
|
||||||
|
for hull volume, facet area, multiple output formats, and
|
||||||
|
graphical output. It can approximate a convex hull. </p>
|
||||||
|
|
||||||
|
<p>Qhull handles roundoff errors from floating point
|
||||||
|
arithmetic. It generates a convex hull with "thick" facets.
|
||||||
|
A facet's outer plane is clearly above all of the points;
|
||||||
|
its inner plane is clearly below the facet's vertices. Any
|
||||||
|
exact convex hull must lie between the inner and outer plane.
|
||||||
|
|
||||||
|
<p>Qhull uses merged facets, triangulated output, or joggled
|
||||||
|
input. Triangulated output triangulates non-simplicial, merged
|
||||||
|
facets. Joggled input also
|
||||||
|
guarantees simplicial output, but it
|
||||||
|
is less accurate than merged facets. For merged facets, Qhull
|
||||||
|
reports the maximum outer and inner plane.
|
||||||
|
|
||||||
|
<p><i>Brad Barber, Arlington, MA</i></p>
|
||||||
|
|
||||||
|
<p><b>Copyright © 1995-2015 C.B. Barber</b></p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h2><a href="#TOP">»</a><a name="TOC">Qhull manual: Table of
|
||||||
|
Contents </a></h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#when">When</a> to use Qhull
|
||||||
|
<ul>
|
||||||
|
<li><a href="http://www.qhull.org/news">News</a> for Qhull
|
||||||
|
with new features and reported bugs.
|
||||||
|
<li><a href="http://www.qhull.org">Home</a> for Qhull with additional URLs
|
||||||
|
(<a href=index.htm>local copy</a>)
|
||||||
|
<li><a href="http://www.qhull.org/html/qh-faq.htm">FAQ</a> for Qhull (<a href="qh-faq.htm">local copy</a>)
|
||||||
|
<li><a href="http://www.qhull.org/download">Download</a> Qhull (<a href=qh-get.htm>local copy</a>)
|
||||||
|
<li><a href="qh-quick.htm#programs">Quick</a> reference for Qhull and its <a href="qh-quick.htm#options">options</a>
|
||||||
|
<p>
|
||||||
|
<li><a href="../COPYING.txt">COPYING.txt</a> - copyright notice<br>
|
||||||
|
<li><a href="../REGISTER.txt">REGISTER.txt</a> - registration<br>
|
||||||
|
<li><a href="../README.txt">README.txt</a> - installation
|
||||||
|
instructions<br>
|
||||||
|
<li><a href="../src/Changes.txt">Changes.txt</a> - change history <br>
|
||||||
|
<li><a href="qhull.txt">qhull.txt</a> - Unix manual page
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<li><a href="#description">Description</a> of Qhull
|
||||||
|
<ul>
|
||||||
|
<li><a href="#definition">de</a>finition • <a
|
||||||
|
href="#input">in</a>put • <a href="#output">ou</a>tput
|
||||||
|
• <a href="#algorithm">al</a>gorithm • <a
|
||||||
|
href="#structure">da</a>ta structure </li>
|
||||||
|
<li><a href="qh-impre.htm">Imprecision</a> in Qhull</li>
|
||||||
|
<li><a href="qh-impre.htm#joggle">Merged facets</a> or joggled input
|
||||||
|
<li><a href="qh-eg.htm">Examples</a> of Qhull</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<li><a href=qh-quick.htm#programs>Qhull programs</a>, with instructions and examples
|
||||||
|
<ul>
|
||||||
|
<li><a href="qconvex.htm">qconvex</a> -- convex hulls
|
||||||
|
<li><a href="qdelaun.htm">qdelaunay</a> -- Delaunay triangulations and
|
||||||
|
furthest-site Delaunay triangulations
|
||||||
|
<li><a href="qhalf.htm">qhalf</a> -- halfspace intersections about a point
|
||||||
|
<li><a href="qhull.htm">qhull</a> -- all structures with additional options
|
||||||
|
<li><a href="qvoronoi.htm">qvoronoi</a> -- Voronoi diagrams and
|
||||||
|
furthest-site Voronoi diagrams
|
||||||
|
<li><a href="rbox.htm">rbox</a> -- generate point distributions for qhull
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<li><a href="qh-quick.htm#options">Qhull options</a><ul>
|
||||||
|
<li><a href="qh-opto.htm#output">Output</a> formats</li>
|
||||||
|
<li><a href="qh-optf.htm#format">Additional</a> I/O
|
||||||
|
formats</li>
|
||||||
|
<li><a href="qh-optg.htm#geomview">Geomview</a>
|
||||||
|
output options</li>
|
||||||
|
<li><a href="qh-optp.htm#print">Print</a> options</li>
|
||||||
|
<li><a href="qh-optq.htm#qhull">Qhull</a> control
|
||||||
|
options</li>
|
||||||
|
<li><a href="qh-optc.htm#prec">Precision</a> options</li>
|
||||||
|
<li><a href="qh-optt.htm#trace">Trace</a> options</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<p>
|
||||||
|
<li><a href="#geomview">Geomview</a>, Qhull's graphical viewer</li>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#geomview-install">Installing Geomview</a></li>
|
||||||
|
<li><a href="#geomview-use">Using Geomview</a></li>
|
||||||
|
<li><a href="#geomview-win">Building Geomview for Windows</a></li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<li><a href="qh-code.htm">Qhull internals</a><ul>
|
||||||
|
<li><a href="qh-code.htm#reentrant">Reentrant</a> Qhull</li>
|
||||||
|
<li><a href="qh-code.htm#convert">How to convert</a> code to reentrant Qhull</li>
|
||||||
|
<li><a href="qh-code.htm#64bit">Qhull</a> on 64-bit computers</li>
|
||||||
|
<li><a href="qh-code.htm#cpp">Calling</a> Qhull
|
||||||
|
from C++ programs</li>
|
||||||
|
<li><a href="qh-code.htm#library">Calling</a> Qhull
|
||||||
|
from C programs</li>
|
||||||
|
<li><a href="qh-code.htm#performance">Performance</a>
|
||||||
|
of Qhull</li>
|
||||||
|
<li><a href="qh-code.htm#enhance">Enhancements</a> to
|
||||||
|
Qhull</li>
|
||||||
|
<li><a href="../src/libqhull_r/index.htm">Reentrant</a> Qhull functions, macros, and
|
||||||
|
data structures </li>
|
||||||
|
<li><a href="../src/libqhull/index.htm">Qhull</a> functions, macros, and
|
||||||
|
data structures </li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<p>
|
||||||
|
<li>Related URLs
|
||||||
|
<ul>
|
||||||
|
|
||||||
|
<li><a href="news:comp.graphics.algorithms">Newsgroup</a>:
|
||||||
|
comp.graphics.algorithms
|
||||||
|
<li><a
|
||||||
|
href="http://www.faqs.org/faqs/graphics/algorithms-faq/">FAQ</a> for computer graphics algorithms and
|
||||||
|
Exaflop's <a href="http://exaflop.org/docs/cgafaq/cga6.html">geometric</a> structures.
|
||||||
|
<li>Amenta's <a href="http://www.geom.uiuc.edu/software/cglist">Directory
|
||||||
|
of Computational Geometry Software </a></li>
|
||||||
|
<li>Erickson's <a
|
||||||
|
href="http://compgeom.cs.uiuc.edu/~jeffe/compgeom/code.html">Computational
|
||||||
|
Geometry Software</a> </li>
|
||||||
|
<li>Fukuda's <a
|
||||||
|
href="http://www.cs.mcgill.ca/~fukuda/soft/polyfaq/polyfaq.html">
|
||||||
|
introduction</a> to convex hulls, Delaunay triangulations,
|
||||||
|
Voronoi diagrams, and linear programming.
|
||||||
|
<li>Stony Brook's <a
|
||||||
|
href="http://www.cs.sunysb.edu/~algorith/major_section/1.6.shtml">Algorithm Repository</a> on computational geometry.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>
|
||||||
|
<li><a href="#bugs">What to do</a> if something goes wrong</li>
|
||||||
|
<li><a href="#email">Email</a></li>
|
||||||
|
<li><a href="#authors">Authors</a></li>
|
||||||
|
<li><a href="#ref">References</a></li>
|
||||||
|
<li><a href="#acknowledge">Acknowledgments</a></li>
|
||||||
|
</ul>
|
||||||
|
<h2><a href="#TOC">»</a><a name="when">When to use Qhull</a></h2>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Qhull constructs convex hulls, Delaunay triangulations,
|
||||||
|
halfspace intersections about a point, Voronoi diagrams, furthest-site Delaunay
|
||||||
|
triangulations, and furthest-site Voronoi diagrams.</p>
|
||||||
|
|
||||||
|
<p>For convex hulls and halfspace intersections, Qhull may be used
|
||||||
|
for 2-d upto 8-d. For Voronoi diagrams and Delaunay triangulations, Qhull may be
|
||||||
|
used for 2-d upto 7-d. In higher dimensions, the size of the output
|
||||||
|
grows rapidly and Qhull does not work well with virtual memory.
|
||||||
|
If <i>n</i> is the size of
|
||||||
|
the input and <i>d</i> is the dimension (d>=3), the size of the output
|
||||||
|
and execution time
|
||||||
|
grows by <i>n^(floor(d/2)</i>
|
||||||
|
[see <a href=qh-code.htm#performance>Performance</a>]. For example, do
|
||||||
|
not try to build a 16-d convex hull of 1000 points. It will
|
||||||
|
have on the order of 1,000,000,000,000,000,000,000,000 facets.
|
||||||
|
|
||||||
|
<p>On a 600 MHz Pentium 3, Qhull computes the 2-d convex hull of
|
||||||
|
300,000 cocircular points in 11 seconds. It computes the
|
||||||
|
2-d Delaunay triangulation and 3-d convex hull of 120,000 points
|
||||||
|
in 12 seconds. It computes the
|
||||||
|
3-d Delaunay triangulation and 4-d convex hull of 40,000 points
|
||||||
|
in 18 seconds. It computes the
|
||||||
|
4-d Delaunay triangulation and 5-d convex hull of 6,000 points
|
||||||
|
in 12 seconds. It computes the
|
||||||
|
5-d Delaunay triangulation and 6-d convex hull of 1,000 points
|
||||||
|
in 12 seconds. It computes the
|
||||||
|
6-d Delaunay triangulation and 7-d convex hull of 300 points
|
||||||
|
in 15 seconds. It computes the
|
||||||
|
7-d Delaunay triangulation and 8-d convex hull of 120 points
|
||||||
|
in 15 seconds. It computes the
|
||||||
|
8-d Delaunay triangulation and 9-d convex hull of 70 points
|
||||||
|
in 15 seconds. It computes the
|
||||||
|
9-d Delaunay triangulation and 10-d convex hull of 50 points
|
||||||
|
in 17 seconds. The 10-d convex hull of 50 points has about 90,000 facets.
|
||||||
|
|
||||||
|
<!-- duplicated in index.htm and html/index.htm -->
|
||||||
|
<p>Qhull does <i>not</i> support constrained Delaunay
|
||||||
|
triangulations, triangulation of non-convex surfaces, mesh
|
||||||
|
generation of non-convex objects, or medium-sized inputs in 9-D
|
||||||
|
and higher. </p>
|
||||||
|
|
||||||
|
<p>This is a big package with many options. It is one of the
|
||||||
|
fastest available. It is the only 3-d code that handles precision
|
||||||
|
problems due to floating point arithmetic. For example, it
|
||||||
|
implements the identity function for extreme points (see <a
|
||||||
|
href="qh-impre.htm">Imprecision in Qhull</a>). </p>
|
||||||
|
|
||||||
|
<p>[2016] A newly discovered, bad case for Qhull is multiple, nearly incident points within a 10^-13 ball of 3-d and higher
|
||||||
|
Delaunay triangulations (input sites in the unit cube). Nearly incident points within substantially
|
||||||
|
smaller or larger balls are OK. Error QH6271 is reported if a problem occurs. A future release of Qhull
|
||||||
|
will handle this case. For more information, see "Nearly coincident points on an edge" in <a href="../html/qh-impre.htm#limit">Limitations of merged facets</a>
|
||||||
|
|
||||||
|
<p>If you need a short code for convex hull, Delaunay
|
||||||
|
triangulation, or Voronoi volumes consider Clarkson's <a
|
||||||
|
href="http://www.netlib.org/voronoi/hull.html">hull
|
||||||
|
program</a>. If you need 2-d Delaunay triangulations consider
|
||||||
|
Shewchuk's <a href="http://www.cs.cmu.edu/~quake/triangle.html">triangle
|
||||||
|
program</a>. It is much faster than Qhull and it allows
|
||||||
|
constraints. Both programs use exact arithmetic. They are in <a
|
||||||
|
href="http://www.netlib.org/voronoi/">http://www.netlib.org/voronoi/</a>.
|
||||||
|
|
||||||
|
<p>If your input is in general position (i.e., no coplanar or colinear points),
|
||||||
|
<li><a href="https://github.com/tomilov/quickhull/blob/master/include/quickhull.hpp">Tomilov's quickhull.hpp</a> (<a href"http://habrahabr.ru/post/245221/"documentation-ru</a/>)
|
||||||
|
or Qhull <a
|
||||||
|
href="http://www.qhull.org/download">version
|
||||||
|
1.0</a> may meet your needs. Both programs detect precision problems,
|
||||||
|
but do not handle them.</p>
|
||||||
|
|
||||||
|
<p><a href=http://www.cgal.org>CGAL</a> is a library of efficient and reliable
|
||||||
|
geometric algorithms. It uses C++ templates and the Boost library to produce dimension-specific
|
||||||
|
code. This allows more efficient use of memory than Qhull's general-dimension
|
||||||
|
code. CGAL simulates arbitrary precision while Qhull handles round-off error
|
||||||
|
with thick facets. Compare the two approaches with <a href="http://doc.cgal.org/latest/Manual/devman_robustness.html">Robustness Issues in CGAL</a>,
|
||||||
|
and <a href+"qh-impre.htm">Imprecision in Qhull</a>.
|
||||||
|
|
||||||
|
|
||||||
|
<p><a href=http://www.algorithmic-solutions.com/enleda.htm>Leda</a> is a
|
||||||
|
library for writing computational
|
||||||
|
geometry programs and other combinatorial algorithms. It
|
||||||
|
includes routines for computing 3-d convex
|
||||||
|
hulls, 2-d Delaunay triangulations, and 3-d Delaunay triangulations.
|
||||||
|
It provides rational arithmetic and graphical output. It runs on most
|
||||||
|
platforms.
|
||||||
|
|
||||||
|
<p>If your problem is in high dimensions with a few,
|
||||||
|
non-simplicial facets, try Fukuda's <a
|
||||||
|
href="http://www.cs.mcgill.ca/~fukuda/soft/cdd_home/cdd.html">cdd</a>.
|
||||||
|
It is much faster than Qhull for these distributions. </p>
|
||||||
|
|
||||||
|
<p>Custom software for 2-d and 3-d convex hulls may be faster
|
||||||
|
than Qhull. Custom software should use less memory. Qhull uses
|
||||||
|
general-dimension data structures and code. The data structures
|
||||||
|
support non-simplicial facets.</p>
|
||||||
|
|
||||||
|
<p>Qhull is not suitable for mesh generation or triangulation of
|
||||||
|
arbitrary surfaces. You may use Qhull if the surface is convex or
|
||||||
|
completely visible from an interior point (e.g., a star-shaped
|
||||||
|
polyhedron). First, project each site to a sphere that is
|
||||||
|
centered at the interior point. Then, compute the convex hull of
|
||||||
|
the projected sites. The facets of the convex hull correspond to
|
||||||
|
a triangulation of the surface. For mesh generation of arbitrary
|
||||||
|
surfaces, see <a
|
||||||
|
href="http://www.robertschneiders.de/meshgeneration/meshgeneration.html">Schneiders'
|
||||||
|
Finite Element Mesh Generation</a>.</p>
|
||||||
|
|
||||||
|
<p>Qhull is not suitable for constrained Delaunay triangulations.
|
||||||
|
With a lot of work, you can write a program that uses Qhull to
|
||||||
|
add constraints by adding additional points to the triangulation.</p>
|
||||||
|
|
||||||
|
<p>Qhull is not suitable for the subdivision of arbitrary
|
||||||
|
objects. Use <tt>qdelaunay</tt> to subdivide a convex object.</p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h2><a href="#TOC">»</a><a name="description">Description of
|
||||||
|
Qhull </a></h2>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<h3><a href="#TOC">»</a><a name="definition">definition</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>The <i>convex hull</i> of a point set <i>P</i> is the smallest
|
||||||
|
convex set that contains <i>P</i>. If <i>P</i> is finite, the
|
||||||
|
convex hull defines a matrix <i>A</i> and a vector <i>b</i> such
|
||||||
|
that for all <i>x</i> in <i>P</i>, <i>Ax+b <= [0,...]</i>. </p>
|
||||||
|
|
||||||
|
<p>Qhull computes the convex hull in 2-d, 3-d, 4-d, and higher
|
||||||
|
dimensions. Qhull represents a convex hull as a list of facets.
|
||||||
|
Each facet has a set of vertices, a set of neighboring facets,
|
||||||
|
and a halfspace. A halfspace is defined by a unit normal and an
|
||||||
|
offset (i.e., a row of <i>A</i> and an element of <i>b</i>). </p>
|
||||||
|
|
||||||
|
<p>Qhull accounts for round-off error. It returns
|
||||||
|
"thick" facets defined by two parallel hyperplanes. The
|
||||||
|
outer planes contain all input points. The inner planes exclude
|
||||||
|
all output vertices. See <a href="qh-impre.htm#imprecise">Imprecise
|
||||||
|
convex hulls</a>.</p>
|
||||||
|
|
||||||
|
<p>Qhull may be used for the Delaunay triangulation or the
|
||||||
|
Voronoi diagram of a set of points. It may be used for the
|
||||||
|
intersection of halfspaces. </p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOC">»</a><a name="input">input format</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>The input data on <tt>stdin</tt> consists of:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>first line contains the dimension</li>
|
||||||
|
<li>second line contains the number of input points</li>
|
||||||
|
<li>remaining lines contain point coordinates</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>For example: </p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
3 #sample 3-d input
|
||||||
|
5
|
||||||
|
0.4 -0.5 1.0
|
||||||
|
1000 -1e-5 -100
|
||||||
|
0.3 0.2 0.1
|
||||||
|
1.0 1.0 1.0
|
||||||
|
0 0 0
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>Input may be entered by hand. End the input with a control-D
|
||||||
|
(^D) character. </p>
|
||||||
|
|
||||||
|
<p>To input data from a file, use I/O redirection or '<a
|
||||||
|
href="qh-optt.htm#TI">TI file</a>'. The filename may not
|
||||||
|
include spaces or quotes.</p>
|
||||||
|
|
||||||
|
<p>A comment starts with a non-numeric character and continues to
|
||||||
|
the end of line. The first comment is reported in summaries and
|
||||||
|
statistics. With multiple <tt>qhull</tt> commands, use option '<a
|
||||||
|
href="qh-optf.htm#FQ">FQ</a>' to place a comment in the output.</p>
|
||||||
|
|
||||||
|
<p>The dimension and number of points can be reversed. Comments
|
||||||
|
and line breaks are ignored. Error reporting is better if there
|
||||||
|
is one point per line.</p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOC">»</a><a name="option">option format</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Use options to specify the output formats and control
|
||||||
|
Qhull. The <tt>qhull</tt> program takes all options. The
|
||||||
|
other programs use a subset of the options. They disallow
|
||||||
|
experimental and inappropriate options.
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
qconvex == qhull
|
||||||
|
<li>
|
||||||
|
qdelaunay == qhull d Qbb
|
||||||
|
<li>
|
||||||
|
qhalf == qhull H
|
||||||
|
<li>
|
||||||
|
qvoronoi == qhull v Qbb
|
||||||
|
</ul>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>Single letters are used for output formats and precision
|
||||||
|
constants. The other options are grouped into menus for formats
|
||||||
|
('<a href="qh-optf.htm#format">F</a>'), Geomview ('<a
|
||||||
|
href="qh-optg.htm#geomview">G </a>'), printing ('<a
|
||||||
|
href="qh-optp.htm#print">P</a>'), Qhull control ('<a
|
||||||
|
href="qh-optq.htm#qhull">Q </a>'), and tracing ('<a
|
||||||
|
href="qh-optt.htm#trace">T</a>'). The menu options may be listed
|
||||||
|
together (e.g., 'GrD3' for 'Gr' and 'GD3'). Options may be in any
|
||||||
|
order. Capitalized options take a numeric argument (except for '<a
|
||||||
|
href="qh-optp.htm#PG">PG</a>' and '<a href="qh-optf.htm#format">F</a>'
|
||||||
|
options). Use option '<a href="qh-optf.htm#FO">FO</a>' to print
|
||||||
|
the selected options.</p>
|
||||||
|
|
||||||
|
<p>Qhull uses zero-relative indexing. If there are <i>n</i>
|
||||||
|
points, the index of the first point is <i>0</i> and the index of
|
||||||
|
the last point is <i>n-1</i>.</p>
|
||||||
|
|
||||||
|
<p>The default options are:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>summary output ('<a href="qh-opto.htm#s">s</a>') </li>
|
||||||
|
<li>merged facets ('<a href="qh-optc.htm#C0">C-0</a>' in 2-d,
|
||||||
|
3-d, 4-d; '<a href="qh-optq.htm#Qx">Qx</a>' in 5-d and
|
||||||
|
up)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Except for bounding box
|
||||||
|
('<a href="qh-optq.htm#Qbk">Qbk:n</a>', etc.), drop facets
|
||||||
|
('<a href="qh-optp.htm#Pdk">Pdk:n</a>', etc.), and
|
||||||
|
Qhull command ('<a href="qh-optf.htm#FQ">FQ</a>'), only the last
|
||||||
|
occurence of an option counts.
|
||||||
|
Bounding box and drop facets may be repeated for each dimension.
|
||||||
|
Option 'FQ' may be repeated any number of times.
|
||||||
|
|
||||||
|
<p>The Unix <tt>tcsh</tt> and <tt>ksh </tt>shells make it easy to
|
||||||
|
try out different options. In Windows 95, use a command window with <tt>doskey</tt>
|
||||||
|
and a window scroller (e.g., <tt>peruse</tt>). </p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOC">»</a><a name="output">output format</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>To write the results to a file, use I/O redirection or '<a
|
||||||
|
href="qh-optt.htm#TO">TO file</a>'. Windows 95 users should use
|
||||||
|
'TO file' or the console. If a filename is surrounded by single quotes,
|
||||||
|
it may include spaces.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>The default output option is a short summary ('<a
|
||||||
|
href="qh-opto.htm#s">s</a>') to <tt>stdout</tt>. There are many
|
||||||
|
others (see <a href="qh-opto.htm">output</a> and <a
|
||||||
|
href="qh-optf.htm">formats</a>). You can list vertex incidences,
|
||||||
|
vertices and facets, vertex coordinates, or facet normals. You
|
||||||
|
can view Qhull objects with Geomview, Mathematica, or Maple. You can
|
||||||
|
print the internal data structures. You can call Qhull from your
|
||||||
|
application (see <a href="qh-code.htm#library">Qhull library</a>).</p>
|
||||||
|
|
||||||
|
<p>For example, 'qhull <a href="qh-opto.htm#o">o</a>' lists the
|
||||||
|
vertices and facets of the convex hull. </p>
|
||||||
|
|
||||||
|
<p>Error messages and additional summaries ('<a
|
||||||
|
href="qh-opto.htm#s">s</a>') go to <tt>stderr</tt>. Unless
|
||||||
|
redirected, <tt>stderr</tt> is the console.</p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOC">»</a><a name="algorithm">algorithm</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Qhull implements the Quickhull algorithm for convex hull
|
||||||
|
[Barber et al. <a href="#bar-dob96">'96</a>]. This algorithm
|
||||||
|
combines the 2-d Quickhull algorithm with the <em>n</em>-d
|
||||||
|
beneath-beyond algorithm [c.f., Preparata & Shamos <a
|
||||||
|
href="#pre-sha85">'85</a>]. It is similar to the randomized
|
||||||
|
algorithms of Clarkson and others [Clarkson & Shor <a
|
||||||
|
href="#cla-sho89">'89</a>; Clarkson et al. <a href="#cla-meh93">'93</a>;
|
||||||
|
Mulmuley <a href="#mulm94">'94</a>]. For a demonstration, see <a
|
||||||
|
href="qh-eg.htm#how">How Qhull adds a point</a>. The main
|
||||||
|
advantages of Quickhull are output sensitive performance (in
|
||||||
|
terms of the number of extreme points), reduced space
|
||||||
|
requirements, and floating-point error handling. </p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOC">»</a><a name="structure">data structures</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Qhull produces the following data structures for dimension <i>d</i>:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>A <em>coordinate</em> is a real number in floating point
|
||||||
|
format. </li>
|
||||||
|
<li>A <em>point</em> is an array of <i>d</i> coordinates.
|
||||||
|
With option '<a href="qh-optq.htm#QJn">QJ</a>', the
|
||||||
|
coordinates are joggled by a small amount. </li>
|
||||||
|
<li>A <em>vertex</em> is an input point. </li>
|
||||||
|
<li>A <em>hyperplane</em> is <i>d</i> normal coefficients and
|
||||||
|
an offset. The length of the normal is one. The
|
||||||
|
hyperplane defines a halfspace. If <i>V</i> is a normal, <i>b</i>
|
||||||
|
is an offset, and <i>x</i> is a point inside the convex
|
||||||
|
hull, then <i>Vx+b <0</i>.</li>
|
||||||
|
<li>An <em>outer plane</em> is a positive
|
||||||
|
offset from a hyperplane. When Qhull is done, all points
|
||||||
|
will be below all outer planes.</li>
|
||||||
|
<li>An <em>inner plane</em> is a negative
|
||||||
|
offset from a hyperplane. When Qhull is done, all
|
||||||
|
vertices will be above the corresponding inner planes.</li>
|
||||||
|
<li>An <em>orientation</em> is either 'top' or 'bottom'. It is the
|
||||||
|
topological equivalent of a hyperplane's geometric
|
||||||
|
orientation. </li>
|
||||||
|
<li>A <em>simplicial facet</em> is a set of
|
||||||
|
<i>d</i> neighboring facets, a set of <i>d</i> vertices, a
|
||||||
|
hyperplane equation, an inner plane, an outer plane, and
|
||||||
|
an orientation. For example in 3-d, a simplicial facet is
|
||||||
|
a triangle. </li>
|
||||||
|
<li>A <em>centrum</em> is a point on a facet's hyperplane. A
|
||||||
|
centrum is the average of a facet's vertices. Neighboring
|
||||||
|
facets are <em>convex</em> if each centrum is below the
|
||||||
|
neighbor facet's hyperplane. </li>
|
||||||
|
<li>A <em>ridge</em> is a set of <i>d-1</i> vertices, two
|
||||||
|
neighboring facets, and an orientation. For example in
|
||||||
|
3-d, a ridge is a line segment. </li>
|
||||||
|
<li>A <em>non-simplicial facet</em> is a set of ridges, a
|
||||||
|
hyperplane equation, a centrum, an outer plane, and an
|
||||||
|
inner plane. The ridges determine a set of neighboring
|
||||||
|
facets, a set of vertices, and an orientation. Qhull
|
||||||
|
produces a non-simplicial facet when it merges two facets
|
||||||
|
together. For example, a cube has six non-simplicial
|
||||||
|
facets. </li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>For examples, use option '<a href="qh-opto.htm#f">f</a>'. See <a
|
||||||
|
href="../src/libqhull/qh-poly.htm">polyhedron operations</a> for further
|
||||||
|
design documentation. </p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOC">»</a>Imprecision in Qhull</h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>See <a href="qh-impre.htm">Imprecision in Qhull</a> and <a href="qh-impre.htm#joggle">Merged facets or joggled input</a></p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOC">»</a>Examples of Qhull</h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>See <a href="qh-eg.htm">Examples of Qhull</a>. Most of these examples require <a href="#geomview">Geomview</a>.
|
||||||
|
Some of the examples have <a
|
||||||
|
href="http://www.geom.uiuc.edu/graphics/pix/Special_Topics/Computational_Geometry/welcome.html">pictures
|
||||||
|
</a>.</p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
</blockquote>
|
||||||
|
<h2><a href="#TOC">»</a>Options for using Qhull </h2>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>See <a href="qh-quick.htm#options">Options</a>.</p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h2><a href="#TOC">»</a>Qhull internals </h2>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>See <a href="qh-code.htm">Internals</a>.</p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h2><a href="#TOC">»</a><a name="geomview">Geomview, Qhull's
|
||||||
|
graphical viewer</a></h2>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p><a href="http://www.geomview.org">Geomview</a>
|
||||||
|
is an interactive geometry viewing program.
|
||||||
|
Geomview provides a good visualization of Qhull's 2-d and 3-d results.
|
||||||
|
|
||||||
|
<p>Qhull includes <a href="qh-eg.htm">Examples of Qhull</a> that may be viewed with Geomview.
|
||||||
|
|
||||||
|
<p>Geomview can help visulalize a 3-d Delaunay triangulation or the surface of a 4-d convex hull,
|
||||||
|
Use option '<a href="qh-optq.htm#QVn">QVn</a>' to select the 3-D facets adjacent to a vertex.
|
||||||
|
|
||||||
|
<p>You may use Geomview to create movies that animate your objects (c.f., <a href="http://www.geomview.org/FAQ/answers.shtml#mpeg">How can I create a video animation?</a>).
|
||||||
|
Geomview helped create the <a href="http://www.geom.uiuc.edu/video/">mathematical videos</a> "Not Knot", "Outside In", and "The Shape of Space" from the Geometry Center.
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a href="#TOC">»</a><a name="geomview-install">Installing Geomview</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Geomview is an <a href=http://sourceforge.net/projects/geomview>open source project</a>
|
||||||
|
under SourceForge.
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For build instructions see
|
||||||
|
<a href="http://www.geomview.org/download/">Downloading Geomview</a>.
|
||||||
|
Geomview builds under Linux, Unix, Macintosh OS X, and Windows.
|
||||||
|
|
||||||
|
<p>Geomview has <a href="https://packages.debian.org/search?keywords=geomview">installable packages</a> for Debian and Ubuntu.
|
||||||
|
The OS X build needs Xcode, an X11 SDK, and Lesstif or Motif.
|
||||||
|
The Windows build uses Cygwin (see <a href="#geomview-win">Building Geomview</a> below for instructions).
|
||||||
|
|
||||||
|
<p>If using Xforms (e.g., for Geomview's <a href="http://www.geomview.org/docs/html/Modules.html">External Modules</a>), install the 'libXpm-devel' package from cygwin and move the xforms directory into your geomview directory, e.g.,<br><tt>mv xforms-1.2.4 geomview-1.9.5/xforms</tt>
|
||||||
|
|
||||||
|
<p>Geomview's <a href="http://www.geom.uiuc.edu/software/geomview/docs/NDview/manpagehelp.html">ndview<a/> provides multiple views into 4-d and higher objects.
|
||||||
|
This module is out-of-date (<a href="http://sourceforge.net/p/geomview/mailman/message/2004152/">geomview-users: 4dview</a>).
|
||||||
|
Download NDview-sgi.tar.Z at <a href="ftp://www.geom.uiuc.edu/pub/software/geomview/newpieces/sgi">newpieces</a> and 4dview at <a href="https://stuff.mit.edu/afs/sipb/project/3d/arch/sgi_62/lib/Geomview/modules/">Geomview/modules</a>.
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOC">»</a><a name="geomview-use">Using Geomview</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Use Geomview to view <a href="qh-eg.htm">Examples of Qhull</a>. You can spin the convex hull, fly a camera through its facets,
|
||||||
|
and see how Qhull produces thick facets in response to round-off error.
|
||||||
|
|
||||||
|
<p>Follow these instructions to view 'eg,01.cube' from Examples of Qhull
|
||||||
|
<ol>
|
||||||
|
<li>Launch an XTerm command shell
|
||||||
|
<ul>
|
||||||
|
<li>If needed, start the X terminal server, Use 'xinit' or 'startx' in /usr/X11R6/bin<br><tt>xinit -- -multiwindow -clipboard</tt><br><tt>startx</tt>
|
||||||
|
<li>Start an XTerm command shell. In Windows, click the Cygwin/bash icon on your desktop.
|
||||||
|
<li>Set the DISPLAY variable, e.g.,<br><tt>export DISPLAY=:0</tt><br><tt>export DISPLAY=:0 >>~/.bashenv</tt>
|
||||||
|
</ul>
|
||||||
|
<li>Use Qhull's <a href="qh-optg.htm">Geomview options</a> to create a geomview object
|
||||||
|
<ul>
|
||||||
|
<li><tt>rbox c D3 | qconvex G >eg.01.cube</tt>
|
||||||
|
<li>On windows, convert the output to Unix text format with 'd2u'<br><tt>rbox c D3 | qconvex G | d2u >eg.01.cube</tt><br><tt>d2u eg.*</tt>
|
||||||
|
</ul>
|
||||||
|
<li>Run Geomview
|
||||||
|
<ul>
|
||||||
|
<li>Start Geomview with your example<br><tt>./geomview eg.01.cube</tt>
|
||||||
|
<li>Follow the instructions in <a href="http://www.geomview.org/docs/html/Tutorial.html">Gemoview Tutorial</a>
|
||||||
|
<li>Geomview creates the <i>Geomview control panel</i> with Targets and External Module, the <i>Geomview toolbar</i> with buttons for controlling Geomview, and the <i>Geomview camera window</i> showing a cube.
|
||||||
|
<li>Clear the camera window by selecting your object in the Targets list and 'Edit > Delete' or 'dd'
|
||||||
|
<li>Load the <i>Geomview files panel</i>. Select 'Open' in the 'File' menu.
|
||||||
|
<li>Set 'Filter' in the files panel to your example directory followed by '/*' (e.g., '/usr/local/qhull-2015.2/eg/*')
|
||||||
|
<li>Click 'Filter' in the files panel to view your examples in the 'Files' list.
|
||||||
|
<li>Load another example into the camera window by selecting it and clicking 'OK'.
|
||||||
|
<li>Review the instructions for <a href="http://www.geomview.org/docs/html/Interaction.html">Interacting with Geomview</a>
|
||||||
|
<li>When viewing multiple objects at once, you may want to turn off normalization. In the 'Inspect > Apperance' control panel, set 'Normalize' to 'None'.
|
||||||
|
</ul>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>Geomview defines GCL (a textual API for controlling Geomview) and OOGL (a textual file format for defining objects).
|
||||||
|
<ul>
|
||||||
|
<li>To control Geomview, you may use any program that reads and writes from stdin and stdout. For example, it could report Qhull's information about a vertex identified by a double-click 'pick' event.
|
||||||
|
<li><a href="http://www.geomview.org/docs/html/GCL.html">GCL</a> command language for controlling Geomview
|
||||||
|
<li><a href="http://www.geomview.org/docs/html/OOGL-File-Formats.html">OOGL</a> file format for defining objects (<a href="http://www.geomview.org/docs/oogltour.html">tutorial</a>).
|
||||||
|
<li><a href="http://www.geomview.org/docs/html/Modules.html">External Modules</a> for interacting with Geomview via GCL
|
||||||
|
<li>Interact with your objects via <a href="http://www.geomview.org/docs/html/pick.html">pick</a> commands in response to right-mouse double clicks. Enable pick events with the <a href="http://www.geomview.org/docs/html/interest.html">interest</a> command.
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOC">»</a><a name="geomview-win">Building Geomview for Windows</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Compile Geomview under Cygwin. For detailed instructions, see
|
||||||
|
<a href="http://www.ee.surrey.ac.uk/Personal/L.Wood/software/SaVi/building-under-Windows/"
|
||||||
|
>Building Savi and Geomview under Windows</a>. These instructions are somewhat out-of-date. Updated
|
||||||
|
instructions follow.
|
||||||
|
|
||||||
|
<p>How to compile Geomview under 32-bit Cygwin (October 2015)</p>
|
||||||
|
<ol>
|
||||||
|
<li><b>Note:</b> L. Wood has run into multiple issues with Geomview on Cygwin. He recommends Virtualbox/Ubuntu
|
||||||
|
and a one-click install of geomview via the Ubuntu package. See his Savi/Geomview link above.
|
||||||
|
<li>Install 32-bit <a href="http://cygwin.com/">Cygwin</a> as follows.
|
||||||
|
For additional guidance, see Cygwin's <a href="https://cygwin.com/install.html">Installing and Updating Cygwin Packages</a>
|
||||||
|
and <a href="http://www.qhull.org/road/road-faq/xml/cmdline.xml#setup-cygwin">Setup cygwin</a>.
|
||||||
|
<ul>
|
||||||
|
<li>Launch the cygwin installer.
|
||||||
|
<li>Select a mirror from <a href="http://cygwin.com/mirrors.html">Cygwin mirrors</a> (e.g., http://mirrors.kernel.org/sourceware/cygwin/ in California).
|
||||||
|
<li>Select the packages to install. Besides the cygwin packages listed in the Savi/Windows instructions consider adding
|
||||||
|
<ul>
|
||||||
|
<li><b>Default</b> -- libXm-devel (required for /usr/include/Xm/Xm.h)
|
||||||
|
<li><b>Devel</b> -- bashdb, gcc-core (in place of gcc), gdb
|
||||||
|
<li><b>Lib</b> -- libGL-devel, libGLU1 (required, obsolete), libGLU-devel (required, obsolete), libjpeg-devel(XForms), libXext-devel (required), libXpm-devel (Xforms)
|
||||||
|
libGL and lib
|
||||||
|
<li><b>Math</b> -- bc
|
||||||
|
<li><b>Net</b> -- autossh, inetutils, openssh
|
||||||
|
<li><b>System</b> -- chere
|
||||||
|
<li><b>Utils</b> -- dos2unix (required for qhull), keychain
|
||||||
|
<li>If installing perl, ActiveState Perl may be a better choice than cygwin's perl. Perl is not used by Geomview or Qhull.
|
||||||
|
<li><a href="https://cygwin.com/cgi-bin2/package-grep.cgi">Cygwin Package Search</a> -- Search for cygwin programs and packages
|
||||||
|
</ul>
|
||||||
|
<li>Click 'Next' to download and install the packages.
|
||||||
|
<li>If the download is incomplete, try again.
|
||||||
|
<li>If you try again after a successful install, cygwin will uninstall and reinstall all modules..
|
||||||
|
<li>Click on the 'Cywin Terminal' icon on the Desktop. It sets up a user directory in /home from /etc/skel/...
|
||||||
|
<li>Mount your disk drives<br>mount c: /c # Ignore the warning /c does not exist
|
||||||
|
</ul>
|
||||||
|
<li>Consider installing the <a href="http://www.qhull.org/bash/doc/road-bash.html">Road Bash</a> scripts (/etc/road-*) from <a href="http://www.qhull.org/road/">Road</a>.
|
||||||
|
They define aliases and functions for Unix command shells (Unix, Linux, Mac OS X, Windows),
|
||||||
|
<ul>
|
||||||
|
<li>Download Road Bash and unzip the downloaded file
|
||||||
|
<li>Copy .../bash/etc/road-* to the Cywin /etc directory (by default, C:\cygwin\etc).
|
||||||
|
<li>Using the cygwin terminal, convert the road scripts to Unix format<br>d2u /etc/road-*
|
||||||
|
<li>Try it<br>source /etc/road-home.bashrc
|
||||||
|
<li>Install it<br>cp /etc/road-home.bashrc ~/.bashrc
|
||||||
|
</ul>
|
||||||
|
<li>Launch the X terminal server from '<tt>Start > All programs > Cygwin-X > Xwin Server</tt>'. Alternatively, run 'startx'
|
||||||
|
<li>Launch an XTerm shell
|
||||||
|
<ul>
|
||||||
|
<li>Right click the Cywin icon on the system tray in the Windows taskbar.
|
||||||
|
<li>Select '<tt>System Tools > XTerm</tt>'
|
||||||
|
</ul>
|
||||||
|
<li>Download and extract Geomview -- <a href="http://www.geomview.org/download/">Downloading Geomview</a>
|
||||||
|
<li>Compile Geomview
|
||||||
|
<ul>
|
||||||
|
<li>./configure
|
||||||
|
<li>make
|
||||||
|
</ul>
|
||||||
|
<li>If './configure' fails, check 'config.log' at the failing step. Look carefully for missing libraries, etc. The <a href="http://www.geomview.org/FAQ/answers.shtml">Geomview FAQ</a> contains suggestions (e.g., "configure claims it can't find OpenGl").
|
||||||
|
<li>If 'make' fails, read the output carefully for error messages. Usually it is a missing include file or package. Locate and install the missing cygwin packages
|
||||||
|
(<a href="https://cygwin.com/cgi-bin2/package-grep.cgi">Cygwin Package Search</a>).
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
</blockquote>
|
||||||
|
<h2><a href="#TOC">»</a><a name="bugs">What to do if something
|
||||||
|
goes wrong</a></h2>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Please report bugs to <a href=mailto:qhull_bug@qhull.org>qhull_bug@qhull.org</a>
|
||||||
|
</a>. Please report if Qhull crashes. Please report if Qhull
|
||||||
|
generates an "internal error". Please report if Qhull
|
||||||
|
produces a poor approximate hull in 2-d, 3-d or 4-d. Please
|
||||||
|
report documentation errors. Please report missing or incorrect
|
||||||
|
links.</p>
|
||||||
|
|
||||||
|
<p>If you do not understand something, try a small example. The <a
|
||||||
|
href="rbox.htm">rbox</a> program is an easy way to generate
|
||||||
|
test cases. The <a href="#geomview">Geomview</a> program helps to
|
||||||
|
visualize the output from Qhull.</p>
|
||||||
|
|
||||||
|
<p>If Qhull does not compile, it is due to an incompatibility
|
||||||
|
between your system and ours. The first thing to check is that
|
||||||
|
your compiler is ANSI standard. Qhull produces a compiler error
|
||||||
|
if __STDC__ is not defined. You may need to set a flag (e.g.,
|
||||||
|
'-A' or '-ansi').</p>
|
||||||
|
|
||||||
|
<p>If Qhull compiles but crashes on the test case (rbox D4),
|
||||||
|
there's still incompatibility between your system and ours.
|
||||||
|
Sometimes it is due to memory management. This can be turned off
|
||||||
|
with qh_NOmem in mem.h. Please let us know if you figure out how
|
||||||
|
to fix these problems. </p>
|
||||||
|
|
||||||
|
<p>If you doubt the output from Qhull, add option '<a
|
||||||
|
href="qh-optt.htm#Tv">Tv</a>'. It checks that every point is
|
||||||
|
inside the outer planes of the convex hull. It checks that every
|
||||||
|
facet is convex with its neighbors. It checks the topology of the
|
||||||
|
convex hull.</p>
|
||||||
|
|
||||||
|
<p>Qhull should work on all inputs. It may report precision
|
||||||
|
errors if you turn off merged facets with option '<a
|
||||||
|
href="qh-optq.htm#Q0">Q0</a>'. This can get as bad as facets with
|
||||||
|
flipped orientation or two facets with the same vertices. You'll
|
||||||
|
get a long help message if you run into such a case. They are
|
||||||
|
easy to generate with <tt>rbox</tt>.</p>
|
||||||
|
|
||||||
|
<p>If you do find a problem, try to simplify it before reporting
|
||||||
|
the error. Try different size inputs to locate the smallest one
|
||||||
|
that causes an error. You're welcome to hunt through the code
|
||||||
|
using the execution trace ('<a href="qh-optt.htm#Tn">T4</a>') as
|
||||||
|
a guide. This is especially true if you're incorporating Qhull
|
||||||
|
into your own program. </p>
|
||||||
|
|
||||||
|
<p>When you report an error, please attach a data set to the end
|
||||||
|
of your message. Include the options that you used with Qhull,
|
||||||
|
the results of option '<a href="qh-optf.htm#FO">FO</a>', and any
|
||||||
|
messages generated by Qhull. This allows me to see the error for
|
||||||
|
myself. Qhull is maintained part-time. </p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h2><a href="#TOC">»</a><a name="email">Email</a></h2>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Please send correspondence to Brad Barber at <a href=mailto:qhull@qhull.org>qhull@qhull.org</a>
|
||||||
|
and report bugs to <a href=mailto:qhull_bug@qhull.org>qhull_bug@qhull.org</a>
|
||||||
|
</a>. Let me know how you use Qhull. If you mention it in a
|
||||||
|
paper, please send a reference and abstract.</p>
|
||||||
|
|
||||||
|
<p>If you would like to get Qhull announcements (e.g., a new
|
||||||
|
version) and news (any bugs that get fixed, etc.), let us know
|
||||||
|
and we will add you to our mailing list. For Internet news about geometric algorithms
|
||||||
|
and convex hulls, look at comp.graphics.algorithms and
|
||||||
|
sci.math.num-analysis. For Qhull news look at <a
|
||||||
|
href="http://www.qhull.org/news">qhull-news.html</a>.</p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h2><a href="#TOC">»</a><a name="authors">Authors</a></h2>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
C. Bradford Barber Hannu Huhdanpaa
|
||||||
|
bradb@shore.net hannu@qhull.org
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h2><a href="#TOC">»</a><a name="acknowledge">Acknowledgments</a></h2>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>A special thanks to David Dobkin for his guidance. A special
|
||||||
|
thanks to Albert Marden, Victor Milenkovic, the Geometry Center,
|
||||||
|
and Harvard University for supporting this work.</p>
|
||||||
|
|
||||||
|
<p>A special thanks to Mark Phillips, Robert Miner, and Stuart Levy for running the Geometry
|
||||||
|
Center web site long after the Geometry Center closed.
|
||||||
|
Stuart moved the web site to the University of Illinois at Champaign-Urbana.
|
||||||
|
Mark and Robert are founders of <a href=http://www.geomtech.com>Geometry Technologies</a>.
|
||||||
|
Mark, Stuart, and Tamara Munzner are the original authors of <a href=http://www.geomview.org>Geomview</a>.
|
||||||
|
|
||||||
|
<p>A special thanks to <a href="http://www.endocardial.com/">Endocardial
|
||||||
|
Solutions, Inc.</a> of St. Paul, Minnesota for their support of the
|
||||||
|
internal documentation (<a href=../src/libqhull/index.htm>src/libqhull/index.htm</a>). They use Qhull to build 3-d models of
|
||||||
|
heart chambers.</p>
|
||||||
|
|
||||||
|
<p>Qhull 1.0 and 2.0 were developed under National Science Foundation
|
||||||
|
grants NSF/DMS-8920161 and NSF-CCR-91-15793 750-7504. If you find
|
||||||
|
it useful, please let us know.</p>
|
||||||
|
|
||||||
|
<p>The Geometry Center was supported by grant DMS-8920161 from the
|
||||||
|
National Science Foundation, by grant DOE/DE-FG02-92ER25137 from
|
||||||
|
the Department of Energy, by the University of Minnesota, and by
|
||||||
|
Minnesota Technology, Inc.</p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h2><a href="#TOC">»</a><a name="ref">References</a></h2>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p><a name="aure91">Aurenhammer</a>, F., "Voronoi diagrams
|
||||||
|
-- A survey of a fundamental geometric data structure," <i>ACM
|
||||||
|
Computing Surveys</i>, 1991, 23:345-405. </p>
|
||||||
|
|
||||||
|
<p><a name="bar-dob96">Barber</a>, C. B., D.P. Dobkin, and H.T.
|
||||||
|
Huhdanpaa, "The Quickhull Algorithm for Convex Hulls," <i>ACM
|
||||||
|
Transactions on Mathematical Software</i>, 22(4):469-483, Dec 1996, www.qhull.org
|
||||||
|
[<a
|
||||||
|
href="http://portal.acm.org/citation.cfm?doid=235815.235821">http://portal.acm.org</a>;
|
||||||
|
<a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.117.405">http://citeseerx.ist.psu.edu</a>].
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><a name="cla-sho89">Clarkson</a>, K.L. and P.W. Shor,
|
||||||
|
"Applications of random sampling in computational geometry,
|
||||||
|
II", <i>Discrete Computational Geometry</i>, 4:387-421, 1989</p>
|
||||||
|
|
||||||
|
<p><a name="cla-meh93">Clarkson</a>, K.L., K. Mehlhorn, and R.
|
||||||
|
Seidel, "Four results on randomized incremental
|
||||||
|
construction," <em>Computational Geometry: Theory and
|
||||||
|
Applications</em>, vol. 3, p. 185-211, 1993.</p>
|
||||||
|
|
||||||
|
<p><a name="devi01">Devillers</a>, et. al.,
|
||||||
|
"Walking in a triangulation," <i>ACM Symposium on
|
||||||
|
Computational Geometry</i>, June 3-5,2001, Medford MA.
|
||||||
|
|
||||||
|
<p><a name="dob-kir90">Dobkin</a>, D.P. and D.G. Kirkpatrick,
|
||||||
|
"Determining the separation of preprocessed polyhedra--a
|
||||||
|
unified approach," in <i>Proc. 17th Inter. Colloq. Automata
|
||||||
|
Lang. Program.</i>, in <i>Lecture Notes in Computer Science</i>,
|
||||||
|
Springer-Verlag, 443:400-413, 1990. </p>
|
||||||
|
|
||||||
|
<p><a name="edel01">Edelsbrunner</a>, H, <i>Geometry and Topology for Mesh Generation</i>,
|
||||||
|
Cambridge University Press, 2001.
|
||||||
|
|
||||||
|
<p><a name=gart99>Gartner, B.</a>, "Fast and robust smallest enclosing balls", <i>Algorithms - ESA '99</i>, LNCS 1643.
|
||||||
|
|
||||||
|
<p><a name=golub83>Golub, G.H. and van Loan, C.F.</a>, <i>Matric Computations</i>, Baltimore, Maryland, USA: John Hopkins Press, 1983
|
||||||
|
|
||||||
|
<p><a name="fort93">Fortune, S.</a>, "Computational
|
||||||
|
geometry," in R. Martin, editor, <i>Directions in Geometric
|
||||||
|
Computation</i>, Information Geometers, 47 Stockers Avenue,
|
||||||
|
Winchester, SO22 5LB, UK, ISBN 1-874728-02-X, 1993.</p>
|
||||||
|
|
||||||
|
<p><a name="mile93">Milenkovic, V.</a>, "Robust polygon
|
||||||
|
modeling," Computer-Aided Design, vol. 25, p. 546-566,
|
||||||
|
September 1993. </p>
|
||||||
|
|
||||||
|
<p><a name="muck96">Mucke</a>, E.P., I. Saias, B. Zhu, <i>Fast
|
||||||
|
randomized point location without preprocessing in Two- and
|
||||||
|
Three-dimensional Delaunay Triangulations</i>, ACM Symposium on
|
||||||
|
Computational Geometry, p. 274-283, 1996 [<a
|
||||||
|
href="http://www.geom.uiuc.edu/software/cglist/GeomDir/">GeomDir</a>].
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p><a name="mulm94">Mulmuley</a>, K., <i>Computational Geometry,
|
||||||
|
An Introduction Through Randomized Algorithms</i>, Prentice-Hall,
|
||||||
|
NJ, 1994.</p>
|
||||||
|
|
||||||
|
<p><a name="orou94">O'Rourke</a>, J., <i>Computational Geometry
|
||||||
|
in C</i>, Cambridge University Press, 1994.</p>
|
||||||
|
|
||||||
|
<p><a name="pre-sha85">Preparata</a>, F. and M. Shamos, <i>Computational
|
||||||
|
Geometry</i>, Springer-Verlag, New York, 1985.</p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<!-- Navigation links -->
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p><b>Up:</b> <a
|
||||||
|
href="http://www.qhull.org">Home page</a> for Qhull<br>
|
||||||
|
<b>Up:</b><a
|
||||||
|
href="http://www.qhull.org/news">News</a> about Qhull<br>
|
||||||
|
<b>Up:</b> <a href="http://www.qhull.org/html/qh-faq.htm">FAQ</a> about Qhull<br>
|
||||||
|
<b>To:</b> <a href="#TOC">Qhull manual</a>: Table of Contents<br>
|
||||||
|
<b>To:</b> <a href="qh-quick.htm#programs">Programs</a>
|
||||||
|
• <a href="qh-quick.htm#options">Options</a>
|
||||||
|
• <a href="qh-opto.htm#output">Output</a>
|
||||||
|
• <a href="qh-optf.htm#format">Formats</a>
|
||||||
|
• <a href="qh-optg.htm#geomview">Geomview</a>
|
||||||
|
• <a href="qh-optp.htm#print">Print</a>
|
||||||
|
• <a href="qh-optq.htm#qhull">Qhull</a>
|
||||||
|
• <a href="qh-optc.htm#prec">Precision</a>
|
||||||
|
• <a href="qh-optt.htm#trace">Trace</a>
|
||||||
|
• <a href="../src/libqhull_r/index.htm">Functions</a><br>
|
||||||
|
<b>Dn:</b> <a href="qh-impre.htm">Imprecision in Qhull</a><br>
|
||||||
|
<b>Dn:</b> <a href="qh-eg.htm">Description of Qhull examples</a><br>
|
||||||
|
<b>Dn:</b> <a href="qh-code.htm">Qhull internals</a><br>
|
||||||
|
<b>Dn:</b> <a href="../src/libqhull/index.htm">Qhull functions, macros, and data
|
||||||
|
structures</a>
|
||||||
|
<!-- GC common information -->
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p><a href="http://www.geom.uiuc.edu/"><img src="qh--geom.gif"
|
||||||
|
align="middle" width="40" height="40"></a><i>The Geometry Center
|
||||||
|
Home Page </i></p>
|
||||||
|
|
||||||
|
<p>Comments to: <a href=mailto:qhull@qhull.org>qhull@qhull.org</a>
|
||||||
|
</a><br>
|
||||||
|
Created: Sept. 25, 1995 --- <!-- hhmts start --> Last modified: see top <!-- hhmts end --> </p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
xs/src/qhull/html/normal_voronoi_knauss_oesterle.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
630
xs/src/qhull/html/qconvex.htm
Normal file
|
|
@ -0,0 +1,630 @@
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>qconvex -- convex hull</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Navigation links -->
|
||||||
|
<a name="TOP"><b>Up</b></a><b>:</b>
|
||||||
|
<a href="http://www.qhull.org">Home page</a> for Qhull<br>
|
||||||
|
<b>Up:</b> <a href="index.htm#TOC">Qhull manual</a> -- Table of Contents<br>
|
||||||
|
<b>To:</b> <a href="qh-quick.htm#programs">Programs</a>
|
||||||
|
• <a href="qh-quick.htm#options">Options</a>
|
||||||
|
• <a href="qh-opto.htm#output">Output</a>
|
||||||
|
• <a href="qh-optf.htm#format">Formats</a>
|
||||||
|
• <a href="qh-optg.htm#geomview">Geomview</a>
|
||||||
|
• <a href="qh-optp.htm#print">Print</a>
|
||||||
|
• <a href="qh-optq.htm#qhull">Qhull</a>
|
||||||
|
• <a href="qh-optc.htm#prec">Precision</a>
|
||||||
|
• <a href="qh-optt.htm#trace">Trace</a>
|
||||||
|
• <a href="../src/libqhull_r/index.htm">Functions</a><br>
|
||||||
|
<b>To:</b> <a href="#synopsis">sy</a>nopsis
|
||||||
|
• <a href="#input">in</a>put • <a href="#outputs">ou</a>tputs
|
||||||
|
• <a href="#controls">co</a>ntrols • <a href="#graphics">gr</a>aphics
|
||||||
|
• <a href="#notes">no</a>tes • <a href="#conventions">co</a>nventions
|
||||||
|
• <a href="#options">op</a>tions
|
||||||
|
<hr>
|
||||||
|
<!-- Main text of document -->
|
||||||
|
<h1><a
|
||||||
|
href="http://www.geom.uiuc.edu/graphics/pix/Special_Topics/Computational_Geometry/cone.html"><img
|
||||||
|
src="qh--cone.gif" alt="[cone]" align="middle" width="100"
|
||||||
|
height="100"></a>qconvex -- convex hull</h1>
|
||||||
|
|
||||||
|
<p>The convex hull of a set of points is the smallest convex set
|
||||||
|
containing the points. See the detailed introduction by O'Rourke
|
||||||
|
[<a href="index.htm#orou94">'94</a>]. See <a
|
||||||
|
href="index.htm#description">Description of Qhull</a> and <a
|
||||||
|
href="qh-eg.htm#how">How Qhull adds a point</a>.</p>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<dl>
|
||||||
|
<dt><b>Example:</b> rbox 10 D3 | qconvex <a
|
||||||
|
href="qh-opto.htm#s">s</a> <a href="qh-opto.htm#o">o</a> <a
|
||||||
|
href="qh-optt.htm#TO">TO result</a></dt>
|
||||||
|
<dd>Compute the 3-d convex hull of 10 random points. Write a
|
||||||
|
summary to the console and the points and facets to
|
||||||
|
'result'.</dd>
|
||||||
|
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox c | qconvex <a
|
||||||
|
href="qh-opto.htm#n">n</a></dt>
|
||||||
|
<dd>Print the normals for each facet of a cube.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox c | qconvex <a
|
||||||
|
href="qh-opto.htm#i">i</a> <a href="qh-optq.htm#Qt">Qt</a></dt>
|
||||||
|
<dd>Print the triangulated facets of a cube.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox y 500 W0 | qconvex</dt>
|
||||||
|
<dd>Compute the convex hull of a simplex with 500
|
||||||
|
points on its surface.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox x W1e-12 1000 | qconvex
|
||||||
|
<a href="qh-optq.htm#QR">QR0</a></dt>
|
||||||
|
<dd>Compute the convex hull of 1000 points near the
|
||||||
|
surface of a randomly rotated simplex. Report
|
||||||
|
the maximum thickness of a facet.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox 1000 s | qconvex <a
|
||||||
|
href="qh-opto.htm#s">s</a> <a
|
||||||
|
href="qh-optf.htm#FA">FA</a> </dt>
|
||||||
|
<dd>Compute the convex hull of 1000 cospherical
|
||||||
|
points. Verify the results and print a summary
|
||||||
|
with the total area and volume.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox d D12 | qconvex <a
|
||||||
|
href="qh-optq.htm#QRn">QR0</a> <a
|
||||||
|
href="qh-optf.htm#FA">FA</a></dt>
|
||||||
|
<dd>Compute the convex hull of a 12-d diamond.
|
||||||
|
Randomly rotate the input. Note the large number
|
||||||
|
of facets and the small volume.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox c D7 | qconvex <a
|
||||||
|
href="qh-optf.htm#FA">FA</a> <a
|
||||||
|
href="qh-optt.htm#TFn">TF1000</a></dt>
|
||||||
|
<dd>Compute the convex hull of the 7-d hypercube.
|
||||||
|
Report on progress every 1000 facets. Computing
|
||||||
|
the convex hull of the 9-d hypercube takes too
|
||||||
|
much time and space. </dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox c d D2 | qconvex <a
|
||||||
|
href="qh-optq.htm#Qc">Qc</a> <a
|
||||||
|
href="qh-opto.htm#s">s</a> <a
|
||||||
|
href="qh-opto.htm#f">f</a> <a
|
||||||
|
href="qh-optf.htm#Fx">Fx</a> | more</dt>
|
||||||
|
<dd>Dump all fields of all facets for a square and a
|
||||||
|
diamond. Also print a summary and a list of
|
||||||
|
vertices. Note the coplanar points.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
</dl>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>Except for rbox, all of the qhull programs compute a convex hull.
|
||||||
|
|
||||||
|
<p>By default, Qhull merges coplanar facets. For example, the convex
|
||||||
|
hull of a cube's vertices has six facets.
|
||||||
|
|
||||||
|
<p>If you use '<a href="qh-optq.htm#Qt">Qt</a>' (triangulated output),
|
||||||
|
all facets will be simplicial (e.g., triangles in 2-d). For the cube
|
||||||
|
example, it will have 12 facets. Some facets may be
|
||||||
|
degenerate and have zero area.
|
||||||
|
|
||||||
|
<p>If you use '<a href="qh-optq.htm#QJn">QJ</a>' (joggled input),
|
||||||
|
all facets will be simplicial. The corresponding vertices will be
|
||||||
|
slightly perturbed and identical points will be joggled apart.
|
||||||
|
Joggled input is less accurate that triangulated
|
||||||
|
output.See <a
|
||||||
|
href="qh-impre.htm#joggle">Merged facets or joggled input</a>. </p>
|
||||||
|
|
||||||
|
<p>The output for 4-d convex hulls may be confusing if the convex
|
||||||
|
hull contains non-simplicial facets (e.g., a hypercube). See
|
||||||
|
<a href=qh-faq.htm#extra>Why
|
||||||
|
are there extra points in a 4-d or higher convex hull?</a><br>
|
||||||
|
</p>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>The 'qconvex' program is equivalent to
|
||||||
|
'<a href=qhull.htm#outputs>qhull</a>' in 2-d to 4-d, and
|
||||||
|
'<a href=qhull.htm#outputs>qhull</a> <a href=qh-optq.htm#Qx>Qx</a>'
|
||||||
|
in 5-d and higher. It disables the following Qhull
|
||||||
|
<a href=qh-quick.htm#options>options</a>: <i>d v H Qbb Qf Qg Qm
|
||||||
|
Qr Qu Qv Qx Qz TR E V Fp Gt Q0,etc</i>.
|
||||||
|
|
||||||
|
<p><b>Copyright © 1995-2015 C.B. Barber</b></p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a href="#TOP">»</a><a name="synopsis">qconvex synopsis</a></h3>
|
||||||
|
<pre>
|
||||||
|
qconvex- compute the convex hull.
|
||||||
|
input (stdin): dimension, number of points, point coordinates
|
||||||
|
comments start with a non-numeric character
|
||||||
|
|
||||||
|
options (qconvex.htm):
|
||||||
|
Qt - triangulated output
|
||||||
|
QJ - joggle input instead of merging facets
|
||||||
|
Tv - verify result: structure, convexity, and point inclusion
|
||||||
|
. - concise list of all options
|
||||||
|
- - one-line description of all options
|
||||||
|
|
||||||
|
output options (subset):
|
||||||
|
s - summary of results (default)
|
||||||
|
i - vertices incident to each facet
|
||||||
|
n - normals with offsets
|
||||||
|
p - vertex coordinates (includes coplanar points if 'Qc')
|
||||||
|
Fx - extreme points (convex hull vertices)
|
||||||
|
FA - compute total area and volume
|
||||||
|
o - OFF format (dim, n, points, facets)
|
||||||
|
G - Geomview output (2-d, 3-d, and 4-d)
|
||||||
|
m - Mathematica output (2-d and 3-d)
|
||||||
|
QVn - print facets that include point n, -n if not
|
||||||
|
TO file- output results to file, may be enclosed in single quotes
|
||||||
|
|
||||||
|
examples:
|
||||||
|
rbox c D2 | qconvex s n rbox c D2 | qconvex i
|
||||||
|
rbox c D2 | qconvex o rbox 1000 s | qconvex s Tv FA
|
||||||
|
rbox c d D2 | qconvex s Qc Fx rbox y 1000 W0 | qconvex s n
|
||||||
|
rbox y 1000 W0 | qconvex s QJ rbox d G1 D12 | qconvex QR0 FA Pp
|
||||||
|
rbox c D7 | qconvex FA TF1000
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<h3><a href="#TOP">»</a><a name="input">qconvex
|
||||||
|
input</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>The input data on <tt>stdin</tt> consists of:</p>
|
||||||
|
<ul>
|
||||||
|
<li>dimension
|
||||||
|
<li>number of points</li>
|
||||||
|
<li>point coordinates</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Use I/O redirection (e.g., qconvex < data.txt), a pipe (e.g., rbox 10 | qconvex),
|
||||||
|
or the '<a href=qh-optt.htm#TI>TI</a>' option (e.g., qconvex TI data.txt).
|
||||||
|
|
||||||
|
<p>Comments start with a non-numeric character. Error reporting is
|
||||||
|
simpler if there is one point per line. Dimension
|
||||||
|
and number of points may be reversed.
|
||||||
|
|
||||||
|
<p>Here is the input for computing the convex
|
||||||
|
hull of the unit cube. The output is the normals, one
|
||||||
|
per facet.</p>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<p>rbox c > data </p>
|
||||||
|
<pre>
|
||||||
|
3 RBOX c
|
||||||
|
8
|
||||||
|
-0.5 -0.5 -0.5
|
||||||
|
-0.5 -0.5 0.5
|
||||||
|
-0.5 0.5 -0.5
|
||||||
|
-0.5 0.5 0.5
|
||||||
|
0.5 -0.5 -0.5
|
||||||
|
0.5 -0.5 0.5
|
||||||
|
0.5 0.5 -0.5
|
||||||
|
0.5 0.5 0.5
|
||||||
|
</pre>
|
||||||
|
<p>qconvex s n < data</p>
|
||||||
|
<pre>
|
||||||
|
|
||||||
|
Convex hull of 8 points in 3-d:
|
||||||
|
|
||||||
|
Number of vertices: 8
|
||||||
|
Number of facets: 6
|
||||||
|
Number of non-simplicial facets: 6
|
||||||
|
|
||||||
|
Statistics for: RBOX c | QCONVEX s n
|
||||||
|
|
||||||
|
Number of points processed: 8
|
||||||
|
Number of hyperplanes created: 11
|
||||||
|
Number of distance tests for qhull: 35
|
||||||
|
Number of merged facets: 6
|
||||||
|
Number of distance tests for merging: 84
|
||||||
|
CPU seconds to compute hull (after input): 0.081
|
||||||
|
|
||||||
|
4
|
||||||
|
6
|
||||||
|
0 0 -1 -0.5
|
||||||
|
0 -1 0 -0.5
|
||||||
|
1 0 0 -0.5
|
||||||
|
-1 0 0 -0.5
|
||||||
|
0 1 0 -0.5
|
||||||
|
0 0 1 -0.5
|
||||||
|
</pre>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="outputs">qconvex outputs</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>These options control the output of qconvex. They may be used
|
||||||
|
individually or together.</p>
|
||||||
|
<blockquote>
|
||||||
|
<dl compact>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>Vertices</b></dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fx">Fx</a></dt>
|
||||||
|
<dd>list extreme points (i.e., vertices). The first line is the number of
|
||||||
|
extreme points. Each point is listed, one per line. The cube example
|
||||||
|
has eight vertices.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fv">Fv</a></dt>
|
||||||
|
<dd>list vertices for each facet. The first line is the number of facets.
|
||||||
|
Each remaining line starts with the number of vertices. For the cube example,
|
||||||
|
each facet has four vertices.</dd>
|
||||||
|
<dt><a href="qh-opto.htm#i">i</a></dt>
|
||||||
|
<dd>list vertices for each facet. The first line is the number of facets. The
|
||||||
|
remaining lines list the vertices for each facet. In 4-d and
|
||||||
|
higher, triangulate non-simplicial facets by adding an extra point.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>Coordinates</b></dd>
|
||||||
|
<dt><a href="qh-opto.htm#o">o</a></dt>
|
||||||
|
<dd>print vertices and facets of the convex hull in OFF format. The
|
||||||
|
first line is the dimension. The second line is the number of
|
||||||
|
vertices, facets, and ridges. The vertex
|
||||||
|
coordinates are next, followed by the facets. Each facet starts with
|
||||||
|
the number of vertices. The cube example has four vertices per facet.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Ft">Ft</a></dt>
|
||||||
|
<dd>print a triangulation of the convex hull in OFF format. The first line
|
||||||
|
is the dimension. The second line is the number of vertices and added points,
|
||||||
|
followed by the number of facets and the number of ridges.
|
||||||
|
The vertex coordinates are next, followed by the centrum coordinates. There is
|
||||||
|
one centrum for each non-simplicial facet.
|
||||||
|
The cube example has six centrums, one per square.
|
||||||
|
Each facet starts with the number of vertices or centrums.
|
||||||
|
In the cube example, each facet uses two vertices and one centrum.</dd>
|
||||||
|
<dt><a href="qh-opto.htm#p">p</a></dt>
|
||||||
|
<dd>print vertex coordinates. The first line is the dimension and the second
|
||||||
|
line is the number of vertices. The following lines are the coordinates of each
|
||||||
|
vertex. The cube example has eight vertices.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#Qc">Qc</a> <a href="qh-opto.htm#p">p</a></dt>
|
||||||
|
<dd>print coordinates of vertices and coplanar points. The first line is the dimension.
|
||||||
|
The second line is the number of vertices and coplanar points. The coordinates
|
||||||
|
are next, one line per point. Use '<a href="qh-optq.htm#Qc">Qc</a> <a href="qh-optq.htm#Qi">Qi</a> p'
|
||||||
|
to print the coordinates of all points.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>Facets</b></dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fn">Fn</a></dt>
|
||||||
|
<dd>list neighboring facets for each facet. The first line is the
|
||||||
|
number of facets. Each remaining line starts with the number of
|
||||||
|
neighboring facets. The cube example has four neighbors per facet.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#FN">FN</a></dt>
|
||||||
|
<dd>list neighboring facets for each point. The first line is the
|
||||||
|
total number of points. Each remaining line starts with the number of
|
||||||
|
neighboring facets. Each vertex of the cube example has three neighboring
|
||||||
|
facets. Use '<a href="qh-optq.htm#Qc">Qc</a> <a href="qh-optq.htm#Qi">Qi</a> FN'
|
||||||
|
to include coplanar and interior points. </dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fa">Fa</a></dt>
|
||||||
|
<dd>print area for each facet. The first line is the number of facets.
|
||||||
|
Facet area follows, one line per facet. For the cube example, each facet has area one.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#FI">FI</a></dt>
|
||||||
|
<dd>list facet IDs. The first line is the number of
|
||||||
|
facets. The IDs follow, one per line.</dd>
|
||||||
|
|
||||||
|
<dt> </dt>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>Coplanar and interior points</b></dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fc">Fc</a></dt>
|
||||||
|
<dd>list coplanar points for each facet. The first line is the number
|
||||||
|
of facets. The remaining lines start with the number of coplanar points.
|
||||||
|
A coplanar point is assigned to one facet.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#Qi">Qi</a> <a href="qh-optf.htm#Fc">Fc</a></dt>
|
||||||
|
<dd>list interior points for each facet. The first line is the number
|
||||||
|
of facets. The remaining lines start with the number of interior points.
|
||||||
|
A coplanar point is assigned to one facet.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#FP">FP</a></dt>
|
||||||
|
<dd>print distance to nearest vertex for coplanar points. The first line is the
|
||||||
|
number of coplanar points. Each remaining line starts with the point ID of
|
||||||
|
a vertex, followed by the point ID of a coplanar point, its facet, and distance.
|
||||||
|
Use '<a href="qh-optq.htm#Qc">Qc</a> <a href="qh-optq.htm#Qi">Qi</a>
|
||||||
|
<a href="qh-optf.htm#FP">FP</a>' for coplanar and interior points.</dd>
|
||||||
|
|
||||||
|
<dt> </dt>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>Hyperplanes</b></dd>
|
||||||
|
<dt><a href="qh-opto.htm#n">n</a></dt>
|
||||||
|
<dd>print hyperplane for each facet. The first line is the dimension. The
|
||||||
|
second line is the number of facets. Each remaining line is the hyperplane's
|
||||||
|
coefficients followed by its offset.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fo">Fo</a></dt>
|
||||||
|
<dd>print outer plane for each facet. The output plane is above all points.
|
||||||
|
The first line is the dimension. The
|
||||||
|
second line is the number of facets. Each remaining line is the outer plane's
|
||||||
|
coefficients followed by its offset.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fi">Fi</a></dt>
|
||||||
|
<dd>print inner plane for each facet. The inner plane of a facet is
|
||||||
|
below its vertices.
|
||||||
|
The first line is the dimension. The
|
||||||
|
second line is the number of facets. Each remaining line is the inner plane's
|
||||||
|
coefficients followed by its offset.</dd>
|
||||||
|
|
||||||
|
<dt> </dt>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>General</b></dd>
|
||||||
|
<dt><a href="qh-opto.htm#s">s</a></dt>
|
||||||
|
<dd>print summary for the convex hull. Use '<a
|
||||||
|
href="qh-optf.htm#Fs">Fs</a>' and '<a
|
||||||
|
href="qh-optf.htm#FS">FS</a>' if you need numeric data.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#FA">FA</a></dt>
|
||||||
|
<dd>compute total area and volume for '<a
|
||||||
|
href="qh-opto.htm#s">s</a>' and '<a href="qh-optf.htm#FS">FS</a>'</dd>
|
||||||
|
<dt><a href="qh-opto.htm#m">m</a></dt>
|
||||||
|
<dd>Mathematica output for the convex hull in 2-d or 3-d.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#FM">FM</a></dt>
|
||||||
|
<dd>Maple output for the convex hull in 2-d or 3-d.</dd>
|
||||||
|
<dt><a href="qh-optg.htm#G">G</a></dt>
|
||||||
|
<dd>Geomview output for the convex hull in 2-d, 3-d, or 4-d.</dd>
|
||||||
|
|
||||||
|
<dt> </dt>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>Scaling and rotation</b></dd>
|
||||||
|
<dt><a href="qh-optq.htm#Qbk">Qbk:n</a></dt>
|
||||||
|
<dd>scale k'th coordinate to lower bound.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#QBk">QBk:n</a></dt>
|
||||||
|
<dd>scale k'th coordinate to upper bound.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#QbB">QbB</a></dt>
|
||||||
|
<dd>scale input to unit cube centered at the origin.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#QRn">QRn</a></dt>
|
||||||
|
<dd>randomly rotate the input with a random seed of n. If n=0, the
|
||||||
|
seed is the time. If n=-1, use time for the random seed, but do
|
||||||
|
not rotate the input.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#Qb0">Qbk:0Bk:0</a></dt>
|
||||||
|
<dd>remove k'th coordinate from input. This computes the
|
||||||
|
convex hull in one lower dimension.</dd>
|
||||||
|
</dl>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="controls">qconvex controls</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>These options provide additional control:</p>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<dl compact>
|
||||||
|
<dt><a href="qh-optq.htm#Qt">Qt</a></dt>
|
||||||
|
<dd>triangulated output. Qhull triangulates non-simplicial facets. It may produce
|
||||||
|
degenerate facets of zero area.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#QJn">QJ</a></dt>
|
||||||
|
<dd>joggle the input instead of merging facets. This guarantees simplicial facets
|
||||||
|
(e.g., triangles in 3-d). It is less accurate than triangulated output ('Qt').</dd>
|
||||||
|
<dt><a href="qh-optq.htm#Qc">Qc</a></dt>
|
||||||
|
<dd>keep coplanar points</dd>
|
||||||
|
<dt><a href="qh-optq.htm#Qi">Qi</a></dt>
|
||||||
|
<dd>keep interior points</dd>
|
||||||
|
<dt><a href="qh-opto.htm#f">f </a></dt>
|
||||||
|
<dd>facet dump. Print the data structure for each facet.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#QVn">QVn</a></dt>
|
||||||
|
<dd>select facets containing point <em>n</em> as a vertex,</dd>
|
||||||
|
<dt><a href="qh-optq.htm#QGn">QGn</a></dt>
|
||||||
|
<dd>select facets that are visible from point <em>n</em>
|
||||||
|
(marked 'good'). Use <em>-n</em> for the remainder.</dd>
|
||||||
|
<dt><a href="qh-optp.htm#PDk">PDk:0</a></dt>
|
||||||
|
<dd>select facets with a negative coordinate for dimension <i>k</i></dd>
|
||||||
|
<dt><a href="qh-optt.htm#TFn">TFn</a></dt>
|
||||||
|
<dd>report progress after constructing <em>n</em> facets</dd>
|
||||||
|
<dt><a href="qh-optt.htm#Tv">Tv</a></dt>
|
||||||
|
<dd>verify result</dd>
|
||||||
|
<dt><a href="qh-optt.htm#TO">TI file</a></dt>
|
||||||
|
<dd>input data from file. The filename may not use spaces or quotes.</dd>
|
||||||
|
<dt><a href="qh-optt.htm#TO">TO file</a></dt>
|
||||||
|
<dd>output results to file. Use single quotes if the filename
|
||||||
|
contains spaces (e.g., <tt>TO 'file with spaces.txt'</tt></dd>
|
||||||
|
<dt><a href="qh-optq.htm#Qs">Qs</a></dt>
|
||||||
|
<dd>search all points for the initial simplex. If Qhull can
|
||||||
|
not construct an initial simplex, it reports a
|
||||||
|
descriptive message. Usually, the point set is degenerate and one
|
||||||
|
or more dimensions should be removed ('<a href="qh-optq.htm#Qb0">Qbk:0Bk:0</a>').
|
||||||
|
If not, use option 'Qs'. It performs an exhaustive search for the
|
||||||
|
best initial simplex. This is expensive is high dimensions.</dd>
|
||||||
|
</dl>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="graphics">qconvex graphics</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Display 2-d, 3-d, and 4-d convex hulls with Geomview ('<a
|
||||||
|
href="qh-optg.htm#G">G</a>').</p>
|
||||||
|
|
||||||
|
<p>Display 2-d and 3-d convex hulls with Mathematica ('<a
|
||||||
|
href="qh-opto.htm#m">m</a>').</p>
|
||||||
|
|
||||||
|
<p>To view 4-d convex hulls in 3-d, use '<a
|
||||||
|
href="qh-optp.htm#Pdk">Pd0d1d2d3</a>' to select the positive
|
||||||
|
octant and '<a href="qh-optg.htm#GDn">GrD2</a>' to drop dimension
|
||||||
|
2. </p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="notes">qconvex notes</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>Qhull always computes a convex hull. The
|
||||||
|
convex hull may be used for other geometric structures. The
|
||||||
|
general technique is to transform the structure into an
|
||||||
|
equivalent convex hull problem. For example, the Delaunay
|
||||||
|
triangulation is equivalent to the convex hull of the input sites
|
||||||
|
after lifting the points to a paraboloid.</p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="conventions">qconvex
|
||||||
|
conventions</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>The following terminology is used for convex hulls in Qhull.
|
||||||
|
See <a href="index.htm#structure">Qhull's data structures</a>.</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><em>point</em> - <em>d</em> coordinates</li>
|
||||||
|
<li><em>vertex</em> - extreme point of the input set</li>
|
||||||
|
<li><em>ridge</em> - <i>d-1</i> vertices between two
|
||||||
|
neighboring facets</li>
|
||||||
|
<li><em>hyperplane</em> - halfspace defined by a unit normal
|
||||||
|
and offset</li>
|
||||||
|
<li><em>coplanar point</em> - a nearly incident point to a
|
||||||
|
hyperplane</li>
|
||||||
|
<li><em>centrum</em> - a point on the hyperplane for testing
|
||||||
|
convexity</li>
|
||||||
|
<li><em>facet</em> - a facet with vertices, ridges, coplanar
|
||||||
|
points, neighboring facets, and hyperplane</li>
|
||||||
|
<li><em>simplicial facet</em> - a facet with <em>d</em>
|
||||||
|
vertices, <em>d</em> ridges, and <em>d</em> neighbors</li>
|
||||||
|
<li><em>non-simplicial facet</em> - a facet with more than <em>d</em>
|
||||||
|
vertices</li>
|
||||||
|
<li><em>good facet</em> - a facet selected by '<a
|
||||||
|
href="qh-optq.htm#QVn">QVn</a>', etc.</li>
|
||||||
|
</ul>
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="options">qconvex options</a></h3>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
qconvex- compute the convex hull
|
||||||
|
http://www.qhull.org
|
||||||
|
|
||||||
|
input (stdin):
|
||||||
|
first lines: dimension and number of points (or vice-versa).
|
||||||
|
other lines: point coordinates, best if one point per line
|
||||||
|
comments: start with a non-numeric character
|
||||||
|
|
||||||
|
options:
|
||||||
|
Qt - triangulated output
|
||||||
|
QJ - joggle input instead of merging facets
|
||||||
|
Qc - keep coplanar points with nearest facet
|
||||||
|
Qi - keep interior points with nearest facet
|
||||||
|
|
||||||
|
Qhull control options:
|
||||||
|
Qbk:n - scale coord k so that low bound is n
|
||||||
|
QBk:n - scale coord k so that upper bound is n (QBk is 0.5)
|
||||||
|
QbB - scale input to unit cube centered at the origin
|
||||||
|
Qbk:0Bk:0 - remove k-th coordinate from input
|
||||||
|
QJn - randomly joggle input in range [-n,n]
|
||||||
|
QRn - random rotation (n=seed, n=0 time, n=-1 time/no rotate)
|
||||||
|
Qs - search all points for the initial simplex
|
||||||
|
QGn - good facet if visible from point n, -n for not visible
|
||||||
|
QVn - good facet if it includes point n, -n if not
|
||||||
|
|
||||||
|
Trace options:
|
||||||
|
T4 - trace at level n, 4=all, 5=mem/gauss, -1= events
|
||||||
|
Tc - check frequently during execution
|
||||||
|
Ts - print statistics
|
||||||
|
Tv - verify result: structure, convexity, and point inclusion
|
||||||
|
Tz - send all output to stdout
|
||||||
|
TFn - report summary when n or more facets created
|
||||||
|
TI file - input data from file, no spaces or single quotes
|
||||||
|
TO file - output results to file, may be enclosed in single quotes
|
||||||
|
TPn - turn on tracing when point n added to hull
|
||||||
|
TMn - turn on tracing at merge n
|
||||||
|
TWn - trace merge facets when width > n
|
||||||
|
TVn - stop qhull after adding point n, -n for before (see TCn)
|
||||||
|
TCn - stop qhull after building cone for point n (see TVn)
|
||||||
|
|
||||||
|
Precision options:
|
||||||
|
Cn - radius of centrum (roundoff added). Merge facets if non-convex
|
||||||
|
An - cosine of maximum angle. Merge facets if cosine > n or non-convex
|
||||||
|
C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
|
||||||
|
Rn - randomly perturb computations by a factor of [1-n,1+n]
|
||||||
|
Un - max distance below plane for a new, coplanar point
|
||||||
|
Wn - min facet width for outside point (before roundoff)
|
||||||
|
|
||||||
|
Output formats (may be combined; if none, produces a summary to stdout):
|
||||||
|
f - facet dump
|
||||||
|
G - Geomview output (see below)
|
||||||
|
i - vertices incident to each facet
|
||||||
|
m - Mathematica output (2-d and 3-d)
|
||||||
|
n - normals with offsets
|
||||||
|
o - OFF file format (dim, points and facets; Voronoi regions)
|
||||||
|
p - point coordinates
|
||||||
|
s - summary (stderr)
|
||||||
|
|
||||||
|
More formats:
|
||||||
|
Fa - area for each facet
|
||||||
|
FA - compute total area and volume for option 's'
|
||||||
|
Fc - count plus coplanar points for each facet
|
||||||
|
use 'Qc' (default) for coplanar and 'Qi' for interior
|
||||||
|
FC - centrum for each facet
|
||||||
|
Fd - use cdd format for input (homogeneous with offset first)
|
||||||
|
FD - use cdd format for numeric output (offset first)
|
||||||
|
FF - facet dump without ridges
|
||||||
|
Fi - inner plane for each facet
|
||||||
|
FI - ID for each facet
|
||||||
|
Fm - merge count for each facet (511 max)
|
||||||
|
FM - Maple output (2-d and 3-d)
|
||||||
|
Fn - count plus neighboring facets for each facet
|
||||||
|
FN - count plus neighboring facets for each point
|
||||||
|
Fo - outer plane (or max_outside) for each facet
|
||||||
|
FO - options and precision constants
|
||||||
|
FP - nearest vertex for each coplanar point
|
||||||
|
FQ - command used for qconvex
|
||||||
|
Fs - summary: #int (8), dimension, #points, tot vertices, tot facets,
|
||||||
|
for output: #vertices, #facets,
|
||||||
|
#coplanar points, #non-simplicial facets
|
||||||
|
#real (2), max outer plane, min vertex
|
||||||
|
FS - sizes: #int (0)
|
||||||
|
#real(2) tot area, tot volume
|
||||||
|
Ft - triangulation with centrums for non-simplicial facets (OFF format)
|
||||||
|
Fv - count plus vertices for each facet
|
||||||
|
FV - average of vertices (a feasible point for 'H')
|
||||||
|
Fx - extreme points (in order for 2-d)
|
||||||
|
|
||||||
|
Geomview output (2-d, 3-d, and 4-d)
|
||||||
|
Ga - all points as dots
|
||||||
|
Gp - coplanar points and vertices as radii
|
||||||
|
Gv - vertices as spheres
|
||||||
|
Gi - inner planes only
|
||||||
|
Gn - no planes
|
||||||
|
Go - outer planes only
|
||||||
|
Gc - centrums
|
||||||
|
Gh - hyperplane intersections
|
||||||
|
Gr - ridges
|
||||||
|
GDn - drop dimension n in 3-d and 4-d output
|
||||||
|
|
||||||
|
Print options:
|
||||||
|
PAn - keep n largest facets by area
|
||||||
|
Pdk:n - drop facet if normal[k] <= n (default 0.0)
|
||||||
|
PDk:n - drop facet if normal[k] >= n
|
||||||
|
Pg - print good facets (needs 'QGn' or 'QVn')
|
||||||
|
PFn - keep facets whose area is at least n
|
||||||
|
PG - print neighbors of good facets
|
||||||
|
PMn - keep n facets with most merges
|
||||||
|
Po - force output. If error, output neighborhood of facet
|
||||||
|
Pp - do not report precision problems
|
||||||
|
|
||||||
|
. - list of all options
|
||||||
|
- - one line descriptions of all options
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!-- Navigation links -->
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p><b>Up:</b> <a href="http://www.qhull.org">Home page</a> for Qhull<br>
|
||||||
|
<b>Up:</b> <a href="index.htm#TOC">Qhull manual</a>: Table of Contents<br>
|
||||||
|
<b>To:</b> <a href="qh-quick.htm#programs">Programs</a>
|
||||||
|
•<a href="qh-quick.htm#options">Options</a>
|
||||||
|
• <a href="qh-opto.htm#output">Output</a>
|
||||||
|
• <a href="qh-optf.htm#format">Formats</a>
|
||||||
|
• <a href="qh-optg.htm#geomview">Geomview</a>
|
||||||
|
• <a href="qh-optp.htm#print">Print</a>
|
||||||
|
• <a href="qh-optq.htm#qhull">Qhull</a>
|
||||||
|
• <a href="qh-optc.htm#prec">Precision</a>
|
||||||
|
• <a href="qh-optt.htm#trace">Trace</a>
|
||||||
|
• <a href="../src/libqhull_r/index.htm">Functions</a><br>
|
||||||
|
<b>To:</b> <a href="#synopsis">sy</a>nopsis
|
||||||
|
• <a href="#input">in</a>put • <a href="#outputs">ou</a>tputs
|
||||||
|
• <a href="#controls">co</a>ntrols • <a href="#graphics">gr</a>aphics
|
||||||
|
• <a href="#notes">no</a>tes • <a href="#conventions">co</a>nventions
|
||||||
|
• <a href="#options">op</a>tions
|
||||||
|
<!-- GC common information -->
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p><a href="http://www.geom.uiuc.edu/"><img src="qh--geom.gif"
|
||||||
|
align="middle" width="40" height="40"></a><i>The Geometry Center
|
||||||
|
Home Page </i></p>
|
||||||
|
|
||||||
|
<p>Comments to: <a href=mailto:qhull@qhull.org>qhull@qhull.org</a>
|
||||||
|
</a><br>
|
||||||
|
Created: Sept. 25, 1995 --- <!-- hhmts start --> Last modified: see top <!-- hhmts end --> </p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
416
xs/src/qhull/html/qdelau_f.htm
Normal file
|
|
@ -0,0 +1,416 @@
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>qdelaunay Qu -- furthest-site Delaunay triangulation</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Navigation links -->
|
||||||
|
<a name="TOP"><b>Up</b></a><b>:</b>
|
||||||
|
<a href="http://www.qhull.org">Home page</a> for Qhull<br>
|
||||||
|
<b>Up:</b> <a href="index.htm#TOC">Qhull manual</a>: Table of Contents<br>
|
||||||
|
<b>To:</b> <a href="qh-quick.htm#programs">Programs</a>
|
||||||
|
• <a href="qh-quick.htm#options">Options</a>
|
||||||
|
• <a href="qh-opto.htm#output">Output</a>
|
||||||
|
• <a href="qh-optf.htm#format">Formats</a>
|
||||||
|
• <a href="qh-optg.htm#geomview">Geomview</a>
|
||||||
|
• <a href="qh-optp.htm#print">Print</a>
|
||||||
|
• <a href="qh-optq.htm#qhull">Qhull</a>
|
||||||
|
• <a href="qh-optc.htm#prec">Precision</a>
|
||||||
|
• <a href="qh-optt.htm#trace">Trace</a>
|
||||||
|
• <a href="../src/libqhull_r/index.htm">Functions</a><br>
|
||||||
|
<b>To:</b> <a href="#synopsis">sy</a>nopsis
|
||||||
|
• <a href="#input">in</a>put • <a href="#outputs">ou</a>tputs
|
||||||
|
• <a href="#controls">co</a>ntrols • <a href="#graphics">gr</a>aphics
|
||||||
|
• <a href="#notes">no</a>tes • <a href="#conventions">co</a>nventions
|
||||||
|
• <a href="#options">op</a>tions
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<!-- Main text of document -->
|
||||||
|
<h1><a
|
||||||
|
href="http://www.geom.uiuc.edu/graphics/pix/Special_Topics/Computational_Geometry/delaunay.html"><img
|
||||||
|
src="qh--dt.gif" alt="[delaunay]" align="middle" width="100"
|
||||||
|
height="100"></a>qdelaunay Qu -- furthest-site Delaunay triangulation</h1>
|
||||||
|
|
||||||
|
<p>The furthest-site Delaunay triangulation corresponds to the upper facets of the <a href="qdelaun.htm">Delaunay construction</a>.
|
||||||
|
Its vertices are the
|
||||||
|
extreme points of the input sites.
|
||||||
|
It is the dual of the <a
|
||||||
|
href="qvoron_f.htm">furthest-site Voronoi diagram</a>.
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<dl>
|
||||||
|
<dt><b>Example:</b> rbox 10 D2 | qdelaunay <a
|
||||||
|
href="qh-optq.htm#Qu">Qu</a> <a
|
||||||
|
href="qh-optq.htm#Qt">Qt</a> <a href="qh-opto.htm#s">s</a>
|
||||||
|
<a href="qh-opto.htm#i">i</a> <a href="qh-optt.htm#TO">TO
|
||||||
|
result</a></dt>
|
||||||
|
<dd>Compute the 2-d, furthest-site Delaunay triangulation of 10 random
|
||||||
|
points. Triangulate the output.
|
||||||
|
Write a summary to the console and the regions to
|
||||||
|
'result'.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox 10 D2 | qdelaunay <a
|
||||||
|
href="qh-optq.htm#Qu">Qu</a> <a
|
||||||
|
href="qh-optq.htm#QJn">QJ</a> <a href="qh-opto.htm#s">s</a>
|
||||||
|
<a href="qh-opto.htm#i">i</a> <a href="qh-optt.htm#TO">TO
|
||||||
|
result</a></dt>
|
||||||
|
<dd>Compute the 2-d, furthest-site Delaunay triangulation of 10 random
|
||||||
|
points. Joggle the input to guarantee triangular output.
|
||||||
|
Write a summary to the console and the regions to
|
||||||
|
'result'.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox r y c G1 D2 | qdelaunay <a
|
||||||
|
href="qh-optq.htm#Qu">Qu</a> <a href="qh-opto.htm#s">s</a>
|
||||||
|
<a href="qh-optf.htm#Fv">Fv</a> <a href="qh-optt.htm#TO">TO
|
||||||
|
result</a></dt>
|
||||||
|
<dd>Compute the 2-d, furthest-site Delaunay triangulation of a triangle inside
|
||||||
|
a square.
|
||||||
|
Write a summary to the console and unoriented regions to 'result'.
|
||||||
|
Merge regions for cocircular input sites (e.g., the square).
|
||||||
|
The square is the only furthest-site
|
||||||
|
Delaunay region.</dd>
|
||||||
|
</dl>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>As with the Delaunay triangulation, Qhull computes the
|
||||||
|
furthest-site Delaunay triangulation by lifting the input sites to a
|
||||||
|
paraboloid. The lower facets correspond to the Delaunay
|
||||||
|
triangulation while the upper facets correspond to the
|
||||||
|
furthest-site triangulation. Neither triangulation includes
|
||||||
|
"vertical" facets (i.e., facets whose last hyperplane
|
||||||
|
coefficient is nearly zero). Vertical facets correspond to input
|
||||||
|
sites that are coplanar to the convex hull of the input. An
|
||||||
|
example is points on the boundary of a lattice.</p>
|
||||||
|
|
||||||
|
<p>By default, qdelaunay merges cocircular and cospherical regions.
|
||||||
|
For example, the furthest-site Delaunay triangulation of a square inside a diamond
|
||||||
|
('rbox D2 c d G4 | qdelaunay Qu') consists of one region (the diamond).
|
||||||
|
|
||||||
|
<p>If you use '<a href="qh-optq.htm#Qt">Qt</a>' (triangulated output),
|
||||||
|
all furthest-site Delaunay regions will be simplicial (e.g., triangles in 2-d).
|
||||||
|
Some regions may be
|
||||||
|
degenerate and have zero area.
|
||||||
|
|
||||||
|
<p>If you use '<a href="qh-optq.htm#QJn">QJ</a>' (joggled input), all furthest-site
|
||||||
|
Delaunay regions
|
||||||
|
will be simplicial (e.g., triangles in 2-d). Joggled input
|
||||||
|
is less accurate than triangulated output ('Qt'). See <a
|
||||||
|
href="qh-impre.htm#joggle">Merged facets or joggled input</a>. </p>
|
||||||
|
|
||||||
|
<p>The output for 3-d, furthest-site Delaunay triangulations may be confusing if the
|
||||||
|
input contains cospherical data. See the FAQ item
|
||||||
|
<a href=qh-faq.htm#extra>Why
|
||||||
|
are there extra points in a 4-d or higher convex hull?</a>
|
||||||
|
Avoid these problems with triangulated output ('<a href="qh-optq.htm#Qt">Qt</a>') or
|
||||||
|
joggled input ('<a href="qh-optq.htm#QJn">QJ</a>').
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>The 'qdelaunay' program is equivalent to
|
||||||
|
'<a href=qhull.htm#outputs>qhull d</a> <a href=qh-optq.htm#Qbb>Qbb</a>' in 2-d to 3-d, and
|
||||||
|
'<a href=qhull.htm#outputs>qhull d</a> <a href=qh-optq.htm#Qbb>Qbb</a> <a href=qh-optq.htm#Qx>Qx</a>'
|
||||||
|
in 4-d and higher. It disables the following Qhull
|
||||||
|
<a href=qh-quick.htm#options>options</a>: <i>d n v H U Qb QB Qc Qf Qg Qi
|
||||||
|
Qm Qr QR Qv Qx TR E V FC Fi Fo Fp FV Q0,etc</i>.
|
||||||
|
|
||||||
|
|
||||||
|
<p><b>Copyright © 1995-2015 C.B. Barber</b></p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a href="#TOP">»</a><a name="synopsis">furthest-site qdelaunay synopsis</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
See <a href="qdelaun.htm#synopsis">qdelaunay synopsis</a>. The same
|
||||||
|
program is used for both constructions. Use option '<a href="qh-optq.htm#Qu">Qu</a>'
|
||||||
|
for furthest-site Delaunay triangulations.
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="input">furthest-site qdelaunay
|
||||||
|
input</a></h3>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<p>The input data on <tt>stdin</tt> consists of:</p>
|
||||||
|
<ul>
|
||||||
|
<li>dimension
|
||||||
|
<li>number of points</li>
|
||||||
|
<li>point coordinates</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Use I/O redirection (e.g., qdelaunay Qu < data.txt), a pipe (e.g., rbox 10 | qdelaunay Qu),
|
||||||
|
or the '<a href=qh-optt.htm#TI>TI</a>' option (e.g., qdelaunay Qu TI data.txt).
|
||||||
|
|
||||||
|
<p>For example, this is a square containing four random points.
|
||||||
|
Its furthest-site Delaunay
|
||||||
|
triangulation contains one square.
|
||||||
|
<p>
|
||||||
|
<blockquote>
|
||||||
|
<tt>rbox c 4 D2 > data</tt>
|
||||||
|
<blockquote><pre>
|
||||||
|
2 RBOX c 4 D2
|
||||||
|
8
|
||||||
|
-0.4999921736307369 -0.3684622117955817
|
||||||
|
0.2556053225468894 -0.0413498678629751
|
||||||
|
0.0327672376602583 -0.2810408135699488
|
||||||
|
-0.452955383763607 0.17886471718444
|
||||||
|
-0.5 -0.5
|
||||||
|
-0.5 0.5
|
||||||
|
0.5 -0.5
|
||||||
|
0.5 0.5
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p><tt>qdelaunay Qu i < data</tt>
|
||||||
|
<blockquote><pre>
|
||||||
|
|
||||||
|
Furthest-site Delaunay triangulation by the convex hull of 8 points in 3-d:
|
||||||
|
|
||||||
|
Number of input sites: 8
|
||||||
|
Number of Delaunay regions: 1
|
||||||
|
Number of non-simplicial Delaunay regions: 1
|
||||||
|
|
||||||
|
Statistics for: RBOX c 4 D2 | QDELAUNAY s Qu i
|
||||||
|
|
||||||
|
Number of points processed: 8
|
||||||
|
Number of hyperplanes created: 20
|
||||||
|
Number of facets in hull: 11
|
||||||
|
Number of distance tests for qhull: 34
|
||||||
|
Number of merged facets: 1
|
||||||
|
Number of distance tests for merging: 107
|
||||||
|
CPU seconds to compute hull (after input): 0.02
|
||||||
|
|
||||||
|
1
|
||||||
|
7 6 4 5
|
||||||
|
</pre></blockquote>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="outputs">furthest-site qdelaunay
|
||||||
|
outputs</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>These options control the output of furthest-site Delaunay triangulations:</p>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<dl compact>
|
||||||
|
<dd><b>furthest-site Delaunay regions</b></dd>
|
||||||
|
<dt><a href="qh-opto.htm#i">i</a></dt>
|
||||||
|
<dd>list input sites for each furthest-site Delaunay region. The first line is the number of regions. The
|
||||||
|
remaining lines list the input sites for each region. The regions are
|
||||||
|
oriented. In 3-d and
|
||||||
|
higher, report cospherical sites by adding extra points. For the points-in-square example,
|
||||||
|
the square is the only furthest-site Delaunay region.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fv">Fv</a></dt>
|
||||||
|
<dd>list input sites for each furthest-site Delaunay region. The first line is the number of regions.
|
||||||
|
Each remaining line starts with the number of input sites. The regions
|
||||||
|
are unoriented. For the points-in-square example,
|
||||||
|
the square is the only furthest-site Delaunay region.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Ft">Ft</a></dt>
|
||||||
|
<dd>print a triangulation of the furthest-site Delaunay regions in OFF format. The first line
|
||||||
|
is the dimension. The second line is the number of input sites and added points,
|
||||||
|
followed by the number of simplices and the number of ridges.
|
||||||
|
The input coordinates are next, followed by the centrum coordinates. There is
|
||||||
|
one centrum for each non-simplicial furthest-site Delaunay region. Each remaining line starts
|
||||||
|
with dimension+1. The
|
||||||
|
simplices are oriented.
|
||||||
|
For the points-in-square example, the square has a centrum at the
|
||||||
|
origin. It splits the square into four triangular regions.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fn">Fn</a></dt>
|
||||||
|
<dd>list neighboring regions for each furthest-site Delaunay region. The first line is the
|
||||||
|
number of regions. Each remaining line starts with the number of
|
||||||
|
neighboring regions. Negative indices (e.g., <em>-1</em>) indicate regions
|
||||||
|
outside of the furthest-site Delaunay triangulation.
|
||||||
|
For the points-in-square example, the four neighboring regions
|
||||||
|
are outside of the triangulation. They belong to the regular
|
||||||
|
Delaunay triangulation.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#FN">FN</a></dt>
|
||||||
|
<dd>list the furthest-site Delaunay regions for each input site. The first line is the
|
||||||
|
total number of input sites. Each remaining line starts with the number of
|
||||||
|
furthest-site Delaunay regions. Negative indices (e.g., <em>-1</em>) indicate regions
|
||||||
|
outside of the furthest-site Delaunay triangulation.
|
||||||
|
For the points-in-square example, the four random points belong to no region
|
||||||
|
while the square's vertices belong to region <em>0</em> and three
|
||||||
|
regions outside of the furthest-site Delaunay triangulation.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fa">Fa</a></dt>
|
||||||
|
<dd>print area for each furthest-site Delaunay region. The first line is the number of regions.
|
||||||
|
The areas follow, one line per region. For the points-in-square example, the
|
||||||
|
square has unit area. </dd>
|
||||||
|
|
||||||
|
<dt> </dt>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>Input sites</b></dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fx">Fx</a></dt>
|
||||||
|
<dd>list extreme points of the input sites. These points are vertices of the furthest-point
|
||||||
|
Delaunay triangulation. They are on the
|
||||||
|
boundary of the convex hull. The first line is the number of
|
||||||
|
extreme points. Each point is listed, one per line. The points-in-square example
|
||||||
|
has four extreme points.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>General</b></dd>
|
||||||
|
<dt><a href="qh-optf.htm#FA">FA</a></dt>
|
||||||
|
<dd>compute total area for '<a href="qh-opto.htm#s">s</a>'
|
||||||
|
and '<a href="qh-optf.htm#FS">FS</a>'. This is the
|
||||||
|
same as the area of the convex hull.</dd>
|
||||||
|
<dt><a href="qh-opto.htm#o">o</a></dt>
|
||||||
|
<dd>print upper facets of the corresponding convex hull (a
|
||||||
|
paraboloid)</dd>
|
||||||
|
<dt><a href="qh-opto.htm#m">m</a></dt>
|
||||||
|
<dd>Mathematica output for the upper facets of the paraboloid (2-d triangulations).</dd>
|
||||||
|
<dt><a href="qh-optf.htm#FM">FM</a></dt>
|
||||||
|
<dd>Maple output for the upper facets of the paraboloid (2-d triangulations).</dd>
|
||||||
|
<dt><a href="qh-optg.htm#G">G</a></dt>
|
||||||
|
<dd>Geomview output for the paraboloid (2-d or 3-d triangulations).</dd>
|
||||||
|
<dt><a href="qh-opto.htm#s">s</a></dt>
|
||||||
|
<dd>print summary for the furthest-site Delaunay triangulation. Use '<a
|
||||||
|
href="qh-optf.htm#Fs">Fs</a>' and '<a
|
||||||
|
href="qh-optf.htm#FS">FS</a>' for numeric data.</dd>
|
||||||
|
</dl>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="controls">furthest-site qdelaunay
|
||||||
|
controls</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>These options provide additional control:</p>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<dl compact>
|
||||||
|
<dt><a href="qh-optq.htm#Qu">Qu</a></dt>
|
||||||
|
<dd>must be used for furthest-site Delaunay triangulation.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#Qt">Qt</a></dt>
|
||||||
|
<dd>triangulated output. Qhull triangulates non-simplicial facets. It may produce
|
||||||
|
degenerate facets of zero area.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#QJn">QJ</a></dt>
|
||||||
|
<dd>joggle the input to avoid cospherical and coincident
|
||||||
|
sites. It is less accurate than triangulated output ('Qt').</dd>
|
||||||
|
<dt><a href="qh-optq.htm#QVn">QVn</a></dt>
|
||||||
|
<dd>select facets adjacent to input site <em>n</em> (marked
|
||||||
|
'good').</dd>
|
||||||
|
<dt><a href="qh-optt.htm#Tv">Tv</a></dt>
|
||||||
|
<dd>verify result.</dd>
|
||||||
|
<dt><a href="qh-optt.htm#TO">TI file</a></dt>
|
||||||
|
<dd>input data from file. The filename may not use spaces or quotes.</dd>
|
||||||
|
<dt><a href="qh-optt.htm#TO">TO file</a></dt>
|
||||||
|
<dd>output results to file. Use single quotes if the filename
|
||||||
|
contains spaces (e.g., <tt>TO 'file with spaces.txt'</tt></dd>
|
||||||
|
<dt><a href="qh-optt.htm#TFn">TFn</a></dt>
|
||||||
|
<dd>report progress after constructing <em>n</em> facets</dd>
|
||||||
|
<dt><a href="qh-optp.htm#PDk">PDk:1</a></dt>
|
||||||
|
<dd>include upper and lower facets in the output. Set <em>k</em>
|
||||||
|
to the last dimension (e.g., 'PD2:1' for 2-d inputs). </dd>
|
||||||
|
<dt><a href="qh-opto.htm#f">f</a></dt>
|
||||||
|
<dd>facet dump. Print the data structure for each facet (i.e., furthest-site Delaunay region).</dd>
|
||||||
|
</dl>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="graphics">furthest-site qdelaunay
|
||||||
|
graphics</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
See <a href="qdelaun.htm#graphics">Delaunay graphics</a>.
|
||||||
|
They are the same except for Mathematica and Maple output.
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="notes">furthest-site
|
||||||
|
qdelaunay notes</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>The furthest-site Delaunay triangulation does not
|
||||||
|
record coincident input sites. Use <tt>qdelaunay</tt> instead.
|
||||||
|
|
||||||
|
<p><tt>qdelaunay Qu</tt> does not work for purely cocircular
|
||||||
|
or cospherical points (e.g., rbox c | qdelaunay Qu). Instead,
|
||||||
|
use <tt>qdelaunay Qz</tt> -- when all points are vertices of the convex
|
||||||
|
hull of the input sites, the Delaunay triangulation is the same
|
||||||
|
as the furthest-site Delaunay triangulation.
|
||||||
|
|
||||||
|
<p>A non-simplicial, furthest-site Delaunay region indicates nearly cocircular or
|
||||||
|
cospherical input sites. To avoid non-simplicial regions triangulate
|
||||||
|
the output ('<a href="qh-optq.htm#Qt">Qt</a>') or joggle
|
||||||
|
the input ('<a href="qh-optq.htm#QJn">QJ</a>'). Joggled input
|
||||||
|
is less accurate than triangulated output.
|
||||||
|
You may also triangulate
|
||||||
|
non-simplicial regions with option '<a
|
||||||
|
href="qh-optf.htm#Ft">Ft</a>'. It adds
|
||||||
|
the centrum to non-simplicial regions. Alternatively, use an <a
|
||||||
|
href="qh-impre.htm#exact">exact arithmetic code</a>.</p>
|
||||||
|
|
||||||
|
<p>Furthest-site Delaunay triangulations do not include facets that are
|
||||||
|
coplanar with the convex hull of the input sites. A facet is
|
||||||
|
coplanar if the last coefficient of its normal is
|
||||||
|
nearly zero (see <a href="../src/libqhull/user.h#ZEROdelaunay">qh_ZEROdelaunay</a>).
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="conventions">furthest-site qdelaunay conventions</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>The following terminology is used for furthest-site Delaunay
|
||||||
|
triangulations in Qhull. The underlying structure is the upper
|
||||||
|
facets of a convex hull in one higher dimension. See <a
|
||||||
|
href="qconvex.htm#conventions">convex hull conventions</a>, <a
|
||||||
|
href="qdelaun.htm#conventions">Delaunay conventions</a>,
|
||||||
|
and <a href="index.htm#structure">Qhull's data structures</a></p>
|
||||||
|
<blockquote>
|
||||||
|
<ul>
|
||||||
|
<li><em>input site</em> - a point in the input (one dimension
|
||||||
|
lower than a point on the convex hull)</li>
|
||||||
|
<li><em>point</em> - <i>d+1</i> coordinates. The last
|
||||||
|
coordinate is the sum of the squares of the input site's
|
||||||
|
coordinates</li>
|
||||||
|
<li><em>vertex</em> - a point on the paraboloid. It
|
||||||
|
corresponds to a unique input site. </li>
|
||||||
|
<li><em>furthest-site Delaunay facet</em> - an upper facet of the
|
||||||
|
paraboloid. The last coefficient of its normal is
|
||||||
|
clearly positive.</li>
|
||||||
|
<li><em>furthest-site Delaunay region</em> - a furthest-site Delaunay
|
||||||
|
facet projected to the input sites</li>
|
||||||
|
<li><em>non-simplicial facet</em> - more than <em>d</em>
|
||||||
|
points are cocircular or cospherical</li>
|
||||||
|
<li><em>good facet</em> - a furthest-site Delaunay facet with optional
|
||||||
|
restrictions by '<a href="qh-optq.htm#QVn">QVn</a>', etc.</li>
|
||||||
|
</ul>
|
||||||
|
</blockquote>
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="options">furthest-site qdelaunay options</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
See <a href="qdelaun.htm#options">qdelaunay options</a>. The same
|
||||||
|
program is used for both constructions. Use option '<a href="qh-optq.htm#Qu">Qu</a>'
|
||||||
|
for furthest-site Delaunay triangulations.
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<!-- Navigation links -->
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p><b>Up:</b> <a href="http://www.qhull.org">Home page</a> for Qhull<br>
|
||||||
|
<b>Up:</b> <a href="index.htm#TOC">Qhull manual</a>: Table of Contents<br>
|
||||||
|
<b>To:</b> <a href="qh-quick.htm#programs">Programs</a>
|
||||||
|
• <a href="qh-quick.htm#options">Options</a>
|
||||||
|
• <a href="qh-opto.htm#output">Output</a>
|
||||||
|
• <a href="qh-optf.htm#format">Formats</a>
|
||||||
|
• <a href="qh-optg.htm#geomview">Geomview</a>
|
||||||
|
• <a href="qh-optp.htm#print">Print</a>
|
||||||
|
• <a href="qh-optq.htm#qhull">Qhull</a>
|
||||||
|
• <a href="qh-optc.htm#prec">Precision</a>
|
||||||
|
• <a href="qh-optt.htm#trace">Trace</a>
|
||||||
|
• <a href="../src/libqhull_r/index.htm">Functions</a><br>
|
||||||
|
<b>To:</b> <a href="#synopsis">sy</a>nopsis
|
||||||
|
• <a href="#input">in</a>put • <a href="#outputs">ou</a>tputs
|
||||||
|
• <a href="#controls">co</a>ntrols • <a href="#graphics">gr</a>aphics
|
||||||
|
• <a href="#notes">no</a>tes • <a href="#conventions">co</a>nventions
|
||||||
|
• <a href="#options">op</a>tions
|
||||||
|
<!-- GC common information -->
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p><a href="http://www.geom.uiuc.edu/"><img src="qh--geom.gif"
|
||||||
|
align="middle" width="40" height="40"></a><i>The Geometry Center
|
||||||
|
Home Page </i></p>
|
||||||
|
|
||||||
|
<p>Comments to: <a href=mailto:qhull@qhull.org>qhull@qhull.org</a>
|
||||||
|
</a><br>
|
||||||
|
Created: Sept. 25, 1995 --- <!-- hhmts start --> Last modified: see top <!-- hhmts end --> </p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
628
xs/src/qhull/html/qdelaun.htm
Normal file
|
|
@ -0,0 +1,628 @@
|
||||||
|
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>qdelaunay -- Delaunay triangulation</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- Navigation links -->
|
||||||
|
<a name="TOP"><b>Up</b></a><b>:</b>
|
||||||
|
<a href="http://www.qhull.org">Home page</a> for Qhull<br>
|
||||||
|
<b>Up:</b> <a href="index.htm#TOC">Qhull manual</a>: Table of Contents<br>
|
||||||
|
<b>To:</b> <a href="qh-quick.htm#programs">Programs</a>
|
||||||
|
• <a href="qh-quick.htm#options">Options</a>
|
||||||
|
• <a href="qh-opto.htm#output">Output</a>
|
||||||
|
• <a href="qh-optf.htm#format">Formats</a>
|
||||||
|
• <a href="qh-optg.htm#geomview">Geomview</a>
|
||||||
|
• <a href="qh-optp.htm#print">Print</a>
|
||||||
|
• <a href="qh-optq.htm#qhull">Qhull</a>
|
||||||
|
• <a href="qh-optc.htm#prec">Precision</a>
|
||||||
|
• <a href="qh-optt.htm#trace">Trace</a>
|
||||||
|
• <a href="../src/libqhull_r/index.htm">Functions</a><br>
|
||||||
|
<b>To:</b> <a href="#synopsis">sy</a>nopsis
|
||||||
|
• <a href="#input">in</a>put • <a href="#outputs">ou</a>tputs
|
||||||
|
• <a href="#controls">co</a>ntrols • <a href="#graphics">gr</a>aphics
|
||||||
|
• <a href="#notes">no</a>tes • <a href="#conventions">co</a>nventions
|
||||||
|
• <a href="#options">op</a>tions
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<!-- Main text of document -->
|
||||||
|
<h1><a
|
||||||
|
href="http://www.geom.uiuc.edu/graphics/pix/Special_Topics/Computational_Geometry/delaunay.html"><img
|
||||||
|
src="qh--dt.gif" alt="[delaunay]" align="middle" width="100"
|
||||||
|
height="100"></a>qdelaunay -- Delaunay triangulation</h1>
|
||||||
|
|
||||||
|
<p>The Delaunay triangulation is the triangulation with empty
|
||||||
|
circumspheres. It has many useful properties and applications.
|
||||||
|
See the survey article by Aurenhammer [<a
|
||||||
|
href="index.htm#aure91">'91</a>] and the detailed introduction
|
||||||
|
by O'Rourke [<a href="index.htm#orou94">'94</a>]. </p>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<dl>
|
||||||
|
<dt><b>Example:</b> rbox r y c G0.1 D2 | qdelaunay <a href="qh-opto.htm#s">s</a>
|
||||||
|
<a href="qh-optf.htm#Fv">Fv</a> <a href="qh-optt.htm#TO">TO
|
||||||
|
result</a></dt>
|
||||||
|
<dd>Compute the 2-d Delaunay triangulation of a triangle and
|
||||||
|
a small square.
|
||||||
|
Write a summary to the console and unoriented regions to 'result'.
|
||||||
|
Merge regions for cocircular input sites (i.e., the
|
||||||
|
square).</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox r y c G0.1 D2 | qdelaunay <a href="qh-opto.htm#s">s</a>
|
||||||
|
<a href="qh-optf.htm#Fv">Fv</a> <a href="qh-optq.htm#Qt">Qt</a></dt>
|
||||||
|
<dd>Compute the 2-d Delaunay triangulation of a triangle and
|
||||||
|
a small square. Write a summary and unoriented
|
||||||
|
regions to the console. Produce triangulated output.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt><b>Example:</b> rbox 10 D2 | qdelaunay <a
|
||||||
|
href="qh-optq.htm#QJn">QJ</a> <a href="qh-opto.htm#s">s</a>
|
||||||
|
<a href="qh-opto.htm#i">i</a> <a href="qh-optt.htm#TO">TO
|
||||||
|
result</a></dt>
|
||||||
|
<dd>Compute the 2-d Delaunay triangulation of 10 random
|
||||||
|
points. Joggle the input to guarantee triangular output.
|
||||||
|
Write a summary to the console and the regions to
|
||||||
|
'result'.</dd>
|
||||||
|
</dl>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
<p>Qhull computes the Delaunay triangulation by computing a
|
||||||
|
convex hull. It lifts the input sites to a paraboloid by adding
|
||||||
|
the sum of the squares of the coordinates. It scales the height
|
||||||
|
of the paraboloid to improve numeric precision ('<a href=qh-optq.htm#Qbb>Qbb</a>').
|
||||||
|
It computes the convex
|
||||||
|
hull of the lifted sites, and projects the lower convex hull to
|
||||||
|
the input.
|
||||||
|
|
||||||
|
<p>Each region of the Delaunay triangulation
|
||||||
|
corresponds to a facet of the lower half of the convex hull.
|
||||||
|
Facets of the upper half of the convex hull correspond to the <a
|
||||||
|
href="qdelau_f.htm">furthest-site Delaunay triangulation</a>.
|
||||||
|
See the examples, <a href="qh-eg.htm#delaunay">Delaunay and
|
||||||
|
Voronoi diagrams</a>.</p>
|
||||||
|
|
||||||
|
<p>See <a href="http://www.qhull.org/html/qh-faq.htm#TOC">Qhull FAQ</a> - Delaunay and
|
||||||
|
Voronoi diagram questions.</p>
|
||||||
|
|
||||||
|
<p>By default, qdelaunay merges cocircular and cospherical regions.
|
||||||
|
For example, the Delaunay triangulation of a square inside a diamond
|
||||||
|
('rbox D2 c d G4 | qdelaunay') contains one region for the square.
|
||||||
|
|
||||||
|
<p>Use option '<a href="qh-optq.htm#Qz">Qz</a>' if the input is circular, cospherical, or
|
||||||
|
nearly so. It improves precision by adding a point "at infinity," above the corresponding paraboloid.
|
||||||
|
|
||||||
|
<p>If you use '<a href="qh-optq.htm#Qt">Qt</a>' (triangulated output),
|
||||||
|
all Delaunay regions will be simplicial (e.g., triangles in 2-d).
|
||||||
|
Some regions may be
|
||||||
|
degenerate and have zero area. Triangulated output identifies coincident
|
||||||
|
points.
|
||||||
|
|
||||||
|
<p>If you use '<a href="qh-optq.htm#QJn">QJ</a>' (joggled input), all Delaunay regions
|
||||||
|
will be simplicial (e.g., triangles in 2-d). Coincident points will
|
||||||
|
create small regions since the points are joggled apart. Joggled input
|
||||||
|
is less accurate than triangulated output ('Qt'). See <a
|
||||||
|
href="qh-impre.htm#joggle">Merged facets or joggled input</a>. </p>
|
||||||
|
|
||||||
|
<p>The output for 3-d Delaunay triangulations may be confusing if the
|
||||||
|
input contains cospherical data. See the FAQ item
|
||||||
|
<a href=qh-faq.htm#extra>Why
|
||||||
|
are there extra points in a 4-d or higher convex hull?</a>
|
||||||
|
Avoid these problems with triangulated output ('<a href="qh-optq.htm#Qt">Qt</a>') or
|
||||||
|
joggled input ('<a href="qh-optq.htm#QJn">QJ</a>').
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>The 'qdelaunay' program is equivalent to
|
||||||
|
'<a href=qhull.htm#outputs>qhull d</a> <a href=qh-optq.htm#Qbb>Qbb</a>' in 2-d to 3-d, and
|
||||||
|
'<a href=qhull.htm#outputs>qhull d</a> <a href=qh-optq.htm#Qbb>Qbb</a> <a href=qh-optq.htm#Qx>Qx</a>'
|
||||||
|
in 4-d and higher. It disables the following Qhull
|
||||||
|
<a href=qh-quick.htm#options>options</a>: <i>d n v H U Qb QB Qc Qf Qg Qi
|
||||||
|
Qm Qr QR Qv Qx TR E V FC Fi Fo Fp Ft FV Q0,etc</i>.
|
||||||
|
|
||||||
|
|
||||||
|
<p><b>Copyright © 1995-2015 C.B. Barber</b></p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h3><a href="#TOP">»</a><a name="synopsis">qdelaunay synopsis</a></h3>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
qdelaunay- compute the Delaunay triangulation.
|
||||||
|
input (stdin): dimension, number of points, point coordinates
|
||||||
|
comments start with a non-numeric character
|
||||||
|
|
||||||
|
options (qdelaun.htm):
|
||||||
|
Qt - triangulated output
|
||||||
|
QJ - joggle input instead of merging facets
|
||||||
|
Qu - furthest-site Delaunay triangulation
|
||||||
|
Tv - verify result: structure, convexity, and in-circle test
|
||||||
|
. - concise list of all options
|
||||||
|
- - one-line description of all options
|
||||||
|
|
||||||
|
output options (subset):
|
||||||
|
s - summary of results (default)
|
||||||
|
i - vertices incident to each Delaunay region
|
||||||
|
Fx - extreme points (vertices of the convex hull)
|
||||||
|
o - OFF format (shows the points lifted to a paraboloid)
|
||||||
|
G - Geomview output (2-d and 3-d points lifted to a paraboloid)
|
||||||
|
m - Mathematica output (2-d inputs lifted to a paraboloid)
|
||||||
|
QVn - print Delaunay regions that include point n, -n if not
|
||||||
|
TO file- output results to file, may be enclosed in single quotes
|
||||||
|
|
||||||
|
examples:
|
||||||
|
rbox c P0 D2 | qdelaunay s o rbox c P0 D2 | qdelaunay i
|
||||||
|
rbox c P0 D3 | qdelaunay Fv Qt rbox c P0 D2 | qdelaunay s Qu Fv
|
||||||
|
rbox c G1 d D2 | qdelaunay s i rbox c G1 d D2 | qdelaunay s i Qt
|
||||||
|
rbox M3,4 z 100 D2 | qdelaunay s rbox M3,4 z 100 D2 | qdelaunay s Qt
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
<h3><a href="#TOP">»</a><a name="input">qdelaunay
|
||||||
|
input</a></h3>
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
<p>The input data on <tt>stdin</tt> consists of:</p>
|
||||||
|
<ul>
|
||||||
|
<li>dimension
|
||||||
|
<li>number of points</li>
|
||||||
|
<li>point coordinates</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Use I/O redirection (e.g., qdelaunay < data.txt), a pipe (e.g., rbox 10 | qdelaunay),
|
||||||
|
or the '<a href=qh-optt.htm#TI>TI</a>' option (e.g., qdelaunay TI data.txt).
|
||||||
|
|
||||||
|
<p>For example, this is four cocircular points inside a square. Its Delaunay
|
||||||
|
triangulation contains 8 triangles and one four-sided
|
||||||
|
figure.
|
||||||
|
<p>
|
||||||
|
<blockquote>
|
||||||
|
<tt>rbox s 4 W0 c G1 D2 > data</tt>
|
||||||
|
<blockquote><pre>
|
||||||
|
2 RBOX s 4 W0 c D2
|
||||||
|
8
|
||||||
|
-0.4941988586954018 -0.07594397977563715
|
||||||
|
-0.06448037284989526 0.4958248496365813
|
||||||
|
0.4911154367094632 0.09383830681375946
|
||||||
|
-0.348353580869097 -0.3586778257652367
|
||||||
|
-1 -1
|
||||||
|
-1 1
|
||||||
|
1 -1
|
||||||
|
1 1
|
||||||
|
</pre></blockquote>
|
||||||
|
|
||||||
|
<p><tt>qdelaunay s i < data</tt>
|
||||||
|
<blockquote><pre>
|
||||||
|
|
||||||
|
Delaunay triangulation by the convex hull of 8 points in 3-d
|
||||||
|
|
||||||
|
Number of input sites: 8
|
||||||
|
Number of Delaunay regions: 9
|
||||||
|
Number of non-simplicial Delaunay regions: 1
|
||||||
|
|
||||||
|
Statistics for: RBOX s 4 W0 c D2 | QDELAUNAY s i
|
||||||
|
|
||||||
|
Number of points processed: 8
|
||||||
|
Number of hyperplanes created: 18
|
||||||
|
Number of facets in hull: 10
|
||||||
|
Number of distance tests for qhull: 33
|
||||||
|
Number of merged facets: 2
|
||||||
|
Number of distance tests for merging: 102
|
||||||
|
CPU seconds to compute hull (after input): 0.028
|
||||||
|
|
||||||
|
9
|
||||||
|
1 7 5
|
||||||
|
6 3 4
|
||||||
|
2 3 6
|
||||||
|
7 2 6
|
||||||
|
2 7 1
|
||||||
|
0 5 4
|
||||||
|
3 0 4
|
||||||
|
0 1 5
|
||||||
|
1 0 3 2
|
||||||
|
</pre></blockquote>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="outputs">qdelaunay
|
||||||
|
outputs</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>These options control the output of Delaunay triangulations:</p>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<dl compact>
|
||||||
|
<dd><b>Delaunay regions</b></dd>
|
||||||
|
<dt><a href="qh-opto.htm#i">i</a></dt>
|
||||||
|
<dd>list input sites for each Delaunay region. The first line is the number of regions. The
|
||||||
|
remaining lines list the input sites for each region. The regions are
|
||||||
|
oriented. In 3-d and
|
||||||
|
higher, report cospherical sites by adding extra points. Use triangulated
|
||||||
|
output ('<a href="qh-optq.htm#Qt">Qt</a>') to avoid non-simpicial regions. For the circle-in-square example,
|
||||||
|
eight Delaunay regions are triangular and the ninth has four input sites.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fv">Fv</a></dt>
|
||||||
|
<dd>list input sites for each Delaunay region. The first line is the number of regions.
|
||||||
|
Each remaining line starts with the number of input sites. The regions
|
||||||
|
are unoriented. For the circle-in-square example,
|
||||||
|
eight Delaunay regions are triangular and the ninth has four input sites.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fn">Fn</a></dt>
|
||||||
|
<dd>list neighboring regions for each Delaunay region. The first line is the
|
||||||
|
number of regions. Each remaining line starts with the number of
|
||||||
|
neighboring regions. Negative indices (e.g., <em>-1</em>) indicate regions
|
||||||
|
outside of the Delaunay triangulation.
|
||||||
|
For the circle-in-square example, the four regions on the square are neighbors to
|
||||||
|
the region-at-infinity.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#FN">FN</a></dt>
|
||||||
|
<dd>list the Delaunay regions for each input site. The first line is the
|
||||||
|
total number of input sites. Each remaining line starts with the number of
|
||||||
|
Delaunay regions. Negative indices (e.g., <em>-1</em>) indicate regions
|
||||||
|
outside of the Delaunay triangulation.
|
||||||
|
For the circle-in-square example, each point on the circle belongs to four
|
||||||
|
Delaunay regions. Use '<a href="qh-optq.htm#Qc">Qc</a> FN'
|
||||||
|
to include coincident input sites and deleted vertices. </dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fa">Fa</a></dt>
|
||||||
|
<dd>print area for each Delaunay region. The first line is the number of regions.
|
||||||
|
The areas follow, one line per region. For the circle-in-square example, the
|
||||||
|
cocircular region has area 0.4. </dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>Input sites</b></dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fc">Fc</a></dt>
|
||||||
|
<dd>list coincident input sites for each Delaunay region.
|
||||||
|
The first line is the number of regions. The remaining lines start with
|
||||||
|
the number of coincident sites and deleted vertices. Deleted vertices
|
||||||
|
indicate highly degenerate input (see'<a href="qh-optf.htm#Fs">Fs</a>').
|
||||||
|
A coincident site is assigned to one Delaunay
|
||||||
|
region. Do not use '<a href="qh-optq.htm#QJn">QJ</a>' with 'Fc'; the joggle will separate
|
||||||
|
coincident sites.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#FP">FP</a></dt>
|
||||||
|
<dd>print coincident input sites with distance to
|
||||||
|
nearest site (i.e., vertex). The first line is the
|
||||||
|
number of coincident sites. Each remaining line starts with the point ID of
|
||||||
|
an input site, followed by the point ID of a coincident point, its region, and distance.
|
||||||
|
Includes deleted vertices which
|
||||||
|
indicate highly degenerate input (see'<a href="qh-optf.htm#Fs">Fs</a>').
|
||||||
|
Do not use '<a href="qh-optq.htm#QJn">QJ</a>' with 'FP'; the joggle will separate
|
||||||
|
coincident sites.</dd>
|
||||||
|
<dt><a href="qh-optf.htm#Fx">Fx</a></dt>
|
||||||
|
<dd>list extreme points of the input sites. These points are on the
|
||||||
|
boundary of the convex hull. The first line is the number of
|
||||||
|
extreme points. Each point is listed, one per line. The circle-in-square example
|
||||||
|
has four extreme points.</dd>
|
||||||
|
<dt> </dt>
|
||||||
|
<dt> </dt>
|
||||||
|
<dd><b>General</b></dd>
|
||||||
|
<dt><a href="qh-optf.htm#FA">FA</a></dt>
|
||||||
|
<dd>compute total area for '<a href="qh-opto.htm#s">s</a>'
|
||||||
|
and '<a href="qh-optf.htm#FS">FS</a>'</dd>
|
||||||
|
<dt><a href="qh-opto.htm#o">o</a></dt>
|
||||||
|
<dd>print lower facets of the corresponding convex hull (a
|
||||||
|
paraboloid)</dd>
|
||||||
|
<dt><a href="qh-opto.htm#m">m</a></dt>
|
||||||
|
<dd>Mathematica output for the lower facets of the paraboloid (2-d triangulations).</dd>
|
||||||
|
<dt><a href="qh-optf.htm#FM">FM</a></dt>
|
||||||
|
<dd>Maple output for the lower facets of the paraboloid (2-d triangulations).</dd>
|
||||||
|
<dt><a href="qh-optg.htm#G">G</a></dt>
|
||||||
|
<dd>Geomview output for the paraboloid (2-d or 3-d triangulations).</dd>
|
||||||
|
<dt><a href="qh-opto.htm#s">s</a></dt>
|
||||||
|
<dd>print summary for the Delaunay triangulation. Use '<a
|
||||||
|
href="qh-optf.htm#Fs">Fs</a>' and '<a
|
||||||
|
href="qh-optf.htm#FS">FS</a>' for numeric data.</dd>
|
||||||
|
</dl>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="controls">qdelaunay
|
||||||
|
controls</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>These options provide additional control:</p>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<dl compact>
|
||||||
|
<dt><a href="qh-optq.htm#Qt">Qt</a></dt>
|
||||||
|
<dd>triangulated output. Qhull triangulates non-simplicial facets. It may produce
|
||||||
|
degenerate facets of zero area.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#QJn">QJ</a></dt>
|
||||||
|
<dd>joggle the input to avoid cospherical and coincident
|
||||||
|
sites. It is less accurate than triangulated output ('Qt').</dd>
|
||||||
|
<dt><a href="qh-optq.htm#Qu">Qu</a></dt>
|
||||||
|
<dd>compute the <a href="qdelau_f.htm">furthest-site Delaunay triangulation</a>.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#Qz">Qz</a></dt>
|
||||||
|
<dd>add a point above the paraboloid to reduce precision
|
||||||
|
errors. Use it for nearly cocircular/cospherical input
|
||||||
|
(e.g., 'rbox c | qdelaunay Qz'). The point is printed for
|
||||||
|
options '<a href="qh-optf.htm#Ft">Ft</a>' and '<a
|
||||||
|
href="qh-opto.htm#o">o</a>'.</dd>
|
||||||
|
<dt><a href="qh-optq.htm#QVn">QVn</a></dt>
|
||||||
|
<dd>select facets adjacent to input site <em>n</em> (marked
|
||||||
|
'good').</dd>
|
||||||
|
<dt><a href="qh-optt.htm#Tv">Tv</a></dt>
|
||||||
|
<dd>verify result.</dd>
|
||||||
|
<dt><a href="qh-optt.htm#TO">TI file</a></dt>
|
||||||
|
<dd>input data from file. The filename may not use spaces or quotes.</dd>
|
||||||
|
<dt><a href="qh-optt.htm#TO">TO file</a></dt>
|
||||||
|
<dd>output results to file. Use single quotes if the filename
|
||||||
|
contains spaces (e.g., <tt>TO 'file with spaces.txt'</tt></dd>
|
||||||
|
<dt><a href="qh-optt.htm#TFn">TFn</a></dt>
|
||||||
|
<dd>report progress after constructing <em>n</em> facets</dd>
|
||||||
|
<dt><a href="qh-optp.htm#PDk">PDk:1</a></dt>
|
||||||
|
<dd>include upper and lower facets in the output. Set <em>k</em>
|
||||||
|
to the last dimension (e.g., 'PD2:1' for 2-d inputs). </dd>
|
||||||
|
<dt><a href="qh-opto.htm#f">f</a></dt>
|
||||||
|
<dd>facet dump. Print the data structure for each facet (i.e., Delaunay region).</dd>
|
||||||
|
</dl>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="graphics">qdelaunay
|
||||||
|
graphics</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>For 2-d and 3-d Delaunay triangulations, Geomview ('qdelaunay <a
|
||||||
|
href="qh-optg.htm#G">G</a>') displays the corresponding convex
|
||||||
|
hull (a paraboloid). </p>
|
||||||
|
|
||||||
|
<p>To view a 2-d Delaunay triangulation, use 'qdelaunay <a
|
||||||
|
href="qh-optg.htm#GDn">GrD2</a>' to drop the last dimension. This
|
||||||
|
is the same as viewing the hull without perspective (see
|
||||||
|
Geomview's 'cameras' menu). </p>
|
||||||
|
|
||||||
|
<p>To view a 3-d Delaunay triangulation, use 'qdelaunay <a
|
||||||
|
href="qh-optg.htm#GDn">GrD3</a>' to drop the last dimension. You
|
||||||
|
may see extra edges. These are interior edges that Geomview moves
|
||||||
|
towards the viewer (see 'lines closer' in Geomview's camera
|
||||||
|
options). Use option '<a href="qh-optg.htm#Gt">Gt</a>' to make
|
||||||
|
the outer ridges transparent in 3-d. See <a
|
||||||
|
href="qh-eg.htm#delaunay">Delaunay and Voronoi examples</a>.</p>
|
||||||
|
|
||||||
|
<p>For 2-d Delaunay triangulations, Mathematica ('<a
|
||||||
|
href="qh-opto.htm#m">m</a>') and Maple ('<a
|
||||||
|
href="qh-optf.htm#FM">FM</a>') output displays the lower facets of the corresponding convex
|
||||||
|
hull (a paraboloid). </p>
|
||||||
|
|
||||||
|
<p>For 2-d, furthest-site Delaunay triangulations, Maple and Mathematica output ('<a
|
||||||
|
href="qh-optq.htm#Qu">Qu</a> <a
|
||||||
|
href="qh-opto.htm#m">m</a>') displays the upper facets of the corresponding convex
|
||||||
|
hull (a paraboloid). </p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="notes">qdelaunay
|
||||||
|
notes</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>You can simplify the Delaunay triangulation by enclosing the input
|
||||||
|
sites in a large square or cube. This is particularly recommended
|
||||||
|
for cocircular or cospherical input data.
|
||||||
|
|
||||||
|
<p>A non-simplicial Delaunay region indicates nearly cocircular or
|
||||||
|
cospherical input sites. To avoid non-simplicial regions either triangulate
|
||||||
|
the output ('<a href="qh-optq.htm#Qt">Qt</a>') or joggle
|
||||||
|
the input ('<a href="qh-optq.htm#QJn">QJ</a>'). Triangulated output
|
||||||
|
is more accurate than joggled input. Alternatively, use an <a
|
||||||
|
href="qh-impre.htm#exact">exact arithmetic code</a>.</p>
|
||||||
|
|
||||||
|
<p>Delaunay triangulations do not include facets that are
|
||||||
|
coplanar with the convex hull of the input sites. A facet is
|
||||||
|
coplanar if the last coefficient of its normal is
|
||||||
|
nearly zero (see <a href="../src/libqhull/user.h#ZEROdelaunay">qh_ZEROdelaunay</a>).
|
||||||
|
|
||||||
|
<p>See <a href=qh-impre.htm#delaunay>Imprecision issues :: Delaunay triangulations</a>
|
||||||
|
for a discussion of precision issues. Deleted vertices indicate
|
||||||
|
highly degenerate input. They are listed in the summary output and
|
||||||
|
option '<a href="qh-optf.htm#Fs">Fs</a>'.</p>
|
||||||
|
|
||||||
|
<p>To compute the Delaunay triangulation of points on a sphere,
|
||||||
|
compute their convex hull. If the sphere is the unit sphere at
|
||||||
|
the origin, the facet normals are the Voronoi vertices of the
|
||||||
|
input. The points may be restricted to a hemisphere. [S. Fortune]
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>The 3-d Delaunay triangulation of regular points on a half
|
||||||
|
spiral (e.g., 'rbox 100 l | qdelaunay') has quadratic size, while the Delaunay triangulation
|
||||||
|
of random 3-d points is
|
||||||
|
approximately linear for reasonably sized point sets.
|
||||||
|
|
||||||
|
<p>With the <a href="qh-code.htm#library">Qhull library</a>, you
|
||||||
|
can use <tt>qh_findbestfacet</tt> in <tt>poly2.c</tt> to locate the facet
|
||||||
|
that contains a point. You should first lift the point to the
|
||||||
|
paraboloid (i.e., the last coordinate is the sum of the squares
|
||||||
|
of the point's coordinates -- <tt>qh_setdelaunay</tt>). Do not use options
|
||||||
|
'<a href="qh-optq.htm#Qbb">Qbb</a>', '<a href="qh-optq.htm#QbB">QbB</a>',
|
||||||
|
'<a href="qh-optq.htm#Qbk">Qbk:n</a>', or '<a
|
||||||
|
href="qh-optq.htm#QBk">QBk:n</a>' since these scale the last
|
||||||
|
coordinate. </p>
|
||||||
|
|
||||||
|
<p>If a point is interior to the convex hull of the input set, it
|
||||||
|
is interior to the adjacent vertices of the Delaunay
|
||||||
|
triangulation. This is demonstrated by the following pipe for
|
||||||
|
point 0:
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
qdelaunay <data s FQ QV0 p | qconvex s Qb3:0B3:0 p
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>The first call to qdelaunay returns the neighboring points of
|
||||||
|
point 0 in the Delaunay triangulation. The second call to qconvex
|
||||||
|
returns the vertices of the convex hull of these points (after
|
||||||
|
dropping the lifted coordinate). If point 0 is interior to the
|
||||||
|
original point set, it is interior to the reduced point set. </p>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="conventions">qdelaunay conventions</a></h3>
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
<p>The following terminology is used for Delaunay triangulations
|
||||||
|
in Qhull for dimension <i>d</i>. The underlying structure is the
|
||||||
|
lower facets of a convex hull in dimension <i>d+1</i>. For
|
||||||
|
further information, see <a href="index.htm#structure">data
|
||||||
|
structures</a> and <a href="qconvex.htm#conventions">convex hull
|
||||||
|
conventions</a>.</p>
|
||||||
|
<blockquote>
|
||||||
|
<ul>
|
||||||
|
<li><em>input site</em> - a point in the input (one dimension
|
||||||
|
lower than a point on the convex hull)</li>
|
||||||
|
<li><em>point</em> - a point has <i>d+1</i> coordinates. The
|
||||||
|
last coordinate is the sum of the squares of the input
|
||||||
|
site's coordinates</li>
|
||||||
|
<li><em>coplanar point</em> - a <em>coincident</em>
|
||||||
|
input site or a deleted vertex. Deleted vertices
|
||||||
|
indicate highly degenerate input.</li>
|
||||||
|
<li><em>vertex</em> - a point on the paraboloid. It
|
||||||
|
corresponds to a unique input site. </li>
|
||||||
|
<li><em>point-at-infinity</em> - a point added above the
|
||||||
|
paraboloid by option '<a href="qh-optq.htm#Qz">Qz</a>'</li>
|
||||||
|
<li><em>lower facet</em> - a facet corresponding to a
|
||||||
|
Delaunay region. The last coefficient of its normal is
|
||||||
|
clearly negative.</li>
|
||||||
|
<li><em>upper facet</em> - a facet corresponding to a
|
||||||
|
furthest-site Delaunay region. The last coefficient of
|
||||||
|
its normal is clearly positive. </li>
|
||||||
|
<li><em>Delaunay region</em> - a
|
||||||
|
lower facet projected to the input sites</li>
|
||||||
|
<li><em>upper Delaunay region</em> - an upper facet projected
|
||||||
|
to the input sites</li>
|
||||||
|
<li><em>non-simplicial facet</em> - more than <em>d</em>
|
||||||
|
input sites are cocircular or cospherical</li>
|
||||||
|
<li><em>good facet</em> - a Delaunay region with optional
|
||||||
|
restrictions by '<a href="qh-optq.htm#QVn">QVn</a>', etc.</li>
|
||||||
|
</ul>
|
||||||
|
</blockquote>
|
||||||
|
</blockquote>
|
||||||
|
<h3><a href="#TOP">»</a><a name="options">qdelaunay options</a></h3>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
qdelaunay- compute the Delaunay triangulation
|
||||||
|
http://www.qhull.org
|
||||||
|
|
||||||
|
input (stdin):
|
||||||
|
first lines: dimension and number of points (or vice-versa).
|
||||||
|
other lines: point coordinates, best if one point per line
|
||||||
|
comments: start with a non-numeric character
|
||||||
|
|
||||||
|
options:
|
||||||
|
Qt - triangulated output
|
||||||
|
QJ - joggle input instead of merging facets
|
||||||
|
Qu - compute furthest-site Delaunay triangulation
|
||||||
|
|
||||||
|
Qhull control options:
|
||||||
|
QJn - randomly joggle input in range [-n,n]
|
||||||
|
Qs - search all points for the initial simplex
|
||||||
|
Qz - add point-at-infinity to Delaunay triangulation
|
||||||
|
QGn - print Delaunay region if visible from point n, -n if not
|
||||||
|
QVn - print Delaunay regions that include point n, -n if not
|
||||||
|
|
||||||
|
Trace options:
|
||||||
|
T4 - trace at level n, 4=all, 5=mem/gauss, -1= events
|
||||||
|
Tc - check frequently during execution
|
||||||
|
Ts - print statistics
|
||||||
|
Tv - verify result: structure, convexity, and in-circle test
|
||||||
|
Tz - send all output to stdout
|
||||||
|
TFn - report summary when n or more facets created
|
||||||
|
TI file - input data from file, no spaces or single quotes
|
||||||
|
TO file - output results to file, may be enclosed in single quotes
|
||||||
|
TPn - turn on tracing when point n added to hull
|
||||||
|
TMn - turn on tracing at merge n
|
||||||
|
TWn - trace merge facets when width > n
|
||||||
|
TVn - stop qhull after adding point n, -n for before (see TCn)
|
||||||
|
TCn - stop qhull after building cone for point n (see TVn)
|
||||||
|
|
||||||
|
Precision options:
|
||||||
|
Cn - radius of centrum (roundoff added). Merge facets if non-convex
|
||||||
|
An - cosine of maximum angle. Merge facets if cosine > n or non-convex
|
||||||
|
C-0 roundoff, A-0.99/C-0.01 pre-merge, A0.99/C0.01 post-merge
|
||||||
|
Rn - randomly perturb computations by a factor of [1-n,1+n]
|
||||||
|
Wn - min facet width for outside point (before roundoff)
|
||||||
|
|
||||||
|
Output formats (may be combined; if none, produces a summary to stdout):
|
||||||
|
f - facet dump
|
||||||
|
G - Geomview output (see below)
|
||||||
|
i - vertices incident to each Delaunay region
|
||||||
|
m - Mathematica output (2-d only, lifted to a paraboloid)
|
||||||
|
o - OFF format (dim, points, and facets as a paraboloid)
|
||||||
|
p - point coordinates (lifted to a paraboloid)
|
||||||
|
s - summary (stderr)
|
||||||
|
|
||||||
|
More formats:
|
||||||
|
Fa - area for each Delaunay region
|
||||||
|
FA - compute total area for option 's'
|
||||||
|
Fc - count plus coincident points for each Delaunay region
|
||||||
|
Fd - use cdd format for input (homogeneous with offset first)
|
||||||
|
FD - use cdd format for numeric output (offset first)
|
||||||
|
FF - facet dump without ridges
|
||||||
|
FI - ID of each Delaunay region
|
||||||
|
Fm - merge count for each Delaunay region (511 max)
|
||||||
|
FM - Maple output (2-d only, lifted to a paraboloid)
|
||||||
|
Fn - count plus neighboring region for each Delaunay region
|
||||||
|
FN - count plus neighboring region for each point
|
||||||
|
FO - options and precision constants
|
||||||
|
FP - nearest point and distance for each coincident point
|
||||||
|
FQ - command used for qdelaunay
|
||||||
|
Fs - summary: #int (8), dimension, #points, tot vertices, tot facets,
|
||||||
|
for output: #vertices, #Delaunay regions,
|
||||||
|
#coincident points, #non-simplicial regions
|
||||||
|
#real (2), max outer plane, min vertex
|
||||||
|
FS - sizes: #int (0)
|
||||||
|
#real (2), tot area, 0
|
||||||
|
Fv - count plus vertices for each Delaunay region
|
||||||
|
Fx - extreme points of Delaunay triangulation (on convex hull)
|
||||||
|
|
||||||
|
Geomview options (2-d and 3-d)
|
||||||
|
Ga - all points as dots
|
||||||
|
Gp - coplanar points and vertices as radii
|
||||||
|
Gv - vertices as spheres
|
||||||
|
Gi - inner planes only
|
||||||
|
Gn - no planes
|
||||||
|
Go - outer planes only
|
||||||
|
Gc - centrums
|
||||||
|
Gh - hyperplane intersections
|
||||||
|
Gr - ridges
|
||||||
|
GDn - drop dimension n in 3-d and 4-d output
|
||||||
|
Gt - transparent outer ridges to view 3-d Delaunay
|
||||||
|
|
||||||
|
Print options:
|
||||||
|
PAn - keep n largest Delaunay regions by area
|
||||||
|
Pdk:n - drop facet if normal[k] <= n (default 0.0)
|
||||||
|
PDk:n - drop facet if normal[k] >= n
|
||||||
|
Pg - print good Delaunay regions (needs 'QGn' or 'QVn')
|
||||||
|
PFn - keep Delaunay regions whose area is at least n
|
||||||
|
PG - print neighbors of good regions (needs 'QGn' or 'QVn')
|
||||||
|
PMn - keep n Delaunay regions with most merges
|
||||||
|
Po - force output. If error, output neighborhood of facet
|
||||||
|
Pp - do not report precision problems
|
||||||
|
|
||||||
|
. - list of all options
|
||||||
|
- - one line descriptions of all options
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<!-- Navigation links -->
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p><b>Up:</b> <a href="http://www.qhull.org">Home page</a> for Qhull<br>
|
||||||
|
<b>Up:</b> <a href="index.htm#TOC">Qhull manual</a>: Table of Contents<br>
|
||||||
|
<b>To:</b> <a href="qh-quick.htm#programs">Programs</a>
|
||||||
|
• <a href="qh-quick.htm#options">Options</a>
|
||||||
|
• <a href="qh-opto.htm#output">Output</a>
|
||||||
|
• <a href="qh-optf.htm#format">Formats</a>
|
||||||
|
• <a href="qh-optg.htm#geomview">Geomview</a>
|
||||||
|
• <a href="qh-optp.htm#print">Print</a>
|
||||||
|
• <a href="qh-optq.htm#qhull">Qhull</a>
|
||||||
|
• <a href="qh-optc.htm#prec">Precision</a>
|
||||||
|
• <a href="qh-optt.htm#trace">Trace</a>
|
||||||
|
• <a href="../src/libqhull_r/index.htm">Functions</a><br>
|
||||||
|
<b>To:</b> <a href="#synopsis">sy</a>nopsis
|
||||||
|
• <a href="#input">in</a>put • <a href="#outputs">ou</a>tputs
|
||||||
|
• <a href="#controls">co</a>ntrols • <a href="#graphics">gr</a>aphics
|
||||||
|
• <a href="#notes">no</a>tes • <a href="#conventions">co</a>nventions
|
||||||
|
• <a href="#options">op</a>tions
|
||||||
|
<!-- GC common information -->
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<p><a href="http://www.geom.uiuc.edu/"><img src="qh--geom.gif"
|
||||||
|
align="middle" width="40" height="40"></a><i>The Geometry Center
|
||||||
|
Home Page </i></p>
|
||||||
|
|
||||||
|
<p>Comments to: <a href=mailto:qhull@qhull.org>qhull@qhull.org</a>
|
||||||
|
</a><br>
|
||||||
|
Created: Sept. 25, 1995 --- <!-- hhmts start --> Last modified: see top <!-- hhmts end --> </p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||