Limit the object movement to the vincinity of the print bed.

This commit is contained in:
bubnikv 2017-06-08 11:02:29 +02:00
parent dabcff1c07
commit 8b5f7f0fb2
8 changed files with 142 additions and 25 deletions

View file

@ -48,6 +48,7 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init
bed_shape bed_shape
bed_triangles bed_triangles
bed_grid_lines bed_grid_lines
bed_polygon
background background
origin origin
_mouse_pos _mouse_pos
@ -55,6 +56,7 @@ __PACKAGE__->mk_accessors( qw(_quat _dirty init
_drag_volume_idx _drag_volume_idx
_drag_start_pos _drag_start_pos
_drag_volume_center_offset
_drag_start_xy _drag_start_xy
_dragged _dragged
@ -388,8 +390,18 @@ sub mouse_event {
if ($volume_idx != -1) { if ($volume_idx != -1) {
if ($e->LeftDown && $self->enable_moving) { if ($e->LeftDown && $self->enable_moving) {
$self->_drag_volume_idx($volume_idx); my $pos3d = $self->mouse_to_3d(@$pos);
$self->_drag_start_pos($self->mouse_to_3d(@$pos)); # Only accept the initial position, if it is inside the volume bounding box.
my $volume_bbox = $self->volumes->[$volume_idx]->transformed_bounding_box;
$volume_bbox->offset(0.01);
if ($volume_bbox->contains_point($pos3d)) {
# The dragging operation is initiated.
$self->_drag_volume_idx($volume_idx);
$self->_drag_start_pos($pos3d);
# Remember the shift to to the object center. The object center will later be used
# to limit the object placement close to the bed.
$self->_drag_volume_center_offset($pos3d->vector_to($volume_bbox->center));
}
} elsif ($e->RightDown) { } elsif ($e->RightDown) {
# if right clicking on volume, propagate event through callback # if right clicking on volume, propagate event through callback
$self->on_right_click->($e->GetPosition) $self->on_right_click->($e->GetPosition)
@ -398,26 +410,29 @@ sub mouse_event {
} }
} }
} elsif ($e->Dragging && $e->LeftIsDown && ! $self->_layer_height_edited && defined($self->_drag_volume_idx)) { } elsif ($e->Dragging && $e->LeftIsDown && ! $self->_layer_height_edited && defined($self->_drag_volume_idx)) {
# get new position at the same Z of the initial click point # Get new position at the same Z of the initial click point.
my $mouse_ray = $self->mouse_ray($e->GetX, $e->GetY); my $cur_pos = $self->mouse_ray($e->GetX, $e->GetY)->intersect_plane($self->_drag_start_pos->z);
my $cur_pos = $mouse_ray->intersect_plane($self->_drag_start_pos->z); # Clip the new position, so the object center remains close to the bed.
{
# calculate the translation vector $cur_pos->translate(@{$self->_drag_volume_center_offset});
my $vector = $self->_drag_start_pos->vector_to($cur_pos); my $cur_pos2 = Slic3r::Point->new(scale($cur_pos->x), scale($cur_pos->y));
if (! $self->bed_polygon->contains_point($cur_pos2)) {
# get volume being dragged my $ip = $self->bed_polygon->point_projection($cur_pos2);
my $volume = $self->volumes->[$self->_drag_volume_idx]; $cur_pos->set_x(unscale($ip->x));
$cur_pos->set_y(unscale($ip->y));
# get all volumes belonging to the same group, if any }
my @volumes; $cur_pos->translate(@{$self->_drag_volume_center_offset->negative});
if ($volume->drag_group_id == -1) {
@volumes = ($volume);
} else {
@volumes = grep $_->drag_group_id == $volume->drag_group_id, @{$self->volumes};
} }
# Calculate the translation vector.
# apply new temporary volume origin and ignore Z my $vector = $self->_drag_start_pos->vector_to($cur_pos);
$_->translate($vector->x, $vector->y, 0) for @volumes; #,, # Get the volume being dragged.
my $volume = $self->volumes->[$self->_drag_volume_idx];
# Get all volumes belonging to the same group, if any.
my @volumes = ($volume->drag_group_id == -1) ?
($volume) :
grep $_->drag_group_id == $volume->drag_group_id, @{$self->volumes};
# Apply new temporary volume origin and ignore Z.
$_->translate($vector->x, $vector->y, 0) for @volumes;
$self->_drag_start_pos($cur_pos); $self->_drag_start_pos($cur_pos);
$self->_dragged(1); $self->_dragged(1);
$self->Refresh; $self->Refresh;
@ -430,6 +445,7 @@ sub mouse_event {
if (defined $self->_drag_start_pos) { if (defined $self->_drag_start_pos) {
my $orig = $self->_drag_start_pos; my $orig = $self->_drag_start_pos;
if (TURNTABLE_MODE) { if (TURNTABLE_MODE) {
# Turntable mode is enabled by default.
$self->_sphi($self->_sphi + ($pos->x - $orig->x) * TRACKBALLSIZE); $self->_sphi($self->_sphi + ($pos->x - $orig->x) * TRACKBALLSIZE);
$self->_stheta($self->_stheta - ($pos->y - $orig->y) * TRACKBALLSIZE); #- $self->_stheta($self->_stheta - ($pos->y - $orig->y) * TRACKBALLSIZE); #-
$self->_stheta(GIMBALL_LOCK_THETA_MAX) if $self->_stheta > GIMBALL_LOCK_THETA_MAX; $self->_stheta(GIMBALL_LOCK_THETA_MAX) if $self->_stheta > GIMBALL_LOCK_THETA_MAX;
@ -668,6 +684,8 @@ sub max_bounding_box {
return $bb; return $bb;
} }
# Used by ObjectCutDialog and ObjectPartsPanel to generate a rectangular ground plane
# to support the scene objects.
sub set_auto_bed_shape { sub set_auto_bed_shape {
my ($self, $bed_shape) = @_; my ($self, $bed_shape) = @_;
@ -680,9 +698,14 @@ sub set_auto_bed_shape {
[ $center->x + $max_size, $center->y + $max_size ], #++ [ $center->x + $max_size, $center->y + $max_size ], #++
[ $center->x - $max_size, $center->y + $max_size ], #++ [ $center->x - $max_size, $center->y + $max_size ], #++
]); ]);
# Set the origin for painting of the coordinate system axes.
$self->origin(Slic3r::Pointf->new(@$center[X,Y])); $self->origin(Slic3r::Pointf->new(@$center[X,Y]));
} }
# Set the bed shape to a single closed 2D polygon (array of two element arrays),
# triangulate the bed and store the triangles into $self->bed_triangles,
# fills the $self->bed_grid_lines and sets $self->origin.
# Sets $self->bed_polygon to limit the object placement.
sub set_bed_shape { sub set_bed_shape {
my ($self, $bed_shape) = @_; my ($self, $bed_shape) = @_;
@ -695,7 +718,7 @@ sub set_bed_shape {
{ {
my @points = (); my @points = ();
foreach my $triangle (@{ $expolygon->triangulate }) { foreach my $triangle (@{ $expolygon->triangulate }) {
push @points, map {+ unscale($_->x), unscale($_->y), GROUND_Z } @$triangle; #)) push @points, map {+ unscale($_->x), unscale($_->y), GROUND_Z } @$triangle;
} }
$self->bed_triangles(OpenGL::Array->new_list(GL_FLOAT, @points)); $self->bed_triangles(OpenGL::Array->new_list(GL_FLOAT, @points));
} }
@ -723,7 +746,10 @@ sub set_bed_shape {
$self->bed_grid_lines(OpenGL::Array->new_list(GL_FLOAT, @points)); $self->bed_grid_lines(OpenGL::Array->new_list(GL_FLOAT, @points));
} }
# Set the origin for painting of the coordinate system axes.
$self->origin(Slic3r::Pointf->new(0,0)); $self->origin(Slic3r::Pointf->new(0,0));
$self->bed_polygon(offset_ex([$expolygon->contour], $bed_bb->radius * 1.7)->[0]->contour->clone);
} }
sub deselect_volumes { sub deselect_volumes {
@ -1073,6 +1099,7 @@ sub Render {
} }
if (TURNTABLE_MODE) { if (TURNTABLE_MODE) {
# Turntable mode is enabled by default.
glRotatef(-$self->_stheta, 1, 0, 0); # pitch glRotatef(-$self->_stheta, 1, 0, 0); # pitch
glRotatef($self->_sphi, 0, 0, 1); # yaw glRotatef($self->_sphi, 0, 0, 1); # yaw
} else { } else {

View file

@ -15,7 +15,7 @@ typedef std::vector<ThickLine> ThickLines;
class Line class Line
{ {
public: public:
Point a; Point a;
Point b; Point b;
Line() {}; Line() {};

View file

@ -140,6 +140,29 @@ MultiPoint::intersection(const Line& line, Point* intersection) const
return false; return false;
} }
bool MultiPoint::first_intersection(const Line& line, Point* intersection) const
{
bool found = false;
double dmin = 0.;
for (const Line &l : this->lines()) {
Point ip;
if (l.intersection(line, &ip)) {
if (! found) {
found = true;
dmin = ip.distance_to(line.a);
*intersection = ip;
} else {
double d = ip.distance_to(line.a);
if (d < dmin) {
dmin = d;
*intersection = ip;
}
}
}
}
return found;
}
std::string std::string
MultiPoint::dump_perl() const MultiPoint::dump_perl() const
{ {

View file

@ -13,7 +13,7 @@ class BoundingBox;
class MultiPoint class MultiPoint
{ {
public: public:
Points points; Points points;
operator Points() const; operator Points() const;
@ -35,8 +35,24 @@ class MultiPoint
double length() const; double length() const;
bool is_valid() const { return this->points.size() >= 2; } bool is_valid() const { return this->points.size() >= 2; }
int find_point(const Point &point) const; int find_point(const Point &point) const;
bool has_boundary_point(const Point &point) const; bool has_boundary_point(const Point &point) const;
int closest_point_index(const Point &point) const {
int idx = -1;
if (! this->points.empty()) {
idx = 0;
double dist_min = this->points.front().distance_to(point);
for (int i = 1; i < int(this->points.size()); ++ i) {
double d = this->points[i].distance_to(point);
if (d < dist_min) {
dist_min = d;
idx = i;
}
}
}
return idx;
}
const Point* closest_point(const Point &point) const { return this->points.empty() ? nullptr : &this->points[this->closest_point_index(point)]; }
BoundingBox bounding_box() const; BoundingBox bounding_box() const;
// Return true if there are exact duplicates. // Return true if there are exact duplicates.
bool has_duplicate_points() const; bool has_duplicate_points() const;
@ -56,6 +72,7 @@ class MultiPoint
} }
bool intersection(const Line& line, Point* intersection) const; bool intersection(const Line& line, Point* intersection) const;
bool first_intersection(const Line& line, Point* intersection) const;
std::string dump_perl() const; std::string dump_perl() const;
static Points _douglas_peucker(const Points &points, const double tolerance); static Points _douglas_peucker(const Points &points, const double tolerance);

View file

@ -293,6 +293,44 @@ Polygon::convex_points(double angle) const
return points; return points;
} }
// Projection of a point onto the polygon.
Point Polygon::point_projection(const Point &point) const
{
Point proj = point;
double dmin = std::numeric_limits<double>::max();
if (! this->points.empty()) {
for (size_t i = 0; i < this->points.size(); ++ i) {
const Point &pt0 = this->points[i];
const Point &pt1 = this->points[(i + 1 == this->points.size()) ? 0 : i + 1];
double d = pt0.distance_to(point);
if (d < dmin) {
dmin = d;
proj = pt0;
}
d = pt1.distance_to(point);
if (d < dmin) {
dmin = d;
proj = pt1;
}
Pointf v1(coordf_t(pt1.x - pt0.x), coordf_t(pt1.y - pt0.y));
coordf_t div = dot(v1);
if (div > 0.) {
Pointf v2(coordf_t(point.x - pt0.x), coordf_t(point.y - pt0.y));
coordf_t t = dot(v1, v2) / div;
if (t > 0. && t < 1.) {
Point foot(coord_t(floor(coordf_t(pt0.x) + t * v1.x + 0.5)), coord_t(floor(coordf_t(pt0.y) + t * v1.y + 0.5)));
d = foot.distance_to(point);
if (d < dmin) {
dmin = d;
proj = foot;
}
}
}
}
}
return proj;
}
BoundingBox get_extents(const Polygon &poly) BoundingBox get_extents(const Polygon &poly)
{ {
return poly.bounding_box(); return poly.bounding_box();

View file

@ -51,6 +51,8 @@ public:
std::string wkt() const; std::string wkt() const;
Points concave_points(double angle = PI) const; Points concave_points(double angle = PI) const;
Points convex_points(double angle = PI) const; Points convex_points(double angle = PI) const;
// Projection of a point onto the polygon.
Point point_projection(const Point &point) const;
}; };
extern BoundingBox get_extents(const Polygon &poly); extern BoundingBox get_extents(const Polygon &poly);

View file

@ -95,6 +95,8 @@ new_from_points(CLASS, points)
void merge_point(Pointf3* point) %code{% THIS->merge(*point); %}; void merge_point(Pointf3* point) %code{% THIS->merge(*point); %};
void scale(double factor); void scale(double factor);
void translate(double x, double y, double z); void translate(double x, double y, double z);
void offset(double delta);
bool contains_point(Pointf3* point) %code{% RETVAL = THIS->contains(*point); %};
Clone<Pointf3> size(); Clone<Pointf3> size();
Clone<Pointf3> center(); Clone<Pointf3> center();
double radius(); double radius();

View file

@ -42,12 +42,20 @@
std::string wkt(); std::string wkt();
Points concave_points(double angle); Points concave_points(double angle);
Points convex_points(double angle); Points convex_points(double angle);
Clone<Point> point_projection(Point* point)
%code{% RETVAL = THIS->point_projection(*point); %};
Clone<Point> intersection(Line* line) Clone<Point> intersection(Line* line)
%code{% %code{%
Point p; Point p;
(void)THIS->intersection(*line, &p); (void)THIS->intersection(*line, &p);
RETVAL = p; RETVAL = p;
%}; %};
Clone<Point> first_intersection(Line* line)
%code{%
Point p;
(void)THIS->first_intersection(*line, &p);
RETVAL = p;
%};
%{ %{
Polygon* Polygon*