Merge remote-tracking branch 'origin/master' into ys_new_features

This commit is contained in:
YuSanka 2019-06-24 13:56:35 +02:00
commit daac165a44
44 changed files with 2572 additions and 646 deletions

View file

@ -125,8 +125,8 @@ namespace Slic3r {
trapezoid.distance = distance;
trapezoid.feedrate = feedrate;
float accelerate_distance = estimate_acceleration_distance(feedrate.entry, feedrate.cruise, acceleration);
float decelerate_distance = estimate_acceleration_distance(feedrate.cruise, feedrate.exit, -acceleration);
float accelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.entry, feedrate.cruise, acceleration));
float decelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.cruise, feedrate.exit, -acceleration));
float cruise_distance = distance - accelerate_distance - decelerate_distance;
// Not enough space to reach the nominal feedrate.

View file

@ -1409,6 +1409,63 @@ Transformation Transformation::operator * (const Transformation& other) const
return Transformation(get_matrix() * other.get_matrix());
}
Transformation Transformation::volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox)
{
Transformation out;
if (instance_transformation.is_scaling_uniform()) {
// No need to run the non-linear least squares fitting for uniform scaling.
// Just set the inverse.
out.set_from_transform(instance_transformation.get_matrix(true).inverse());
}
else if (is_rotation_ninety_degrees(instance_transformation.get_rotation()))
{
// Anisotropic scaling, rotation by multiples of ninety degrees.
Eigen::Matrix3d instance_rotation_trafo =
(Eigen::AngleAxisd(instance_transformation.get_rotation().z(), Vec3d::UnitZ()) *
Eigen::AngleAxisd(instance_transformation.get_rotation().y(), Vec3d::UnitY()) *
Eigen::AngleAxisd(instance_transformation.get_rotation().x(), Vec3d::UnitX())).toRotationMatrix();
Eigen::Matrix3d volume_rotation_trafo =
(Eigen::AngleAxisd(-instance_transformation.get_rotation().x(), Vec3d::UnitX()) *
Eigen::AngleAxisd(-instance_transformation.get_rotation().y(), Vec3d::UnitY()) *
Eigen::AngleAxisd(-instance_transformation.get_rotation().z(), Vec3d::UnitZ())).toRotationMatrix();
// 8 corners of the bounding box.
auto pts = Eigen::MatrixXd(8, 3);
pts(0, 0) = bbox.min.x(); pts(0, 1) = bbox.min.y(); pts(0, 2) = bbox.min.z();
pts(1, 0) = bbox.min.x(); pts(1, 1) = bbox.min.y(); pts(1, 2) = bbox.max.z();
pts(2, 0) = bbox.min.x(); pts(2, 1) = bbox.max.y(); pts(2, 2) = bbox.min.z();
pts(3, 0) = bbox.min.x(); pts(3, 1) = bbox.max.y(); pts(3, 2) = bbox.max.z();
pts(4, 0) = bbox.max.x(); pts(4, 1) = bbox.min.y(); pts(4, 2) = bbox.min.z();
pts(5, 0) = bbox.max.x(); pts(5, 1) = bbox.min.y(); pts(5, 2) = bbox.max.z();
pts(6, 0) = bbox.max.x(); pts(6, 1) = bbox.max.y(); pts(6, 2) = bbox.min.z();
pts(7, 0) = bbox.max.x(); pts(7, 1) = bbox.max.y(); pts(7, 2) = bbox.max.z();
// Corners of the bounding box transformed into the modifier mesh coordinate space, with inverse rotation applied to the modifier.
auto qs = pts *
(instance_rotation_trafo *
Eigen::Scaling(instance_transformation.get_scaling_factor().cwiseProduct(instance_transformation.get_mirror())) *
volume_rotation_trafo).inverse().transpose();
// Fill in scaling based on least squares fitting of the bounding box corners.
Vec3d scale;
for (int i = 0; i < 3; ++i)
scale(i) = pts.col(i).dot(qs.col(i)) / pts.col(i).dot(pts.col(i));
out.set_rotation(Geometry::extract_euler_angles(volume_rotation_trafo));
out.set_scaling_factor(Vec3d(std::abs(scale(0)), std::abs(scale(1)), std::abs(scale(2))));
out.set_mirror(Vec3d(scale(0) > 0 ? 1. : -1, scale(1) > 0 ? 1. : -1, scale(2) > 0 ? 1. : -1));
}
else
{
// General anisotropic scaling, general rotation.
// Keep the modifier mesh in the instance coordinate system, so the modifier mesh will not be aligned with the world.
// Scale it to get the required size.
out.set_scaling_factor(instance_transformation.get_scaling_factor().cwiseInverse());
}
return out;
}
Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to)
{
return

View file

@ -258,6 +258,11 @@ public:
const Transform3d& get_matrix(bool dont_translate = false, bool dont_rotate = false, bool dont_scale = false, bool dont_mirror = false) const;
Transformation operator * (const Transformation& other) const;
// Find volume transformation, so that the chained (instance_trafo * volume_trafo) will be as close to identity
// as possible in least squares norm in regard to the 8 corners of bbox.
// Bounding box is expected to be centered around zero in all axes.
static Transformation volume_to_bed_transformation(const Transformation& instance_transformation, const BoundingBoxf3& bbox);
};
// Rotation when going from the first coordinate system with rotation rot_xyz_from applied

View file

@ -1,172 +1,218 @@
#ifndef MTUTILS_HPP
#define MTUTILS_HPP
#include <atomic> // for std::atomic_flag and memory orders
#include <mutex> // for std::lock_guard
#include <functional> // for std::function
#include <utility> // for std::forward
#include <atomic> // for std::atomic_flag and memory orders
#include <mutex> // for std::lock_guard
#include <functional> // for std::function
#include <utility> // for std::forward
#include <algorithm>
namespace Slic3r {
/// Handy little spin mutex for the cached meshes.
/// Implements the "Lockable" concept
class SpinMutex {
std::atomic_flag m_flg;
class SpinMutex
{
std::atomic_flag m_flg;
static const /*constexpr*/ auto MO_ACQ = std::memory_order_acquire;
static const /*constexpr*/ auto MO_REL = std::memory_order_release;
public:
inline SpinMutex() { m_flg.clear(MO_REL); }
inline void lock() { while(m_flg.test_and_set(MO_ACQ)); }
inline void lock() { while (m_flg.test_and_set(MO_ACQ)) ; }
inline bool try_lock() { return !m_flg.test_and_set(MO_ACQ); }
inline void unlock() { m_flg.clear(MO_REL); }
};
/// A wrapper class around arbitrary object that needs thread safe caching.
template<class T> class CachedObject {
template<class T> class CachedObject
{
public:
// Method type which refreshes the object when it has been invalidated
using Setter = std::function<void(T&)>;
using Setter = std::function<void(T &)>;
private:
T m_obj; // the object itself
bool m_valid; // invalidation flag
SpinMutex m_lck; // to make the caching thread safe
T m_obj; // the object itself
bool m_valid; // invalidation flag
SpinMutex m_lck; // to make the caching thread safe
// the setter will be called just before the object's const value is
// about to be retrieved.
std::function<void(T &)> m_setter;
// the setter will be called just before the object's const value is about
// to be retrieved.
std::function<void(T&)> m_setter;
public:
// Forwarded constructor
template<class...Args> inline CachedObject(Setter fn, Args&&...args):
m_obj(std::forward<Args>(args)...), m_valid(false), m_setter(fn) {}
template<class... Args>
inline CachedObject(Setter fn, Args &&... args)
: m_obj(std::forward<Args>(args)...), m_valid(false), m_setter(fn)
{}
// invalidate the value of the object. The object will be refreshed at the
// next retrieval (Setter will be called). The data that is used in
// the setter function should be guarded as well during modification so the
// modification has to take place in fn.
inline void invalidate(std::function<void()> fn) {
std::lock_guard<SpinMutex> lck(m_lck); fn(); m_valid = false;
// invalidate the value of the object. The object will be refreshed at
// the next retrieval (Setter will be called). The data that is used in
// the setter function should be guarded as well during modification so
// the modification has to take place in fn.
inline void invalidate(std::function<void()> fn)
{
std::lock_guard<SpinMutex> lck(m_lck);
fn();
m_valid = false;
}
// Get the const object properly updated.
inline const T& get() {
inline const T &get()
{
std::lock_guard<SpinMutex> lck(m_lck);
if(!m_valid) { m_setter(m_obj); m_valid = true; }
if (!m_valid) {
m_setter(m_obj);
m_valid = true;
}
return m_obj;
}
};
/// An std compatible random access iterator which uses indices to the source
/// vector thus resistant to invalidation caused by relocations. It also "knows"
/// its container. No comparison is neccesary to the container "end()" iterator.
/// The template can be instantiated with a different value type than that of
/// the container's but the types must be compatible. E.g. a base class of the
/// contained objects is compatible.
/// An std compatible random access iterator which uses indices to the
/// source vector thus resistant to invalidation caused by relocations. It
/// also "knows" its container. No comparison is neccesary to the container
/// "end()" iterator. The template can be instantiated with a different
/// value type than that of the container's but the types must be
/// compatible. E.g. a base class of the contained objects is compatible.
///
/// For a constant iterator, one can instantiate this template with a value
/// type preceded with 'const'.
template<class Vector, // The container type, must be random access...
template<class Vector, // The container type, must be random access...
class Value = typename Vector::value_type // The value type
>
class IndexBasedIterator {
class IndexBasedIterator
{
static const size_t NONE = size_t(-1);
std::reference_wrapper<Vector> m_index_ref;
size_t m_idx = NONE;
public:
size_t m_idx = NONE;
using value_type = Value;
using pointer = Value *;
using reference = Value &;
using difference_type = long;
public:
using value_type = Value;
using pointer = Value *;
using reference = Value &;
using difference_type = long;
using iterator_category = std::random_access_iterator_tag;
inline explicit
IndexBasedIterator(Vector& index, size_t idx):
m_index_ref(index), m_idx(idx) {}
inline explicit IndexBasedIterator(Vector &index, size_t idx)
: m_index_ref(index), m_idx(idx)
{}
// Post increment
inline IndexBasedIterator operator++(int) {
IndexBasedIterator cpy(*this); ++m_idx; return cpy;
inline IndexBasedIterator operator++(int)
{
IndexBasedIterator cpy(*this);
++m_idx;
return cpy;
}
inline IndexBasedIterator operator--(int) {
IndexBasedIterator cpy(*this); --m_idx; return cpy;
inline IndexBasedIterator operator--(int)
{
IndexBasedIterator cpy(*this);
--m_idx;
return cpy;
}
inline IndexBasedIterator& operator++() {
++m_idx; return *this;
inline IndexBasedIterator &operator++()
{
++m_idx;
return *this;
}
inline IndexBasedIterator& operator--() {
--m_idx; return *this;
inline IndexBasedIterator &operator--()
{
--m_idx;
return *this;
}
inline IndexBasedIterator& operator+=(difference_type l) {
m_idx += size_t(l); return *this;
inline IndexBasedIterator &operator+=(difference_type l)
{
m_idx += size_t(l);
return *this;
}
inline IndexBasedIterator operator+(difference_type l) {
auto cpy = *this; cpy += l; return cpy;
inline IndexBasedIterator operator+(difference_type l)
{
auto cpy = *this;
cpy += l;
return cpy;
}
inline IndexBasedIterator& operator-=(difference_type l) {
m_idx -= size_t(l); return *this;
inline IndexBasedIterator &operator-=(difference_type l)
{
m_idx -= size_t(l);
return *this;
}
inline IndexBasedIterator operator-(difference_type l) {
auto cpy = *this; cpy -= l; return cpy;
inline IndexBasedIterator operator-(difference_type l)
{
auto cpy = *this;
cpy -= l;
return cpy;
}
operator difference_type() { return difference_type(m_idx); }
/// Tesing the end of the container... this is not possible with std
/// iterators.
inline bool is_end() const { return m_idx >= m_index_ref.get().size();}
inline bool is_end() const
{
return m_idx >= m_index_ref.get().size();
}
inline Value & operator*() const {
inline Value &operator*() const
{
assert(m_idx < m_index_ref.get().size());
return m_index_ref.get().operator[](m_idx);
}
inline Value * operator->() const {
inline Value *operator->() const
{
assert(m_idx < m_index_ref.get().size());
return &m_index_ref.get().operator[](m_idx);
}
/// If both iterators point past the container, they are equal...
inline bool operator ==(const IndexBasedIterator& other) {
inline bool operator==(const IndexBasedIterator &other)
{
size_t e = m_index_ref.get().size();
return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e);
}
inline bool operator !=(const IndexBasedIterator& other) {
inline bool operator!=(const IndexBasedIterator &other)
{
return !(*this == other);
}
inline bool operator <=(const IndexBasedIterator& other) {
inline bool operator<=(const IndexBasedIterator &other)
{
return (m_idx < other.m_idx) || (*this == other);
}
inline bool operator <(const IndexBasedIterator& other) {
inline bool operator<(const IndexBasedIterator &other)
{
return m_idx < other.m_idx && (*this != other);
}
inline bool operator >=(const IndexBasedIterator& other) {
inline bool operator>=(const IndexBasedIterator &other)
{
return m_idx > other.m_idx || *this == other;
}
inline bool operator >(const IndexBasedIterator& other) {
inline bool operator>(const IndexBasedIterator &other)
{
return m_idx > other.m_idx && *this != other;
}
};
/// A very simple range concept implementation with iterator-like objects.
template<class It> class Range {
template<class It> class Range
{
It from, to;
public:
public:
// The class is ready for range based for loops.
It begin() const { return from; }
It end() const { return to; }
@ -175,15 +221,17 @@ public:
using Type = It;
Range() = default;
Range(It &&b, It &&e):
from(std::forward<It>(b)), to(std::forward<It>(e)) {}
Range(It &&b, It &&e)
: from(std::forward<It>(b)), to(std::forward<It>(e))
{}
// Some useful container-like methods...
inline size_t size() const { return end() - begin(); }
inline bool empty() const { return size() == 0; }
inline bool empty() const { return size() == 0; }
};
template<class C> bool all_of(const C &container) {
template<class C> bool all_of(const C &container)
{
return std::all_of(container.begin(),
container.end(),
[](const typename C::value_type &v) {
@ -191,6 +239,15 @@ template<class C> bool all_of(const C &container) {
});
}
template<class X, class Y> inline X ceil_i(X x, Y y)
{
static_assert(std::is_integral<X>::value &&
std::is_integral<Y>::value && sizeof(X) >= sizeof(Y),
"");
return (x % y) ? x / y + 1 : x / y;
}
} // namespace Slic3r
#endif // MTUTILS_HPP

View file

@ -489,21 +489,57 @@ void Model::convert_multipart_object(unsigned int max_extruders)
reset_auto_extruder_id();
bool is_single_object = (this->objects.size() == 1);
for (const ModelObject* o : this->objects)
{
for (const ModelVolume* v : o->volumes)
{
ModelVolume* new_v = object->add_volume(*v);
if (new_v != nullptr)
if (is_single_object)
{
new_v->name = o->name;
new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string(max_extruders));
new_v->translate(-o->origin_translation);
// If there is only one object, just copy the volumes
ModelVolume* new_v = object->add_volume(*v);
if (new_v != nullptr)
{
new_v->name = o->name;
new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string(max_extruders));
new_v->translate(-o->origin_translation);
}
}
else
{
// If there are more than one object, put all volumes together
// Each object may contain any number of volumes and instances
// The volumes transformations are relative to the object containing them...
int counter = 1;
for (const ModelInstance* i : o->instances)
{
ModelVolume* new_v = object->add_volume(*v);
if (new_v != nullptr)
{
new_v->name = o->name + "_" + std::to_string(counter++);
new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string(max_extruders));
new_v->translate(-o->origin_translation);
// ...so, transform everything to a common reference system (world)
new_v->set_transformation(i->get_transformation() * v->get_transformation());
}
}
}
}
}
if (is_single_object)
{
// If there is only one object, keep its instances
for (const ModelInstance* i : this->objects.front()->instances)
{
object->add_instance(*i);
}
}
else
// If there are more than one object, create a single instance
object->add_instance();
for (const ModelInstance* i : this->objects.front()->instances)
object->add_instance(*i);
this->clear_objects();
this->objects.push_back(object);
}

View file

@ -2,6 +2,7 @@
#include "Model.hpp"
#include "Geometry.hpp"
#include "SVG.hpp"
#include "MTUtils.hpp"
#include <libnest2d.h>
@ -820,15 +821,13 @@ bool arrange(Model &model, // The model with the geometries
BoundingBox bbb(bed);
auto& cfn = stopcondition;
coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON;
auto binbb = Box({
static_cast<libnest2d::Coord>(bbb.min(0)),
static_cast<libnest2d::Coord>(bbb.min(1))
},
{
static_cast<libnest2d::Coord>(bbb.max(0)),
static_cast<libnest2d::Coord>(bbb.max(1))
});
auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md,
libnest2d::Coord{bbb.min(1)} - md},
{libnest2d::Coord{bbb.max(0)} + md,
libnest2d::Coord{bbb.max(1)} + md});
switch(bedhint.type) {
case BedShapeType::BOX: {
@ -916,15 +915,13 @@ void find_new_position(const Model &model,
BedShapeHint bedhint = bedShape(bed);
BoundingBox bbb(bed);
auto binbb = Box({
static_cast<libnest2d::Coord>(bbb.min(0)),
static_cast<libnest2d::Coord>(bbb.min(1))
},
{
static_cast<libnest2d::Coord>(bbb.max(0)),
static_cast<libnest2d::Coord>(bbb.max(1))
});
coord_t md = ceil_i(min_obj_distance, 2) - SCALED_EPSILON;
auto binbb = Box({libnest2d::Coord{bbb.min(0)} - md,
libnest2d::Coord{bbb.min(1)} - md},
{libnest2d::Coord{bbb.max(0)} + md,
libnest2d::Coord{bbb.max(1)} + md});
for(auto it = shapemap.begin(); it != shapemap.end(); ++it) {
if(std::find(toadd.begin(), toadd.end(), it->first) == toadd.end()) {

View file

@ -13,6 +13,8 @@
#define ENABLE_RENDER_SELECTION_CENTER 0
// Shows an imgui dialog with render related data
#define ENABLE_RENDER_STATISTICS 0
// Shows an imgui dialog with camera related data
#define ENABLE_CAMERA_STATISTICS 0
//====================