diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 5b8f9a111..6b6c121af 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -1140,7 +1140,7 @@ sub _extrusionentity_to_verts { my $polyline = $entity->polyline->clone; $polyline->translate(@$copy); $lines = $polyline->lines; - $widths = [ map scale($entity->width), 0..$#$lines ]; + $widths = [ map $entity->width, 0..$#$lines ]; $heights = [ map $entity->height, 0..$#$lines ]; $closed = 0; } else { @@ -1153,206 +1153,13 @@ sub _extrusionentity_to_verts { $polyline->translate(@$copy); my $path_lines = $polyline->lines; push @$lines, @$path_lines; - push @$widths, map scale($path->width), 0..$#$path_lines; + push @$widths, map $path->width, 0..$#$path_lines; push @$heights, map $path->height, 0..$#$path_lines; } } - my ($prev_line, $prev_b1, $prev_b2, $prev_xy_left_normal, $prev_xy_right_normal); - - # loop once more in case of closed loops - my $first_done = 0; - for my $i (0..$#$lines, 0) { - my $line = $lines->[$i]; - last if $i == 0 && $first_done && !$closed; - - my $len = $line->length; - my $unscaled_len = unscale $len; - next if $len == 0; - - my $bottom_z = $top_z - $heights->[$i]; - my $middle_z = ($top_z + $bottom_z) / 2; - my $dist = $widths->[$i]/2; # scaled - - my $v = Slic3r::Pointf3->new_unscale(@{$line->vector}); - $v->scale(1/$unscaled_len); - - my $a = $line->a; - my $b = $line->b; - my $a1 = $a->clone; - my $a2 = $a->clone; - $a1->translate(+$dist*$v->y, -$dist*$v->x); #,, - $a2->translate(-$dist*$v->y, +$dist*$v->x); #,, - my $b1 = $b->clone; - my $b2 = $b->clone; - $b1->translate(+$dist*$v->y, -$dist*$v->x); #,, - $b2->translate(-$dist*$v->y, +$dist*$v->x); #,, - - # calculate new XY normals - my $xy_right_normal = Slic3r::Pointf3->new_unscale(@{$line->normal}, 0); - $xy_right_normal->scale(1/$unscaled_len); - my $xy_left_normal = $xy_right_normal->clone; - $xy_left_normal->scale(-1); - - if ($first_done) { - # if we're making a ccw turn, draw the triangles on the right side, otherwise draw them on the left side - my $ccw = $b->ccw(@$prev_line); - if ($ccw > epsilon) { - # top-right vertex triangle between previous line and this one - { - # use the normal going to the right calculated for the previous line - push @$tnorms, @$prev_xy_right_normal; - push @$tverts, (map unscale($_), @$prev_b1), $middle_z; - - # use the normal going to the right calculated for this line - push @$tnorms, @$xy_right_normal; - push @$tverts, (map unscale($_), @$a1), $middle_z; - - # normal going upwards - push @$tnorms, (0,0,1); - push @$tverts, (map unscale($_), @$a), $top_z; - } - # bottom-right vertex triangle between previous line and this one - { - # use the normal going to the right calculated for the previous line - push @$tnorms, @$prev_xy_right_normal; - push @$tverts, (map unscale($_), @$prev_b1), $middle_z; - - # normal going downwards - push @$tnorms, (0,0,-1); - push @$tverts, (map unscale($_), @$a), $bottom_z; - - # use the normal going to the right calculated for this line - push @$tnorms, @$xy_right_normal; - push @$tverts, (map unscale($_), @$a1), $middle_z; - } - } elsif ($ccw < -&epsilon) { - # top-left vertex triangle between previous line and this one - { - # use the normal going to the left calculated for the previous line - push @$tnorms, @$prev_xy_left_normal; - push @$tverts, (map unscale($_), @$prev_b2), $middle_z; - - # normal going upwards - push @$tnorms, (0,0,1); - push @$tverts, (map unscale($_), @$a), $top_z; - - # use the normal going to the right calculated for this line - push @$tnorms, @$xy_left_normal; - push @$tverts, (map unscale($_), @$a2), $middle_z; - } - # bottom-left vertex triangle between previous line and this one - { - # use the normal going to the left calculated for the previous line - push @$tnorms, @$prev_xy_left_normal; - push @$tverts, (map unscale($_), @$prev_b2), $middle_z; - - # use the normal going to the right calculated for this line - push @$tnorms, @$xy_left_normal; - push @$tverts, (map unscale($_), @$a2), $middle_z; - - # normal going downwards - push @$tnorms, (0,0,-1); - push @$tverts, (map unscale($_), @$a), $bottom_z; - } - } - } - - # if this was the extra iteration we were only interested in the triangles - last if $first_done && $i == 0; - - $prev_line = $line; - $prev_b1 = $b1; - $prev_b2 = $b2; - $prev_xy_right_normal = $xy_right_normal; - $prev_xy_left_normal = $xy_left_normal; - - if (!$closed) { - # terminate open paths with caps - if ($i == 0) { - # normal pointing downwards - push @$qnorms, (0,0,-1); - push @$qverts, (map unscale($_), @$a), $bottom_z; - - # normal pointing to the right - push @$qnorms, @$xy_right_normal; - push @$qverts, (map unscale($_), @$a1), $middle_z; - - # normal pointing upwards - push @$qnorms, (0,0,1); - push @$qverts, (map unscale($_), @$a), $top_z; - - # normal pointing to the left - push @$qnorms, @$xy_left_normal; - push @$qverts, (map unscale($_), @$a2), $middle_z; - } elsif ($i == $#$lines) { - # normal pointing downwards - push @$qnorms, (0,0,-1); - push @$qverts, (map unscale($_), @$b), $bottom_z; - - # normal pointing to the left - push @$qnorms, @$xy_left_normal; - push @$qverts, (map unscale($_), @$b2), $middle_z; - - # normal pointing upwards - push @$qnorms, (0,0,1); - push @$qverts, (map unscale($_), @$b), $top_z; - - # normal pointing to the right - push @$qnorms, @$xy_right_normal; - push @$qverts, (map unscale($_), @$b1), $middle_z; - } - } - - # bottom-right face - { - # normal going downwards - push @$qnorms, (0,0,-1), (0,0,-1); - push @$qverts, (map unscale($_), @$a), $bottom_z; - push @$qverts, (map unscale($_), @$b), $bottom_z; - - push @$qnorms, @$xy_right_normal, @$xy_right_normal; - push @$qverts, (map unscale($_), @$b1), $middle_z; - push @$qverts, (map unscale($_), @$a1), $middle_z; - } - - # top-right face - { - push @$qnorms, @$xy_right_normal, @$xy_right_normal; - push @$qverts, (map unscale($_), @$a1), $middle_z; - push @$qverts, (map unscale($_), @$b1), $middle_z; - - # normal going upwards - push @$qnorms, (0,0,1), (0,0,1); - push @$qverts, (map unscale($_), @$b), $top_z; - push @$qverts, (map unscale($_), @$a), $top_z; - } - - # top-left face - { - push @$qnorms, (0,0,1), (0,0,1); - push @$qverts, (map unscale($_), @$a), $top_z; - push @$qverts, (map unscale($_), @$b), $top_z; - - push @$qnorms, @$xy_left_normal, @$xy_left_normal; - push @$qverts, (map unscale($_), @$b2), $middle_z; - push @$qverts, (map unscale($_), @$a2), $middle_z; - } - - # bottom-left face - { - push @$qnorms, @$xy_left_normal, @$xy_left_normal; - push @$qverts, (map unscale($_), @$a2), $middle_z; - push @$qverts, (map unscale($_), @$b2), $middle_z; - - # normal going downwards - push @$qnorms, (0,0,-1), (0,0,-1); - push @$qverts, (map unscale($_), @$b), $bottom_z; - push @$qverts, (map unscale($_), @$a), $bottom_z; - } - - $first_done++; - } + Slic3r::GUI::_3DScene::_extrusionentity_to_verts_do($lines, $widths, $heights, + $closed, $top_z, $copy, $qverts, $qnorms, $tverts, $tnorms); } sub object_idx { diff --git a/xs/src/libslic3r/GUI/3DScene.cpp b/xs/src/libslic3r/GUI/3DScene.cpp new file mode 100644 index 000000000..9d26e3fa6 --- /dev/null +++ b/xs/src/libslic3r/GUI/3DScene.cpp @@ -0,0 +1,220 @@ +#include "3DScene.hpp" + +namespace Slic3r { + +void +_3DScene::_extrusionentity_to_verts_do(const Lines &lines, const std::vector &widths, + const std::vector &heights, bool closed, double top_z, const Point ©, + Pointf3s* qverts, Pointf3s* qnorms, Pointf3s* tverts, Pointf3s* tnorms) +{ + Line prev_line; + Pointf prev_b1, prev_b2; + Vectorf3 prev_xy_left_normal, prev_xy_right_normal; + + // loop once more in case of closed loops + bool first_done = false; + for (int i = 0; i <= lines.size(); ++i) { + if (i == lines.size()) i = 0; + + const Line &line = lines.at(i); + if (i == 0 && first_done && !closed) break; + + double len = line.length(); + if (len == 0) continue; + double unscaled_len = unscale(len); + + double bottom_z = top_z - heights.at(i); + double middle_z = (top_z + bottom_z) / 2; + double dist = widths.at(i)/2; // scaled + + Vectorf v = Vectorf::new_unscale(line.vector()); + v.scale(1/unscaled_len); + + Pointf a = Pointf::new_unscale(line.a); + Pointf b = Pointf::new_unscale(line.b); + Pointf a1 = a; + Pointf a2 = a; + a1.translate(+dist*v.y, -dist*v.x); + a2.translate(-dist*v.y, +dist*v.x); + Pointf b1 = b; + Pointf b2 = b; + b1.translate(+dist*v.y, -dist*v.x); + b2.translate(-dist*v.y, +dist*v.x); + + // calculate new XY normals + Vector n = line.normal(); + Vectorf3 xy_right_normal = Vectorf3::new_unscale(n.x, n.y, 0); + xy_right_normal.scale(1/unscaled_len); + Vectorf3 xy_left_normal = xy_right_normal; + xy_left_normal.scale(-1); + + if (first_done) { + // if we're making a ccw turn, draw the triangles on the right side, otherwise draw them on the left side + double ccw = line.b.ccw(prev_line); + if (ccw > EPSILON) { + // top-right vertex triangle between previous line and this one + { + // use the normal going to the right calculated for the previous line + tnorms->push_back(prev_xy_right_normal); + tverts->push_back(Pointf3(prev_b1.x, prev_b1.y, middle_z)); + + // use the normal going to the right calculated for this line + tnorms->push_back(xy_right_normal); + tverts->push_back(Pointf3(a1.x, a1.y, middle_z)); + + // normal going upwards + tnorms->push_back(Pointf3(0,0,1)); + tverts->push_back(Pointf3(a.x, a.y, top_z)); + } + // bottom-right vertex triangle between previous line and this one + { + // use the normal going to the right calculated for the previous line + tnorms->push_back(prev_xy_right_normal); + tverts->push_back(Pointf3(prev_b1.x, prev_b1.y, middle_z)); + + // normal going downwards + tnorms->push_back(Pointf3(0,0,-1)); + tverts->push_back(Pointf3(a.x, a.y, bottom_z)); + + // use the normal going to the right calculated for this line + tnorms->push_back(xy_right_normal); + tverts->push_back(Pointf3(a1.x, a1.y, middle_z)); + } + } else if (ccw < -EPSILON) { + // top-left vertex triangle between previous line and this one + { + // use the normal going to the left calculated for the previous line + tnorms->push_back(prev_xy_left_normal); + tverts->push_back(Pointf3(prev_b2.x, prev_b2.y, middle_z)); + + // normal going upwards + tnorms->push_back(Pointf3(0,0,1)); + tverts->push_back(Pointf3(a.x, a.y, top_z)); + + // use the normal going to the right calculated for this line + tnorms->push_back(xy_left_normal); + tverts->push_back(Pointf3(a2.x, a2.y, middle_z)); + } + // bottom-left vertex triangle between previous line and this one + { + // use the normal going to the left calculated for the previous line + tnorms->push_back(prev_xy_left_normal); + tverts->push_back(Pointf3(prev_b2.x, prev_b2.y, middle_z)); + + // use the normal going to the right calculated for this line + tnorms->push_back(xy_left_normal); + tverts->push_back(Pointf3(a2.x, a2.y, middle_z)); + + // normal going downwards + tnorms->push_back(Pointf3(0,0,-1)); + tverts->push_back(Pointf3(a.x, a.y, bottom_z)); + } + } + } + + // if this was the extra iteration we were only interested in the triangles + if (first_done && i == 0) break; + + prev_line = line; + prev_b1 = b1; + prev_b2 = b2; + prev_xy_right_normal = xy_right_normal; + prev_xy_left_normal = xy_left_normal; + + if (!closed) { + // terminate open paths with caps + if (i == 0) { + // normal pointing downwards + qnorms->push_back(Pointf3(0,0,-1)); + qverts->push_back(Pointf3(a.x, a.y, bottom_z)); + + // normal pointing to the right + qnorms->push_back(xy_right_normal); + qverts->push_back(Pointf3(a1.x, a1.y, middle_z)); + + // normal pointing upwards + qnorms->push_back(Pointf3(0,0,1)); + qverts->push_back(Pointf3(a.x, a.y, top_z)); + + // normal pointing to the left + qnorms->push_back(xy_left_normal); + qverts->push_back(Pointf3(a2.x, a2.y, middle_z)); + } else if (i == lines.size()-1) { + // normal pointing downwards + qnorms->push_back(Pointf3(0,0,-1)); + qverts->push_back(Pointf3(b.x, b.y, bottom_z)); + + // normal pointing to the left + qnorms->push_back(xy_left_normal); + qverts->push_back(Pointf3(b2.x, b2.y, middle_z)); + + // normal pointing upwards + qnorms->push_back(Pointf3(0,0,1)); + qverts->push_back(Pointf3(b.x, b.y, top_z)); + + // normal pointing to the right + qnorms->push_back(xy_right_normal); + qverts->push_back(Pointf3(b1.x, b1.y, middle_z)); + } + } + + // bottom-right face + { + // normal going downwards + qnorms->push_back(Pointf3(0,0,-1)); + qnorms->push_back(Pointf3(0,0,-1)); + qverts->push_back(Pointf3(a.x, a.y, bottom_z)); + qverts->push_back(Pointf3(b.x, b.y, bottom_z)); + + qnorms->push_back(xy_right_normal); + qnorms->push_back(xy_right_normal); + qverts->push_back(Pointf3(b1.x, b1.y, middle_z)); + qverts->push_back(Pointf3(a1.x, a1.y, middle_z)); + } + + // top-right face + { + qnorms->push_back(xy_right_normal); + qnorms->push_back(xy_right_normal); + qverts->push_back(Pointf3(a1.x, a1.y, middle_z)); + qverts->push_back(Pointf3(b1.x, b1.y, middle_z)); + + // normal going upwards + qnorms->push_back(Pointf3(0,0,1)); + qnorms->push_back(Pointf3(0,0,1)); + qverts->push_back(Pointf3(b.x, b.y, top_z)); + qverts->push_back(Pointf3(a.x, a.y, top_z)); + } + + // top-left face + { + qnorms->push_back(Pointf3(0,0,1)); + qnorms->push_back(Pointf3(0,0,1)); + qverts->push_back(Pointf3(a.x, a.y, top_z)); + qverts->push_back(Pointf3(b.x, b.y, top_z)); + + qnorms->push_back(xy_left_normal); + qnorms->push_back(xy_left_normal); + qverts->push_back(Pointf3(b2.x, b2.y, middle_z)); + qverts->push_back(Pointf3(a2.x, a2.y, middle_z)); + } + + // bottom-left face + { + qnorms->push_back(xy_left_normal); + qnorms->push_back(xy_left_normal); + qverts->push_back(Pointf3(a2.x, a2.y, middle_z)); + qverts->push_back(Pointf3(b2.x, b2.y, middle_z)); + + // normal going downwards + qnorms->push_back(Pointf3(0,0,-1)); + qnorms->push_back(Pointf3(0,0,-1)); + qverts->push_back(Pointf3(b.x, b.y, bottom_z)); + qverts->push_back(Pointf3(a.x, a.y, bottom_z)); + } + + first_done = true; + } +} + +} diff --git a/xs/src/libslic3r/GUI/3DScene.hpp b/xs/src/libslic3r/GUI/3DScene.hpp new file mode 100644 index 000000000..c718fb1b6 --- /dev/null +++ b/xs/src/libslic3r/GUI/3DScene.hpp @@ -0,0 +1,20 @@ +#ifndef slic3r_3DScene_hpp_ +#define slic3r_3DScene_hpp_ + +#include +#include "../Point.hpp" +#include "../Line.hpp" + +namespace Slic3r { + +class _3DScene +{ + public: + static void _extrusionentity_to_verts_do(const Lines &lines, const std::vector &widths, + const std::vector &heights, bool closed, double top_z, const Point ©, + Pointf3s* qverts, Pointf3s* qnorms, Pointf3s* tverts, Pointf3s* tnorms); +}; + +} + +#endif diff --git a/xs/src/libslic3r/Line.hpp b/xs/src/libslic3r/Line.hpp index c64288cf6..a7e5d26ff 100644 --- a/xs/src/libslic3r/Line.hpp +++ b/xs/src/libslic3r/Line.hpp @@ -48,6 +48,15 @@ class Line #endif }; +class Linef +{ + public: + Pointf a; + Pointf b; + Linef() {}; + explicit Linef(Pointf _a, Pointf _b): a(_a), b(_b) {}; +}; + class Linef3 { public: diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp index a3283c260..327199690 100644 --- a/xs/src/libslic3r/Point.hpp +++ b/xs/src/libslic3r/Point.hpp @@ -9,6 +9,7 @@ namespace Slic3r { class Line; +class Linef; class MultiPoint; class Point; class Pointf; @@ -82,6 +83,12 @@ class Pointf coordf_t x; coordf_t y; explicit Pointf(coordf_t _x = 0, coordf_t _y = 0): x(_x), y(_y) {}; + static Pointf new_unscale(coord_t x, coord_t y) { + return Pointf(unscale(x), unscale(y)); + }; + static Pointf new_unscale(const Point &p) { + return Pointf(unscale(p.x), unscale(p.y)); + }; void scale(double factor); void translate(double x, double y); void rotate(double angle, const Pointf ¢er); @@ -100,6 +107,9 @@ class Pointf3 : public Pointf public: coordf_t z; explicit Pointf3(coordf_t _x = 0, coordf_t _y = 0, coordf_t _z = 0): Pointf(_x, _y), z(_z) {}; + static Pointf3 new_unscale(coord_t x, coord_t y, coord_t z) { + return Pointf3(unscale(x), unscale(y), unscale(z)); + }; void scale(double factor); void translate(const Vectorf3 &vector); void translate(double x, double y, double z); diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp new file mode 100644 index 000000000..7a67320be --- /dev/null +++ b/xs/xsp/GUI_3DScene.xsp @@ -0,0 +1,49 @@ +%module{Slic3r::XS}; + +#include +#include "libslic3r/GUI/3DScene.hpp" + +%package{Slic3r::GUI::_3DScene}; +%{ + +void +_extrusionentity_to_verts_do(Lines lines, std::vector widths, std::vector heights, bool closed, double top_z, Point* copy, SV* qverts, SV* qnorms, SV* tverts, SV* tnorms) + CODE: + Pointf3s _qverts, _qnorms, _tverts, _tnorms; + _3DScene::_extrusionentity_to_verts_do(lines, widths, heights, closed, + top_z, *copy, &_qverts, &_qnorms, &_tverts, &_tnorms); + + { + AV* av = (AV*)SvRV(qverts); + for (Pointf3s::const_iterator it = _qverts.begin(); it != _qverts.end(); ++it) { + av_push(av, newSVnv(it->x)); + av_push(av, newSVnv(it->y)); + av_push(av, newSVnv(it->z)); + } + } + { + AV* av = (AV*)SvRV(qnorms); + for (Pointf3s::const_iterator it = _qnorms.begin(); it != _qnorms.end(); ++it) { + av_push(av, newSVnv(it->x)); + av_push(av, newSVnv(it->y)); + av_push(av, newSVnv(it->z)); + } + } + { + AV* av = (AV*)SvRV(tverts); + for (Pointf3s::const_iterator it = _tverts.begin(); it != _tverts.end(); ++it) { + av_push(av, newSVnv(it->x)); + av_push(av, newSVnv(it->y)); + av_push(av, newSVnv(it->z)); + } + } + { + AV* av = (AV*)SvRV(tnorms); + for (Pointf3s::const_iterator it = _tnorms.begin(); it != _tnorms.end(); ++it) { + av_push(av, newSVnv(it->x)); + av_push(av, newSVnv(it->y)); + av_push(av, newSVnv(it->z)); + } + } + +%} \ No newline at end of file