Merge branch 'master' into gui3-shortcuts

This commit is contained in:
Alessandro Ranellucci 2017-05-20 16:19:33 +02:00
commit dd6864314d
73 changed files with 5651 additions and 464 deletions

View File

@ -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`_

View File

@ -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:

View File

@ -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);

View File

@ -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}) {

View File

@ -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;

View File

@ -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 {

View File

@ -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;

View File

@ -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);
}

View File

@ -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';

View File

@ -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) = @_;

View File

@ -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;
}
});

View File

@ -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;
}

View File

@ -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}} ];
}

View File

@ -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;
}

View File

@ -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};

View File

@ -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

View File

@ -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,
[

View File

@ -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]

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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;
}
{

View File

@ -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__

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 725 B

BIN
var/zoom_out.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 708 B

2484
xs/libslic3r.doxygen Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View 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
View 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

View 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

View 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
View 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

View 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
View 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

View File

@ -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));

View File

@ -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:

View File

@ -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;

View File

@ -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 {};
}

View File

@ -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;
};
};
}

View File

@ -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)) {

View File

@ -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;

View File

@ -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];

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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)

View File

@ -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';

View File

@ -31,6 +31,7 @@
bool is_infill();
bool is_solid_infill();
Polygons grow();
Clone<Polyline> as_polyline();
%{
SV*

View File

@ -27,6 +27,7 @@
bool is_solid_infill();
bool is_bridge();
Polygons grow();
Clone<Polyline> as_polyline();
%{
ExtrusionPath*

View File

@ -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