mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-13 08:48:58 +08:00
Merge branch 'master' into gui3-shortcuts
This commit is contained in:
commit
dd6864314d
4
.github/ISSUE_TEMPLATE.md
vendored
4
.github/ISSUE_TEMPLATE.md
vendored
@ -1,7 +1,9 @@
|
||||
### Version
|
||||
_Version of Slic3r used goes here_
|
||||
|
||||
_Use `About->About Slic3r` for release versions_
|
||||
_Use `About->About Slic3r` for release versions._
|
||||
|
||||
_Do not report Prusa3D Slic3r bugs here without confirming it is a problem on a development release of Slic3r, or your issue will be closed. *Only* use normal Slic3r version IDs._
|
||||
|
||||
_For -dev versions, use `git describe --tag` or get the hash value for the version you downloaded or `git rev-parse HEAD`_
|
||||
|
||||
|
26
appveyor.yml
26
appveyor.yml
@ -7,6 +7,7 @@ environment:
|
||||
SLIC3R_STATIC: 1
|
||||
SLIC3R_VERSION: 1.3.0
|
||||
BOOST_DIR: C:\dev\boost_1_63_0
|
||||
WXDIR: C:\dev\wxwidgets
|
||||
WXSHARED: SHARED=0
|
||||
FORCE_WX_BUILD: 0
|
||||
FORCE_BOOST_REINSTALL: 0
|
||||
@ -14,32 +15,37 @@ environment:
|
||||
secure: QfeTOSKXz1uFCEACqFKLNw==
|
||||
UPLOAD_USER:
|
||||
secure: fYPwnI3p6HNR+eMRJR3JfmyNolFn+Uc0MUn2bBXp9uU=
|
||||
matrix:
|
||||
- ARCH: 64bit
|
||||
- ARCH: 32bit
|
||||
|
||||
install:
|
||||
- IF DEFINED ENC_SECRET nuget install secure-file -ExcludeVersion
|
||||
- IF DEFINED ENC_SECRET secure-file\tools\secure-file -decrypt package/deploy/slic3r-upload.ppk.enc -secret %ENC_SECRET%
|
||||
- ps: "& package/win/appveyor_preinstall.ps1"
|
||||
cache:
|
||||
- C:\Users\appveyor\boost.1.63.0.7z
|
||||
- C:\Users\appveyor\local-lib.7z
|
||||
- C:\Strawberry\perl\site
|
||||
- C:\Users\appveyor\freeglut.7z
|
||||
- C:\users\appveyor\strawberry.msi
|
||||
- C:\Users\appveyor\local-lib-64bit.7z
|
||||
- C:\Users\appveyor\local-lib-32bit.7z
|
||||
- C:\Users\appveyor\freeglut.64bit.7z
|
||||
- C:\Users\appveyor\freeglut.32bit.7z
|
||||
- C:\users\appveyor\strawberry.64bit.msi
|
||||
- C:\users\appveyor\strawberry.32bit.msi
|
||||
- C:\Users\appveyor\winscp.zip
|
||||
- C:\Users\appveyor\extra_perl.7z
|
||||
- C:\Users\appveyor\wxwidgets.7z
|
||||
- C:\Users\appveyor\wxwidgets-64bit.7z
|
||||
- C:\Users\appveyor\wxwidgets-32bit.7z
|
||||
- C:\Users\appveyor\boost.1.63.0.32bit.7z
|
||||
- C:\Users\appveyor\boost.1.63.0.64bit.7z
|
||||
build_script:
|
||||
- ps: "& package/win/appveyor_buildscript.ps1"
|
||||
test_script:
|
||||
- ps: "mkdir C:\\Andrés\nwget \"http://www.thingiverse.com/download:73351\" -o\"C:\\Andrés\\5mm.stl\"\necho \"bed_temperature=60\" > C:\\Andrés\\test.ini\n\ncd C:\\projects\\slic3r\nperl slic3r.pl --load \"C:\\Andrés\\test.ini\" \"C:\\Andrés\\5mm.stl\"\n\nif (!(Test-Path \"C:\\Andrés\\5mm.gcode\")) {\necho \"IS IT HERE\"\n}"
|
||||
artifacts:
|
||||
- path: .\slic3r*zip
|
||||
name: slic3r-dev
|
||||
deploy_script:
|
||||
- ps: "& package/win/appveyor_deploy.ps1"
|
||||
- ps: "cd C:/projects/slic3r; & package/win/appveyor_deploy.ps1"
|
||||
on_success:
|
||||
- ps:
|
||||
on_failure:
|
||||
- ps:
|
||||
- ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
on_finish:
|
||||
- ps:
|
||||
|
@ -300,6 +300,8 @@ sub resume_all_threads {
|
||||
sub encode_path {
|
||||
my ($path) = @_;
|
||||
|
||||
return undef if !defined $path;
|
||||
|
||||
$path = Unicode::Normalize::NFC($path);
|
||||
$path = Encode::encode(locale_fs => $path);
|
||||
|
||||
@ -310,6 +312,8 @@ sub encode_path {
|
||||
sub decode_path {
|
||||
my ($path) = @_;
|
||||
|
||||
return undef if !defined $path;
|
||||
|
||||
$path = Encode::decode(locale_fs => $path)
|
||||
unless utf8::is_utf8($path);
|
||||
|
||||
|
@ -95,7 +95,8 @@ sub load {
|
||||
|
||||
# legacy syntax of load()
|
||||
my $config = $class->new;
|
||||
$config->_load(Slic3r::encode_path($file));
|
||||
|
||||
$config->_load($file);
|
||||
return $config;
|
||||
}
|
||||
|
||||
@ -103,7 +104,7 @@ sub save {
|
||||
my $self = shift;
|
||||
my ($file) = @_;
|
||||
|
||||
return $self->_save(Slic3r::encode_path($file));
|
||||
return $self->_save($file);
|
||||
}
|
||||
|
||||
# Deserialize a perl hash into the underlying C++ Slic3r::DynamicConfig class,
|
||||
@ -269,12 +270,6 @@ sub validate {
|
||||
qw(perimeter infill solid_infill top_infill support_material first_layer);
|
||||
}
|
||||
|
||||
# support material
|
||||
if ($self->support_material) {
|
||||
die "Value of 0 is illegal. Use some % value instead (e.g. 150%) for auto.\n"
|
||||
if $self->support_material_threshold =~ /^0+/;
|
||||
}
|
||||
|
||||
|
||||
# general validation, quick and dirty
|
||||
foreach my $opt_key (@{$self->get_keys}) {
|
||||
|
@ -93,14 +93,18 @@ our $Settings = {
|
||||
|
||||
our $have_button_icons = &Wx::wxVERSION_STRING =~ / (?:2\.9\.[1-9]|3\.)/;
|
||||
our $small_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
$small_font->SetPointSize(11) if !&Wx::wxMSW;
|
||||
$small_font->SetPointSize(11) if &Wx::wxMAC;
|
||||
our $small_bold_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
$small_bold_font->SetPointSize(11) if !&Wx::wxMSW;
|
||||
$small_bold_font->SetPointSize(11) if &Wx::wxMAC;
|
||||
$small_bold_font->SetWeight(wxFONTWEIGHT_BOLD);
|
||||
our $medium_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
$medium_font->SetPointSize(12);
|
||||
our $grey = Wx::Colour->new(200,200,200);
|
||||
|
||||
# to use in ScrolledWindow::SetScrollRate(xstep, ystep)
|
||||
# step related to system font point size
|
||||
our $scroll_step = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)->GetPointSize;
|
||||
|
||||
our $VERSION_CHECK_EVENT : shared = Wx::NewEventType;
|
||||
|
||||
our $DLP_projection_screen;
|
||||
|
@ -330,6 +330,19 @@ sub set_viewport_from_scene {
|
||||
$self->_dirty(1);
|
||||
}
|
||||
|
||||
sub zoom{
|
||||
my ($self, $direction) = @_;
|
||||
if( $direction eq 'in'){
|
||||
$self->_zoom($self->_zoom / (1-0.3));
|
||||
}
|
||||
elsif($direction eq 'out'){
|
||||
$self->_zoom($self->_zoom / (1+0.3));
|
||||
}
|
||||
$self->on_viewport_changed->() if $self->on_viewport_changed;
|
||||
$self->_dirty(1);
|
||||
$self->Refresh;
|
||||
}
|
||||
|
||||
# Set the camera to a default orientation,
|
||||
# zoom to volumes.
|
||||
sub select_view {
|
||||
|
@ -40,7 +40,7 @@ sub new {
|
||||
|
||||
EVT_LEFT_DOWN($btn, sub {
|
||||
my $menu = Wx::Menu->new;
|
||||
my %presets = map { $_->name => $_ } wxTheApp->presets('printer');
|
||||
my %presets = map { $_->name => $_ } @{wxTheApp->presets->{printer}};
|
||||
|
||||
# remove printers that already exist
|
||||
my @panels = $self->print_panels;
|
||||
|
@ -182,6 +182,10 @@ sub _init_menubar {
|
||||
wxTheApp->append_menu_item($self->{plater_menu}, "Select Prev Object\tCtrl+Left", 'Select Previous Object in the plater', sub {
|
||||
$plater->select_prev;
|
||||
}, undef, 'arrow_left.png');
|
||||
wxTheApp->append_menu_item($self->{plater_menu}, "Zoom In\tCtrl+up", 'Zoom In',
|
||||
sub { $self->{plater}->zoom('in') }, undef, 'zoom_in.png');
|
||||
wxTheApp->append_menu_item($self->{plater_menu}, "Zoom Out\tCtrl+down", 'Zoom Out',
|
||||
sub { $self->{plater}->zoom('out') }, undef, 'zoom_out.png');
|
||||
$self->{plater_menu}->AppendSeparator();
|
||||
wxTheApp->append_menu_item($self->{plater_menu}, "Export G-code...", 'Export current plate as G-code', sub {
|
||||
$plater->export_gcode;
|
||||
@ -192,8 +196,8 @@ sub _init_menubar {
|
||||
wxTheApp->append_menu_item($self->{plater_menu}, "Export plate with modifiers as AMF...", 'Export current plate as AMF, including all modifier meshes', sub {
|
||||
$plater->export_amf;
|
||||
}, undef, 'brick_go.png');
|
||||
|
||||
$self->{object_menu} = $self->{plater}->object_menu;
|
||||
$self->on_plater_object_list_changed(0);
|
||||
$self->on_plater_selection_changed(0);
|
||||
}
|
||||
|
||||
@ -309,6 +313,14 @@ sub is_loaded {
|
||||
return $self->{loaded};
|
||||
}
|
||||
|
||||
sub on_plater_object_list_changed {
|
||||
my ($self, $have_objects) = @_;
|
||||
|
||||
return if !defined $self->{plater_menu};
|
||||
$self->{plater_menu}->Enable($_->GetId, $have_objects)
|
||||
for $self->{plater_menu}->GetMenuItems;
|
||||
}
|
||||
|
||||
sub on_plater_selection_changed {
|
||||
my ($self, $have_selection) = @_;
|
||||
|
||||
@ -457,9 +469,9 @@ sub repair_stl {
|
||||
}
|
||||
|
||||
my $tmesh = Slic3r::TriangleMesh->new;
|
||||
$tmesh->ReadSTLFile(Slic3r::encode_path($input_file));
|
||||
$tmesh->ReadSTLFile($input_file);
|
||||
$tmesh->repair;
|
||||
$tmesh->WriteOBJFile(Slic3r::encode_path($output_file));
|
||||
$tmesh->WriteOBJFile($output_file);
|
||||
Slic3r::GUI::show_info($self, "Your file was repaired.", "Repair");
|
||||
}
|
||||
|
||||
@ -626,7 +638,7 @@ sub select_tab {
|
||||
# Set a camera direction, zoom to all objects.
|
||||
sub select_view {
|
||||
my ($self, $direction) = @_;
|
||||
|
||||
|
||||
$self->{plater}->select_view($direction);
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ sub new {
|
||||
my $on_instances_moved = sub {
|
||||
$self->on_model_change;
|
||||
};
|
||||
|
||||
|
||||
# Initialize 3D plater
|
||||
if ($Slic3r::GUI::have_OpenGL) {
|
||||
$self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{config});
|
||||
@ -1504,7 +1504,7 @@ sub pause_background_process {
|
||||
return 1;
|
||||
} elsif (defined $self->{apply_config_timer} && $self->{apply_config_timer}->IsRunning) {
|
||||
$self->{apply_config_timer}->Stop;
|
||||
return 1;
|
||||
return 0; # we didn't actually pause any running thread; need to reschedule
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2171,6 +2171,9 @@ sub object_list_changed {
|
||||
$self->{htoolbar}->EnableTool($_, $have_objects)
|
||||
for (TB_RESET, TB_ARRANGE);
|
||||
}
|
||||
|
||||
# prepagate the event to the frame (a custom Wx event would be cleaner)
|
||||
$self->GetFrame->on_plater_object_list_changed($have_objects);
|
||||
}
|
||||
|
||||
sub selection_changed {
|
||||
@ -2442,6 +2445,21 @@ sub select_view {
|
||||
}
|
||||
}
|
||||
|
||||
sub zoom{
|
||||
my ($self, $direction) = @_;
|
||||
#Apply Zoom to the current active tab
|
||||
my ($currentSelection) = $self->{preview_notebook}->GetSelection;
|
||||
if($currentSelection == 0){
|
||||
$self->{canvas3D}->zoom($direction) if($self->{canvas3D});
|
||||
}
|
||||
elsif($currentSelection == 2){ #3d Preview tab
|
||||
$self->{preview3D}->canvas->zoom($direction) if($self->{preview3D});
|
||||
}
|
||||
elsif($currentSelection == 3) { #2D toolpaths tab
|
||||
$self->{toolpaths2D}->{canvas}->zoom($direction) if($self->{toolpaths2D});
|
||||
}
|
||||
}
|
||||
|
||||
package Slic3r::GUI::Plater::DropTarget;
|
||||
use Wx::DND;
|
||||
use base 'Wx::FileDropTarget';
|
||||
|
@ -60,6 +60,8 @@ sub new {
|
||||
} elsif ($key == 68 || $key == 317) {
|
||||
$slider->SetValue($slider->GetValue - 1);
|
||||
$self->set_z($self->{layers_z}[$slider->GetValue]);
|
||||
} else {
|
||||
$event->Skip;
|
||||
}
|
||||
});
|
||||
|
||||
@ -187,21 +189,21 @@ sub new {
|
||||
$zoom /= 10;
|
||||
$self->_zoom($self->_zoom / (1-$zoom));
|
||||
$self->_zoom(1) if $self->_zoom > 1; # prevent from zooming out too much
|
||||
|
||||
|
||||
{
|
||||
# In order to zoom around the mouse point we need to translate
|
||||
# the camera target. This math is almost there but not perfect yet...
|
||||
my $camera_bb_size = $self->_camera_bb->size;
|
||||
my $size = Slic3r::Pointf->new($self->GetSizeWH);
|
||||
my $pos = Slic3r::Pointf->new($e->GetPositionXY);
|
||||
|
||||
|
||||
# calculate the zooming center in pixel coordinates relative to the viewport center
|
||||
my $vec = Slic3r::Pointf->new($pos->x - $size->x/2, $pos->y - $size->y/2); #-
|
||||
|
||||
|
||||
# calculate where this point will end up after applying the new zoom
|
||||
my $vec2 = $vec->clone;
|
||||
$vec2->scale($old_zoom / $self->_zoom);
|
||||
|
||||
|
||||
# move the camera target by the difference of the two positions
|
||||
$self->_camera_target->translate(
|
||||
-($vec->x - $vec2->x) * $camera_bb_size->x / $size->x,
|
||||
@ -217,6 +219,20 @@ sub new {
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub zoom{
|
||||
my($self, $direction) = @_;
|
||||
if( $direction eq 'in'){
|
||||
$self->_zoom($self->_zoom / (1+0.3));
|
||||
}
|
||||
elsif($direction eq 'out'){
|
||||
$self->_zoom($self->_zoom / (1-0.3));
|
||||
$self->_zoom(1) if $self->_zoom > 1; # prevent from zooming out too much
|
||||
}
|
||||
#apply changes
|
||||
$self->_dirty(1);
|
||||
$self->Refresh;
|
||||
}
|
||||
|
||||
sub mouse_event {
|
||||
my ($self, $e) = @_;
|
||||
|
||||
|
@ -58,6 +58,8 @@ sub new {
|
||||
} elsif ($key == 68 || $key == 317) {
|
||||
$slider->SetValue($slider->GetValue - 1);
|
||||
$self->set_z($self->{layers_z}[$slider->GetValue]);
|
||||
} else {
|
||||
$event->Skip;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -30,6 +30,9 @@ sub new {
|
||||
# notify tabs
|
||||
$self->{layers}->Closing;
|
||||
|
||||
# save window size
|
||||
wxTheApp->save_window_pos($self, "object_settings");
|
||||
|
||||
$self->EndModal(wxID_OK);
|
||||
$self->Destroy;
|
||||
});
|
||||
@ -41,6 +44,8 @@ sub new {
|
||||
$self->SetSizer($sizer);
|
||||
$self->SetMinSize($self->GetSize);
|
||||
|
||||
wxTheApp->restore_window_pos($self, "object_settings");
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
@ -53,16 +53,23 @@ sub new {
|
||||
EVT_LEFT_DOWN($btn, sub {
|
||||
my $menu = Wx::Menu->new;
|
||||
my $last_cat = '';
|
||||
|
||||
# create category submenus
|
||||
my %categories = (); # category => submenu
|
||||
foreach my $opt_key (@{$self->{options}}) {
|
||||
# add icon, if we have one for this category
|
||||
my $icon;
|
||||
if (my $cat = $Slic3r::Config::Options->{$opt_key}{category}) {
|
||||
if ($last_cat && $cat ne $last_cat) {
|
||||
$menu->AppendSeparator;
|
||||
}
|
||||
$last_cat = $cat;
|
||||
$icon = $icons{$cat};
|
||||
$categories{$cat} //= Wx::Menu->new;
|
||||
}
|
||||
}
|
||||
|
||||
# append submenus to main menu
|
||||
foreach my $cat (sort keys %categories) {
|
||||
wxTheApp->append_submenu($menu, $cat, "", $categories{$cat}, undef, $icons{$cat});
|
||||
}
|
||||
|
||||
# append options to submenus
|
||||
foreach my $opt_key (@{$self->{options}}) {
|
||||
my $cat = $Slic3r::Config::Options->{$opt_key}{category} or next;
|
||||
|
||||
my $cb = sub {
|
||||
$self->{config}->set($opt_key, $self->{default_config}->get($opt_key));
|
||||
@ -70,8 +77,8 @@ sub new {
|
||||
$self->{on_change}->($opt_key) if $self->{on_change};
|
||||
};
|
||||
|
||||
wxTheApp->append_menu_item($menu, $self->{option_labels}{$opt_key},
|
||||
$Slic3r::Config::Options->{$opt_key}{tooltip}, $cb, undef, $icon);
|
||||
wxTheApp->append_menu_item($categories{$cat}, $self->{option_labels}{$opt_key},
|
||||
$Slic3r::Config::Options->{$opt_key}{tooltip}, $cb);
|
||||
}
|
||||
$self->PopupMenu($menu, $btn->GetPosition);
|
||||
$menu->Destroy;
|
||||
@ -83,7 +90,9 @@ sub new {
|
||||
}
|
||||
|
||||
$self->SetSizer($self->{sizer});
|
||||
$self->SetScrollbars(0, 1, 0, 1);
|
||||
|
||||
# http://docs.wxwidgets.org/3.0/classwx_scrolled.html#details
|
||||
$self->SetScrollRate(0, $Slic3r::GUI::scroll_step);
|
||||
|
||||
$self->set_opt_keys($params{opt_keys}) if $params{opt_keys};
|
||||
$self->update_optgroup;
|
||||
@ -108,17 +117,11 @@ sub set_config {
|
||||
sub set_opt_keys {
|
||||
my ($self, $opt_keys) = @_;
|
||||
|
||||
# sort options by category+label
|
||||
# sort options by label
|
||||
$self->{option_labels} = {};
|
||||
foreach my $opt_key (@$opt_keys) {
|
||||
my $def = $Slic3r::Config::Options->{$opt_key} or next;
|
||||
if (!$def->{category}) {
|
||||
#printf "Skipping %s\n", $opt_key;
|
||||
next;
|
||||
}
|
||||
$self->{option_labels}{$opt_key} = sprintf '%s > %s',
|
||||
$def->{category},
|
||||
$def->{full_label} // $def->{label};
|
||||
$self->{option_labels}{$opt_key} = $def->{full_label} // $def->{label};
|
||||
};
|
||||
$self->{options} = [ sort { $self->{option_labels}{$a} cmp $self->{option_labels}{$b} } keys %{$self->{option_labels}} ];
|
||||
}
|
||||
|
@ -1602,11 +1602,12 @@ sub new {
|
||||
$self->{title} = $title;
|
||||
$self->{iconID} = $iconID;
|
||||
|
||||
$self->SetScrollbars(1, 1, 1, 1);
|
||||
|
||||
$self->{vsizer} = Wx::BoxSizer->new(wxVERTICAL);
|
||||
$self->SetSizer($self->{vsizer});
|
||||
|
||||
# http://docs.wxwidgets.org/3.0/classwx_scrolled.html#details
|
||||
$self->SetScrollRate($Slic3r::GUI::scroll_step, $Slic3r::GUI::scroll_step);
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
@ -42,8 +42,10 @@ sub size {
|
||||
sub process {
|
||||
my ($self) = @_;
|
||||
|
||||
$self->status_cb->(20, "Generating perimeters");
|
||||
$_->make_perimeters for @{$self->objects};
|
||||
### No need to call this as we call it as part of prepare_infill()
|
||||
### until we fix the idempotency issue.
|
||||
###$self->status_cb->(20, "Generating perimeters");
|
||||
###$_->make_perimeters for @{$self->objects};
|
||||
|
||||
$self->status_cb->(70, "Infilling layers");
|
||||
$_->infill for @{$self->objects};
|
||||
|
@ -403,8 +403,8 @@ sub process_layer {
|
||||
push @mm3_per_mm, $layer->support_interface_fills->min_mm3_per_mm;
|
||||
}
|
||||
}
|
||||
# filter out 0-width segments
|
||||
@mm3_per_mm = grep $_ > 0.000001, @mm3_per_mm;
|
||||
# ignore too thin segments
|
||||
@mm3_per_mm = grep $_ > 0.01, @mm3_per_mm;
|
||||
if (@mm3_per_mm) {
|
||||
my $min_mm3_per_mm = min(@mm3_per_mm);
|
||||
# In order to honor max_print_speed we need to find a target volumetric
|
||||
|
@ -208,20 +208,29 @@ sub contact_area {
|
||||
|
||||
if ($conf->dont_support_bridges) {
|
||||
# compute the area of bridging perimeters
|
||||
# Note: this is duplicate code from GCode.pm, we need to refactor
|
||||
|
||||
my $bridged_perimeters; # Polygons
|
||||
{
|
||||
my $bridge_flow = $layerm->flow(FLOW_ROLE_PERIMETER, 1);
|
||||
|
||||
my $nozzle_diameter = $self->print_config->get_at('nozzle_diameter', $layerm->region->config->perimeter_extruder-1);
|
||||
my $lower_grown_slices = offset([ map @$_, @{$lower_layer->slices} ], +scale($nozzle_diameter/2));
|
||||
# Get the lower layer's slices and grow them by half the nozzle diameter
|
||||
# because we will consider the upper perimeters supported even if half nozzle
|
||||
# falls outside the lower slices.
|
||||
my $lower_grown_slices;
|
||||
{
|
||||
my $nozzle_diameter = $self->print_config->get_at('nozzle_diameter', $layerm->region->config->perimeter_extruder-1);
|
||||
$lower_grown_slices = offset(
|
||||
[ map @$_, @{$lower_layer->slices} ],
|
||||
+scale($nozzle_diameter/2),
|
||||
);
|
||||
}
|
||||
|
||||
# TODO: split_at_first_point() could split a bridge mid-way
|
||||
my @overhang_perimeters =
|
||||
map { $_->isa('Slic3r::ExtrusionLoop') ? $_->polygon->split_at_first_point : $_->polyline->clone }
|
||||
map @$_, @{$layerm->perimeters};
|
||||
# Get all perimeters as polylines.
|
||||
# TODO: split_at_first_point() (called by as_polyline() for ExtrusionLoops)
|
||||
# could split a bridge mid-way
|
||||
my @overhang_perimeters = map $_->as_polyline, @{$layerm->perimeters->flatten};
|
||||
|
||||
# Only consider the overhang parts of such perimeters,
|
||||
# overhangs being those parts not supported by
|
||||
# workaround for Clipper bug, see Slic3r::Polygon::clip_as_polyline()
|
||||
$_->[0]->translate(1,0) for @overhang_perimeters;
|
||||
@overhang_perimeters = @{diff_pl(
|
||||
@ -243,11 +252,16 @@ sub contact_area {
|
||||
|
||||
# convert bridging polylines into polygons by inflating them with their thickness
|
||||
{
|
||||
# since we're dealing with bridges, we can't assume width is larger than spacing,
|
||||
# so we take the largest value and also apply safety offset to be ensure no gaps
|
||||
# are left in between
|
||||
my $w = max($bridge_flow->scaled_width, $bridge_flow->scaled_spacing);
|
||||
# For bridges we can't assume width is larger than spacing because they
|
||||
# are positioned according to non-bridging perimeters spacing.
|
||||
my $w = max(
|
||||
$bridge_flow->scaled_width,
|
||||
$bridge_flow->scaled_spacing,
|
||||
$fw, # width of external perimeters
|
||||
$layerm->flow(FLOW_ROLE_PERIMETER)->scaled_width,
|
||||
);
|
||||
$bridged_perimeters = union([
|
||||
# Also apply safety offset to ensure no gaps are left in between.
|
||||
map @{$_->grow($w/2 + 10)}, @overhang_perimeters
|
||||
]);
|
||||
}
|
||||
@ -258,7 +272,7 @@ sub contact_area {
|
||||
my @bridges = map $_->expolygon,
|
||||
grep $_->bridge_angle != -1,
|
||||
@{$layerm->fill_surfaces->filter_by_type(S_TYPE_BOTTOMBRIDGE)};
|
||||
|
||||
|
||||
$diff = diff(
|
||||
$diff,
|
||||
[
|
||||
|
@ -133,6 +133,13 @@ sub mesh {
|
||||
$facets = [
|
||||
[0,1,2],[1,0,3],[2,1,4],[2,5,0],[0,6,3],[1,3,7],[1,8,4],[4,9,2],[10,5,2],[5,6,0],[6,11,3],[3,12,7],[7,8,1],[4,8,11],[4,11,9],[9,10,2],[10,13,5],[14,6,5],[9,11,6],[11,12,3],[12,8,7],[11,8,15],[13,10,9],[5,13,14],[14,13,6],[6,13,9],[15,12,11],[15,8,12]
|
||||
];
|
||||
} elsif ($name eq 'bridge_with_hole') {
|
||||
$vertices = [
|
||||
[75,69.5,8],[80,76.9091644287109,8],[75,94.5,8],[125,69.5,8],[120,76.9091644287109,8],[120,87.0908355712891,8],[80,87.0908355712891,8],[125,94.5,8],[80,87.0908355712891,5],[120,87.0908355712891,5],[125,94.5,0],[120,69.5,0],[120,94.5,0],[125,69.5,0],[120,94.5,5],[80,94.5,5],[80,94.5,0],[75,94.5,0],[80,69.5,5],[80,69.5,0],[80,76.9091644287109,5],[120,69.5,5],[75,69.5,0],[120,76.9091644287109,5]
|
||||
];
|
||||
$facets = [
|
||||
[0,1,2],[1,0,3],[1,3,4],[4,3,5],[2,6,7],[6,2,1],[7,6,5],[7,5,3],[5,8,9],[8,5,6],[10,11,12],[11,10,13],[14,8,15],[8,14,9],[2,16,17],[16,2,15],[15,2,14],[14,10,12],[10,14,7],[7,14,2],[16,18,19],[18,16,20],[20,16,1],[1,16,8],[8,16,15],[6,1,8],[3,11,13],[11,3,21],[21,3,18],[18,22,19],[22,18,0],[0,18,3],[16,22,17],[22,16,19],[2,22,0],[22,2,17],[5,23,4],[23,11,21],[11,23,12],[12,23,9],[9,23,5],[12,9,14],[23,18,20],[18,23,21],[10,3,13],[3,10,7],[1,23,20],[23,1,4]
|
||||
];
|
||||
} elsif ($name eq 'step') {
|
||||
$vertices = [
|
||||
[0,20,5],[0,20,0],[0,0,5],[0,0,0],[20,0,0],[20,0,5],[1,19,5],[1,1,5],[19,1,5],[20,20,5],[19,19,5],[20,20,0],[19,19,10],[1,19,10],[1,1,10],[19,1,10]
|
||||
|
@ -1,20 +1,26 @@
|
||||
if (!(Test-Path "C:\users\appveyor\local-lib.7z")) {
|
||||
wget "http://www.siusgs.com/slic3r/buildserver/win/slic3r-perl-dependencies-5.24.0-win-seh-gcc6.3.0-x64.7z" -o "C:\users\appveyor\local-lib.7z" | Write-Output
|
||||
if (!(Test-Path "C:\users\appveyor\local-lib-$env:ARCH.7z")) {
|
||||
wget "https://bintray.com/lordofhyphens/Slic3r/download_file?file_path=local-lib-$env:ARCH.7z" -o "C:\users\appveyor\local-lib-$env:ARCH.7z" | Write-Output
|
||||
}
|
||||
|
||||
if (Test-Path "C:\users\appveyor\local-lib.7z") {
|
||||
cmd /c "7z x C:\Users\appveyor\local-lib.7z -oC:\projects\slic3r" -y | Write-Output
|
||||
if (Test-Path "C:\users\appveyor\local-lib-$env:ARCH.7z") {
|
||||
cmd /c "7z x C:\Users\appveyor\local-lib-$env:ARCH.7z -oC:\projects\slic3r" -y | Write-Output
|
||||
rm -r 'C:\projects\slic3r\local-lib\Slic3r*'
|
||||
}
|
||||
|
||||
$env:Path = "C:\Strawberry\c\bin;C:\Strawberry\perl\bin;" + $env:Path
|
||||
cd C:\projects\slic3r
|
||||
|
||||
rm -r 'C:\Program Files (x86)\Microsoft Vis*\bin' -Force
|
||||
|
||||
Add-AppveyorCompilationMessage -Message "Building Slic3r XS"
|
||||
perl Build.pl
|
||||
if (-NOT ($LASTEXITCODE -eq 0)) {
|
||||
perl ./Build.pl
|
||||
|
||||
if ($LastExitCode -ne 0) {
|
||||
Add-AppveyorCompilationMessage -Message "XS Failed to Build" -Category Error
|
||||
$host.SetShouldExit($LastExitCode)
|
||||
exit
|
||||
}
|
||||
|
||||
Add-AppveyorCompilationMessage -Message "Making ZIP package"
|
||||
cd package/win
|
||||
./compile_wrapper.ps1 524| Write-Output
|
||||
|
@ -1,19 +1,28 @@
|
||||
mkdir C:\projects\slic3r\FreeGLUT
|
||||
if (!(Test-Path "C:\users\appveyor\freeglut.7z"))
|
||||
if (!(Test-Path "C:\users\appveyor\freeglut.$env:ARCH.7z"))
|
||||
{
|
||||
wget "http://www.siusgs.com/slic3r/buildserver/win/freeglut-mingw-3.0.0.win64.7z" -o C:\users\appveyor\freeglut.7z
|
||||
wget "https://bintray.com/lordofhyphens/Slic3r/download_file?file_path=freeglut-mingw-3.0.0.$env:ARCH.7z" -o C:\users\appveyor\freeglut.$env:ARCH.7z
|
||||
}
|
||||
cmd /c "7z x C:\Users\appveyor\freeglut.7z -oC:\projects\slic3r\FreeGLUT"
|
||||
cmd /c "7z x C:\Users\appveyor\freeglut.$env:ARCH.7z -oC:\projects\slic3r\FreeGLUT"
|
||||
|
||||
if (!(Test-Path "C:\users\appveyor\strawberry.msi")) {
|
||||
wget "https://bintray.com/lordofhyphens/Slic3r/download_file?file_path=slic3r-perl-5.24.1.4-64bit.msi" -o "C:\users\appveyor\strawberry.msi" | Write-Output
|
||||
}
|
||||
if (!(Test-Path "C:\users\appveyor\extra_perl.7z")) {
|
||||
wget "https://bintray.com/lordofhyphens/Slic3r/download_file?file_path=Strawberry-6.3.0-seg-archive.7z" -o "C:\users\appveyor\extra_perl.7z" | Write-Output
|
||||
if (!(Test-Path "C:\users\appveyor\strawberry.$env:ARCH.msi")) {
|
||||
if ($env:ARCH -eq "64bit") {
|
||||
wget "https://bintray.com/lordofhyphens/Slic3r/download_file?file_path=slic3r-perl-5.24.1.4-64bit.msi" -o "C:\users\appveyor\strawberry.$env:ARCH.msi" | Write-Output
|
||||
} else {
|
||||
wget "http://strawberryperl.com/download/5.24.1.1/strawberry-perl-5.24.1.1-32bit.msi" -o "C:\users\appveyor\strawberry.$env:ARCH.msi" | Write-Output
|
||||
}
|
||||
}
|
||||
|
||||
msiexec.exe /i "C:\users\appveyor\strawberry.msi" /quiet
|
||||
cmd /c "7z x -aoa C:\Users\appveyor\extra_perl.7z -oC:\"
|
||||
if (!($env:ARCH -eq "32bit")) {
|
||||
if (!(Test-Path "C:\users\appveyor\extra_perl.7z")) {
|
||||
wget "https://bintray.com/lordofhyphens/Slic3r/download_file?file_path=Strawberry-6.3.0-seg-archive.7z" -o "C:\users\appveyor\extra_perl.7z" | Write-Output
|
||||
}
|
||||
}
|
||||
|
||||
msiexec.exe /i "C:\users\appveyor\strawberry.$env:ARCH.msi" /quiet
|
||||
if (!($env:ARCH -eq "32bit")) {
|
||||
cmd /c "7z x -aoa C:\Users\appveyor\extra_perl.7z -oC:\"
|
||||
}
|
||||
|
||||
if (!(Test-Path "C:\users\appveyor\winscp.zip")) {
|
||||
wget "https://bintray.com/lordofhyphens/Slic3r/download_file?file_path=WinSCP-5.9.4-Portable.zip" -o "C:\users\appveyor\winscp.zip" | Write-Output
|
||||
@ -32,11 +41,15 @@ if(Test-Path -Path 'C:\Strawberry' ) {
|
||||
copy C:\Strawberry\c\bin\gcc.exe C:\Strawberry\c\bin\cc.exe
|
||||
cmd /c mklink /D C:\Perl C:\Strawberry\perl
|
||||
mkdir C:\dev
|
||||
if (!(Test-Path "C:\users\appveyor\boost.1.63.0.7z") -Or $env:FORCE_BOOST_REINSTALL -eq 1) {
|
||||
wget "https://bintray.com/lordofhyphens/Slic3r/download_file?file_path=boost_1_63_0-x64-gcc-6.3.0-seh.7z" -O "C:\users\appveyor\boost.1.63.0.7z" | Write-Output
|
||||
if (!(Test-Path "C:\users\appveyor\boost.1.63.0.$env:ARCH.7z") -Or $env:FORCE_BOOST_REINSTALL -eq 1) {
|
||||
if ($env:ARCH -eq "64bit") {
|
||||
wget "http://www.siusgs.com/slic3r/buildserver/win/boost_1_63_0-x64-gcc-6.3.0-seh.7z" -O "C:\users\appveyor\boost.1.63.0.$env:ARCH.7z" | Write-Output
|
||||
} else {
|
||||
wget "https://bintray.com/lordofhyphens/Slic3r/download_file?file_path=boost_1_63_0-x32-gcc-4.9.2-sjlj.7z" -O "C:\users\appveyor\boost.1.63.0.$env:ARCH.7z" | Write-Output
|
||||
}
|
||||
}
|
||||
Add-AppveyorCompilationMessage -Message "Extracting cached archive."
|
||||
cmd /c "7z x C:\Users\appveyor\boost.1.63.0.7z -oC:\dev"
|
||||
cmd /c "7z x C:\Users\appveyor\boost.1.63.0.$env:ARCH.7z -oC:\dev"
|
||||
|
||||
mkdir C:\dev\CitrusPerl
|
||||
cmd /C mklink /D C:\dev\CitrusPerl\mingw32 C:\Strawberry\c
|
||||
@ -53,19 +66,14 @@ if(Test-Path -Path 'C:\Strawberry' ) {
|
||||
|
||||
Add-AppveyorCompilationMessage -Message "Installing wxWidgets (xsgui dependency))"
|
||||
if ($env:FORCE_WX_BUILD -eq 1) {
|
||||
rm "C:\Users\appveyor\wxwidgets.7z" -Force
|
||||
rm "C:\Users\appveyor\wxwidgets-$env:ARCH.7z" -Force
|
||||
}
|
||||
if (!(Test-Path "C:\Users\appveyor\wxwidgets.7z")) {
|
||||
Add-AppveyorCompilationMessage -Message "Compiling wxWidgets"
|
||||
git clone https://github.com/wxWidgets/wxWidgets -b "v3.1.0" -q C:\dev\wxWidgets
|
||||
cd C:\dev\wxwidgets
|
||||
cp .\include\wx\msw\setup0.h include/wx/msw/setup.h
|
||||
cd build\msw
|
||||
mingw32-make -f makefile.gcc CXXFLAGS="-std=gnu++11" BUILD=release VENDOR=Slic3r
|
||||
cd C:\dev
|
||||
7z a C:\Users\appveyor\wxwidgets.7z wxwidgets
|
||||
cd C:\projects\slic3r
|
||||
|
||||
if (!(Test-Path "C:\Users\appveyor\wxwidgets-$env:ARCH.7z")) {
|
||||
Add-AppveyorCompilationMessage -Message "Extracting wxWidgets for $env:ARCH"
|
||||
wget "https://bintray.com/lordofhyphens/Slic3r/download_file?file_path=wxwidgets-$env:ARCH.7z" -o C:\users\appveyor\wxwidgets-$env:ARCH.7z
|
||||
7z x C:\users\appveyor\wxwidgets-$env:ARCH.7z -oC:\dev
|
||||
} else {
|
||||
Add-AppveyorCompilationMessage -Message "Extracting prebuilt wxWidgets."
|
||||
7z x "C:\Users\appveyor\wxwidgets.7z" -oC:\dev
|
||||
7z x "C:\Users\appveyor\wxwidgets-$env:ARCH.7z" -oC:\dev
|
||||
}
|
||||
|
@ -41,6 +41,16 @@ if ($exe) {
|
||||
New-Variable -Name "STRAWBERRY_PATH" -Value "C:\Strawberry"
|
||||
|
||||
cpanm "PAR::Packer"
|
||||
if ($env:ARCH -eq "32bit") {
|
||||
$perlarch = "sjlj"
|
||||
$glut = "libglut-0_.dll"
|
||||
$pthread= "pthreadGC2-w32.dll"
|
||||
} else {
|
||||
$perlarch = "seh"
|
||||
$glut = "libglut-0__.dll"
|
||||
$pthread= "pthreadGC2-w64.dll"
|
||||
}
|
||||
|
||||
|
||||
pp `
|
||||
-a "slic3r.exe;slic3r.exe" `
|
||||
@ -54,10 +64,10 @@ pp `
|
||||
-a "../../FreeGLUT/freeglut.dll;freeglut.dll" `
|
||||
-a "${STRAWBERRY_PATH}\perl\bin\perl${perlversion}.dll;perl${perlversion}.dll" `
|
||||
-a "${STRAWBERRY_PATH}\perl\bin\libstdc++-6.dll;libstdc++-6.dll" `
|
||||
-a "${STRAWBERRY_PATH}\perl\bin\libgcc_s_seh-1.dll;libgcc_s_seh-1.dll" `
|
||||
-a "${STRAWBERRY_PATH}\perl\bin\libgcc_s_${perlarch}-1.dll;libgcc_s_${perlarch}-1.dll" `
|
||||
-a "${STRAWBERRY_PATH}\perl\bin\libwinpthread-1.dll;libwinpthread-1.dll" `
|
||||
-a "${STRAWBERRY_PATH}\c\bin\pthreadGC2-w64.dll;pthreadGC2-w64.dll" `
|
||||
-a "${STRAWBERRY_PATH}\c\bin\libglut-0__.dll;libglut-0__.dll" `
|
||||
-a "${STRAWBERRY_PATH}\c\bin\${pthread};${pthread}" `
|
||||
-a "${STRAWBERRY_PATH}\c\bin\${glut};${glut}" `
|
||||
-M AutoLoader `
|
||||
-M B `
|
||||
-M Carp `
|
||||
@ -152,7 +162,7 @@ if ($exe) {
|
||||
} else {
|
||||
# make this more useful for not being on the appveyor server
|
||||
if ($env:APPVEYOR) {
|
||||
copy ..\..\slic3r.par "..\..\slic3r-${current_branch}.${current_date}.${env:APPVEYOR_BUILD_NUMBER}.$(git rev-parse --short HEAD).zip"
|
||||
copy ..\..\slic3r.par "..\..\slic3r-${current_branch}.${current_date}.${env:APPVEYOR_BUILD_NUMBER}.$(git rev-parse --short HEAD).$env:ARCH.zip"
|
||||
} else {
|
||||
copy ..\..\slic3r.par "..\..\slic3r-${current_branch}.${current_date}.$(git rev-parse --short HEAD).zip"
|
||||
del ..\..\slic3r.par
|
||||
|
@ -18,6 +18,7 @@ use Slic3r::Geometry qw(epsilon X Y Z deg2rad);
|
||||
use Time::HiRes qw(gettimeofday tv_interval);
|
||||
$|++;
|
||||
binmode STDOUT, ':utf8';
|
||||
binmode STDERR, ':utf8';
|
||||
|
||||
our %opt = ();
|
||||
my %cli_options = ();
|
||||
@ -74,9 +75,9 @@ my @external_configs = ();
|
||||
if ($opt{load}) {
|
||||
foreach my $configfile (@{$opt{load}}) {
|
||||
$configfile = Slic3r::decode_path($configfile);
|
||||
if (-e $configfile) {
|
||||
if (-e Slic3r::encode_path($configfile)) {
|
||||
push @external_configs, Slic3r::Config->load($configfile);
|
||||
} elsif (-e "$FindBin::Bin/$configfile") {
|
||||
} elsif (-e Slic3r::encode_path("$FindBin::Bin/$configfile")) {
|
||||
printf STDERR "Loading $FindBin::Bin/$configfile\n";
|
||||
push @external_configs, Slic3r::Config->load("$FindBin::Bin/$configfile");
|
||||
} else {
|
||||
@ -99,7 +100,7 @@ if ($opt{save}) {
|
||||
if (@{$config->get_keys} > 0) {
|
||||
$config->save($opt{save});
|
||||
} else {
|
||||
Slic3r::Config->new_from_defaults->save($opt{save});
|
||||
Slic3r::Config->new_from_defaults->save(Slic3r::decode_path($opt{save}));
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,7 +267,7 @@ if (@ARGV) { # slicing from command line
|
||||
my ($percent, $message) = @_;
|
||||
printf "=> %s\n", $message;
|
||||
},
|
||||
output_file => $opt{output},
|
||||
output_file => Slic3r::decode_path($opt{output}),
|
||||
);
|
||||
|
||||
$sprint->apply_config($config);
|
||||
|
@ -10,15 +10,22 @@
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
#include "boost/filesystem.hpp"
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/args.hpp>
|
||||
#include <boost/nowide/iostream.hpp>
|
||||
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
void confess_at(const char *file, int line, const char *func, const char *pat, ...){}
|
||||
|
||||
int
|
||||
main(const int argc, const char **argv)
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
// Convert arguments to UTF-8 (needed on Windows).
|
||||
// argv then points to memory owned by a.
|
||||
boost::nowide::args a(argc, argv);
|
||||
|
||||
// parse all command line options into a DynamicConfig
|
||||
ConfigDef config_def;
|
||||
config_def.merge(cli_config_def);
|
||||
@ -34,18 +41,17 @@ main(const int argc, const char **argv)
|
||||
DynamicPrintConfig print_config;
|
||||
|
||||
// load config files supplied via --load
|
||||
for (std::vector<std::string>::const_iterator file = cli_config.load.values.begin();
|
||||
file != cli_config.load.values.end(); ++file) {
|
||||
if (!boost::filesystem::exists(*file)) {
|
||||
std::cout << "No such file: " << *file << std::endl;
|
||||
for (const std::string &file : cli_config.load.values) {
|
||||
if (!boost::filesystem::exists(file)) {
|
||||
boost::nowide::cout << "No such file: " << file << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
DynamicPrintConfig c;
|
||||
try {
|
||||
c.load(*file);
|
||||
c.load(file);
|
||||
} catch (std::exception &e) {
|
||||
std::cout << "Error while reading config file: " << e.what() << std::endl;
|
||||
boost::nowide::cout << "Error while reading config file: " << e.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
c.normalize();
|
||||
@ -62,85 +68,85 @@ main(const int argc, const char **argv)
|
||||
|
||||
// read input file(s) if any
|
||||
std::vector<Model> models;
|
||||
for (t_config_option_keys::const_iterator it = input_files.begin(); it != input_files.end(); ++it) {
|
||||
if (!boost::filesystem::exists(*it)) {
|
||||
std::cout << "No such file: " << *it << std::endl;
|
||||
for (const t_config_option_key &file : input_files) {
|
||||
if (!boost::filesystem::exists(file)) {
|
||||
boost::nowide::cerr << "No such file: " << file << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Model model;
|
||||
try {
|
||||
model = Model::read_from_file(*it);
|
||||
model = Model::read_from_file(file);
|
||||
} catch (std::exception &e) {
|
||||
std::cout << *it << ": " << e.what() << std::endl;
|
||||
boost::nowide::cerr << file << ": " << e.what() << std::endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (model.objects.empty()) {
|
||||
printf("Error: file is empty: %s\n", it->c_str());
|
||||
boost::nowide::cerr << "Error: file is empty: " << file << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
model.add_default_instances();
|
||||
|
||||
// apply command line transform options
|
||||
for (ModelObjectPtrs::iterator o = model.objects.begin(); o != model.objects.end(); ++o) {
|
||||
for (ModelObject* o : model.objects) {
|
||||
if (cli_config.scale_to_fit.is_positive_volume())
|
||||
(*o)->scale_to_fit(cli_config.scale_to_fit.value);
|
||||
o->scale_to_fit(cli_config.scale_to_fit.value);
|
||||
|
||||
// TODO: honor option order?
|
||||
(*o)->scale(cli_config.scale.value);
|
||||
(*o)->rotate(Geometry::deg2rad(cli_config.rotate_x.value), X);
|
||||
(*o)->rotate(Geometry::deg2rad(cli_config.rotate_y.value), Y);
|
||||
(*o)->rotate(Geometry::deg2rad(cli_config.rotate.value), Z);
|
||||
o->scale(cli_config.scale.value);
|
||||
o->rotate(Geometry::deg2rad(cli_config.rotate_x.value), X);
|
||||
o->rotate(Geometry::deg2rad(cli_config.rotate_y.value), Y);
|
||||
o->rotate(Geometry::deg2rad(cli_config.rotate.value), Z);
|
||||
}
|
||||
|
||||
// TODO: handle --merge
|
||||
models.push_back(model);
|
||||
}
|
||||
|
||||
for (std::vector<Model>::iterator model = models.begin(); model != models.end(); ++model) {
|
||||
for (Model &model : models) {
|
||||
if (cli_config.info) {
|
||||
// --info works on unrepaired model
|
||||
model->print_info();
|
||||
model.print_info();
|
||||
} else if (cli_config.export_obj) {
|
||||
std::string outfile = cli_config.output.value;
|
||||
if (outfile.empty()) outfile = model->objects.front()->input_file + ".obj";
|
||||
if (outfile.empty()) outfile = model.objects.front()->input_file + ".obj";
|
||||
|
||||
TriangleMesh mesh = model->mesh();
|
||||
TriangleMesh mesh = model.mesh();
|
||||
mesh.repair();
|
||||
IO::OBJ::write(mesh, outfile);
|
||||
printf("File exported to %s\n", outfile.c_str());
|
||||
boost::nowide::cout << "File exported to " << outfile << std::endl;
|
||||
} else if (cli_config.export_pov) {
|
||||
std::string outfile = cli_config.output.value;
|
||||
if (outfile.empty()) outfile = model->objects.front()->input_file + ".pov";
|
||||
if (outfile.empty()) outfile = model.objects.front()->input_file + ".pov";
|
||||
|
||||
TriangleMesh mesh = model->mesh();
|
||||
TriangleMesh mesh = model.mesh();
|
||||
mesh.repair();
|
||||
IO::POV::write(mesh, outfile);
|
||||
printf("File exported to %s\n", outfile.c_str());
|
||||
boost::nowide::cout << "File exported to " << outfile << std::endl;
|
||||
} else if (cli_config.export_svg) {
|
||||
std::string outfile = cli_config.output.value;
|
||||
if (outfile.empty()) outfile = model->objects.front()->input_file + ".svg";
|
||||
if (outfile.empty()) outfile = model.objects.front()->input_file + ".svg";
|
||||
|
||||
SLAPrint print(&*model);
|
||||
SLAPrint print(&model);
|
||||
print.config.apply(print_config, true);
|
||||
print.slice();
|
||||
print.write_svg(outfile);
|
||||
printf("SVG file exported to %s\n", outfile.c_str());
|
||||
boost::nowide::cout << "SVG file exported to " << outfile << std::endl;
|
||||
} else if (cli_config.cut_x > 0 || cli_config.cut_y > 0 || cli_config.cut > 0) {
|
||||
model->repair();
|
||||
model->translate(0, 0, -model->bounding_box().min.z);
|
||||
model.repair();
|
||||
model.translate(0, 0, -model.bounding_box().min.z);
|
||||
|
||||
if (!model->objects.empty()) {
|
||||
if (!model.objects.empty()) {
|
||||
// FIXME: cut all objects
|
||||
Model out;
|
||||
if (cli_config.cut_x > 0) {
|
||||
model->objects.front()->cut(X, cli_config.cut_x, &out);
|
||||
model.objects.front()->cut(X, cli_config.cut_x, &out);
|
||||
} else if (cli_config.cut_y > 0) {
|
||||
model->objects.front()->cut(Y, cli_config.cut_y, &out);
|
||||
model.objects.front()->cut(Y, cli_config.cut_y, &out);
|
||||
} else {
|
||||
model->objects.front()->cut(Z, cli_config.cut, &out);
|
||||
model.objects.front()->cut(Z, cli_config.cut, &out);
|
||||
}
|
||||
|
||||
ModelObject &upper = *out.objects[0];
|
||||
@ -156,18 +162,19 @@ main(const int argc, const char **argv)
|
||||
}
|
||||
}
|
||||
} else if (cli_config.cut_grid.value.x > 0 && cli_config.cut_grid.value.y > 0) {
|
||||
TriangleMesh mesh = model->mesh();
|
||||
TriangleMesh mesh = model.mesh();
|
||||
mesh.repair();
|
||||
|
||||
TriangleMeshPtrs meshes = mesh.cut_by_grid(cli_config.cut_grid.value);
|
||||
for (TriangleMeshPtrs::iterator m = meshes.begin(); m != meshes.end(); ++m) {
|
||||
size_t i = 0;
|
||||
for (TriangleMesh* m : meshes) {
|
||||
std::ostringstream ss;
|
||||
ss << model->objects.front()->input_file << "_" << (m - meshes.begin()) << ".stl";
|
||||
IO::STL::write(**m, ss.str());
|
||||
delete *m;
|
||||
ss << model.objects.front()->input_file << "_" << i++ << ".stl";
|
||||
IO::STL::write(*m, ss.str());
|
||||
delete m;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "error: command not supported" << std::endl;
|
||||
boost::nowide::cerr << "error: command not supported" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,20 @@
|
||||
#include "IO.hpp"
|
||||
#include "TriangleMesh.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include <boost/nowide/args.hpp>
|
||||
#include <boost/nowide/iostream.hpp>
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
void confess_at(const char *file, int line, const char *func, const char *pat, ...){}
|
||||
|
||||
int
|
||||
main(const int argc, const char **argv)
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
// Convert arguments to UTF-8 (needed on Windows).
|
||||
// argv then points to memory owned by a.
|
||||
boost::nowide::args a(argc, argv);
|
||||
|
||||
// read config
|
||||
ConfigDef config_def;
|
||||
{
|
||||
@ -40,7 +46,7 @@ main(const int argc, const char **argv)
|
||||
if (outfile.empty()) outfile = *it + "_extruded.stl";
|
||||
|
||||
Slic3r::IO::STL::write(mesh, outfile);
|
||||
printf("Extruded mesh written to %s\n", outfile.c_str());
|
||||
boost::nowide::cout << "Extruded mesh written to " << outfile << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
26
t/bridges.t
26
t/bridges.t
@ -1,4 +1,4 @@
|
||||
use Test::More tests => 18;
|
||||
use Test::More tests => 20;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
@ -99,6 +99,24 @@ use Slic3r::Test;
|
||||
'correct bridge angle for rectangle';
|
||||
}
|
||||
|
||||
{
|
||||
# GH #3929: This test case checks that narrow gaps in lower slices don't prevent correct
|
||||
# direction detection.
|
||||
my $bridge = Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new([10099996,45867519],[3762370,45867519],[3762370,2132479],[10099996,2132479]),
|
||||
);
|
||||
my $lower = [
|
||||
Slic3r::ExPolygon->new(
|
||||
Slic3r::Polygon->new([13534103,210089],[13629884,235753],[14249999,401901],[14269611,421510],[14272931,424830],[14287518,439411],[14484206,636101],[15348099,1500000],[15360812,1547449],[15365467,1564815],[15388623,1651235],[15391897,1663454],[15393088,1667906],[15399044,1690134],[15457593,1908648],[15750000,2999999],[15750000,45000000],[15742825,45026783],[15741540,45031580],[15735900,45052628],[15663980,45321047],[15348099,46500000],[15151410,46696691],[14287518,47560587],[14267907,47580196],[14264587,47583515],[14249999,47598100],[14211041,47608539],[14204785,47610215],[14176024,47617916],[14105602,47636784],[14097768,47638884],[14048000,47652220],[13871472,47699515],[12750000,48000000],[10446106,48000000],[10446124,47990347],[10446124,9652],[10446106,0],[12750000,0]),
|
||||
Slic3r::Polygon->new([10251886,5013],[10251886,47994988],[10251907,48000000],[10100006,48000000],[10100006,0],[10251907,0]),
|
||||
Slic3r::Polygon->new([3762360,17017],[3762360,47982984],[3762397,48000000],[1249999,48000000],[536029,47808700],[456599,47787419],[73471,47684764],[0,47665076],[0,23124327],[119299,22907322],[159278,22834601],[196290,22690451],[239412,22522516],[303787,22271780],[639274,20965103],[639274,19034896],[616959,18947983],[607651,18911729],[559146,18722807],[494769,18472073],[159278,17165397],[38931,16946491],[0,16875676],[0,334922],[128529,300484],[1250000,0],[3762397,0]),
|
||||
),
|
||||
];
|
||||
|
||||
ok check_angle($lower, $bridge, 0, undef, $bridge->area, 500000),
|
||||
'correct bridge angle when lower slices have narrow gap';
|
||||
}
|
||||
|
||||
sub check_angle {
|
||||
my ($lower, $bridge, $expected, $tolerance, $expected_coverage, $extrusion_width) = @_;
|
||||
|
||||
@ -121,9 +139,9 @@ sub check_angle {
|
||||
# our epsilon is equal to the steps used by the bridge detection algorithm
|
||||
###use XXX; YYY [ rad2deg($result), $expected ];
|
||||
# returned value must be non-negative, check for that too
|
||||
my $delta=rad2deg($result) - $expected;
|
||||
$delta-=180 if $delta>=180 - epsilon;
|
||||
return defined $result && $result>=0 && abs($delta) < $tolerance;
|
||||
my $delta = rad2deg($result) - $expected;
|
||||
$delta -= 180 if $delta >= 180 - epsilon;
|
||||
return defined $result && $result >= 0 && abs($delta) < $tolerance;
|
||||
}
|
||||
|
||||
{
|
||||
|
12
t/geometry.t
12
t/geometry.t
@ -2,7 +2,7 @@ use Test::More;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
plan tests => 42;
|
||||
plan tests => 44;
|
||||
|
||||
BEGIN {
|
||||
use FindBin;
|
||||
@ -254,4 +254,14 @@ my $polygons = [
|
||||
is scalar(@$simplified), 3, 'triangle is never simplified to less than 3 points';
|
||||
}
|
||||
|
||||
{
|
||||
# Two concave vertices of this polygon have angle = PI*4/3, so this test fails
|
||||
# if epsilon is not used.
|
||||
my $polygon = Slic3r::Polygon->new(
|
||||
[60246458,14802768],[64477191,12360001],[63727343,11060995],[64086449,10853608],[66393722,14850069],[66034704,15057334],[65284646,13758387],[61053864,16200839],[69200258,30310849],[62172547,42483120],[61137680,41850279],[67799985,30310848],[51399866,1905506],[38092663,1905506],[38092663,692699],[52100125,692699],
|
||||
);
|
||||
is scalar(@{$polygon->concave_points(PI*4/3)}), 6, 'expected number of concave points';
|
||||
is scalar(@{$polygon->convex_points(PI*2/3)}), 10, 'expected number of convex points';
|
||||
}
|
||||
|
||||
__END__
|
||||
|
@ -1,4 +1,4 @@
|
||||
use Test::More tests => 59;
|
||||
use Test::More tests => 63;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
@ -393,10 +393,37 @@ use Slic3r::Test;
|
||||
});
|
||||
return scalar keys %z_with_bridges;
|
||||
};
|
||||
ok $test->(Slic3r::Test::init_print('V', config => $config)) == 1,
|
||||
is $test->(Slic3r::Test::init_print('V', config => $config)), 1,
|
||||
'no overhangs printed with bridge speed'; # except for the first internal solid layers above void
|
||||
ok $test->(Slic3r::Test::init_print('V', config => $config, scale_xyz => [3,1,1])) > 1,
|
||||
'overhangs printed with bridge speed';
|
||||
|
||||
$config->set('bottom_solid_layers', 0);
|
||||
$config->set('top_solid_layers', 0);
|
||||
my $test2 = sub {
|
||||
my ($print) = @_;
|
||||
my $num_bridges = 0;
|
||||
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
|
||||
my ($self, $cmd, $args, $info) = @_;
|
||||
|
||||
if ($info->{extruding} && $info->{dist_XY} > 0) {
|
||||
$num_bridges++ if ($args->{F} // $self->F) == $config->bridge_speed*60;
|
||||
}
|
||||
});
|
||||
return $num_bridges;
|
||||
};
|
||||
is $test2->(Slic3r::Test::init_print('overhang', config => $config)), $config->perimeters*3,
|
||||
'expected number of segments use bridge speed (overhang)';
|
||||
is $test2->(Slic3r::Test::init_print('bridge', config => $config)), $config->perimeters*2,
|
||||
'expected number of segments use bridge speed (bridge)';
|
||||
is $test2->(Slic3r::Test::init_print('bridge_with_hole', config => $config)), $config->perimeters*4,
|
||||
'expected number of segments use bridge speed (bridge with hole)';
|
||||
|
||||
# scale the test model so that the hole perimeter length is smaller than small perimeter
|
||||
# threshold (~40mm). check that we still use overhang settings regardless of it being small
|
||||
is $test2->(Slic3r::Test::init_print('bridge_with_hole', config => $config, scale_xyz => [0.3,0.5,1])),
|
||||
$config->perimeters*4,
|
||||
'expected number of segments use bridge speed (bridge with small hole)';
|
||||
}
|
||||
|
||||
{
|
||||
|
BIN
var/zoom_in.png
Executable file
BIN
var/zoom_in.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 725 B |
BIN
var/zoom_out.png
Executable file
BIN
var/zoom_out.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 708 B |
2484
xs/libslic3r.doxygen
Normal file
2484
xs/libslic3r.doxygen
Normal file
File diff suppressed because it is too large
Load Diff
@ -141,7 +141,7 @@ stl_generate_shared_vertices(stl_file *stl) {
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_off(stl_file *stl, char *file) {
|
||||
stl_write_off(stl_file *stl, ADMESH_CHAR *file) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
char *error_msg;
|
||||
@ -149,14 +149,9 @@ stl_write_off(stl_file *stl, char *file) {
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = fopen(file, "w");
|
||||
fp = stl_fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
perror("stl_write_ascii: Couldn't open file for writing");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
@ -177,7 +172,7 @@ stl_write_off(stl_file *stl, char *file) {
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_vrml(stl_file *stl, char *file) {
|
||||
stl_write_vrml(stl_file *stl, ADMESH_CHAR *file) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
char *error_msg;
|
||||
@ -185,14 +180,9 @@ stl_write_vrml(stl_file *stl, char *file) {
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = fopen(file, "w");
|
||||
fp = stl_fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
perror("stl_write_ascii: Couldn't open file for writing");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
@ -234,19 +224,16 @@ stl_write_vrml(stl_file *stl, char *file) {
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void stl_write_obj (stl_file *stl, const char *file) {
|
||||
void stl_write_obj (stl_file *stl, const ADMESH_CHAR *file) {
|
||||
int i;
|
||||
FILE* fp;
|
||||
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = fopen(file, "w");
|
||||
fp = stl_fopen(file, "w");
|
||||
if (fp == NULL) {
|
||||
char* error_msg = (char*)malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing", file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
perror("stl_write_ascii: Couldn't open file for writing");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
|
@ -32,6 +32,15 @@
|
||||
#error "admesh works correctly on little endian machines only!"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
|
||||
#include "windows.h"
|
||||
#define ADMESH_CHAR wchar_t
|
||||
#define stl_fopen(file, mode) _wfopen(file, L##mode)
|
||||
#else
|
||||
#define ADMESH_CHAR char
|
||||
#define stl_fopen(file, mode) fopen(file, mode)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -163,15 +172,15 @@ typedef struct {
|
||||
} stl_file;
|
||||
|
||||
|
||||
extern void stl_open(stl_file *stl, const char *file);
|
||||
extern void stl_open(stl_file *stl, const ADMESH_CHAR *file);
|
||||
extern void stl_close(stl_file *stl);
|
||||
extern void stl_stats_out(stl_file *stl, FILE *file, char *input_file);
|
||||
extern void stl_print_edges(stl_file *stl, FILE *file);
|
||||
extern void stl_print_neighbors(stl_file *stl, char *file);
|
||||
extern void stl_print_neighbors(stl_file *stl, ADMESH_CHAR *file);
|
||||
extern void stl_put_little_int(FILE *fp, int value_in);
|
||||
extern void stl_put_little_float(FILE *fp, float value_in);
|
||||
extern void stl_write_ascii(stl_file *stl, const char *file, const char *label);
|
||||
extern void stl_write_binary(stl_file *stl, const char *file, const char *label);
|
||||
extern void stl_write_ascii(stl_file *stl, const ADMESH_CHAR *file, const char *label);
|
||||
extern void stl_write_binary(stl_file *stl, const ADMESH_CHAR *file, const char *label);
|
||||
extern void stl_write_binary_block(stl_file *stl, FILE *fp);
|
||||
extern void stl_check_facets_exact(stl_file *stl);
|
||||
extern void stl_check_facets_nearby(stl_file *stl, float tolerance);
|
||||
@ -180,7 +189,7 @@ extern void stl_write_vertex(stl_file *stl, int facet, int vertex);
|
||||
extern void stl_write_facet(stl_file *stl, char *label, int facet);
|
||||
extern void stl_write_edge(stl_file *stl, char *label, stl_hash_edge edge);
|
||||
extern void stl_write_neighbor(stl_file *stl, int facet);
|
||||
extern void stl_write_quad_object(stl_file *stl, char *file);
|
||||
extern void stl_write_quad_object(stl_file *stl, ADMESH_CHAR *file);
|
||||
extern void stl_verify_neighbors(stl_file *stl);
|
||||
extern void stl_fill_holes(stl_file *stl);
|
||||
extern void stl_fix_normal_directions(stl_file *stl);
|
||||
@ -198,13 +207,13 @@ extern void stl_mirror_xy(stl_file *stl);
|
||||
extern void stl_mirror_yz(stl_file *stl);
|
||||
extern void stl_mirror_xz(stl_file *stl);
|
||||
extern void stl_transform(stl_file *stl, float *trafo3x4);
|
||||
extern void stl_open_merge(stl_file *stl, char *file);
|
||||
extern void stl_open_merge(stl_file *stl, ADMESH_CHAR *file);
|
||||
extern void stl_invalidate_shared_vertices(stl_file *stl);
|
||||
extern void stl_generate_shared_vertices(stl_file *stl);
|
||||
extern void stl_write_obj(stl_file *stl, const 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_vrml(stl_file *stl, char *file);
|
||||
extern void stl_write_obj(stl_file *stl, const ADMESH_CHAR *file);
|
||||
extern void stl_write_off(stl_file *stl, ADMESH_CHAR *file);
|
||||
extern void stl_write_dxf(stl_file *stl, ADMESH_CHAR *file, char *label);
|
||||
extern void stl_write_vrml(stl_file *stl, ADMESH_CHAR *file);
|
||||
extern void stl_calculate_normal(float normal[], stl_facet *facet);
|
||||
extern void stl_normalize_vector(float v[]);
|
||||
extern void stl_calculate_volume(stl_file *stl);
|
||||
@ -212,7 +221,7 @@ 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_initialize(stl_file *stl);
|
||||
extern void stl_count_facets(stl_file *stl, const char *file);
|
||||
extern void stl_count_facets(stl_file *stl, const ADMESH_CHAR *file);
|
||||
extern void stl_allocate(stl_file *stl);
|
||||
extern void stl_read(stl_file *stl, int first_facet, int first);
|
||||
extern void stl_facet_stats(stl_file *stl, stl_facet facet, int first);
|
||||
|
@ -124,7 +124,7 @@ Normals fixed : %5d\n", stl->stats.normals_fixed);
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_ascii(stl_file *stl, const char *file, const char *label) {
|
||||
stl_write_ascii(stl_file *stl, const ADMESH_CHAR *file, const char *label) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
char *error_msg;
|
||||
@ -132,14 +132,9 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) {
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = fopen(file, "w");
|
||||
fp = stl_fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
perror("stl_write_ascii: Couldn't open file for writing");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
@ -170,7 +165,7 @@ stl_write_ascii(stl_file *stl, const char *file, const char *label) {
|
||||
}
|
||||
|
||||
void
|
||||
stl_print_neighbors(stl_file *stl, char *file) {
|
||||
stl_print_neighbors(stl_file *stl, ADMESH_CHAR *file) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
char *error_msg;
|
||||
@ -178,14 +173,9 @@ stl_print_neighbors(stl_file *stl, char *file) {
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = fopen(file, "w");
|
||||
fp = stl_fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_print_neighbors: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
perror("stl_print_neighbors: Couldn't open file for writing");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
@ -204,7 +194,7 @@ stl_print_neighbors(stl_file *stl, char *file) {
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_binary(stl_file *stl, const char *file, const char *label) {
|
||||
stl_write_binary(stl_file *stl, const ADMESH_CHAR *file, const char *label) {
|
||||
FILE *fp;
|
||||
int i;
|
||||
char *error_msg;
|
||||
@ -212,14 +202,9 @@ stl_write_binary(stl_file *stl, const char *file, const char *label) {
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = fopen(file, "wb");
|
||||
fp = stl_fopen(file, "wb");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_binary: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
perror("stl_write_binary: Couldn't open file for writing");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
@ -278,7 +263,7 @@ stl_write_neighbor(stl_file *stl, int facet) {
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_quad_object(stl_file *stl, char *file) {
|
||||
stl_write_quad_object(stl_file *stl, ADMESH_CHAR *file) {
|
||||
FILE *fp;
|
||||
int i;
|
||||
int j;
|
||||
@ -292,14 +277,9 @@ stl_write_quad_object(stl_file *stl, char *file) {
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = fopen(file, "w");
|
||||
fp = stl_fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_quad_object: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
perror("stl_write_quad_object: Couldn't open file for writing");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
@ -352,7 +332,7 @@ stl_write_quad_object(stl_file *stl, char *file) {
|
||||
}
|
||||
|
||||
void
|
||||
stl_write_dxf(stl_file *stl, char *file, char *label) {
|
||||
stl_write_dxf(stl_file *stl, ADMESH_CHAR *file, char *label) {
|
||||
int i;
|
||||
FILE *fp;
|
||||
char *error_msg;
|
||||
@ -360,14 +340,9 @@ stl_write_dxf(stl_file *stl, char *file, char *label) {
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file */
|
||||
fp = fopen(file, "w");
|
||||
fp = stl_fopen(file, "w");
|
||||
if(fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_write_ascii: Couldn't open %s for writing",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
perror("stl_write_ascii: Couldn't open file for writing");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@
|
||||
#endif
|
||||
|
||||
void
|
||||
stl_open(stl_file *stl, const char *file) {
|
||||
stl_open(stl_file *stl, const ADMESH_CHAR *file) {
|
||||
stl_initialize(stl);
|
||||
stl_count_facets(stl, file);
|
||||
stl_allocate(stl);
|
||||
@ -66,7 +66,7 @@ stl_initialize(stl_file *stl) {
|
||||
}
|
||||
|
||||
void
|
||||
stl_count_facets(stl_file *stl, const char *file) {
|
||||
stl_count_facets(stl_file *stl, const ADMESH_CHAR *file) {
|
||||
long file_size;
|
||||
int header_num_facets;
|
||||
int num_facets;
|
||||
@ -79,14 +79,9 @@ stl_count_facets(stl_file *stl, const char *file) {
|
||||
if (stl->error) return;
|
||||
|
||||
/* Open the file in binary mode first */
|
||||
stl->fp = fopen(file, "rb");
|
||||
stl->fp = stl_fopen(file, "rb");
|
||||
if(stl->fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
perror("stl_initialize: Couldn't open file for reading");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
@ -144,16 +139,12 @@ stl_count_facets(stl_file *stl, const char *file) {
|
||||
/* Reopen the file in text mode (for getting correct newlines on Windows) */
|
||||
// fix to silence a warning about unused return value.
|
||||
// obviously if it fails we have problems....
|
||||
stl->fp = freopen(file, "r", stl->fp);
|
||||
fclose(stl->fp);
|
||||
stl->fp = stl_fopen(file, "r");
|
||||
|
||||
// do another null check to be safe
|
||||
if(stl->fp == NULL) {
|
||||
error_msg = (char*)
|
||||
malloc(81 + strlen(file)); /* Allow 80 chars+file size for message */
|
||||
sprintf(error_msg, "stl_initialize: Couldn't open %s for reading",
|
||||
file);
|
||||
perror(error_msg);
|
||||
free(error_msg);
|
||||
perror("stl_initialize: Couldn't open file for reading");
|
||||
stl->error = 1;
|
||||
return;
|
||||
}
|
||||
@ -201,7 +192,7 @@ stl_allocate(stl_file *stl) {
|
||||
}
|
||||
|
||||
void
|
||||
stl_open_merge(stl_file *stl, char *file_to_merge) {
|
||||
stl_open_merge(stl_file *stl, ADMESH_CHAR *file_to_merge) {
|
||||
int num_facets_so_far;
|
||||
stl_type origStlType;
|
||||
FILE *origFp;
|
||||
|
167
xs/src/boost/nowide/args.hpp
Executable file
167
xs/src/boost/nowide/args.hpp
Executable file
@ -0,0 +1,167 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_ARGS_HPP_INCLUDED
|
||||
#define BOOST_NOWIDE_ARGS_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/nowide/stackstring.hpp>
|
||||
#include <vector>
|
||||
#ifdef BOOST_WINDOWS
|
||||
#include <boost/nowide/windows.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN)
|
||||
class args {
|
||||
public:
|
||||
args(int &,char **&) {}
|
||||
args(int &,char **&,char **&){}
|
||||
~args() {}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
///
|
||||
/// \brief args is a class that fixes standard main() function arguments and changes them to UTF-8 under
|
||||
/// Microsoft Windows.
|
||||
///
|
||||
/// The class uses \c GetCommandLineW(), \c CommandLineToArgvW() and \c GetEnvironmentStringsW()
|
||||
/// in order to obtain the information. It does not relates to actual values of argc,argv and env
|
||||
/// under Windows.
|
||||
///
|
||||
/// It restores the original values in its destructor
|
||||
///
|
||||
/// \note the class owns the memory of the newly allocated strings
|
||||
///
|
||||
class args {
|
||||
public:
|
||||
|
||||
///
|
||||
/// Fix command line agruments
|
||||
///
|
||||
args(int &argc,char **&argv) :
|
||||
old_argc_(argc),
|
||||
old_argv_(argv),
|
||||
old_env_(0),
|
||||
old_argc_ptr_(&argc),
|
||||
old_argv_ptr_(&argv),
|
||||
old_env_ptr_(0)
|
||||
{
|
||||
fix_args(argc,argv);
|
||||
}
|
||||
///
|
||||
/// Fix command line agruments and environment
|
||||
///
|
||||
args(int &argc,char **&argv,char **&en) :
|
||||
old_argc_(argc),
|
||||
old_argv_(argv),
|
||||
old_env_(en),
|
||||
old_argc_ptr_(&argc),
|
||||
old_argv_ptr_(&argv),
|
||||
old_env_ptr_(&en)
|
||||
{
|
||||
fix_args(argc,argv);
|
||||
fix_env(en);
|
||||
}
|
||||
///
|
||||
/// Restore original argc,argv,env values, if changed
|
||||
///
|
||||
~args()
|
||||
{
|
||||
if(old_argc_ptr_)
|
||||
*old_argc_ptr_ = old_argc_;
|
||||
if(old_argv_ptr_)
|
||||
*old_argv_ptr_ = old_argv_;
|
||||
if(old_env_ptr_)
|
||||
*old_env_ptr_ = old_env_;
|
||||
}
|
||||
private:
|
||||
void fix_args(int &argc,char **&argv)
|
||||
{
|
||||
int wargc;
|
||||
wchar_t **wargv = CommandLineToArgvW(GetCommandLineW(),&wargc);
|
||||
if(!wargv) {
|
||||
argc = 0;
|
||||
static char *dummy = 0;
|
||||
argv = &dummy;
|
||||
return;
|
||||
}
|
||||
try{
|
||||
args_.resize(wargc+1,0);
|
||||
arg_values_.resize(wargc);
|
||||
for(int i=0;i<wargc;i++) {
|
||||
if(!arg_values_[i].convert(wargv[i])) {
|
||||
wargc = i;
|
||||
break;
|
||||
}
|
||||
args_[i] = arg_values_[i].c_str();
|
||||
}
|
||||
argc = wargc;
|
||||
argv = &args_[0];
|
||||
}
|
||||
catch(...) {
|
||||
LocalFree(wargv);
|
||||
throw;
|
||||
}
|
||||
LocalFree(wargv);
|
||||
}
|
||||
void fix_env(char **&en)
|
||||
{
|
||||
static char *dummy = 0;
|
||||
en = &dummy;
|
||||
wchar_t *wstrings = GetEnvironmentStringsW();
|
||||
if(!wstrings)
|
||||
return;
|
||||
try {
|
||||
wchar_t *wstrings_end = 0;
|
||||
int count = 0;
|
||||
for(wstrings_end = wstrings;*wstrings_end;wstrings_end+=wcslen(wstrings_end)+1)
|
||||
count++;
|
||||
if(env_.convert(wstrings,wstrings_end)) {
|
||||
envp_.resize(count+1,0);
|
||||
char *p=env_.c_str();
|
||||
int pos = 0;
|
||||
for(int i=0;i<count;i++) {
|
||||
if(*p!='=')
|
||||
envp_[pos++] = p;
|
||||
p+=strlen(p)+1;
|
||||
}
|
||||
en = &envp_[0];
|
||||
}
|
||||
}
|
||||
catch(...) {
|
||||
FreeEnvironmentStringsW(wstrings);
|
||||
throw;
|
||||
}
|
||||
FreeEnvironmentStringsW(wstrings);
|
||||
|
||||
}
|
||||
|
||||
std::vector<char *> args_;
|
||||
std::vector<short_stackstring> arg_values_;
|
||||
stackstring env_;
|
||||
std::vector<char *> envp_;
|
||||
|
||||
int old_argc_;
|
||||
char **old_argv_;
|
||||
char **old_env_;
|
||||
|
||||
int *old_argc_ptr_;
|
||||
char ***old_argv_ptr_;
|
||||
char ***old_env_ptr_;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
#endif
|
||||
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
126
xs/src/boost/nowide/cenv.hpp
Executable file
126
xs/src/boost/nowide/cenv.hpp
Executable file
@ -0,0 +1,126 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_CENV_H_INCLUDED
|
||||
#define BOOST_NOWIDE_CENV_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <stdlib.h>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/nowide/stackstring.hpp>
|
||||
#include <vector>
|
||||
|
||||
#ifdef BOOST_WINDOWS
|
||||
#include <boost/nowide/windows.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN)
|
||||
using ::getenv;
|
||||
using ::setenv;
|
||||
using ::unsetenv;
|
||||
using ::putenv;
|
||||
#else
|
||||
///
|
||||
/// \brief UTF-8 aware getenv. Returns 0 if the variable is not set.
|
||||
///
|
||||
/// This function is not thread safe or reenterable as defined by the standard library
|
||||
///
|
||||
inline char *getenv(char const *key)
|
||||
{
|
||||
static stackstring value;
|
||||
|
||||
wshort_stackstring name;
|
||||
if(!name.convert(key))
|
||||
return 0;
|
||||
|
||||
static const size_t buf_size = 64;
|
||||
wchar_t buf[buf_size];
|
||||
std::vector<wchar_t> tmp;
|
||||
wchar_t *ptr = buf;
|
||||
size_t n = GetEnvironmentVariableW(name.c_str(),buf,buf_size);
|
||||
if(n == 0 && GetLastError() == 203) // ERROR_ENVVAR_NOT_FOUND
|
||||
return 0;
|
||||
if(n >= buf_size) {
|
||||
tmp.resize(n+1,L'\0');
|
||||
n = GetEnvironmentVariableW(name.c_str(),&tmp[0],static_cast<unsigned>(tmp.size() - 1));
|
||||
// The size may have changed
|
||||
if(n >= tmp.size() - 1)
|
||||
return 0;
|
||||
ptr = &tmp[0];
|
||||
}
|
||||
if(!value.convert(ptr))
|
||||
return 0;
|
||||
return value.c_str();
|
||||
}
|
||||
///
|
||||
/// \brief UTF-8 aware setenv, \a key - the variable name, \a value is a new UTF-8 value,
|
||||
///
|
||||
/// if override is not 0, that the old value is always overridded, otherwise,
|
||||
/// if the variable exists it remains unchanged
|
||||
///
|
||||
inline int setenv(char const *key,char const *value,int override)
|
||||
{
|
||||
wshort_stackstring name;
|
||||
if(!name.convert(key))
|
||||
return -1;
|
||||
if(!override) {
|
||||
wchar_t unused[2];
|
||||
if(!(GetEnvironmentVariableW(name.c_str(),unused,2)==0 && GetLastError() == 203)) // ERROR_ENVVAR_NOT_FOUND
|
||||
return 0;
|
||||
}
|
||||
wstackstring wval;
|
||||
if(!wval.convert(value))
|
||||
return -1;
|
||||
if(SetEnvironmentVariableW(name.c_str(),wval.c_str()))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
///
|
||||
/// \brief Remove enviroment variable \a key
|
||||
///
|
||||
inline int unsetenv(char const *key)
|
||||
{
|
||||
wshort_stackstring name;
|
||||
if(!name.convert(key))
|
||||
return -1;
|
||||
if(SetEnvironmentVariableW(name.c_str(),0))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
///
|
||||
/// \brief UTF-8 aware putenv implementation, expects string in format KEY=VALUE
|
||||
///
|
||||
inline int putenv(char *string)
|
||||
{
|
||||
char const *key = string;
|
||||
char const *key_end = string;
|
||||
while(*key_end!='=' && key_end!='\0')
|
||||
key_end++;
|
||||
if(*key_end == '\0')
|
||||
return -1;
|
||||
wshort_stackstring wkey;
|
||||
if(!wkey.convert(key,key_end))
|
||||
return -1;
|
||||
|
||||
wstackstring wvalue;
|
||||
if(!wvalue.convert(key_end+1))
|
||||
return -1;
|
||||
|
||||
if(SetEnvironmentVariableW(wkey.c_str(),wvalue.c_str()))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
54
xs/src/boost/nowide/config.hpp
Executable file
54
xs/src/boost/nowide/config.hpp
Executable file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_CONFIG_HPP_INCLUDED
|
||||
#define BOOST_NOWIDE_CONFIG_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#ifndef BOOST_SYMBOL_VISIBLE
|
||||
# define BOOST_SYMBOL_VISIBLE
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_DECLSPEC
|
||||
# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_NOWIDE_DYN_LINK)
|
||||
# ifdef BOOST_NOWIDE_SOURCE
|
||||
# define BOOST_NOWIDE_DECL BOOST_SYMBOL_EXPORT
|
||||
# else
|
||||
# define BOOST_NOWIDE_DECL BOOST_SYMBOL_IMPORT
|
||||
# endif // BOOST_NOWIDE_SOURCE
|
||||
# endif // DYN_LINK
|
||||
#endif // BOOST_HAS_DECLSPEC
|
||||
|
||||
#ifndef BOOST_NOWIDE_DECL
|
||||
# define BOOST_NOWIDE_DECL
|
||||
#endif
|
||||
|
||||
//
|
||||
// Automatically link to the correct build variant where possible.
|
||||
//
|
||||
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_NOWIDE_NO_LIB) && !defined(BOOST_NOWIDE_SOURCE)
|
||||
//
|
||||
// Set the name of our library, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
//
|
||||
#define BOOST_LIB_NAME boost_nowide
|
||||
//
|
||||
// If we're importing code from a dll, then tell auto_link.hpp about it:
|
||||
//
|
||||
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_NOWIDE_DYN_LINK)
|
||||
# define BOOST_DYN_LINK
|
||||
#endif
|
||||
//
|
||||
// And include the header that does the work:
|
||||
//
|
||||
#include <boost/config/auto_link.hpp>
|
||||
#endif // auto-linking disabled
|
||||
|
||||
|
||||
#endif // boost/nowide/config.hpp
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
154
xs/src/boost/nowide/convert.hpp
Executable file
154
xs/src/boost/nowide/convert.hpp
Executable file
@ -0,0 +1,154 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_CONVERT_H_INCLUDED
|
||||
#define BOOST_NOWIDE_CONVERT_H_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <boost/locale/encoding_utf.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
///
|
||||
/// \brief Template function that converts a buffer of UTF sequences in range [source_begin,source_end)
|
||||
/// to the output \a buffer of size \a buffer_size.
|
||||
///
|
||||
/// In case of success a NULL terminated string is returned (buffer), otherwise 0 is returned.
|
||||
///
|
||||
/// If there is not enough room in the buffer or the source sequence contains invalid UTF,
|
||||
/// 0 is returned, and the contents of the buffer are undefined.
|
||||
///
|
||||
template<typename CharOut,typename CharIn>
|
||||
CharOut *basic_convert(CharOut *buffer,size_t buffer_size,CharIn const *source_begin,CharIn const *source_end)
|
||||
{
|
||||
CharOut *rv = buffer;
|
||||
if(buffer_size == 0)
|
||||
return 0;
|
||||
buffer_size --;
|
||||
while(source_begin!=source_end) {
|
||||
using namespace boost::locale::utf;
|
||||
code_point c = utf_traits<CharIn>::template decode<CharIn const *>(source_begin,source_end);
|
||||
if(c==illegal || c==incomplete) {
|
||||
rv = 0;
|
||||
break;
|
||||
}
|
||||
size_t width = utf_traits<CharOut>::width(c);
|
||||
if(buffer_size < width) {
|
||||
rv=0;
|
||||
break;
|
||||
}
|
||||
buffer = utf_traits<CharOut>::template encode<CharOut *>(c,buffer);
|
||||
buffer_size -= width;
|
||||
}
|
||||
*buffer++ = 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
/// \cond INTERNAL
|
||||
namespace details {
|
||||
//
|
||||
// wcslen defined only in C99... So we will not use it
|
||||
//
|
||||
template<typename Char>
|
||||
Char const *basic_strend(Char const *s)
|
||||
{
|
||||
while(*s)
|
||||
s++;
|
||||
return s;
|
||||
}
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
///
|
||||
/// Convert NULL terminated UTF source string to NULL terminated \a output string of size at
|
||||
/// most output_size (including NULL)
|
||||
///
|
||||
/// In case of success output is returned, if the input sequence is illegal,
|
||||
/// or there is not enough room NULL is returned
|
||||
///
|
||||
inline char *narrow(char *output,size_t output_size,wchar_t const *source)
|
||||
{
|
||||
return basic_convert(output,output_size,source,details::basic_strend(source));
|
||||
}
|
||||
///
|
||||
/// Convert UTF text in range [begin,end) to NULL terminated \a output string of size at
|
||||
/// most output_size (including NULL)
|
||||
///
|
||||
/// In case of success output is returned, if the input sequence is illegal,
|
||||
/// or there is not enough room NULL is returned
|
||||
///
|
||||
inline char *narrow(char *output,size_t output_size,wchar_t const *begin,wchar_t const *end)
|
||||
{
|
||||
return basic_convert(output,output_size,begin,end);
|
||||
}
|
||||
///
|
||||
/// Convert NULL terminated UTF source string to NULL terminated \a output string of size at
|
||||
/// most output_size (including NULL)
|
||||
///
|
||||
/// In case of success output is returned, if the input sequence is illegal,
|
||||
/// or there is not enough room NULL is returned
|
||||
///
|
||||
inline wchar_t *widen(wchar_t *output,size_t output_size,char const *source)
|
||||
{
|
||||
return basic_convert(output,output_size,source,details::basic_strend(source));
|
||||
}
|
||||
///
|
||||
/// Convert UTF text in range [begin,end) to NULL terminated \a output string of size at
|
||||
/// most output_size (including NULL)
|
||||
///
|
||||
/// In case of success output is returned, if the input sequence is illegal,
|
||||
/// or there is not enough room NULL is returned
|
||||
///
|
||||
inline wchar_t *widen(wchar_t *output,size_t output_size,char const *begin,char const *end)
|
||||
{
|
||||
return basic_convert(output,output_size,begin,end);
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// Convert between Wide - UTF-16/32 string and UTF-8 string.
|
||||
///
|
||||
/// boost::locale::conv::conversion_error is thrown in a case of a error
|
||||
///
|
||||
inline std::string narrow(wchar_t const *s)
|
||||
{
|
||||
return boost::locale::conv::utf_to_utf<char>(s);
|
||||
}
|
||||
///
|
||||
/// Convert between UTF-8 and UTF-16 string, implemented only on Windows platform
|
||||
///
|
||||
/// boost::locale::conv::conversion_error is thrown in a case of a error
|
||||
///
|
||||
inline std::wstring widen(char const *s)
|
||||
{
|
||||
return boost::locale::conv::utf_to_utf<wchar_t>(s);
|
||||
}
|
||||
///
|
||||
/// Convert between Wide - UTF-16/32 string and UTF-8 string
|
||||
///
|
||||
/// boost::locale::conv::conversion_error is thrown in a case of a error
|
||||
///
|
||||
inline std::string narrow(std::wstring const &s)
|
||||
{
|
||||
return boost::locale::conv::utf_to_utf<char>(s);
|
||||
}
|
||||
///
|
||||
/// Convert between UTF-8 and UTF-16 string, implemented only on Windows platform
|
||||
///
|
||||
/// boost::locale::conv::conversion_error is thrown in a case of a error
|
||||
///
|
||||
inline std::wstring widen(std::string const &s)
|
||||
{
|
||||
return boost::locale::conv::utf_to_utf<wchar_t>(s);
|
||||
}
|
||||
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
101
xs/src/boost/nowide/cstdio.hpp
Executable file
101
xs/src/boost/nowide/cstdio.hpp
Executable file
@ -0,0 +1,101 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_CSTDIO_H_INCLUDED
|
||||
#define BOOST_NOWIDE_CSTDIO_H_INCLUDED
|
||||
|
||||
#include <cstdio>
|
||||
#include <stdio.h>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/stackstring.hpp>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4996)
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN)
|
||||
using std::fopen;
|
||||
using std::freopen;
|
||||
using std::remove;
|
||||
using std::rename;
|
||||
#else
|
||||
|
||||
///
|
||||
/// \brief Same as freopen but file_name and mode are UTF-8 strings
|
||||
///
|
||||
/// If invalid UTF-8 given, NULL is returned and errno is set to EINVAL
|
||||
///
|
||||
inline FILE *freopen(char const *file_name,char const *mode,FILE *stream)
|
||||
{
|
||||
wstackstring wname;
|
||||
wshort_stackstring wmode;
|
||||
if(!wname.convert(file_name) || !wmode.convert(mode)) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
return _wfreopen(wname.c_str(),wmode.c_str(),stream);
|
||||
}
|
||||
///
|
||||
/// \brief Same as fopen but file_name and mode are UTF-8 strings
|
||||
///
|
||||
/// If invalid UTF-8 given, NULL is returned and errno is set to EINVAL
|
||||
///
|
||||
inline FILE *fopen(char const *file_name,char const *mode)
|
||||
{
|
||||
wstackstring wname;
|
||||
wshort_stackstring wmode;
|
||||
if(!wname.convert(file_name) || !wmode.convert(mode)) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
return _wfopen(wname.c_str(),wmode.c_str());
|
||||
}
|
||||
///
|
||||
/// \brief Same as rename but old_name and new_name are UTF-8 strings
|
||||
///
|
||||
/// If invalid UTF-8 given, -1 is returned and errno is set to EINVAL
|
||||
///
|
||||
inline int rename(char const *old_name,char const *new_name)
|
||||
{
|
||||
wstackstring wold,wnew;
|
||||
if(!wold.convert(old_name) || !wnew.convert(new_name)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return _wrename(wold.c_str(),wnew.c_str());
|
||||
}
|
||||
///
|
||||
/// \brief Same as rename but name is UTF-8 string
|
||||
///
|
||||
/// If invalid UTF-8 given, -1 is returned and errno is set to EINVAL
|
||||
///
|
||||
inline int remove(char const *name)
|
||||
{
|
||||
wstackstring wname;
|
||||
if(!wname.convert(name)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return _wremove(wname.c_str());
|
||||
}
|
||||
#endif
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
16
xs/src/boost/nowide/cstdlib.hpp
Executable file
16
xs/src/boost/nowide/cstdlib.hpp
Executable file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_CSTDLIB_HPP_INCLUDED
|
||||
#define BOOST_NOWIDE_CSTDLIB_HPP_INCLUDED
|
||||
|
||||
#include <boost/nowide/cenv.hpp>
|
||||
#include <boost/nowide/system.hpp>
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
415
xs/src/boost/nowide/filebuf.hpp
Executable file
415
xs/src/boost/nowide/filebuf.hpp
Executable file
@ -0,0 +1,415 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_FILEBUF_HPP
|
||||
#define BOOST_NOWIDE_FILEBUF_HPP
|
||||
|
||||
#include <iosfwd>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/nowide/stackstring.hpp>
|
||||
#include <fstream>
|
||||
#include <streambuf>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4996 4244 4800)
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_FSTREAM_TESTS) && !defined(BOOST_NOWIDE_DOXYGEN)
|
||||
using std::basic_filebuf;
|
||||
using std::filebuf;
|
||||
#else // Windows
|
||||
|
||||
///
|
||||
/// \brief This forward declaration defined the basic_filebuf type.
|
||||
///
|
||||
/// it is implemented and specialized for CharType = char, it behaves
|
||||
/// implements std::filebuf over standard C I/O
|
||||
///
|
||||
template<typename CharType,typename Traits = std::char_traits<CharType> >
|
||||
class basic_filebuf;
|
||||
|
||||
///
|
||||
/// \brief This is implementation of std::filebuf
|
||||
///
|
||||
/// it is implemented and specialized for CharType = char, it behaves
|
||||
/// implements std::filebuf over standard C I/O
|
||||
///
|
||||
template<>
|
||||
class basic_filebuf<char> : public std::basic_streambuf<char> {
|
||||
public:
|
||||
///
|
||||
/// Creates new filebuf
|
||||
///
|
||||
basic_filebuf() :
|
||||
buffer_size_(4),
|
||||
buffer_(0),
|
||||
file_(0),
|
||||
own_(true),
|
||||
mode_(std::ios::in | std::ios::out)
|
||||
{
|
||||
setg(0,0,0);
|
||||
setp(0,0);
|
||||
}
|
||||
|
||||
virtual ~basic_filebuf()
|
||||
{
|
||||
if(file_) {
|
||||
::fclose(file_);
|
||||
file_ = 0;
|
||||
}
|
||||
if(own_ && buffer_)
|
||||
delete [] buffer_;
|
||||
}
|
||||
|
||||
///
|
||||
/// Same as std::filebuf::open but s is UTF-8 string
|
||||
///
|
||||
basic_filebuf *open(std::string const &s,std::ios_base::openmode mode)
|
||||
{
|
||||
return open(s.c_str(),mode);
|
||||
}
|
||||
///
|
||||
/// Same as std::filebuf::open but s is UTF-8 string
|
||||
///
|
||||
basic_filebuf *open(char const *s,std::ios_base::openmode mode)
|
||||
{
|
||||
if(file_) {
|
||||
sync();
|
||||
::fclose(file_);
|
||||
file_ = 0;
|
||||
}
|
||||
bool ate = bool(mode & std::ios_base::ate);
|
||||
if(ate)
|
||||
mode = mode ^ std::ios_base::ate;
|
||||
wchar_t const *smode = get_mode(mode);
|
||||
if(!smode)
|
||||
return 0;
|
||||
wstackstring name;
|
||||
if(!name.convert(s))
|
||||
return 0;
|
||||
#ifdef BOOST_NOWIDE_FSTREAM_TESTS
|
||||
FILE *f = ::fopen(s,boost::nowide::convert(smode).c_str());
|
||||
#else
|
||||
FILE *f = ::_wfopen(name.c_str(),smode);
|
||||
#endif
|
||||
if(!f)
|
||||
return 0;
|
||||
if(ate && fseek(f,0,SEEK_END)!=0) {
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
file_ = f;
|
||||
return this;
|
||||
}
|
||||
///
|
||||
/// Same as std::filebuf::close()
|
||||
///
|
||||
basic_filebuf *close()
|
||||
{
|
||||
bool res = sync() == 0;
|
||||
if(file_) {
|
||||
if(::fclose(file_)!=0)
|
||||
res = false;
|
||||
file_ = 0;
|
||||
}
|
||||
return res ? this : 0;
|
||||
}
|
||||
///
|
||||
/// Same as std::filebuf::is_open()
|
||||
///
|
||||
bool is_open() const
|
||||
{
|
||||
return file_ != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void make_buffer()
|
||||
{
|
||||
if(buffer_)
|
||||
return;
|
||||
if(buffer_size_ > 0) {
|
||||
buffer_ = new char [buffer_size_];
|
||||
own_ = true;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
|
||||
virtual std::streambuf *setbuf(char *s,std::streamsize n)
|
||||
{
|
||||
if(!buffer_ && n>=0) {
|
||||
buffer_ = s;
|
||||
buffer_size_ = n;
|
||||
own_ = false;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
#ifdef BOOST_NOWIDE_DEBUG_FILEBUF
|
||||
|
||||
void print_buf(char *b,char *p,char *e)
|
||||
{
|
||||
std::cerr << "-- Is Null: " << (b==0) << std::endl;;
|
||||
if(b==0)
|
||||
return;
|
||||
if(e != 0)
|
||||
std::cerr << "-- Total: " << e - b <<" offset from start " << p - b << std::endl;
|
||||
else
|
||||
std::cerr << "-- Total: " << p - b << std::endl;
|
||||
|
||||
std::cerr << "-- [";
|
||||
for(char *ptr = b;ptr<p;ptr++)
|
||||
std::cerr << *ptr;
|
||||
if(e!=0) {
|
||||
std::cerr << "|";
|
||||
for(char *ptr = p;ptr<e;ptr++)
|
||||
std::cerr << *ptr;
|
||||
}
|
||||
std::cerr << "]" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
void print_state()
|
||||
{
|
||||
std::cerr << "- Output:" << std::endl;
|
||||
print_buf(pbase(),pptr(),0);
|
||||
std::cerr << "- Input:" << std::endl;
|
||||
print_buf(eback(),gptr(),egptr());
|
||||
std::cerr << "- fpos: " << (file_ ? ftell(file_) : -1L) << std::endl;
|
||||
}
|
||||
|
||||
struct print_guard
|
||||
{
|
||||
print_guard(basic_filebuf *p,char const *func)
|
||||
{
|
||||
self = p;
|
||||
f=func;
|
||||
std::cerr << "In: " << f << std::endl;
|
||||
self->print_state();
|
||||
}
|
||||
~print_guard()
|
||||
{
|
||||
std::cerr << "Out: " << f << std::endl;
|
||||
self->print_state();
|
||||
}
|
||||
basic_filebuf *self;
|
||||
char const *f;
|
||||
};
|
||||
#else
|
||||
#endif
|
||||
|
||||
int overflow(int c)
|
||||
{
|
||||
#ifdef BOOST_NOWIDE_DEBUG_FILEBUF
|
||||
print_guard g(this,__FUNCTION__);
|
||||
#endif
|
||||
if(!file_)
|
||||
return EOF;
|
||||
|
||||
if(fixg() < 0)
|
||||
return EOF;
|
||||
|
||||
size_t n = pptr() - pbase();
|
||||
if(n > 0) {
|
||||
if(::fwrite(pbase(),1,n,file_) < n)
|
||||
return -1;
|
||||
fflush(file_);
|
||||
}
|
||||
|
||||
if(buffer_size_ > 0) {
|
||||
make_buffer();
|
||||
setp(buffer_,buffer_+buffer_size_);
|
||||
if(c!=EOF)
|
||||
sputc(c);
|
||||
}
|
||||
else if(c!=EOF) {
|
||||
if(::fputc(c,file_)==EOF)
|
||||
return EOF;
|
||||
fflush(file_);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int sync()
|
||||
{
|
||||
return overflow(EOF);
|
||||
}
|
||||
|
||||
int underflow()
|
||||
{
|
||||
#ifdef BOOST_NOWIDE_DEBUG_FILEBUF
|
||||
print_guard g(this,__FUNCTION__);
|
||||
#endif
|
||||
if(!file_)
|
||||
return EOF;
|
||||
if(fixp() < 0)
|
||||
return EOF;
|
||||
if(buffer_size_ == 0) {
|
||||
int c = ::fgetc(file_);
|
||||
if(c==EOF) {
|
||||
return EOF;
|
||||
}
|
||||
last_char_ = c;
|
||||
setg(&last_char_,&last_char_,&last_char_ + 1);
|
||||
return c;
|
||||
}
|
||||
make_buffer();
|
||||
size_t n = ::fread(buffer_,1,buffer_size_,file_);
|
||||
setg(buffer_,buffer_,buffer_+n);
|
||||
if(n == 0)
|
||||
return EOF;
|
||||
return std::char_traits<char>::to_int_type(*gptr());
|
||||
}
|
||||
|
||||
int pbackfail(int)
|
||||
{
|
||||
return pubseekoff(-1,std::ios::cur);
|
||||
}
|
||||
|
||||
std::streampos seekoff(std::streamoff off,
|
||||
std::ios_base::seekdir seekdir,
|
||||
std::ios_base::openmode /*m*/)
|
||||
{
|
||||
#ifdef BOOST_NOWIDE_DEBUG_FILEBUF
|
||||
print_guard g(this,__FUNCTION__);
|
||||
#endif
|
||||
if(!file_)
|
||||
return EOF;
|
||||
if(fixp() < 0 || fixg() < 0)
|
||||
return EOF;
|
||||
if(seekdir == std::ios_base::cur) {
|
||||
if( ::fseek(file_,off,SEEK_CUR) < 0)
|
||||
return EOF;
|
||||
}
|
||||
else if(seekdir == std::ios_base::beg) {
|
||||
if( ::fseek(file_,off,SEEK_SET) < 0)
|
||||
return EOF;
|
||||
}
|
||||
else if(seekdir == std::ios_base::end) {
|
||||
if( ::fseek(file_,off,SEEK_END) < 0)
|
||||
return EOF;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
return ftell(file_);
|
||||
}
|
||||
std::streampos seekpos(std::streampos off,std::ios_base::openmode m)
|
||||
{
|
||||
return seekoff(std::streamoff(off),std::ios_base::beg,m);
|
||||
}
|
||||
private:
|
||||
int fixg()
|
||||
{
|
||||
if(gptr()!=egptr()) {
|
||||
std::streamsize off = gptr() - egptr();
|
||||
setg(0,0,0);
|
||||
if(fseek(file_,off,SEEK_CUR) != 0)
|
||||
return -1;
|
||||
}
|
||||
setg(0,0,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fixp()
|
||||
{
|
||||
if(pptr()!=0) {
|
||||
int r = sync();
|
||||
setp(0,0);
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void reset(FILE *f = 0)
|
||||
{
|
||||
sync();
|
||||
if(file_) {
|
||||
fclose(file_);
|
||||
file_ = 0;
|
||||
}
|
||||
file_ = f;
|
||||
}
|
||||
|
||||
|
||||
static wchar_t const *get_mode(std::ios_base::openmode mode)
|
||||
{
|
||||
//
|
||||
// done according to n2914 table 106 27.9.1.4
|
||||
//
|
||||
|
||||
// note can't use switch case as overload operator can't be used
|
||||
// in constant expression
|
||||
if(mode == (std::ios_base::out))
|
||||
return L"w";
|
||||
if(mode == (std::ios_base::out | std::ios_base::app))
|
||||
return L"a";
|
||||
if(mode == (std::ios_base::app))
|
||||
return L"a";
|
||||
if(mode == (std::ios_base::out | std::ios_base::trunc))
|
||||
return L"w";
|
||||
if(mode == (std::ios_base::in))
|
||||
return L"r";
|
||||
if(mode == (std::ios_base::in | std::ios_base::out))
|
||||
return L"r+";
|
||||
if(mode == (std::ios_base::in | std::ios_base::out | std::ios_base::trunc))
|
||||
return L"w+";
|
||||
if(mode == (std::ios_base::in | std::ios_base::out | std::ios_base::app))
|
||||
return L"a+";
|
||||
if(mode == (std::ios_base::in | std::ios_base::app))
|
||||
return L"a+";
|
||||
if(mode == (std::ios_base::binary | std::ios_base::out))
|
||||
return L"wb";
|
||||
if(mode == (std::ios_base::binary | std::ios_base::out | std::ios_base::app))
|
||||
return L"ab";
|
||||
if(mode == (std::ios_base::binary | std::ios_base::app))
|
||||
return L"ab";
|
||||
if(mode == (std::ios_base::binary | std::ios_base::out | std::ios_base::trunc))
|
||||
return L"wb";
|
||||
if(mode == (std::ios_base::binary | std::ios_base::in))
|
||||
return L"rb";
|
||||
if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out))
|
||||
return L"r+b";
|
||||
if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::trunc))
|
||||
return L"w+b";
|
||||
if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::out | std::ios_base::app))
|
||||
return L"a+b";
|
||||
if(mode == (std::ios_base::binary | std::ios_base::in | std::ios_base::app))
|
||||
return L"a+b";
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t buffer_size_;
|
||||
char *buffer_;
|
||||
FILE *file_;
|
||||
bool own_;
|
||||
char last_char_;
|
||||
std::ios::openmode mode_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Convinience typedef
|
||||
///
|
||||
typedef basic_filebuf<char> filebuf;
|
||||
|
||||
#endif // windows
|
||||
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
283
xs/src/boost/nowide/fstream.hpp
Executable file
283
xs/src/boost/nowide/fstream.hpp
Executable file
@ -0,0 +1,283 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_FSTREAM_INCLUDED_HPP
|
||||
#define BOOST_NOWIDE_FSTREAM_INCLUDED_HPP
|
||||
|
||||
//#include <iosfwd>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <boost/nowide/filebuf.hpp>
|
||||
|
||||
namespace boost {
|
||||
///
|
||||
/// \brief This namespace includes implementation of the standard library functios
|
||||
/// such that they accept UTF-8 strings on Windows. On other platforms it is just an alias
|
||||
/// of std namespace (i.e. not on Windows)
|
||||
///
|
||||
namespace nowide {
|
||||
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_FSTREAM_TESTS) && !defined(BOOST_NOWIDE_DOXYGEN)
|
||||
|
||||
using std::basic_ifstream;
|
||||
using std::basic_ofstream;
|
||||
using std::basic_fstream;
|
||||
using std::ifstream;
|
||||
using std::ofstream;
|
||||
using std::fstream;
|
||||
|
||||
#else
|
||||
///
|
||||
/// \brief Same as std::basic_ifstream<char> but accepts UTF-8 strings under Windows
|
||||
///
|
||||
template<typename CharType,typename Traits = std::char_traits<CharType> >
|
||||
class basic_ifstream : public std::basic_istream<CharType,Traits>
|
||||
{
|
||||
public:
|
||||
typedef basic_filebuf<CharType,Traits> internal_buffer_type;
|
||||
typedef std::basic_istream<CharType,Traits> internal_stream_type;
|
||||
|
||||
basic_ifstream() :
|
||||
internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
}
|
||||
|
||||
explicit basic_ifstream(char const *file_name,std::ios_base::openmode mode = std::ios_base::in) :
|
||||
internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name,mode);
|
||||
}
|
||||
|
||||
explicit basic_ifstream(std::string const &file_name,std::ios_base::openmode mode = std::ios_base::in) :
|
||||
internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name,mode);
|
||||
}
|
||||
|
||||
|
||||
void open(std::string const &file_name,std::ios_base::openmode mode = std::ios_base::in)
|
||||
{
|
||||
open(file_name.c_str(),mode);
|
||||
}
|
||||
void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::in)
|
||||
{
|
||||
if(!buf_->open(file_name,mode | std::ios_base::in)) {
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
else {
|
||||
this->clear();
|
||||
}
|
||||
}
|
||||
bool is_open()
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
bool is_open() const
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
void close()
|
||||
{
|
||||
if(!buf_->close())
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
internal_buffer_type *rdbuf() const
|
||||
{
|
||||
return buf_.get();
|
||||
}
|
||||
~basic_ifstream()
|
||||
{
|
||||
buf_->close();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::scoped_ptr<internal_buffer_type> buf_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Same as std::basic_ofstream<char> but accepts UTF-8 strings under Windows
|
||||
///
|
||||
|
||||
template<typename CharType,typename Traits = std::char_traits<CharType> >
|
||||
class basic_ofstream : public std::basic_ostream<CharType,Traits>
|
||||
{
|
||||
public:
|
||||
typedef basic_filebuf<CharType,Traits> internal_buffer_type;
|
||||
typedef std::basic_ostream<CharType,Traits> internal_stream_type;
|
||||
|
||||
basic_ofstream() :
|
||||
internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
}
|
||||
explicit basic_ofstream(char const *file_name,std::ios_base::openmode mode = std::ios_base::out) :
|
||||
internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name,mode);
|
||||
}
|
||||
explicit basic_ofstream(std::string const &file_name,std::ios_base::openmode mode = std::ios_base::out) :
|
||||
internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name,mode);
|
||||
}
|
||||
void open(std::string const &file_name,std::ios_base::openmode mode = std::ios_base::out)
|
||||
{
|
||||
open(file_name.c_str(),mode);
|
||||
}
|
||||
void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::out)
|
||||
{
|
||||
if(!buf_->open(file_name,mode | std::ios_base::out)) {
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
else {
|
||||
this->clear();
|
||||
}
|
||||
}
|
||||
bool is_open()
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
bool is_open() const
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
void close()
|
||||
{
|
||||
if(!buf_->close())
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
internal_buffer_type *rdbuf() const
|
||||
{
|
||||
return buf_.get();
|
||||
}
|
||||
~basic_ofstream()
|
||||
{
|
||||
buf_->close();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::scoped_ptr<internal_buffer_type> buf_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Same as std::basic_fstream<char> but accepts UTF-8 strings under Windows
|
||||
///
|
||||
|
||||
template<typename CharType,typename Traits = std::char_traits<CharType> >
|
||||
class basic_fstream : public std::basic_iostream<CharType,Traits>
|
||||
{
|
||||
public:
|
||||
typedef basic_filebuf<CharType,Traits> internal_buffer_type;
|
||||
typedef std::basic_iostream<CharType,Traits> internal_stream_type;
|
||||
|
||||
basic_fstream() :
|
||||
internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
}
|
||||
explicit basic_fstream(char const *file_name,std::ios_base::openmode mode = std::ios_base::out | std::ios_base::in) :
|
||||
internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name,mode);
|
||||
}
|
||||
explicit basic_fstream(std::string const &file_name,std::ios_base::openmode mode = std::ios_base::out | std::ios_base::in) :
|
||||
internal_stream_type(0)
|
||||
{
|
||||
buf_.reset(new internal_buffer_type());
|
||||
std::ios::rdbuf(buf_.get());
|
||||
open(file_name,mode);
|
||||
}
|
||||
void open(std::string const &file_name,std::ios_base::openmode mode = std::ios_base::out | std::ios_base::out)
|
||||
{
|
||||
open(file_name.c_str(),mode);
|
||||
}
|
||||
void open(char const *file_name,std::ios_base::openmode mode = std::ios_base::out | std::ios_base::out)
|
||||
{
|
||||
if(!buf_->open(file_name,mode)) {
|
||||
this->setstate(std::ios_base::failbit);
|
||||
}
|
||||
else {
|
||||
this->clear();
|
||||
}
|
||||
}
|
||||
bool is_open()
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
bool is_open() const
|
||||
{
|
||||
return buf_->is_open();
|
||||
}
|
||||
void close()
|
||||
{
|
||||
if(!buf_->close())
|
||||
this->setstate(std::ios_base::failbit);
|
||||
else
|
||||
this->clear();
|
||||
}
|
||||
|
||||
internal_buffer_type *rdbuf() const
|
||||
{
|
||||
return buf_.get();
|
||||
}
|
||||
~basic_fstream()
|
||||
{
|
||||
buf_->close();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::scoped_ptr<internal_buffer_type> buf_;
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
/// \brief Same as std::filebuf but accepts UTF-8 strings under Windows
|
||||
///
|
||||
typedef basic_filebuf<char> filebuf;
|
||||
///
|
||||
/// Same as std::ifstream but accepts UTF-8 strings under Windows
|
||||
///
|
||||
typedef basic_ifstream<char> ifstream;
|
||||
///
|
||||
/// Same as std::ofstream but accepts UTF-8 strings under Windows
|
||||
///
|
||||
typedef basic_ofstream<char> ofstream;
|
||||
///
|
||||
/// Same as std::fstream but accepts UTF-8 strings under Windows
|
||||
///
|
||||
typedef basic_fstream<char> fstream;
|
||||
|
||||
#endif
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
28
xs/src/boost/nowide/integration/filesystem.hpp
Executable file
28
xs/src/boost/nowide/integration/filesystem.hpp
Executable file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_INTEGRATION_FILESYSTEM_HPP_INCLUDED
|
||||
#define BOOST_NOWIDE_INTEGRATION_FILESYSTEM_HPP_INCLUDED
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/nowide/utf8_codecvt.hpp>
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
///
|
||||
/// Instal utf8_codecvt facet into boost::filesystem::path such all char strings are interpreted as utf-8 strings
|
||||
///
|
||||
inline void nowide_filesystem()
|
||||
{
|
||||
std::locale tmp = std::locale(std::locale(),new boost::nowide::utf8_codecvt<wchar_t>());
|
||||
boost::filesystem::path::imbue(tmp);
|
||||
}
|
||||
} // nowide
|
||||
} // boost
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
261
xs/src/boost/nowide/iostream.cpp
Executable file
261
xs/src/boost/nowide/iostream.cpp
Executable file
@ -0,0 +1,261 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#define BOOST_NOWIDE_SOURCE
|
||||
#include <boost/nowide/iostream.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
#ifdef BOOST_WINDOWS
|
||||
|
||||
#ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
#endif
|
||||
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
namespace details {
|
||||
class console_output_buffer : public std::streambuf {
|
||||
public:
|
||||
console_output_buffer(HANDLE h) :
|
||||
handle_(h),
|
||||
isatty_(false)
|
||||
{
|
||||
if(handle_) {
|
||||
DWORD dummy;
|
||||
isatty_ = GetConsoleMode(handle_,&dummy) == TRUE;
|
||||
}
|
||||
}
|
||||
protected:
|
||||
int sync()
|
||||
{
|
||||
return overflow(EOF);
|
||||
}
|
||||
int overflow(int c)
|
||||
{
|
||||
if(!handle_)
|
||||
return -1;
|
||||
int n = pptr() - pbase();
|
||||
int r = 0;
|
||||
|
||||
if(n > 0 && (r=write(pbase(),n)) < 0)
|
||||
return -1;
|
||||
if(r < n) {
|
||||
memmove(pbase(),pbase() + r,n-r);
|
||||
}
|
||||
setp(buffer_, buffer_ + buffer_size);
|
||||
pbump(n-r);
|
||||
if(c!=EOF)
|
||||
sputc(c);
|
||||
return 0;
|
||||
}
|
||||
private:
|
||||
|
||||
int write(char const *p,int n)
|
||||
{
|
||||
namespace uf = boost::locale::utf;
|
||||
char const *b = p;
|
||||
char const *e = p+n;
|
||||
DWORD size=0;
|
||||
if(!isatty_) {
|
||||
if(!WriteFile(handle_,p,n,&size,0) || static_cast<int>(size) != n)
|
||||
return -1;
|
||||
return n;
|
||||
}
|
||||
if(n > buffer_size)
|
||||
return -1;
|
||||
wchar_t *out = wbuffer_;
|
||||
uf::code_point c;
|
||||
size_t decoded = 0;
|
||||
while(p < e && (c = uf::utf_traits<char>::decode(p,e))!=uf::illegal && c!=uf::incomplete) {
|
||||
out = uf::utf_traits<wchar_t>::encode(c,out);
|
||||
decoded = p-b;
|
||||
}
|
||||
if(c==uf::illegal)
|
||||
return -1;
|
||||
if(!WriteConsoleW(handle_,wbuffer_,out - wbuffer_,&size,0))
|
||||
return -1;
|
||||
return decoded;
|
||||
}
|
||||
|
||||
static const int buffer_size = 1024;
|
||||
char buffer_[buffer_size];
|
||||
wchar_t wbuffer_[buffer_size]; // for null
|
||||
HANDLE handle_;
|
||||
bool isatty_;
|
||||
};
|
||||
|
||||
class console_input_buffer: public std::streambuf {
|
||||
public:
|
||||
console_input_buffer(HANDLE h) :
|
||||
handle_(h),
|
||||
isatty_(false),
|
||||
wsize_(0)
|
||||
{
|
||||
if(handle_) {
|
||||
DWORD dummy;
|
||||
isatty_ = GetConsoleMode(handle_,&dummy) == TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
int pbackfail(int c)
|
||||
{
|
||||
if(c==EOF)
|
||||
return EOF;
|
||||
|
||||
if(gptr()!=eback()) {
|
||||
gbump(-1);
|
||||
*gptr() = c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(pback_buffer_.empty()) {
|
||||
pback_buffer_.resize(4);
|
||||
char *b = &pback_buffer_[0];
|
||||
char *e = b + pback_buffer_.size();
|
||||
setg(b,e-1,e);
|
||||
*gptr() = c;
|
||||
}
|
||||
else {
|
||||
size_t n = pback_buffer_.size();
|
||||
std::vector<char> tmp;
|
||||
tmp.resize(n*2);
|
||||
memcpy(&tmp[n],&pback_buffer_[0],n);
|
||||
tmp.swap(pback_buffer_);
|
||||
char *b = &pback_buffer_[0];
|
||||
char *e = b + n * 2;
|
||||
char *p = b+n-1;
|
||||
*p = c;
|
||||
setg(b,p,e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int underflow()
|
||||
{
|
||||
if(!handle_)
|
||||
return -1;
|
||||
if(!pback_buffer_.empty())
|
||||
pback_buffer_.clear();
|
||||
|
||||
size_t n = read();
|
||||
setg(buffer_,buffer_,buffer_+n);
|
||||
if(n == 0)
|
||||
return EOF;
|
||||
return std::char_traits<char>::to_int_type(*gptr());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
size_t read()
|
||||
{
|
||||
namespace uf = boost::locale::utf;
|
||||
if(!isatty_) {
|
||||
DWORD read_bytes = 0;
|
||||
if(!ReadFile(handle_,buffer_,buffer_size,&read_bytes,0))
|
||||
return 0;
|
||||
return read_bytes;
|
||||
}
|
||||
DWORD read_wchars = 0;
|
||||
size_t n = wbuffer_size - wsize_;
|
||||
if(!ReadConsoleW(handle_,wbuffer_,n,&read_wchars,0))
|
||||
return 0;
|
||||
wsize_ += read_wchars;
|
||||
char *out = buffer_;
|
||||
wchar_t *b = wbuffer_;
|
||||
wchar_t *e = b + wsize_;
|
||||
wchar_t *p = b;
|
||||
uf::code_point c;
|
||||
wsize_ = e-p;
|
||||
while(p < e && (c = uf::utf_traits<wchar_t>::decode(p,e))!=uf::illegal && c!=uf::incomplete) {
|
||||
out = uf::utf_traits<char>::encode(c,out);
|
||||
wsize_ = e-p;
|
||||
}
|
||||
|
||||
if(c==uf::illegal)
|
||||
return -1;
|
||||
|
||||
|
||||
if(c==uf::incomplete) {
|
||||
memmove(b,e-wsize_,sizeof(wchar_t)*wsize_);
|
||||
}
|
||||
|
||||
return out - buffer_;
|
||||
}
|
||||
|
||||
static const size_t buffer_size = 1024 * 3;
|
||||
static const size_t wbuffer_size = 1024;
|
||||
char buffer_[buffer_size];
|
||||
wchar_t wbuffer_[buffer_size]; // for null
|
||||
HANDLE handle_;
|
||||
bool isatty_;
|
||||
int wsize_;
|
||||
std::vector<char> pback_buffer_;
|
||||
};
|
||||
|
||||
winconsole_ostream::winconsole_ostream(int fd) : std::ostream(0)
|
||||
{
|
||||
HANDLE h = 0;
|
||||
switch(fd) {
|
||||
case 1:
|
||||
h = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
break;
|
||||
case 2:
|
||||
h = GetStdHandle(STD_ERROR_HANDLE);
|
||||
break;
|
||||
}
|
||||
d.reset(new console_output_buffer(h));
|
||||
std::ostream::rdbuf(d.get());
|
||||
}
|
||||
|
||||
winconsole_ostream::~winconsole_ostream()
|
||||
{
|
||||
}
|
||||
|
||||
winconsole_istream::winconsole_istream() : std::istream(0)
|
||||
{
|
||||
HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
|
||||
d.reset(new console_input_buffer(h));
|
||||
std::istream::rdbuf(d.get());
|
||||
}
|
||||
|
||||
winconsole_istream::~winconsole_istream()
|
||||
{
|
||||
}
|
||||
|
||||
} // details
|
||||
|
||||
BOOST_NOWIDE_DECL details::winconsole_istream cin;
|
||||
BOOST_NOWIDE_DECL details::winconsole_ostream cout(1);
|
||||
BOOST_NOWIDE_DECL details::winconsole_ostream cerr(2);
|
||||
BOOST_NOWIDE_DECL details::winconsole_ostream clog(2);
|
||||
|
||||
namespace {
|
||||
struct initialize {
|
||||
initialize()
|
||||
{
|
||||
boost::nowide::cin.tie(&boost::nowide::cout);
|
||||
boost::nowide::cerr.tie(&boost::nowide::cout);
|
||||
boost::nowide::clog.tie(&boost::nowide::cout);
|
||||
}
|
||||
} inst;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
99
xs/src/boost/nowide/iostream.hpp
Executable file
99
xs/src/boost/nowide/iostream.hpp
Executable file
@ -0,0 +1,99 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_IOSTREAM_HPP_INCLUDED
|
||||
#define BOOST_NOWIDE_IOSTREAM_HPP_INCLUDED
|
||||
|
||||
#include <boost/nowide/config.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <istream>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable : 4251)
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN)
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::cin;
|
||||
using std::clog;
|
||||
#else
|
||||
|
||||
/// \cond INTERNAL
|
||||
namespace details {
|
||||
class console_output_buffer;
|
||||
class console_input_buffer;
|
||||
|
||||
class BOOST_NOWIDE_DECL winconsole_ostream : public std::ostream {
|
||||
winconsole_ostream(winconsole_ostream const &);
|
||||
void operator=(winconsole_ostream const &);
|
||||
public:
|
||||
winconsole_ostream(int fd);
|
||||
~winconsole_ostream();
|
||||
private:
|
||||
boost::scoped_ptr<console_output_buffer> d;
|
||||
};
|
||||
|
||||
class BOOST_NOWIDE_DECL winconsole_istream : public std::istream {
|
||||
winconsole_istream(winconsole_istream const &);
|
||||
void operator=(winconsole_istream const &);
|
||||
public:
|
||||
|
||||
winconsole_istream();
|
||||
~winconsole_istream();
|
||||
private:
|
||||
struct data;
|
||||
boost::scoped_ptr<console_input_buffer> d;
|
||||
};
|
||||
} // details
|
||||
|
||||
/// \endcond
|
||||
|
||||
///
|
||||
/// \brief Same as std::cin, but uses UTF-8
|
||||
///
|
||||
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
|
||||
///
|
||||
extern BOOST_NOWIDE_DECL details::winconsole_istream cin;
|
||||
///
|
||||
/// \brief Same as std::cout, but uses UTF-8
|
||||
///
|
||||
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
|
||||
///
|
||||
extern BOOST_NOWIDE_DECL details::winconsole_ostream cout;
|
||||
///
|
||||
/// \brief Same as std::cerr, but uses UTF-8
|
||||
///
|
||||
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
|
||||
///
|
||||
extern BOOST_NOWIDE_DECL details::winconsole_ostream cerr;
|
||||
///
|
||||
/// \brief Same as std::clog, but uses UTF-8
|
||||
///
|
||||
/// Note, the stream is not synchronized with stdio and not affected by std::ios::sync_with_stdio
|
||||
///
|
||||
extern BOOST_NOWIDE_DECL details::winconsole_ostream clog;
|
||||
|
||||
#endif
|
||||
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
154
xs/src/boost/nowide/stackstring.hpp
Executable file
154
xs/src/boost/nowide/stackstring.hpp
Executable file
@ -0,0 +1,154 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_DETAILS_WIDESTR_H_INCLUDED
|
||||
#define BOOST_NOWIDE_DETAILS_WIDESTR_H_INCLUDED
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
|
||||
///
|
||||
/// \brief A class that allows to create a temporary wide or narrow UTF strings from
|
||||
/// wide or narrow UTF source.
|
||||
///
|
||||
/// It uses on stack buffer of the string is short enough
|
||||
/// and allocated a buffer on the heap if the size of the buffer is too small
|
||||
///
|
||||
template<typename CharOut=wchar_t,typename CharIn = char,size_t BufferSize = 256>
|
||||
class basic_stackstring {
|
||||
public:
|
||||
|
||||
static const size_t buffer_size = BufferSize;
|
||||
typedef CharOut output_char;
|
||||
typedef CharIn input_char;
|
||||
|
||||
basic_stackstring(basic_stackstring const &other) :
|
||||
mem_buffer_(0)
|
||||
{
|
||||
clear();
|
||||
if(other.mem_buffer_) {
|
||||
size_t len = 0;
|
||||
while(other.mem_buffer_[len])
|
||||
len ++;
|
||||
mem_buffer_ = new output_char[len + 1];
|
||||
memcpy(mem_buffer_,other.mem_buffer_,sizeof(output_char) * (len+1));
|
||||
}
|
||||
else {
|
||||
memcpy(buffer_,other.buffer_,buffer_size * sizeof(output_char));
|
||||
}
|
||||
}
|
||||
|
||||
void swap(basic_stackstring &other)
|
||||
{
|
||||
std::swap(mem_buffer_,other.mem_buffer_);
|
||||
for(size_t i=0;i<buffer_size;i++)
|
||||
std::swap(buffer_[i],other.buffer_[i]);
|
||||
}
|
||||
basic_stackstring &operator=(basic_stackstring const &other)
|
||||
{
|
||||
if(this != &other) {
|
||||
basic_stackstring tmp(other);
|
||||
swap(tmp);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
basic_stackstring() : mem_buffer_(0)
|
||||
{
|
||||
}
|
||||
bool convert(input_char const *input)
|
||||
{
|
||||
return convert(input,details::basic_strend(input));
|
||||
}
|
||||
bool convert(input_char const *begin,input_char const *end)
|
||||
{
|
||||
clear();
|
||||
|
||||
size_t space = get_space(sizeof(input_char),sizeof(output_char),end - begin) + 1;
|
||||
if(space <= buffer_size) {
|
||||
if(basic_convert(buffer_,buffer_size,begin,end))
|
||||
return true;
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
mem_buffer_ = new output_char[space];
|
||||
if(!basic_convert(mem_buffer_,space,begin,end)) {
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
output_char *c_str()
|
||||
{
|
||||
if(mem_buffer_)
|
||||
return mem_buffer_;
|
||||
return buffer_;
|
||||
}
|
||||
output_char const *c_str() const
|
||||
{
|
||||
if(mem_buffer_)
|
||||
return mem_buffer_;
|
||||
return buffer_;
|
||||
}
|
||||
void clear()
|
||||
{
|
||||
if(mem_buffer_) {
|
||||
delete [] mem_buffer_;
|
||||
mem_buffer_=0;
|
||||
}
|
||||
buffer_[0] = 0;
|
||||
}
|
||||
~basic_stackstring()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
private:
|
||||
static size_t get_space(size_t insize,size_t outsize,size_t in)
|
||||
{
|
||||
if(insize <= outsize)
|
||||
return in;
|
||||
else if(insize == 2 && outsize == 1)
|
||||
return 3 * in;
|
||||
else if(insize == 4 && outsize == 1)
|
||||
return 4 * in;
|
||||
else // if(insize == 4 && outsize == 2)
|
||||
return 2 * in;
|
||||
}
|
||||
output_char buffer_[buffer_size];
|
||||
output_char *mem_buffer_;
|
||||
}; //basic_stackstring
|
||||
|
||||
///
|
||||
/// Convinience typedef
|
||||
///
|
||||
typedef basic_stackstring<wchar_t,char,256> wstackstring;
|
||||
///
|
||||
/// Convinience typedef
|
||||
///
|
||||
typedef basic_stackstring<char,wchar_t,256> stackstring;
|
||||
///
|
||||
/// Convinience typedef
|
||||
///
|
||||
typedef basic_stackstring<wchar_t,char,16> wshort_stackstring;
|
||||
///
|
||||
/// Convinience typedef
|
||||
///
|
||||
typedef basic_stackstring<char,wchar_t,16> short_stackstring;
|
||||
|
||||
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
46
xs/src/boost/nowide/system.hpp
Executable file
46
xs/src/boost/nowide/system.hpp
Executable file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_CSTDLIB_HPP
|
||||
#define BOOST_NOWIDE_CSTDLIB_HPP
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <boost/nowide/stackstring.hpp>
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
|
||||
#if !defined(BOOST_WINDOWS) && !defined(BOOST_NOWIDE_DOXYGEN)
|
||||
|
||||
using ::system;
|
||||
|
||||
#else // Windows
|
||||
|
||||
///
|
||||
/// Same as std::system but cmd is UTF-8.
|
||||
///
|
||||
/// If the input is not valid UTF-8, -1 returned and errno set to EINVAL
|
||||
///
|
||||
inline int system(char const *cmd)
|
||||
{
|
||||
if(!cmd)
|
||||
return _wsystem(0);
|
||||
wstackstring wcmd;
|
||||
if(!wcmd.convert(cmd)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return _wsystem(wcmd.c_str());
|
||||
}
|
||||
|
||||
#endif
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
499
xs/src/boost/nowide/utf8_codecvt.hpp
Executable file
499
xs/src/boost/nowide/utf8_codecvt.hpp
Executable file
@ -0,0 +1,499 @@
|
||||
//
|
||||
// Copyright (c) 2015 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_UTF8_CODECVT_HPP
|
||||
#define BOOST_NOWIDE_UTF8_CODECVT_HPP
|
||||
|
||||
#include <boost/locale/utf.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <locale>
|
||||
|
||||
namespace boost {
|
||||
namespace nowide {
|
||||
|
||||
//
|
||||
// Make sure that mbstate can keep 16 bit of UTF-16 sequence
|
||||
//
|
||||
BOOST_STATIC_ASSERT(sizeof(std::mbstate_t)>=2);
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// MSVC do_length is non-standard it counts wide characters instead of narrow and does not change mbstate
|
||||
#define BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
#endif
|
||||
|
||||
template<typename CharType,int CharSize=sizeof(CharType)>
|
||||
class utf8_codecvt;
|
||||
|
||||
template<typename CharType>
|
||||
class utf8_codecvt<CharType,2> : public std::codecvt<CharType,char,std::mbstate_t>
|
||||
{
|
||||
public:
|
||||
utf8_codecvt(size_t refs = 0) : std::codecvt<CharType,char,std::mbstate_t>(refs)
|
||||
{
|
||||
}
|
||||
protected:
|
||||
|
||||
typedef CharType uchar;
|
||||
|
||||
virtual std::codecvt_base::result do_unshift(std::mbstate_t &s,char *from,char * /*to*/,char *&next) const
|
||||
{
|
||||
boost::uint16_t &state = *reinterpret_cast<boost::uint16_t *>(&s);
|
||||
#ifdef DEBUG_CODECVT
|
||||
std::cout << "Entering unshift " << std::hex << state << std::dec << std::endl;
|
||||
#endif
|
||||
if(state != 0)
|
||||
return std::codecvt_base::error;
|
||||
next=from;
|
||||
return std::codecvt_base::ok;
|
||||
}
|
||||
virtual int do_encoding() const throw()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int do_max_length() const throw()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
virtual bool do_always_noconv() const throw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual int
|
||||
do_length( std::mbstate_t
|
||||
#ifdef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
const
|
||||
#endif
|
||||
&std_state,
|
||||
char const *from,
|
||||
char const *from_end,
|
||||
size_t max) const
|
||||
{
|
||||
#ifndef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
char const *save_from = from;
|
||||
boost::uint16_t &state = *reinterpret_cast<boost::uint16_t *>(&std_state);
|
||||
#else
|
||||
size_t save_max = max;
|
||||
boost::uint16_t state = *reinterpret_cast<boost::uint16_t const *>(&std_state);
|
||||
#endif
|
||||
while(max > 0 && from < from_end){
|
||||
char const *prev_from = from;
|
||||
boost::uint32_t ch=boost::locale::utf::utf_traits<char>::decode(from,from_end);
|
||||
if(ch==boost::locale::utf::incomplete || ch==boost::locale::utf::illegal) {
|
||||
from = prev_from;
|
||||
break;
|
||||
}
|
||||
max --;
|
||||
if(ch > 0xFFFF) {
|
||||
if(state == 0) {
|
||||
from = prev_from;
|
||||
state = 1;
|
||||
}
|
||||
else {
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifndef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
return from - save_from;
|
||||
#else
|
||||
return save_max - max;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
virtual std::codecvt_base::result
|
||||
do_in( std::mbstate_t &std_state,
|
||||
char const *from,
|
||||
char const *from_end,
|
||||
char const *&from_next,
|
||||
uchar *to,
|
||||
uchar *to_end,
|
||||
uchar *&to_next) const
|
||||
{
|
||||
std::codecvt_base::result r=std::codecvt_base::ok;
|
||||
|
||||
// mbstate_t is POD type and should be initialized to 0 (i.a. state = stateT())
|
||||
// according to standard. We use it to keep a flag 0/1 for surrogate pair writing
|
||||
//
|
||||
// if 0 no code above >0xFFFF observed, of 1 a code above 0xFFFF observerd
|
||||
// and first pair is written, but no input consumed
|
||||
boost::uint16_t &state = *reinterpret_cast<boost::uint16_t *>(&std_state);
|
||||
while(to < to_end && from < from_end)
|
||||
{
|
||||
#ifdef DEBUG_CODECVT
|
||||
std::cout << "Entering IN--------------" << std::endl;
|
||||
std::cout << "State " << std::hex << state <<std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
|
||||
#endif
|
||||
char const *from_saved = from;
|
||||
|
||||
uint32_t ch=boost::locale::utf::utf_traits<char>::decode(from,from_end);
|
||||
|
||||
if(ch==boost::locale::utf::illegal) {
|
||||
from = from_saved;
|
||||
r=std::codecvt_base::error;
|
||||
break;
|
||||
}
|
||||
if(ch==boost::locale::utf::incomplete) {
|
||||
from = from_saved;
|
||||
r=std::codecvt_base::partial;
|
||||
break;
|
||||
}
|
||||
// Normal codepoints go direcly to stream
|
||||
if(ch <= 0xFFFF) {
|
||||
*to++=ch;
|
||||
}
|
||||
else {
|
||||
// for other codepoints we do following
|
||||
//
|
||||
// 1. We can't consume our input as we may find ourselfs
|
||||
// in state where all input consumed but not all output written,i.e. only
|
||||
// 1st pair is written
|
||||
// 2. We only write first pair and mark this in the state, we also revert back
|
||||
// the from pointer in order to make sure this codepoint would be read
|
||||
// once again and then we would consume our input together with writing
|
||||
// second surrogate pair
|
||||
ch-=0x10000;
|
||||
boost::uint16_t vh = ch >> 10;
|
||||
boost::uint16_t vl = ch & 0x3FF;
|
||||
boost::uint16_t w1 = vh + 0xD800;
|
||||
boost::uint16_t w2 = vl + 0xDC00;
|
||||
if(state == 0) {
|
||||
from = from_saved;
|
||||
*to++ = w1;
|
||||
state = 1;
|
||||
}
|
||||
else {
|
||||
*to++ = w2;
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
from_next=from;
|
||||
to_next=to;
|
||||
if(r == std::codecvt_base::ok && (from!=from_end || state!=0))
|
||||
r = std::codecvt_base::partial;
|
||||
#ifdef DEBUG_CODECVT
|
||||
std::cout << "Returning ";
|
||||
switch(r) {
|
||||
case std::codecvt_base::ok:
|
||||
std::cout << "ok" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::partial:
|
||||
std::cout << "partial" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::error:
|
||||
std::cout << "error" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cout << "other" << std::endl;
|
||||
break;
|
||||
}
|
||||
std::cout << "State " << std::hex << state <<std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
virtual std::codecvt_base::result
|
||||
do_out( std::mbstate_t &std_state,
|
||||
uchar const *from,
|
||||
uchar const *from_end,
|
||||
uchar const *&from_next,
|
||||
char *to,
|
||||
char *to_end,
|
||||
char *&to_next) const
|
||||
{
|
||||
std::codecvt_base::result r=std::codecvt_base::ok;
|
||||
// mbstate_t is POD type and should be initialized to 0 (i.a. state = stateT())
|
||||
// according to standard. We assume that sizeof(mbstate_t) >=2 in order
|
||||
// to be able to store first observerd surrogate pair
|
||||
//
|
||||
// State: state!=0 - a first surrogate pair was observerd (state = first pair),
|
||||
// we expect the second one to come and then zero the state
|
||||
///
|
||||
boost::uint16_t &state = *reinterpret_cast<boost::uint16_t *>(&std_state);
|
||||
while(to < to_end && from < from_end)
|
||||
{
|
||||
#ifdef DEBUG_CODECVT
|
||||
std::cout << "Entering OUT --------------" << std::endl;
|
||||
std::cout << "State " << std::hex << state <<std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
|
||||
#endif
|
||||
boost::uint32_t ch=0;
|
||||
if(state != 0) {
|
||||
// if the state idecates that 1st surrogate pair was written
|
||||
// we should make sure that the second one that comes is actually
|
||||
// second surrogate
|
||||
boost::uint16_t w1 = state;
|
||||
boost::uint16_t w2 = *from;
|
||||
// we don't forward from as writing may fail to incomplete or
|
||||
// partial conversion
|
||||
if(0xDC00 <= w2 && w2<=0xDFFF) {
|
||||
boost::uint16_t vh = w1 - 0xD800;
|
||||
boost::uint16_t vl = w2 - 0xDC00;
|
||||
ch=((uint32_t(vh) << 10) | vl) + 0x10000;
|
||||
}
|
||||
else {
|
||||
// Invalid surrogate
|
||||
r=std::codecvt_base::error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ch = *from;
|
||||
if(0xD800 <= ch && ch<=0xDBFF) {
|
||||
// if this is a first surrogate pair we put
|
||||
// it into the state and consume it, note we don't
|
||||
// go forward as it should be illegal so we increase
|
||||
// the from pointer manually
|
||||
state = ch;
|
||||
from++;
|
||||
continue;
|
||||
}
|
||||
else if(0xDC00 <= ch && ch<=0xDFFF) {
|
||||
// if we observe second surrogate pair and
|
||||
// first only may be expected we should break from the loop with error
|
||||
// as it is illegal input
|
||||
r=std::codecvt_base::error;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!boost::locale::utf::is_valid_codepoint(ch)) {
|
||||
r=std::codecvt_base::error;
|
||||
break;
|
||||
}
|
||||
int len = boost::locale::utf::utf_traits<char>::width(ch);
|
||||
if(to_end - to < len) {
|
||||
r=std::codecvt_base::partial;
|
||||
break;
|
||||
}
|
||||
to = boost::locale::utf::utf_traits<char>::encode(ch,to);
|
||||
state = 0;
|
||||
from++;
|
||||
}
|
||||
from_next=from;
|
||||
to_next=to;
|
||||
if(r==std::codecvt_base::ok && from!=from_end)
|
||||
r = std::codecvt_base::partial;
|
||||
#ifdef DEBUG_CODECVT
|
||||
std::cout << "Returning ";
|
||||
switch(r) {
|
||||
case std::codecvt_base::ok:
|
||||
std::cout << "ok" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::partial:
|
||||
std::cout << "partial" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::error:
|
||||
std::cout << "error" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cout << "other" << std::endl;
|
||||
break;
|
||||
}
|
||||
std::cout << "State " << std::hex << state <<std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename CharType>
|
||||
class utf8_codecvt<CharType,4> : public std::codecvt<CharType,char,std::mbstate_t>
|
||||
{
|
||||
public:
|
||||
utf8_codecvt(size_t refs = 0) : std::codecvt<CharType,char,std::mbstate_t>(refs)
|
||||
{
|
||||
}
|
||||
protected:
|
||||
|
||||
typedef CharType uchar;
|
||||
|
||||
virtual std::codecvt_base::result do_unshift(std::mbstate_t &/*s*/,char *from,char * /*to*/,char *&next) const
|
||||
{
|
||||
next=from;
|
||||
return std::codecvt_base::ok;
|
||||
}
|
||||
virtual int do_encoding() const throw()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int do_max_length() const throw()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
virtual bool do_always_noconv() const throw()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual int
|
||||
do_length( std::mbstate_t
|
||||
#ifdef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
const
|
||||
#endif
|
||||
&/*state*/,
|
||||
char const *from,
|
||||
char const *from_end,
|
||||
size_t max) const
|
||||
{
|
||||
#ifndef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
char const *start_from = from;
|
||||
#else
|
||||
size_t save_max = max;
|
||||
#endif
|
||||
|
||||
while(max > 0 && from < from_end){
|
||||
char const *save_from = from;
|
||||
boost::uint32_t ch=boost::locale::utf::utf_traits<char>::decode(from,from_end);
|
||||
if(ch==boost::locale::utf::incomplete || ch==boost::locale::utf::illegal) {
|
||||
from = save_from;
|
||||
break;
|
||||
}
|
||||
max--;
|
||||
}
|
||||
#ifndef BOOST_NOWIDE_DO_LENGTH_MBSTATE_CONST
|
||||
return from - start_from;
|
||||
#else
|
||||
return save_max - max;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
virtual std::codecvt_base::result
|
||||
do_in( std::mbstate_t &/*state*/,
|
||||
char const *from,
|
||||
char const *from_end,
|
||||
char const *&from_next,
|
||||
uchar *to,
|
||||
uchar *to_end,
|
||||
uchar *&to_next) const
|
||||
{
|
||||
std::codecvt_base::result r=std::codecvt_base::ok;
|
||||
|
||||
// mbstate_t is POD type and should be initialized to 0 (i.a. state = stateT())
|
||||
// according to standard. We use it to keep a flag 0/1 for surrogate pair writing
|
||||
//
|
||||
// if 0 no code above >0xFFFF observed, of 1 a code above 0xFFFF observerd
|
||||
// and first pair is written, but no input consumed
|
||||
while(to < to_end && from < from_end)
|
||||
{
|
||||
#ifdef DEBUG_CODECVT
|
||||
std::cout << "Entering IN--------------" << std::endl;
|
||||
std::cout << "State " << std::hex << state <<std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
|
||||
#endif
|
||||
char const *from_saved = from;
|
||||
|
||||
uint32_t ch=boost::locale::utf::utf_traits<char>::decode(from,from_end);
|
||||
|
||||
if(ch==boost::locale::utf::illegal) {
|
||||
r=std::codecvt_base::error;
|
||||
from = from_saved;
|
||||
break;
|
||||
}
|
||||
if(ch==boost::locale::utf::incomplete) {
|
||||
r=std::codecvt_base::partial;
|
||||
from=from_saved;
|
||||
break;
|
||||
}
|
||||
*to++=ch;
|
||||
}
|
||||
from_next=from;
|
||||
to_next=to;
|
||||
if(r == std::codecvt_base::ok && from!=from_end)
|
||||
r = std::codecvt_base::partial;
|
||||
#ifdef DEBUG_CODECVT
|
||||
std::cout << "Returning ";
|
||||
switch(r) {
|
||||
case std::codecvt_base::ok:
|
||||
std::cout << "ok" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::partial:
|
||||
std::cout << "partial" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::error:
|
||||
std::cout << "error" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cout << "other" << std::endl;
|
||||
break;
|
||||
}
|
||||
std::cout << "State " << std::hex << state <<std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
virtual std::codecvt_base::result
|
||||
do_out( std::mbstate_t &std_state,
|
||||
uchar const *from,
|
||||
uchar const *from_end,
|
||||
uchar const *&from_next,
|
||||
char *to,
|
||||
char *to_end,
|
||||
char *&to_next) const
|
||||
{
|
||||
std::codecvt_base::result r=std::codecvt_base::ok;
|
||||
while(to < to_end && from < from_end)
|
||||
{
|
||||
#ifdef DEBUG_CODECVT
|
||||
std::cout << "Entering OUT --------------" << std::endl;
|
||||
std::cout << "State " << std::hex << state <<std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
|
||||
#endif
|
||||
boost::uint32_t ch=0;
|
||||
ch = *from;
|
||||
if(!boost::locale::utf::is_valid_codepoint(ch)) {
|
||||
r=std::codecvt_base::error;
|
||||
break;
|
||||
}
|
||||
int len = boost::locale::utf::utf_traits<char>::width(ch);
|
||||
if(to_end - to < len) {
|
||||
r=std::codecvt_base::partial;
|
||||
break;
|
||||
}
|
||||
to = boost::locale::utf::utf_traits<char>::encode(ch,to);
|
||||
from++;
|
||||
}
|
||||
from_next=from;
|
||||
to_next=to;
|
||||
if(r==std::codecvt_base::ok && from!=from_end)
|
||||
r = std::codecvt_base::partial;
|
||||
#ifdef DEBUG_CODECVT
|
||||
std::cout << "Returning ";
|
||||
switch(r) {
|
||||
case std::codecvt_base::ok:
|
||||
std::cout << "ok" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::partial:
|
||||
std::cout << "partial" << std::endl;
|
||||
break;
|
||||
case std::codecvt_base::error:
|
||||
std::cout << "error" << std::endl;
|
||||
break;
|
||||
default:
|
||||
std::cout << "other" << std::endl;
|
||||
break;
|
||||
}
|
||||
std::cout << "State " << std::hex << state <<std::endl;
|
||||
std::cout << "Left in " << std::dec << from_end - from << " out " << to_end -to << std::endl;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
} // nowide
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
39
xs/src/boost/nowide/windows.hpp
Executable file
39
xs/src/boost/nowide/windows.hpp
Executable file
@ -0,0 +1,39 @@
|
||||
//
|
||||
// Copyright (c) 2012 Artyom Beilis (Tonkikh)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
#ifndef BOOST_NOWIDE_WINDOWS_HPP_INCLUDED
|
||||
#define BOOST_NOWIDE_WINDOWS_HPP_INCLUDED
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef BOOST_NOWIDE_USE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#else
|
||||
|
||||
//
|
||||
// These are function prototypes... Allow to to include windows.h
|
||||
//
|
||||
extern "C" {
|
||||
|
||||
__declspec(dllimport) wchar_t* __stdcall GetEnvironmentStringsW(void);
|
||||
__declspec(dllimport) int __stdcall FreeEnvironmentStringsW(wchar_t *);
|
||||
__declspec(dllimport) wchar_t* __stdcall GetCommandLineW(void);
|
||||
__declspec(dllimport) wchar_t** __stdcall CommandLineToArgvW(wchar_t const *,int *);
|
||||
__declspec(dllimport) unsigned long __stdcall GetLastError();
|
||||
__declspec(dllimport) void* __stdcall LocalFree(void *);
|
||||
__declspec(dllimport) int __stdcall SetEnvironmentVariableW(wchar_t const *,wchar_t const *);
|
||||
__declspec(dllimport) unsigned long __stdcall GetEnvironmentVariableW(wchar_t const *,wchar_t *,unsigned long);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
///
|
||||
// vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
|
@ -7,13 +7,23 @@ namespace Slic3r {
|
||||
|
||||
BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonCollection &_lower_slices,
|
||||
coord_t _extrusion_width)
|
||||
: expolygon(_expolygon), lower_slices(_lower_slices), extrusion_width(_extrusion_width),
|
||||
: expolygon(_expolygon), extrusion_width(_extrusion_width),
|
||||
resolution(PI/36.0), angle(-1)
|
||||
{
|
||||
/* outset our bridge by an arbitrary amout; we'll use this outer margin
|
||||
for detecting anchors */
|
||||
Polygons grown = offset(this->expolygon, this->extrusion_width);
|
||||
|
||||
// remove narrow gaps from lower slices
|
||||
// (this is only needed as long as we use clipped test lines for angle detection
|
||||
// and we check their endpoints: when endpoint fall in the gap we'd get false
|
||||
// negatives)
|
||||
this->lower_slices.expolygons = offset2_ex(
|
||||
_lower_slices,
|
||||
+this->extrusion_width/2,
|
||||
-this->extrusion_width/2
|
||||
);
|
||||
|
||||
// detect what edges lie on lower slices by turning bridge contour and holes
|
||||
// into polylines and then clipping them with each lower slice's contour
|
||||
this->_edges = intersection_pl(grown, this->lower_slices.contours());
|
||||
@ -34,6 +44,10 @@ BridgeDetector::BridgeDetector(const ExPolygon &_expolygon, const ExPolygonColle
|
||||
svg.draw(this->_anchors, "yellow");
|
||||
svg.draw(this->_edges, "black", scale_(0.2));
|
||||
svg.Close();
|
||||
|
||||
std::cout << "expolygon: " << this->expolygon.dump_perl() << std::endl;
|
||||
for (const ExPolygon &e : this->lower_slices.expolygons)
|
||||
std::cout << "lower: " << e.dump_perl() << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -133,6 +147,13 @@ BridgeDetector::detect_angle()
|
||||
));
|
||||
}
|
||||
if (candidate.coverage > 0) have_coverage = true;
|
||||
|
||||
#if 0
|
||||
std::cout << "angle = " << Slic3r::Geometry::rad2deg(candidate.angle)
|
||||
<< "; coverage = " << candidate.coverage
|
||||
<< "; max_length = " << candidate.max_length
|
||||
<< std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
// if no direction produced coverage, then there's no bridge direction
|
||||
@ -159,12 +180,16 @@ BridgeDetector::detect_angle()
|
||||
return true;
|
||||
}
|
||||
|
||||
Polygons
|
||||
BridgeDetector::coverage() const
|
||||
{
|
||||
if (this->angle == -1) return Polygons();
|
||||
return this->coverage(this->angle);
|
||||
}
|
||||
|
||||
Polygons
|
||||
BridgeDetector::coverage(double angle) const
|
||||
{
|
||||
if (angle == -1) angle = this->angle;
|
||||
if (angle == -1) return Polygons();
|
||||
|
||||
// Clone our expolygon and rotate it so that we work with vertical lines.
|
||||
ExPolygon expolygon = this->expolygon;
|
||||
expolygon.rotate(PI/2.0 - angle, Point(0,0));
|
||||
|
@ -23,7 +23,8 @@ public:
|
||||
|
||||
BridgeDetector(const ExPolygon &_expolygon, const ExPolygonCollection &_lower_slices, coord_t _extrusion_width);
|
||||
bool detect_angle();
|
||||
Polygons coverage(double angle = -1) const;
|
||||
Polygons coverage() const;
|
||||
Polygons coverage(double angle) const;
|
||||
Polylines unsupported_edges(double angle = -1) const;
|
||||
|
||||
private:
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "Config.hpp"
|
||||
#include <stdlib.h> // for setenv()
|
||||
#include <assert.h>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
@ -11,16 +10,15 @@
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/nowide/cenv.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(setenv) && defined(_putenv_s)
|
||||
#define setenv(k, v, o) _putenv_s(k, v)
|
||||
#endif
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
std::string escape_string_cstyle(const std::string &str)
|
||||
@ -360,7 +358,6 @@ ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over)
|
||||
void
|
||||
ConfigBase::setenv_()
|
||||
{
|
||||
#ifdef setenv
|
||||
t_config_option_keys opt_keys = this->keys();
|
||||
for (t_config_option_keys::const_iterator it = opt_keys.begin(); it != opt_keys.end(); ++it) {
|
||||
// prepend the SLIC3R_ prefix
|
||||
@ -373,9 +370,8 @@ ConfigBase::setenv_()
|
||||
for (size_t i = 0; i < envname.size(); ++i)
|
||||
envname[i] = (envname[i] <= 'z' && envname[i] >= 'a') ? envname[i]-('a'-'A') : envname[i];
|
||||
|
||||
setenv(envname.c_str(), this->serialize(*it).c_str(), 1);
|
||||
boost::nowide::setenv(envname.c_str(), this->serialize(*it).c_str(), 1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const ConfigOption*
|
||||
@ -393,7 +389,8 @@ ConfigBase::load(const std::string &file)
|
||||
{
|
||||
namespace pt = boost::property_tree;
|
||||
pt::ptree tree;
|
||||
pt::read_ini(file, tree);
|
||||
boost::nowide::ifstream ifs(file);
|
||||
pt::read_ini(ifs, tree);
|
||||
BOOST_FOREACH(const pt::ptree::value_type &v, tree) {
|
||||
try {
|
||||
t_config_option_key opt_key = v.first;
|
||||
@ -409,8 +406,8 @@ void
|
||||
ConfigBase::save(const std::string &file) const
|
||||
{
|
||||
using namespace std;
|
||||
ofstream c;
|
||||
c.open(file.c_str(), ios::out | ios::trunc);
|
||||
boost::nowide::ofstream c;
|
||||
c.open(file, ios::out | ios::trunc);
|
||||
|
||||
{
|
||||
time_t now;
|
||||
@ -527,19 +524,19 @@ DynamicConfig::empty() const {
|
||||
void
|
||||
DynamicConfig::read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra)
|
||||
{
|
||||
std::vector<const char*> _argv;
|
||||
std::vector<char*> _argv;
|
||||
|
||||
// push a bogus executable name (argv[0])
|
||||
_argv.push_back("");
|
||||
_argv.push_back(const_cast<char*>(""));
|
||||
|
||||
for (size_t i = 0; i < tokens.size(); ++i)
|
||||
_argv.push_back(const_cast<const char*>(tokens[i].c_str()));
|
||||
_argv.push_back(const_cast<char *>(tokens[i].c_str()));
|
||||
|
||||
this->read_cli(_argv.size(), &_argv[0], extra);
|
||||
}
|
||||
|
||||
void
|
||||
DynamicConfig::read_cli(const int argc, const char** argv, t_config_option_keys* extra)
|
||||
DynamicConfig::read_cli(int argc, char** argv, t_config_option_keys* extra)
|
||||
{
|
||||
// cache the CLI option => opt_key mapping
|
||||
std::map<std::string,std::string> opts;
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Name of the configuration option.
|
||||
/// Name of the configuration option.
|
||||
typedef std::string t_config_option_key;
|
||||
typedef std::vector<std::string> t_config_option_keys;
|
||||
|
||||
@ -24,7 +24,11 @@ extern std::string escape_strings_cstyle(const std::vector<std::string> &strs);
|
||||
extern bool unescape_string_cstyle(const std::string &str, std::string &out);
|
||||
extern bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &out);
|
||||
|
||||
// A generic value of a configuration option.
|
||||
/// \brief Public interface for configuration options.
|
||||
///
|
||||
/// Defines get/set for all supported data types.
|
||||
/// Default value for output values is 0 for numeric/boolean types and "" for string types.
|
||||
/// Subclasses override the appropriate functions in the interface and return real data.
|
||||
class ConfigOption {
|
||||
public:
|
||||
virtual ~ConfigOption() {};
|
||||
@ -41,7 +45,7 @@ class ConfigOption {
|
||||
friend bool operator!= (const ConfigOption &a, const ConfigOption &b);
|
||||
};
|
||||
|
||||
// Value of a single valued option (bool, int, float, string, point, enum)
|
||||
/// Value of a single valued option (bool, int, float, string, point, enum)
|
||||
template <class T>
|
||||
class ConfigOptionSingle : public ConfigOption {
|
||||
public:
|
||||
@ -55,14 +59,14 @@ class ConfigOptionSingle : public ConfigOption {
|
||||
};
|
||||
};
|
||||
|
||||
// Value of a vector valued option (bools, ints, floats, strings, points)
|
||||
/// Virtual base class, represents value of a vector valued option (bools, ints, floats, strings, points)
|
||||
class ConfigOptionVectorBase : public ConfigOption {
|
||||
public:
|
||||
virtual ~ConfigOptionVectorBase() {};
|
||||
virtual std::vector<std::string> vserialize() const = 0;
|
||||
};
|
||||
|
||||
// Value of a vector valued option (bools, ints, floats, strings, points), template
|
||||
/// Value of a vector valued option (bools, ints, floats, strings, points), template
|
||||
template <class T>
|
||||
class ConfigOptionVector : public ConfigOptionVectorBase
|
||||
{
|
||||
@ -86,6 +90,8 @@ class ConfigOptionVector : public ConfigOptionVectorBase
|
||||
};
|
||||
};
|
||||
|
||||
/// Template specialization for a single ConfigOption
|
||||
/// Internally resolves to a double.
|
||||
class ConfigOptionFloat : public ConfigOptionSingle<double>
|
||||
{
|
||||
public:
|
||||
@ -108,6 +114,7 @@ class ConfigOptionFloat : public ConfigOptionSingle<double>
|
||||
};
|
||||
};
|
||||
|
||||
/// Vector form of template specialization for floating point numbers.
|
||||
class ConfigOptionFloats : public ConfigOptionVector<double>
|
||||
{
|
||||
public:
|
||||
@ -231,7 +238,7 @@ class ConfigOptionString : public ConfigOptionSingle<std::string>
|
||||
};
|
||||
};
|
||||
|
||||
// semicolon-separated strings
|
||||
/// semicolon-separated strings
|
||||
class ConfigOptionStrings : public ConfigOptionVector<std::string>
|
||||
{
|
||||
public:
|
||||
@ -253,6 +260,8 @@ class ConfigOptionStrings : public ConfigOptionVector<std::string>
|
||||
};
|
||||
};
|
||||
|
||||
/// \brief Specialized floating point class to represent some percentage value of
|
||||
/// another numeric configuration option.
|
||||
class ConfigOptionPercent : public ConfigOptionFloat
|
||||
{
|
||||
public:
|
||||
@ -260,6 +269,8 @@ class ConfigOptionPercent : public ConfigOptionFloat
|
||||
ConfigOptionPercent(double _value) : ConfigOptionFloat(_value) {};
|
||||
ConfigOptionPercent* clone() const { return new ConfigOptionPercent(this->value); };
|
||||
|
||||
/// Calculate the value of this option as it relates to some
|
||||
/// other numerical value.
|
||||
double get_abs_value(double ratio_over) const {
|
||||
return ratio_over * this->value / 100;
|
||||
};
|
||||
@ -280,6 +291,9 @@ class ConfigOptionPercent : public ConfigOptionFloat
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/// Combination class that can store a raw float or a percentage
|
||||
/// value. Includes a flag to indicate how it should be interpreted.
|
||||
class ConfigOptionFloatOrPercent : public ConfigOptionPercent
|
||||
{
|
||||
public:
|
||||
@ -321,6 +335,7 @@ class ConfigOptionFloatOrPercent : public ConfigOptionPercent
|
||||
};
|
||||
};
|
||||
|
||||
/// \brief Configuration option to store a 2D (x,y) tuple.
|
||||
class ConfigOptionPoint : public ConfigOptionSingle<Pointf>
|
||||
{
|
||||
public:
|
||||
@ -339,6 +354,7 @@ class ConfigOptionPoint : public ConfigOptionSingle<Pointf>
|
||||
bool deserialize(std::string str, bool append = false);
|
||||
};
|
||||
|
||||
/// \brief Configuration option to store a 3D (x,y,z) tuple.
|
||||
class ConfigOptionPoint3 : public ConfigOptionSingle<Pointf3>
|
||||
{
|
||||
public:
|
||||
@ -394,6 +410,8 @@ class ConfigOptionPoints : public ConfigOptionVector<Pointf>
|
||||
bool deserialize(std::string str, bool append = false);
|
||||
};
|
||||
|
||||
|
||||
/// \brief Represents a boolean flag
|
||||
class ConfigOptionBool : public ConfigOptionSingle<bool>
|
||||
{
|
||||
public:
|
||||
@ -450,9 +468,10 @@ class ConfigOptionBools : public ConfigOptionVector<bool>
|
||||
};
|
||||
};
|
||||
|
||||
// Map from an enum name to an enum integer value.
|
||||
/// Map from an enum name to an enum integer value.
|
||||
typedef std::map<std::string,int> t_config_enum_values;
|
||||
|
||||
/// \brief Templated enumeration representation.
|
||||
template <class T>
|
||||
class ConfigOptionEnum : public ConfigOptionSingle<T>
|
||||
{
|
||||
@ -477,14 +496,15 @@ class ConfigOptionEnum : public ConfigOptionSingle<T>
|
||||
return true;
|
||||
};
|
||||
|
||||
// Map from an enum name to an enum integer value.
|
||||
/// Map from an enum name to an enum integer value.
|
||||
//FIXME The map is called often, it shall be initialized statically.
|
||||
static t_config_enum_values get_enum_values();
|
||||
};
|
||||
|
||||
// Generic enum configuration value.
|
||||
// We use this one in DynamicConfig objects when creating a config value object for ConfigOptionType == coEnum.
|
||||
// In the StaticConfig, it is better to use the specialized ConfigOptionEnum<T> containers.
|
||||
/// \brief Generic enum configuration value.
|
||||
///
|
||||
/// We use this one in DynamicConfig objects when creating a config value object for ConfigOptionType == coEnum.
|
||||
/// In the StaticConfig, it is better to use the specialized ConfigOptionEnum<T> containers.
|
||||
class ConfigOptionEnumGeneric : public ConfigOptionInt
|
||||
{
|
||||
public:
|
||||
@ -504,102 +524,120 @@ class ConfigOptionEnumGeneric : public ConfigOptionInt
|
||||
};
|
||||
};
|
||||
|
||||
// Type of a configuration value.
|
||||
/// Type of a configuration value.
|
||||
enum ConfigOptionType {
|
||||
coNone,
|
||||
// single float
|
||||
/// single float
|
||||
coFloat,
|
||||
// vector of floats
|
||||
/// vector of floats
|
||||
coFloats,
|
||||
// single int
|
||||
/// single int
|
||||
coInt,
|
||||
// vector of ints
|
||||
/// vector of ints
|
||||
coInts,
|
||||
// single string
|
||||
/// single string
|
||||
coString,
|
||||
// vector of strings
|
||||
/// vector of strings
|
||||
coStrings,
|
||||
// percent value. Currently only used for infill.
|
||||
/// percent value. Currently only used for infill.
|
||||
coPercent,
|
||||
// a fraction or an absolute value
|
||||
/// a fraction or an absolute value
|
||||
coFloatOrPercent,
|
||||
// single 2d point. Currently not used.
|
||||
/// single 2d point. Currently not used.
|
||||
coPoint,
|
||||
// vector of 2d points. Currently used for the definition of the print bed and for the extruder offsets.
|
||||
/// vector of 2d points. Currently used for the definition of the print bed and for the extruder offsets.
|
||||
coPoints,
|
||||
coPoint3,
|
||||
// single boolean value
|
||||
/// single boolean value
|
||||
coBool,
|
||||
// vector of boolean values
|
||||
/// vector of boolean values
|
||||
coBools,
|
||||
// a generic enum
|
||||
/// a generic enum
|
||||
coEnum,
|
||||
};
|
||||
|
||||
// Definition of a configuration value for the purpose of GUI presentation, editing, value mapping and config file handling.
|
||||
/// Definition of a configuration value for the purpose of GUI presentation, editing, value mapping and config file handling.
|
||||
class ConfigOptionDef
|
||||
{
|
||||
public:
|
||||
// What type? bool, int, string etc.
|
||||
/// \brief Type of option referenced.
|
||||
///
|
||||
/// The following (and any vector version) are supported:
|
||||
/// \sa ConfigOptionFloat
|
||||
/// \sa ConfigOptionInt
|
||||
/// \sa ConfigOptionString
|
||||
/// \sa ConfigOptionPercent
|
||||
/// \sa ConfigOptionFloatOrPercent
|
||||
/// \sa ConfigOptionPoint
|
||||
/// \sa ConfigOptionBool
|
||||
/// \sa ConfigOptionPoint3
|
||||
/// \sa ConfigOptionBool
|
||||
ConfigOptionType type;
|
||||
// Default value of this option. The default value object is owned by ConfigDef, it is released in its destructor.
|
||||
/// \brief Default value of this option.
|
||||
///
|
||||
/// The default value object is owned by ConfigDef, it is released in its destructor.
|
||||
ConfigOption* default_value;
|
||||
|
||||
// Usually empty.
|
||||
// Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection,
|
||||
// "select_open" - to open a selection dialog (currently only a serial port selection).
|
||||
/// \brief Specialization to indicate to the GUI what kind of control is more appropriate.
|
||||
///
|
||||
/// Usually empty.
|
||||
/// Special values - "i_enum_open", "f_enum_open" to provide combo box for int or float selection,
|
||||
/// "select_open" - to open a selection dialog (currently only a serial port selection).
|
||||
std::string gui_type;
|
||||
// The flags may be combined.
|
||||
// "show_value" - even if enum_values / enum_labels are set, still display the value, not the enum label.
|
||||
// "align_label_right" - align label to right
|
||||
/// The flags may be combined.
|
||||
/// "show_value" - even if enum_values / enum_labels are set, still display the value, not the enum label.
|
||||
/// "align_label_right" - align label to right
|
||||
std::string gui_flags;
|
||||
// Label of the GUI input field.
|
||||
// In case the GUI input fields are grouped in some views, the label defines a short label of a grouped value,
|
||||
// while full_label contains a label of a stand-alone field.
|
||||
// The full label is shown, when adding an override parameter for an object or a modified object.
|
||||
/// Label of the GUI input field.
|
||||
/// In case the GUI input fields are grouped in some views, the label defines a short label of a grouped value,
|
||||
/// while full_label contains a label of a stand-alone field.
|
||||
/// The full label is shown, when adding an override parameter for an object or a modified object.
|
||||
std::string label;
|
||||
std::string full_label;
|
||||
// Category of a configuration field, from the GUI perspective.
|
||||
// One of: "Layers and Perimeters", "Infill", "Support material", "Speed", "Extruders", "Advanced", "Extrusion Width"
|
||||
/// Category of a configuration field, from the GUI perspective.
|
||||
/// One of: "Layers and Perimeters", "Infill", "Support material", "Speed", "Extruders", "Advanced", "Extrusion Width"
|
||||
std::string category;
|
||||
// A tooltip text shown in the GUI.
|
||||
/// A tooltip text shown in the GUI.
|
||||
std::string tooltip;
|
||||
// Text right from the input field, usually a unit of measurement.
|
||||
/// Text right from the input field, usually a unit of measurement.
|
||||
std::string sidetext;
|
||||
// Format of this parameter on a command line.
|
||||
/// Format of this parameter on a command line.
|
||||
std::string cli;
|
||||
// Set for type == coFloatOrPercent.
|
||||
// It provides a link to a configuration value, of which this option provides a ratio.
|
||||
// For example,
|
||||
// For example external_perimeter_speed may be defined as a fraction of perimeter_speed.
|
||||
/// Set for type == coFloatOrPercent.
|
||||
/// It provides a link to a configuration value, of which this option provides a ratio.
|
||||
/// For example,
|
||||
/// For example external_perimeter_speed may be defined as a fraction of perimeter_speed.
|
||||
t_config_option_key ratio_over;
|
||||
// True for multiline strings.
|
||||
/// True for multiline strings.
|
||||
bool multiline;
|
||||
// For text input: If true, the GUI text box spans the complete page width.
|
||||
/// For text input: If true, the GUI text box spans the complete page width.
|
||||
bool full_width;
|
||||
// Not editable. Currently only used for the display of the number of threads.
|
||||
|
||||
/// This configuration item is not editable.
|
||||
/// Currently only used for the display of the number of threads.
|
||||
bool readonly;
|
||||
// Height of a multiline GUI text box.
|
||||
/// Height of a multiline GUI text box.
|
||||
int height;
|
||||
// Optional width of an input field.
|
||||
/// Optional width of an input field.
|
||||
int width;
|
||||
// <min, max> limit of a numeric input.
|
||||
// If not set, the <min, max> is set to <INT_MIN, INT_MAX>
|
||||
// By setting min=0, only nonnegative input is allowed.
|
||||
/// <min, max> limit of a numeric input.
|
||||
/// If not set, the <min, max> is set to <INT_MIN, INT_MAX>
|
||||
/// By setting min=0, only nonnegative input is allowed.
|
||||
int min;
|
||||
int max;
|
||||
// Legacy names for this configuration option.
|
||||
// Used when parsing legacy configuration file.
|
||||
|
||||
/// Legacy names for this configuration option.
|
||||
/// Used when parsing legacy configuration file.
|
||||
std::vector<t_config_option_key> aliases;
|
||||
// Sometimes a single value may well define multiple values in a "beginner" mode.
|
||||
// Currently used for aliasing "solid_layers" to "top_solid_layers", "bottom_solid_layers".
|
||||
/// Sometimes a single value may well define multiple values in a "beginner" mode.
|
||||
/// Currently used for aliasing "solid_layers" to "top_solid_layers", "bottom_solid_layers".
|
||||
std::vector<t_config_option_key> shortcut;
|
||||
// Definition of values / labels for a combo box.
|
||||
// Mostly used for enums (when type == coEnum), but may be used for ints resp. floats, if gui_type is set to "i_enum_open" resp. "f_enum_open".
|
||||
/// Definition of values / labels for a combo box.
|
||||
/// Mostly used for enums (when type == coEnum), but may be used for ints resp. floats, if gui_type is set to "i_enum_open" resp. "f_enum_open".
|
||||
std::vector<std::string> enum_values;
|
||||
std::vector<std::string> enum_labels;
|
||||
// For enums (when type == coEnum). Maps enum_values to enums.
|
||||
// Initialized by ConfigOptionEnum<xxx>::get_enum_values()
|
||||
/// For enums (when type == coEnum). Maps enum_values to enums.
|
||||
/// Initialized by ConfigOptionEnum<xxx>::get_enum_values()
|
||||
t_config_enum_values enum_keys_map;
|
||||
|
||||
ConfigOptionDef() : type(coNone), default_value(NULL),
|
||||
@ -612,14 +650,14 @@ class ConfigOptionDef
|
||||
ConfigOptionDef& operator= (ConfigOptionDef other);
|
||||
};
|
||||
|
||||
// Map from a config option name to its definition.
|
||||
// The definition does not carry an actual value of the config option, only its constant default value.
|
||||
// t_config_option_key is std::string
|
||||
/// Map from a config option name to its definition.
|
||||
//i The definition does not carry an actual value of the config option, only its constant default value.
|
||||
//i t_config_option_key is std::string
|
||||
typedef std::map<t_config_option_key,ConfigOptionDef> t_optiondef_map;
|
||||
|
||||
// Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
|
||||
// The configuration definition is static: It does not carry the actual configuration values,
|
||||
// but it carries the defaults of the configuration values.
|
||||
/// Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
|
||||
/// The configuration definition is static: It does not carry the actual configuration values,
|
||||
/// but it carries the defaults of the configuration values.
|
||||
class ConfigDef
|
||||
{
|
||||
public:
|
||||
@ -631,14 +669,14 @@ class ConfigDef
|
||||
void merge(const ConfigDef &other);
|
||||
};
|
||||
|
||||
// An abstract configuration store.
|
||||
/// An abstract configuration store.
|
||||
class ConfigBase
|
||||
{
|
||||
public:
|
||||
// Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
|
||||
// The configuration definition is static: It does not carry the actual configuration values,
|
||||
// but it carries the defaults of the configuration values.
|
||||
// ConfigBase does not own ConfigDef, it only references it.
|
||||
/// Definition of configuration values for the purpose of GUI presentation, editing, value mapping and config file handling.
|
||||
/// The configuration definition is static: It does not carry the actual configuration values,
|
||||
/// but it carries the defaults of the configuration values.
|
||||
/// ConfigBase does not own ConfigDef, it only references it.
|
||||
const ConfigDef* def;
|
||||
|
||||
ConfigBase() : def(NULL) {};
|
||||
@ -668,8 +706,8 @@ class ConfigBase
|
||||
void save(const std::string &file) const;
|
||||
};
|
||||
|
||||
// Configuration store with dynamic number of configuration values.
|
||||
// In Slic3r, the dynamic config is mostly used at the user interface layer.
|
||||
/// Configuration store with dynamic number of configuration values.
|
||||
/// In Slic3r, the dynamic config is mostly used at the user interface layer.
|
||||
class DynamicConfig : public virtual ConfigBase
|
||||
{
|
||||
public:
|
||||
@ -685,29 +723,30 @@ class DynamicConfig : public virtual ConfigBase
|
||||
void clear();
|
||||
bool empty() const;
|
||||
void read_cli(const std::vector<std::string> &tokens, t_config_option_keys* extra);
|
||||
void read_cli(const int argc, const char **argv, t_config_option_keys* extra);
|
||||
void read_cli(int argc, char** argv, t_config_option_keys* extra);
|
||||
|
||||
private:
|
||||
typedef std::map<t_config_option_key,ConfigOption*> t_options_map;
|
||||
t_options_map options;
|
||||
};
|
||||
|
||||
// Configuration store with a static definition of configuration values.
|
||||
// In Slic3r, the static configuration stores are during the slicing / g-code generation for efficiency reasons,
|
||||
// because the configuration values could be accessed directly.
|
||||
/// Configuration store with a static definition of configuration values.
|
||||
/// In Slic3r, the static configuration stores are during the slicing / g-code generation for efficiency reasons,
|
||||
/// because the configuration values could be accessed directly.
|
||||
class StaticConfig : public virtual ConfigBase
|
||||
{
|
||||
public:
|
||||
StaticConfig() : ConfigBase() {};
|
||||
// Gets list of config option names for each config option of this->def, which has a static counter-part defined by the derived object
|
||||
// and which could be resolved by this->optptr(key) call.
|
||||
/// Gets list of config option names for each config option of this->def, which has a static counter-part defined by the derived object
|
||||
/// and which could be resolved by this->optptr(key) call.
|
||||
t_config_option_keys keys() const;
|
||||
// Set all statically defined config options to their defaults defined by this->def.
|
||||
/// Set all statically defined config options to their defaults defined by this->def.
|
||||
void set_defaults();
|
||||
// The derived class has to implement optptr to resolve a static configuration value.
|
||||
// virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) = 0;
|
||||
/// The derived class has to implement optptr to resolve a static configuration value.
|
||||
/// virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) = 0;
|
||||
};
|
||||
|
||||
/// Specialization of std::exception to indicate that an unknown config option has been encountered.
|
||||
class UnknownOptionException : public std::exception {};
|
||||
|
||||
}
|
||||
|
@ -167,6 +167,11 @@ class ExtrusionLoop : public ExtrusionEntity
|
||||
void append(const ExtrusionPath &path) {
|
||||
this->paths.push_back(path);
|
||||
};
|
||||
bool has(ExtrusionRole role) const {
|
||||
for (const auto &path : this->paths)
|
||||
if (path.role == role) return true;
|
||||
return false;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
#define DEBUG
|
||||
#undef NDEBUG
|
||||
#include <cassert>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../ClipperUtils.hpp"
|
||||
#include "../Geometry.hpp"
|
||||
#include "../Surface.hpp"
|
||||
#include "../PrintConfig.hpp"
|
||||
|
||||
@ -96,10 +95,8 @@ Fill::_infill_direction(const Surface &surface) const
|
||||
|
||||
if (surface.bridge_angle >= 0) {
|
||||
// use bridge angle
|
||||
//FIXME Vojtech: Add a debugf?
|
||||
// Slic3r::debugf "Filling bridge with angle %d\n", rad2deg($surface->bridge_angle);
|
||||
#ifdef SLIC3R_DEBUG
|
||||
printf("Filling bridge with angle %f\n", surface.bridge_angle);
|
||||
printf("Filling bridge with angle %f\n", Slic3r::Geometry::rad2deg(surface.bridge_angle));
|
||||
#endif
|
||||
out_angle = surface.bridge_angle;
|
||||
} else if (this->layer_id != size_t(-1)) {
|
||||
|
@ -334,25 +334,19 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
|
||||
|
||||
// restore original winding order so that concave and convex detection always happens
|
||||
// on the right/outer side of the polygon
|
||||
if (was_clockwise) {
|
||||
for (Polygons::iterator p = simplified.begin(); p != simplified.end(); ++p)
|
||||
p->reverse();
|
||||
}
|
||||
if (was_clockwise)
|
||||
for (Polygon &p : simplified)
|
||||
p.reverse();
|
||||
|
||||
// concave vertices have priority
|
||||
Points candidates;
|
||||
for (Polygons::const_iterator p = simplified.begin(); p != simplified.end(); ++p) {
|
||||
Points concave = p->concave_points(PI*4/3);
|
||||
candidates.insert(candidates.end(), concave.begin(), concave.end());
|
||||
}
|
||||
for (const Polygon &p : simplified)
|
||||
append_to(candidates, p.concave_points(PI*4/3));
|
||||
|
||||
// if no concave points were found, look for convex vertices
|
||||
if (candidates.empty()) {
|
||||
for (Polygons::const_iterator p = simplified.begin(); p != simplified.end(); ++p) {
|
||||
Points convex = p->convex_points(PI*2/3);
|
||||
candidates.insert(candidates.end(), convex.begin(), convex.end());
|
||||
}
|
||||
}
|
||||
if (candidates.empty())
|
||||
for (const Polygon &p : simplified)
|
||||
append_to(candidates, p.convex_points(PI*2/3));
|
||||
|
||||
// retrieve the last start position for this object
|
||||
if (this->layer != NULL) {
|
||||
@ -375,10 +369,9 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
|
||||
if (!loop.split_at_vertex(point)) loop.split_at(point);
|
||||
} else if (!candidates.empty()) {
|
||||
Points non_overhang;
|
||||
for (Points::const_iterator p = candidates.begin(); p != candidates.end(); ++p) {
|
||||
if (!loop.has_overhang_point(*p))
|
||||
non_overhang.push_back(*p);
|
||||
}
|
||||
for (const Point &p : candidates)
|
||||
if (!loop.has_overhang_point(p))
|
||||
non_overhang.push_back(p);
|
||||
|
||||
if (!non_overhang.empty())
|
||||
candidates = non_overhang;
|
||||
@ -389,8 +382,15 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
|
||||
point = last_pos.projection_onto(polygon);
|
||||
loop.split_at(point);
|
||||
}
|
||||
if (this->layer != NULL)
|
||||
if (this->layer != NULL) {
|
||||
/* Keeping a single starting point for each object works best with objects
|
||||
having a single island. In the other cases, this works when layers are
|
||||
similar, so the algorithm picks the same chain of points. But when an
|
||||
island disappears, the others might suffer from a starting point change
|
||||
even if their shape didn't change. We should probably keep multiple
|
||||
starting points for each layer and test all of them. */
|
||||
this->_seam_position[this->layer->object()] = point;
|
||||
}
|
||||
} else if (seam_position == spRandom) {
|
||||
if (loop.role == elrContourInternalPerimeter) {
|
||||
Polygon polygon = loop.polygon();
|
||||
@ -415,9 +415,11 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
|
||||
if (paths.empty()) return "";
|
||||
|
||||
// apply the small perimeter speed
|
||||
if (paths.front().is_perimeter() && loop.length() <= SMALL_PERIMETER_LENGTH) {
|
||||
if (speed == -1) speed = this->config.get_abs_value("small_perimeter_speed");
|
||||
}
|
||||
if (paths.front().is_perimeter()
|
||||
&& !loop.has(erOverhangPerimeter)
|
||||
&& loop.length() <= SMALL_PERIMETER_LENGTH
|
||||
&& speed == -1)
|
||||
speed = this->config.get_abs_value("small_perimeter_speed");
|
||||
|
||||
// extrude along the path
|
||||
std::string gcode;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
|
||||
#define TINYOBJLOADER_IMPLEMENTATION
|
||||
#include "tiny_obj_loader.h"
|
||||
@ -12,7 +13,6 @@ namespace Slic3r { namespace IO {
|
||||
bool
|
||||
STL::read(std::string input_file, TriangleMesh* mesh)
|
||||
{
|
||||
// TODO: encode file name
|
||||
// TODO: check that file exists
|
||||
|
||||
try {
|
||||
@ -81,7 +81,8 @@ OBJ::read(std::string input_file, Model* model)
|
||||
std::vector<tinyobj::shape_t> shapes;
|
||||
std::vector<tinyobj::material_t> materials;
|
||||
std::string err;
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, input_file.c_str());
|
||||
boost::nowide::ifstream ifs(input_file);
|
||||
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &err, &ifs);
|
||||
|
||||
if (!err.empty()) { // `err` may contain warning message.
|
||||
std::cerr << err << std::endl;
|
||||
@ -153,7 +154,7 @@ POV::write(TriangleMesh& mesh, std::string output_file)
|
||||
mesh2.center_around_origin();
|
||||
|
||||
using namespace std;
|
||||
ofstream pov;
|
||||
boost::nowide::ofstream pov;
|
||||
pov.open(output_file.c_str(), ios::out | ios::trunc);
|
||||
for (int i = 0; i < mesh2.stl.stats.number_of_facets; ++i) {
|
||||
const stl_facet &f = mesh2.stl.facet_start[i];
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/nowide/fstream.hpp>
|
||||
#include <boost/nowide/iostream.hpp>
|
||||
#include <expat/expat.h>
|
||||
|
||||
namespace Slic3r { namespace IO {
|
||||
@ -453,10 +455,10 @@ AMF::read(std::string input_file, Model* model)
|
||||
printf("Couldn't allocate memory for parser\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE *pFile = ::fopen(input_file.c_str(), "rt");
|
||||
if (pFile == NULL) {
|
||||
printf("Cannot open file %s\n", input_file.c_str());
|
||||
|
||||
boost::nowide::ifstream fin(input_file, std::ios::in);
|
||||
if (!fin.is_open()) {
|
||||
boost::nowide::cerr << "Cannot open file: " << input_file << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -467,27 +469,26 @@ AMF::read(std::string input_file, Model* model)
|
||||
|
||||
char buff[8192];
|
||||
bool result = false;
|
||||
for (;;) {
|
||||
int len = (int)fread(buff, 1, 8192, pFile);
|
||||
if (ferror(pFile)) {
|
||||
while (!fin.eof()) {
|
||||
fin.read(buff, sizeof(buff));
|
||||
if (fin.bad()) {
|
||||
printf("AMF parser: Read error\n");
|
||||
break;
|
||||
}
|
||||
int done = feof(pFile);
|
||||
if (XML_Parse(parser, buff, len, done) == XML_STATUS_ERROR) {
|
||||
if (XML_Parse(parser, buff, fin.gcount(), fin.eof()) == XML_STATUS_ERROR) {
|
||||
printf("AMF parser: Parse error at line %lu:\n%s\n",
|
||||
XML_GetCurrentLineNumber(parser),
|
||||
XML_ErrorString(XML_GetErrorCode(parser)));
|
||||
break;
|
||||
}
|
||||
if (done) {
|
||||
if (fin.eof()) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
XML_ParserFree(parser);
|
||||
::fclose(pFile);
|
||||
fin.close();
|
||||
|
||||
if (result)
|
||||
ctx.endDocument();
|
||||
@ -499,12 +500,12 @@ AMF::write(Model& model, std::string output_file)
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
ofstream file;
|
||||
boost::nowide::ofstream file;
|
||||
file.open(output_file, ios::out | ios::trunc);
|
||||
|
||||
file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl
|
||||
<< "<amf unit=\"millimeter\">" << endl
|
||||
<< "<metadata type=\"cad\">Slic3r " << SLIC3R_VERSION << "</metadata>" << endl;
|
||||
<< " <metadata type=\"cad\">Slic3r " << SLIC3R_VERSION << "</metadata>" << endl;
|
||||
|
||||
for (const auto &material : model.materials) {
|
||||
if (material.first.empty())
|
||||
@ -598,7 +599,7 @@ AMF::write(Model& model, std::string output_file)
|
||||
<< " <instance objectid=\"" << object_id << "\">" << endl
|
||||
<< " <deltax>" << instance->offset.x + object->origin_translation.x << "</deltax>" << endl
|
||||
<< " <deltay>" << instance->offset.y + object->origin_translation.y << "</deltay>" << endl
|
||||
<< " <rz>%" << instance->rotation << "</rz>" << endl
|
||||
<< " <rz>" << instance->rotation << "</rz>" << endl
|
||||
<< " <scale>" << instance->scaling_factor << "</scale>" << endl
|
||||
<< " </instance>" << endl;
|
||||
}
|
||||
|
@ -98,19 +98,21 @@ Layer::make_slices()
|
||||
this->slices.expolygons.reserve(slices.size());
|
||||
|
||||
// prepare ordering points
|
||||
// While it's more computationally expensive, we use centroid()
|
||||
// instead of first_point() because it's [much more] deterministic
|
||||
// and preserves ordering across similar layers.
|
||||
Points ordering_points;
|
||||
ordering_points.reserve(slices.size());
|
||||
for (ExPolygons::const_iterator ex = slices.begin(); ex != slices.end(); ++ex)
|
||||
ordering_points.push_back(ex->contour.first_point());
|
||||
for (const ExPolygon &ex : slices)
|
||||
ordering_points.push_back(ex.contour.centroid());
|
||||
|
||||
// sort slices
|
||||
std::vector<Points::size_type> order;
|
||||
Slic3r::Geometry::chained_path(ordering_points, order);
|
||||
|
||||
// populate slices vector
|
||||
for (std::vector<Points::size_type>::const_iterator it = order.begin(); it != order.end(); ++it) {
|
||||
this->slices.expolygons.push_back(slices[*it]);
|
||||
}
|
||||
for (const Points::size_type &o : order)
|
||||
this->slices.expolygons.push_back(slices[o]);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -74,17 +74,17 @@ LayerRegion::process_external_surfaces()
|
||||
Surfaces &surfaces = this->fill_surfaces.surfaces;
|
||||
|
||||
for (size_t j = 0; j < surfaces.size(); ++j) {
|
||||
Surface &surface = surfaces[j];
|
||||
// we don't get any reference to surface because it would be invalidated
|
||||
// by the erase() call below
|
||||
|
||||
if (this->layer()->lower_layer != NULL && surface.is_bridge()) {
|
||||
if (this->layer()->lower_layer != NULL && surfaces[j].is_bridge()) {
|
||||
// If this bridge has one or more holes that are internal surfaces
|
||||
// (thus not visible from the outside), like a slab sustained by
|
||||
// pillars, include them in the bridge in order to have better and
|
||||
// more continuous bridging.
|
||||
Polygons &holes = surface.expolygon.holes;
|
||||
for (int i = 0; i < holes.size(); ++i) {
|
||||
for (int i = 0; i < surfaces[j].expolygon.holes.size(); ++i) {
|
||||
// reverse the hole and consider it a polygon
|
||||
Polygon h = holes[i];
|
||||
Polygon h = surfaces[j].expolygon.holes[i];
|
||||
h.reverse();
|
||||
|
||||
// Is this hole fully contained in the layer slices?
|
||||
@ -94,10 +94,12 @@ LayerRegion::process_external_surfaces()
|
||||
if (k == j) continue;
|
||||
if (h.contains(surfaces[k].expolygon.contour.first_point())) {
|
||||
surfaces.erase(surfaces.begin() + k);
|
||||
if (j > k) --j;
|
||||
--k;
|
||||
}
|
||||
}
|
||||
|
||||
Polygons &holes = surfaces[j].expolygon.holes;
|
||||
holes.erase(holes.begin() + i);
|
||||
--i;
|
||||
}
|
||||
|
@ -13,17 +13,17 @@ MotionPlanner::MotionPlanner(const ExPolygons &islands)
|
||||
: initialized(false)
|
||||
{
|
||||
ExPolygons expp;
|
||||
for (ExPolygons::const_iterator island = islands.begin(); island != islands.end(); ++island)
|
||||
island->simplify(SCALED_EPSILON, &expp);
|
||||
for (const ExPolygon &island : islands)
|
||||
island.simplify(MP_INNER_MARGIN/10, &expp);
|
||||
|
||||
for (ExPolygons::const_iterator island = expp.begin(); island != expp.end(); ++island)
|
||||
this->islands.push_back(MotionPlannerEnv(*island));
|
||||
for (const ExPolygon &island : expp)
|
||||
this->islands.push_back(MotionPlannerEnv(island));
|
||||
}
|
||||
|
||||
MotionPlanner::~MotionPlanner()
|
||||
{
|
||||
for (std::vector<MotionPlannerGraph*>::iterator graph = this->graphs.begin(); graph != this->graphs.end(); ++graph)
|
||||
delete *graph;
|
||||
for (MotionPlannerGraph* graph : this->graphs)
|
||||
delete graph;
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -40,20 +40,20 @@ MotionPlanner::initialize()
|
||||
|
||||
// loop through islands in order to create inner expolygons and collect their contours
|
||||
Polygons outer_holes;
|
||||
for (std::vector<MotionPlannerEnv>::iterator island = this->islands.begin(); island != this->islands.end(); ++island) {
|
||||
for (MotionPlannerEnv &island : this->islands) {
|
||||
// generate the internal env boundaries by shrinking the island
|
||||
// we'll use these inner rings for motion planning (endpoints of the Voronoi-based
|
||||
// graph, visibility check) in order to avoid moving too close to the boundaries
|
||||
island->env = offset_ex(island->island, -MP_INNER_MARGIN);
|
||||
island.env = offset_ex(island.island, -MP_INNER_MARGIN);
|
||||
|
||||
// island contours are holes of our external environment
|
||||
outer_holes.push_back(island->island.contour);
|
||||
outer_holes.push_back(island.island.contour);
|
||||
}
|
||||
|
||||
// generate outer contour as bounding box of everything
|
||||
BoundingBox bb;
|
||||
for (Polygons::const_iterator contour = outer_holes.begin(); contour != outer_holes.end(); ++contour)
|
||||
bb.merge(contour->bounding_box());
|
||||
for (const Polygon contour : outer_holes)
|
||||
bb.merge(contour.bounding_box());
|
||||
|
||||
// grow outer contour
|
||||
Polygons contour = offset(bb.polygon(), +MP_OUTER_MARGIN*2);
|
||||
@ -166,12 +166,16 @@ MotionPlanner::shortest_path(const Point &from, const Point &to)
|
||||
}
|
||||
}
|
||||
|
||||
// Perform some quick simplification (simplify_by_visibility() would make this
|
||||
// unnecessary, but this is much faster)
|
||||
polyline.simplify(MP_INNER_MARGIN/10);
|
||||
|
||||
// remove unnecessary vertices
|
||||
// Note: this is computationally intensive and does not look very necessary
|
||||
// now that we prune the endpoints with the logic above,
|
||||
// so we comment it for now until a good test case arises
|
||||
//polyline.simplify_by_visibility(grown_env);
|
||||
|
||||
|
||||
/*
|
||||
SVG svg("shortest_path.svg");
|
||||
svg.draw(grown_env.expolygons);
|
||||
|
@ -17,8 +17,6 @@ class MultiPoint
|
||||
Points points;
|
||||
|
||||
operator Points() const;
|
||||
MultiPoint() {};
|
||||
explicit MultiPoint(const Points &_points): points(_points) {};
|
||||
void scale(double factor);
|
||||
void translate(double x, double y);
|
||||
void translate(const Point &vector);
|
||||
@ -48,6 +46,11 @@ class MultiPoint
|
||||
std::string dump_perl() const;
|
||||
|
||||
static Points _douglas_peucker(const Points &points, const double tolerance);
|
||||
|
||||
protected:
|
||||
MultiPoint() {};
|
||||
explicit MultiPoint(const Points &_points): points(_points) {};
|
||||
~MultiPoint() = default;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
@ -349,11 +349,10 @@ PerimeterGenerator::_traverse_loops(const PerimeterGeneratorLoops &loops,
|
||||
&& !(this->object_config->support_material && this->object_config->support_material_contact_distance.value == 0)) {
|
||||
// get non-overhang paths by intersecting this loop with the grown lower slices
|
||||
{
|
||||
Polylines polylines = intersection_pl(loop->polygon, this->_lower_slices_p);
|
||||
|
||||
for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline) {
|
||||
const Polylines polylines = intersection_pl(loop->polygon, this->_lower_slices_p);
|
||||
for (const Polyline &polyline : polylines) {
|
||||
ExtrusionPath path(role);
|
||||
path.polyline = *polyline;
|
||||
path.polyline = polyline;
|
||||
path.mm3_per_mm = is_external ? this->_ext_mm3_per_mm : this->_mm3_per_mm;
|
||||
path.width = is_external ? this->ext_perimeter_flow.width : this->perimeter_flow.width;
|
||||
path.height = this->layer_height;
|
||||
@ -365,11 +364,10 @@ PerimeterGenerator::_traverse_loops(const PerimeterGeneratorLoops &loops,
|
||||
// outside the grown lower slices (thus where the distance between
|
||||
// the loop centerline and original lower slices is >= half nozzle diameter
|
||||
{
|
||||
Polylines polylines = diff_pl(loop->polygon, this->_lower_slices_p);
|
||||
|
||||
for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline) {
|
||||
const Polylines polylines = diff_pl(loop->polygon, this->_lower_slices_p);
|
||||
for (const Polyline &polyline : polylines) {
|
||||
ExtrusionPath path(erOverhangPerimeter);
|
||||
path.polyline = *polyline;
|
||||
path.polyline = polyline;
|
||||
path.mm3_per_mm = this->_mm3_per_mm_overhang;
|
||||
path.width = this->overhang_flow.width;
|
||||
path.height = this->overhang_flow.height;
|
||||
|
@ -248,23 +248,24 @@ Polygon::wkt() const
|
||||
Points
|
||||
Polygon::concave_points(double angle) const
|
||||
{
|
||||
Points points;
|
||||
angle = 2*PI - angle;
|
||||
angle = 2*PI - angle + EPSILON;
|
||||
const Points &pp = this->points;
|
||||
Points concave;
|
||||
|
||||
// check whether first point forms a concave angle
|
||||
if (this->points.front().ccw_angle(this->points.back(), *(this->points.begin()+1)) <= angle)
|
||||
points.push_back(this->points.front());
|
||||
if (pp.front().ccw_angle(pp.back(), *(pp.begin()+1)) <= angle)
|
||||
concave.push_back(pp.front());
|
||||
|
||||
// check whether points 1..(n-1) form concave angles
|
||||
for (Points::const_iterator p = this->points.begin()+1; p != this->points.end()-1; ++p) {
|
||||
if (p->ccw_angle(*(p-1), *(p+1)) <= angle) points.push_back(*p);
|
||||
}
|
||||
for (Points::const_iterator p = pp.begin()+1; p != pp.end()-1; ++p)
|
||||
if (p->ccw_angle(*(p-1), *(p+1)) <= angle)
|
||||
concave.push_back(*p);
|
||||
|
||||
// check whether last point forms a concave angle
|
||||
if (this->points.back().ccw_angle(*(this->points.end()-2), this->points.front()) <= angle)
|
||||
points.push_back(this->points.back());
|
||||
if (pp.back().ccw_angle(*(pp.end()-2), pp.front()) <= angle)
|
||||
concave.push_back(pp.back());
|
||||
|
||||
return points;
|
||||
return concave;
|
||||
}
|
||||
|
||||
// find all convex vertices (i.e. having an internal angle smaller than the supplied angle)
|
||||
@ -272,23 +273,24 @@ Polygon::concave_points(double angle) const
|
||||
Points
|
||||
Polygon::convex_points(double angle) const
|
||||
{
|
||||
Points points;
|
||||
angle = 2*PI - angle;
|
||||
angle = 2*PI - angle - EPSILON;
|
||||
const Points &pp = this->points;
|
||||
Points convex;
|
||||
|
||||
// check whether first point forms a convex angle
|
||||
if (this->points.front().ccw_angle(this->points.back(), *(this->points.begin()+1)) >= angle)
|
||||
points.push_back(this->points.front());
|
||||
if (pp.front().ccw_angle(pp.back(), *(pp.begin()+1)) >= angle)
|
||||
convex.push_back(pp.front());
|
||||
|
||||
// check whether points 1..(n-1) form convex angles
|
||||
for (Points::const_iterator p = this->points.begin()+1; p != this->points.end()-1; ++p) {
|
||||
if (p->ccw_angle(*(p-1), *(p+1)) >= angle) points.push_back(*p);
|
||||
}
|
||||
for (Points::const_iterator p = pp.begin()+1; p != pp.end()-1; ++p)
|
||||
if (p->ccw_angle(*(p-1), *(p+1)) >= angle)
|
||||
convex.push_back(*p);
|
||||
|
||||
// check whether last point forms a convex angle
|
||||
if (this->points.back().ccw_angle(*(this->points.end()-2), this->points.front()) >= angle)
|
||||
points.push_back(this->points.back());
|
||||
if (pp.back().ccw_angle(*(pp.end()-2), pp.front()) >= angle)
|
||||
convex.push_back(pp.back());
|
||||
|
||||
return points;
|
||||
return convex;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -198,12 +198,12 @@ Polyline::is_straight() const
|
||||
/* Check that each segment's direction is equal to the line connecting
|
||||
first point and last point. (Checking each line against the previous
|
||||
one would cause the error to accumulate.) */
|
||||
double dir = Line(this->first_point(), this->last_point()).direction();
|
||||
const double dir = Line(this->first_point(), this->last_point()).direction();
|
||||
|
||||
for (const Line &line : this->lines())
|
||||
if (!line.parallel_to(dir))
|
||||
return false;
|
||||
|
||||
Lines lines = this->lines();
|
||||
for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
|
||||
if (!line->parallel_to(dir)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -578,7 +578,7 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->default_value = opt;
|
||||
}
|
||||
|
||||
def = this->add("gap_fill_speed", coFloat);
|
||||
def = this->add("gap_fill_speed", coFloatOrPercent);
|
||||
def->label = "↳ gaps";
|
||||
def->full_label = "Gap fill speed";
|
||||
def->gui_type = "f_enum_open";
|
||||
@ -590,7 +590,7 @@ PrintConfigDef::PrintConfigDef()
|
||||
def->min = 0;
|
||||
def->enum_values.push_back("0");
|
||||
def->enum_labels.push_back("auto");
|
||||
def->default_value = new ConfigOptionFloat(20);
|
||||
def->default_value = new ConfigOptionFloatOrPercent(20, false);
|
||||
|
||||
def = this->add("gcode_arcs", coBool);
|
||||
def->label = "Use native G-code arcs";
|
||||
@ -1384,7 +1384,6 @@ PrintConfigDef::PrintConfigDef()
|
||||
|
||||
def = this->add("support_material_interface_speed", coFloatOrPercent);
|
||||
def->label = "↳ interface";
|
||||
def->label = "Interface Speed";
|
||||
def->category = "Support material interface speed";
|
||||
def->gui_type = "f_enum_open";
|
||||
def->category = "Support material";
|
||||
@ -1706,6 +1705,10 @@ PrintConfigBase::_handle_legacy(t_config_option_key &opt_key, std::string &value
|
||||
values is a dirty hack and will need to be removed sometime in the future, but it
|
||||
will avoid lots of complaints for now. */
|
||||
value = "0";
|
||||
} else if (opt_key == "support_material_threshold" && value == "0") {
|
||||
// 0 used to be automatic threshold, but we introduced percent values so let's
|
||||
// transform it into the default value
|
||||
value = "60%";
|
||||
}
|
||||
|
||||
// cemetery of old config settings
|
||||
|
@ -219,7 +219,7 @@ class PrintRegionConfig : public virtual StaticPrintConfig
|
||||
ConfigOptionPercent fill_density;
|
||||
ConfigOptionBool fill_gaps;
|
||||
ConfigOptionEnum<InfillPattern> fill_pattern;
|
||||
ConfigOptionFloat gap_fill_speed;
|
||||
ConfigOptionFloatOrPercent gap_fill_speed;
|
||||
ConfigOptionInt infill_extruder;
|
||||
ConfigOptionFloatOrPercent infill_extrusion_width;
|
||||
ConfigOptionInt infill_every_layers;
|
||||
|
@ -625,8 +625,6 @@ void PrintObject::_slice()
|
||||
{
|
||||
|
||||
coordf_t raft_height = 0;
|
||||
coordf_t print_z = 0;
|
||||
coordf_t height = 0;
|
||||
coordf_t first_layer_height = this->config.first_layer_height.get_abs_value(this->config.layer_height.value);
|
||||
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include <stdexcept>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
|
||||
#ifdef SLIC3R_DEBUG
|
||||
#include "SVG.hpp"
|
||||
@ -110,20 +112,32 @@ TriangleMesh::~TriangleMesh() {
|
||||
|
||||
void
|
||||
TriangleMesh::ReadSTLFile(const std::string &input_file) {
|
||||
#ifdef BOOST_WINDOWS
|
||||
stl_open(&stl, boost::nowide::widen(input_file).c_str());
|
||||
#else
|
||||
stl_open(&stl, input_file.c_str());
|
||||
#endif
|
||||
if (this->stl.error != 0) throw std::runtime_error("Failed to read STL file");
|
||||
}
|
||||
|
||||
void
|
||||
TriangleMesh::write_ascii(const std::string &output_file)
|
||||
{
|
||||
#ifdef BOOST_WINDOWS
|
||||
stl_write_ascii(&this->stl, boost::nowide::widen(output_file).c_str(), "");
|
||||
#else
|
||||
stl_write_ascii(&this->stl, output_file.c_str(), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
TriangleMesh::write_binary(const std::string &output_file)
|
||||
{
|
||||
#ifdef BOOST_WINDOWS
|
||||
stl_write_binary(&this->stl, boost::nowide::widen(output_file).c_str(), "");
|
||||
#else
|
||||
stl_write_binary(&this->stl, output_file.c_str(), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -234,7 +248,12 @@ TriangleMesh::facets_count() const
|
||||
void
|
||||
TriangleMesh::WriteOBJFile(const std::string &output_file) {
|
||||
stl_generate_shared_vertices(&stl);
|
||||
|
||||
#ifdef BOOST_WINDOWS
|
||||
stl_write_obj(&stl, boost::nowide::widen(output_file).c_str());
|
||||
#else
|
||||
stl_write_obj(&stl, output_file.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
void TriangleMesh::scale(float factor)
|
||||
|
@ -107,6 +107,7 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintCo
|
||||
is_deeply [ map $_->pp, @{$config->get('extruder_offset')} ], [[10,20],[30,45]], 'set/get points';
|
||||
$config->set('extruder_offset', [Slic3r::Pointf->new(10,20),Slic3r::Pointf->new(30,45)]);
|
||||
is_deeply [ map $_->pp, @{$config->get('extruder_offset')} ], [[10,20],[30,45]], 'set/get points';
|
||||
$config->set_deserialize('extruder_offset', $config->serialize('extruder_offset'));
|
||||
is $config->serialize('extruder_offset'), '10x20,30x45', 'serialize points';
|
||||
$config->set_deserialize('extruder_offset', '20x10');
|
||||
is_deeply [ map $_->pp, @{$config->get('extruder_offset')} ], [[20,10]], 'deserialize points';
|
||||
|
@ -31,6 +31,7 @@
|
||||
bool is_infill();
|
||||
bool is_solid_infill();
|
||||
Polygons grow();
|
||||
Clone<Polyline> as_polyline();
|
||||
%{
|
||||
|
||||
SV*
|
||||
|
@ -27,6 +27,7 @@
|
||||
bool is_solid_infill();
|
||||
bool is_bridge();
|
||||
Polygons grow();
|
||||
Clone<Polyline> as_polyline();
|
||||
%{
|
||||
|
||||
ExtrusionPath*
|
||||
|
@ -275,7 +275,7 @@ INPUT
|
||||
T_STD_STRING
|
||||
{
|
||||
size_t len;
|
||||
const char * c = SvPV($arg, len);
|
||||
const char * c = SvPVutf8($arg, len);
|
||||
$var = std::string(c, len);
|
||||
}
|
||||
|
||||
@ -290,7 +290,7 @@ T_STD_VECTOR_STD_STRING
|
||||
for (unsigned int i = 0; i < alen; i++) {
|
||||
elem = av_fetch(av, i, 0);
|
||||
if (elem != NULL) {
|
||||
tmp = SvPV(*elem, len);
|
||||
tmp = SvPVutf8(*elem, len);
|
||||
${var}[i] = std::string(tmp, len);
|
||||
}
|
||||
else
|
||||
|
Loading…
x
Reference in New Issue
Block a user