mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-24 09:11:23 -06:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_custom_gcode_detection
This commit is contained in:
commit
c7771a576b
73 changed files with 2263 additions and 2165 deletions
|
|
@ -287,6 +287,11 @@ bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
|
|||
}
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#ifdef CLIPPERLIB_INT32
|
||||
inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool /* UseFullInt64Range */) {
|
||||
return int64_t(dy1) * int64_t(dx2) == int64_t(dx1) * int64_t(dy2);
|
||||
}
|
||||
#else
|
||||
inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cInt dy2, bool UseFullInt64Range) {
|
||||
return (UseFullInt64Range) ?
|
||||
// |dx1| < 2^63, |dx2| < 2^63 etc,
|
||||
|
|
@ -296,6 +301,8 @@ inline bool SlopesEqual(const cInt dx1, const cInt dy1, const cInt dx2, const cI
|
|||
// therefore the following computation could be done with 64bit arithmetics.
|
||||
dy1 * dx2 == dx1 * dy2;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range)
|
||||
{ return SlopesEqual(e1.Delta.X, e1.Delta.Y, e2.Delta.X, e2.Delta.Y, UseFullInt64Range); }
|
||||
inline bool SlopesEqual(const IntPoint &pt1, const IntPoint &pt2, const IntPoint &pt3, bool UseFullInt64Range)
|
||||
|
|
@ -363,8 +370,8 @@ void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
|
|||
}
|
||||
else
|
||||
{
|
||||
b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx;
|
||||
b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx;
|
||||
b1 = double(Edge1.Bot.X) - double(Edge1.Bot.Y) * Edge1.Dx;
|
||||
b2 = double(Edge2.Bot.X) - double(Edge2.Bot.Y) * Edge2.Dx;
|
||||
double q = (b2-b1) / (Edge1.Dx - Edge2.Dx);
|
||||
ip.Y = Round(q);
|
||||
ip.X = (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx)) ?
|
||||
|
|
@ -569,6 +576,7 @@ bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
|
|||
// ClipperBase class methods ...
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
// Called from ClipperBase::AddPath() to verify the scale of the input polygon coordinates.
|
||||
inline void RangeTest(const IntPoint& Pt, bool& useFullRange)
|
||||
{
|
||||
|
|
@ -583,6 +591,7 @@ inline void RangeTest(const IntPoint& Pt, bool& useFullRange)
|
|||
RangeTest(Pt, useFullRange);
|
||||
}
|
||||
}
|
||||
#endif // CLIPPERLIB_INT32
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Called from ClipperBase::AddPath() to construct the Local Minima List.
|
||||
|
|
@ -805,13 +814,17 @@ bool ClipperBase::AddPathInternal(const Path &pg, int highI, PolyType PolyTyp, b
|
|||
try
|
||||
{
|
||||
edges[1].Curr = pg[1];
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
RangeTest(pg[0], m_UseFullRange);
|
||||
RangeTest(pg[highI], m_UseFullRange);
|
||||
#endif // CLIPPERLIB_INT32
|
||||
InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]);
|
||||
InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]);
|
||||
for (int i = highI - 1; i >= 1; --i)
|
||||
{
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
RangeTest(pg[i], m_UseFullRange);
|
||||
#endif // CLIPPERLIB_INT32
|
||||
InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]);
|
||||
}
|
||||
}
|
||||
|
|
@ -967,7 +980,9 @@ void ClipperBase::Clear()
|
|||
CLIPPERLIB_PROFILE_FUNC();
|
||||
m_MinimaList.clear();
|
||||
m_edges.clear();
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
m_UseFullRange = false;
|
||||
#endif // CLIPPERLIB_INT32
|
||||
m_HasOpenPaths = false;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -3322,9 +3337,9 @@ DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
|
|||
if(pt2.X == pt1.X && pt2.Y == pt1.Y)
|
||||
return DoublePoint(0, 0);
|
||||
|
||||
double Dx = (double)(pt2.X - pt1.X);
|
||||
double dy = (double)(pt2.Y - pt1.Y);
|
||||
double f = 1 *1.0/ std::sqrt( Dx*Dx + dy*dy );
|
||||
double Dx = double(pt2.X - pt1.X);
|
||||
double dy = double(pt2.Y - pt1.Y);
|
||||
double f = 1.0 / std::sqrt( Dx*Dx + dy*dy );
|
||||
Dx *= f;
|
||||
dy *= f;
|
||||
return DoublePoint(dy, -Dx);
|
||||
|
|
@ -3530,8 +3545,9 @@ void ClipperOffset::DoOffset(double delta)
|
|||
}
|
||||
|
||||
//see offset_triginometry3.svg in the documentation folder ...
|
||||
if (MiterLimit > 2) m_miterLim = 2/(MiterLimit * MiterLimit);
|
||||
else m_miterLim = 0.5;
|
||||
m_miterLim = (MiterLimit > 2) ?
|
||||
2. / (MiterLimit * MiterLimit) :
|
||||
0.5;
|
||||
|
||||
double y;
|
||||
if (ArcTolerance <= 0.0) y = def_arc_tolerance;
|
||||
|
|
@ -3633,11 +3649,9 @@ void ClipperOffset::DoOffset(double delta)
|
|||
if (node.m_endtype == etOpenButt)
|
||||
{
|
||||
int j = len - 1;
|
||||
pt1 = IntPoint(Round(m_srcPoly[j].X + m_normals[j].X *
|
||||
delta), Round(m_srcPoly[j].Y + m_normals[j].Y * delta));
|
||||
pt1 = IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * delta), Round(m_srcPoly[j].Y + m_normals[j].Y * delta));
|
||||
m_destPoly.push_back(pt1);
|
||||
pt1 = IntPoint(Round(m_srcPoly[j].X - m_normals[j].X *
|
||||
delta), Round(m_srcPoly[j].Y - m_normals[j].Y * delta));
|
||||
pt1 = IntPoint(Round(m_srcPoly[j].X - m_normals[j].X * delta), Round(m_srcPoly[j].Y - m_normals[j].Y * delta));
|
||||
m_destPoly.push_back(pt1);
|
||||
}
|
||||
else
|
||||
|
|
@ -3662,11 +3676,9 @@ void ClipperOffset::DoOffset(double delta)
|
|||
|
||||
if (node.m_endtype == etOpenButt)
|
||||
{
|
||||
pt1 = IntPoint(Round(m_srcPoly[0].X - m_normals[0].X * delta),
|
||||
Round(m_srcPoly[0].Y - m_normals[0].Y * delta));
|
||||
pt1 = IntPoint(Round(m_srcPoly[0].X - m_normals[0].X * delta), Round(m_srcPoly[0].Y - m_normals[0].Y * delta));
|
||||
m_destPoly.push_back(pt1);
|
||||
pt1 = IntPoint(Round(m_srcPoly[0].X + m_normals[0].X * delta),
|
||||
Round(m_srcPoly[0].Y + m_normals[0].Y * delta));
|
||||
pt1 = IntPoint(Round(m_srcPoly[0].X + m_normals[0].X * delta), Round(m_srcPoly[0].Y + m_normals[0].Y * delta));
|
||||
m_destPoly.push_back(pt1);
|
||||
}
|
||||
else
|
||||
|
|
@ -3753,7 +3765,7 @@ void ClipperOffset::DoRound(int j, int k)
|
|||
{
|
||||
double a = std::atan2(m_sinA,
|
||||
m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y);
|
||||
int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1);
|
||||
auto steps = std::max<int>(Round(m_StepsPerRad * std::fabs(a)), 1);
|
||||
|
||||
double X = m_normals[k].X, Y = m_normals[k].Y, X2;
|
||||
for (int i = 0; i < steps; ++i)
|
||||
|
|
@ -3885,8 +3897,8 @@ void SimplifyPolygons(Paths &polys, PolyFillType fillType)
|
|||
|
||||
inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2)
|
||||
{
|
||||
double Dx = ((double)pt1.X - pt2.X);
|
||||
double dy = ((double)pt1.Y - pt2.Y);
|
||||
auto Dx = double(pt1.X - pt2.X);
|
||||
auto dy = double(pt1.Y - pt2.Y);
|
||||
return (Dx*Dx + dy*dy);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -3937,8 +3949,8 @@ bool SlopesNearCollinear(const IntPoint& pt1,
|
|||
|
||||
bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd)
|
||||
{
|
||||
double Dx = (double)pt1.X - pt2.X;
|
||||
double dy = (double)pt1.Y - pt2.Y;
|
||||
auto Dx = double(pt1.X - pt2.X);
|
||||
auto dy = double(pt1.Y - pt2.Y);
|
||||
return ((Dx * Dx) + (dy * dy) <= distSqrd);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -71,12 +71,22 @@ enum PolyType { ptSubject, ptClip };
|
|||
//see http://glprogramming.com/red/chapter11.html
|
||||
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
|
||||
|
||||
// If defined, Clipper will work with 32bit signed int coordinates to reduce memory
|
||||
// consumption and to speed up exact orientation predicate calculation.
|
||||
// In that case, coordinates and their differences (vectors of the coordinates) have to fit int32_t.
|
||||
#define CLIPPERLIB_INT32
|
||||
|
||||
// Point coordinate type
|
||||
typedef int64_t cInt;
|
||||
// Maximum cInt value to allow a cross product calculation using 32bit expressions.
|
||||
static cInt const loRange = 0x3FFFFFFF;
|
||||
// Maximum allowed cInt value.
|
||||
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
|
||||
#ifdef CLIPPERLIB_INT32
|
||||
// Coordinates and their differences (vectors of the coordinates) have to fit int32_t.
|
||||
typedef int32_t cInt;
|
||||
#else
|
||||
typedef int64_t cInt;
|
||||
// Maximum cInt value to allow a cross product calculation using 32bit expressions.
|
||||
static constexpr cInt const loRange = 0x3FFFFFFF; // 0x3FFFFFFF = 1 073 741 823
|
||||
// Maximum allowed cInt value.
|
||||
static constexpr cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
|
||||
#endif // CLIPPERLIB_INT32
|
||||
|
||||
struct IntPoint {
|
||||
cInt X;
|
||||
|
|
@ -289,7 +299,11 @@ enum EdgeSide { esLeft = 1, esRight = 2};
|
|||
class ClipperBase
|
||||
{
|
||||
public:
|
||||
ClipperBase() : m_UseFullRange(false), m_HasOpenPaths(false) {}
|
||||
ClipperBase() :
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
m_UseFullRange(false),
|
||||
#endif // CLIPPERLIB_INT32
|
||||
m_HasOpenPaths(false) {}
|
||||
~ClipperBase() { Clear(); }
|
||||
bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
|
||||
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
|
||||
|
|
@ -310,9 +324,14 @@ protected:
|
|||
// Local minima (Y, left edge, right edge) sorted by ascending Y.
|
||||
std::vector<LocalMinimum> m_MinimaList;
|
||||
|
||||
#ifdef CLIPPERLIB_INT32
|
||||
static constexpr const bool m_UseFullRange = false;
|
||||
#else // CLIPPERLIB_INT32
|
||||
// True if the input polygons have abs values higher than loRange, but lower than hiRange.
|
||||
// False if the input polygons have abs values lower or equal to loRange.
|
||||
bool m_UseFullRange;
|
||||
#endif // CLIPPERLIB_INT32
|
||||
|
||||
// A vector of edges per each input path.
|
||||
std::vector<std::vector<TEdge>> m_edges;
|
||||
// Don't remove intermediate vertices of a collinear sequence of points.
|
||||
|
|
|
|||
|
|
@ -474,8 +474,8 @@ inline _Box<P> _Box<P>::infinite(const P& center) {
|
|||
|
||||
// It is important for Mx and My to be strictly less than half of the
|
||||
// range of type C. width(), height() and area() will not overflow this way.
|
||||
C Mx = C((std::numeric_limits<C>::lowest() + 2 * getX(center)) / 2.01);
|
||||
C My = C((std::numeric_limits<C>::lowest() + 2 * getY(center)) / 2.01);
|
||||
C Mx = C((std::numeric_limits<C>::lowest() + 2 * getX(center)) / 4.01);
|
||||
C My = C((std::numeric_limits<C>::lowest() + 2 * getY(center)) / 4.01);
|
||||
|
||||
ret.maxCorner() = center - P{Mx, My};
|
||||
ret.minCorner() = center + P{Mx, My};
|
||||
|
|
|
|||
|
|
@ -220,7 +220,9 @@ inline NfpResult<RawShape> nfpConvexOnly(const RawShape& sh,
|
|||
auto next = std::next(first);
|
||||
|
||||
while(next != sl::cend(sh)) {
|
||||
edgelist.emplace_back(*(first), *(next));
|
||||
if (pl::magnsq(*next - *first) > 0)
|
||||
edgelist.emplace_back(*(first), *(next));
|
||||
|
||||
++first; ++next;
|
||||
}
|
||||
}
|
||||
|
|
@ -230,7 +232,9 @@ inline NfpResult<RawShape> nfpConvexOnly(const RawShape& sh,
|
|||
auto next = std::next(first);
|
||||
|
||||
while(next != sl::cend(other)) {
|
||||
edgelist.emplace_back(*(next), *(first));
|
||||
if (pl::magnsq(*next - *first) > 0)
|
||||
edgelist.emplace_back(*(next), *(first));
|
||||
|
||||
++first; ++next;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ void BridgeDetector::initialize()
|
|||
this->angle = -1.;
|
||||
|
||||
// Outset our bridge by an arbitrary amout; we'll use this outer margin for detecting anchors.
|
||||
Polygons grown = offset(to_polygons(this->expolygons), float(this->spacing));
|
||||
Polygons grown = offset(this->expolygons, float(this->spacing));
|
||||
|
||||
// Detect possible anchoring edges of this bridging region.
|
||||
// Detect what edges lie on lower slices by turning bridge contour and holes
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ err:
|
|||
}
|
||||
#endif /* CLIPPER_UTILS_DEBUG */
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
void scaleClipperPolygon(ClipperLib::Path &polygon)
|
||||
{
|
||||
CLIPPERUTILS_PROFILE_FUNC();
|
||||
|
|
@ -98,6 +99,7 @@ void unscaleClipperPolygons(ClipperLib::Paths &polygons)
|
|||
pit->Y >>= CLIPPER_OFFSET_POWER_OF_2;
|
||||
}
|
||||
}
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
//-----------------------------------------------------------
|
||||
// legacy code from Clipper documentation
|
||||
|
|
@ -222,8 +224,10 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input)
|
|||
|
||||
ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit)
|
||||
{
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// scale input
|
||||
scaleClipperPolygons(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
// perform offset
|
||||
ClipperLib::ClipperOffset co;
|
||||
|
|
@ -231,14 +235,20 @@ ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType
|
|||
co.ArcTolerance = miterLimit;
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
co.AddPaths(input, joinType, endType);
|
||||
ClipperLib::Paths retval;
|
||||
co.Execute(retval, delta_scaled);
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// unscale output
|
||||
unscaleClipperPolygons(retval);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -257,14 +267,24 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
|||
{
|
||||
// printf("new ExPolygon offset\n");
|
||||
// 1) Offset the outer contour.
|
||||
const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ClipperLib::Paths contours;
|
||||
{
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(expolygon.contour);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
scaleClipperPolygon(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
|
|
@ -278,17 +298,23 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
|||
holes.reserve(expolygon.holes.size());
|
||||
for (Polygons::const_iterator it_hole = expolygon.holes.begin(); it_hole != expolygon.holes.end(); ++ it_hole) {
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
scaleClipperPolygon(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
co.AddPath(input, joinType, ClipperLib::etClosedPolygon);
|
||||
ClipperLib::Paths out;
|
||||
co.Execute(out, - delta_scaled);
|
||||
holes.insert(holes.end(), out.begin(), out.end());
|
||||
append(holes, std::move(out));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -305,7 +331,9 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
|||
}
|
||||
|
||||
// 4) Unscale the output.
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
unscaleClipperPolygons(output);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +343,11 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygon &expolygon, const float delta,
|
|||
ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delta,
|
||||
ClipperLib::JoinType joinType, double miterLimit)
|
||||
{
|
||||
const float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta * float(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled = delta;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
// Offsetted ExPolygons before they are united.
|
||||
ClipperLib::Paths contours_cummulative;
|
||||
contours_cummulative.reserve(expolygons.size());
|
||||
|
|
@ -327,10 +359,16 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt
|
|||
ClipperLib::Paths contours;
|
||||
{
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath(it_expoly->contour);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
scaleClipperPolygon(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
|
|
@ -351,10 +389,16 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt
|
|||
{
|
||||
for (Polygons::const_iterator it_hole = it_expoly->holes.begin(); it_hole != it_expoly->holes.end(); ++ it_hole) {
|
||||
ClipperLib::Path input = Slic3rMultiPoint_to_ClipperPath_reversed(*it_hole);
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
scaleClipperPolygon(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ClipperLib::ClipperOffset co;
|
||||
if (joinType == jtRound)
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit * double(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ArcTolerance = miterLimit;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
else
|
||||
co.MiterLimit = miterLimit;
|
||||
co.ShortestEdgeLength = double(std::abs(delta_scaled * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR));
|
||||
|
|
@ -413,8 +457,10 @@ ClipperLib::Paths _offset(const Slic3r::ExPolygons &expolygons, const float delt
|
|||
output = std::move(contours_cummulative);
|
||||
}
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// 4) Unscale the output.
|
||||
unscaleClipperPolygons(output);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
@ -425,8 +471,10 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2,
|
|||
// read input
|
||||
ClipperLib::Paths input = Slic3rMultiPoints_to_ClipperPaths(polygons);
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// scale input
|
||||
scaleClipperPolygons(input);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
// prepare ClipperOffset object
|
||||
ClipperLib::ClipperOffset co;
|
||||
|
|
@ -435,8 +483,13 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2,
|
|||
} else {
|
||||
co.MiterLimit = miterLimit;
|
||||
}
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled1 = delta1 * float(CLIPPER_OFFSET_SCALE);
|
||||
float delta_scaled2 = delta2 * float(CLIPPER_OFFSET_SCALE);
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
float delta_scaled1 = delta1;
|
||||
float delta_scaled2 = delta2;
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.ShortestEdgeLength = double(std::max(std::abs(delta_scaled1), std::abs(delta_scaled2)) * CLIPPER_OFFSET_SHORTEST_EDGE_FACTOR);
|
||||
|
||||
// perform first offset
|
||||
|
|
@ -450,8 +503,10 @@ _offset2(const Polygons &polygons, const float delta1, const float delta2,
|
|||
ClipperLib::Paths retval;
|
||||
co.Execute(retval, delta_scaled2);
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// unscale output
|
||||
unscaleClipperPolygons(retval);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -789,8 +844,10 @@ void safety_offset(ClipperLib::Paths* paths)
|
|||
{
|
||||
CLIPPERUTILS_PROFILE_FUNC();
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// scale input
|
||||
scaleClipperPolygons(*paths);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
// perform offset (delta = scale 1e-05)
|
||||
ClipperLib::ClipperOffset co;
|
||||
|
|
@ -816,7 +873,11 @@ void safety_offset(ClipperLib::Paths* paths)
|
|||
CLIPPERUTILS_PROFILE_BLOCK(safety_offset_Execute);
|
||||
// offset outside by 10um
|
||||
ClipperLib::Paths out_this;
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
co.Execute(out_this, ccw ? 10.f * float(CLIPPER_OFFSET_SCALE) : -10.f * float(CLIPPER_OFFSET_SCALE));
|
||||
#else // CLIPPERUTILS_OFFSET_SCALE
|
||||
co.Execute(out_this, ccw ? 10.f : -10.f);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
if (! ccw) {
|
||||
// Reverse the resulting contours once again.
|
||||
for (ClipperLib::Paths::iterator it = out_this.begin(); it != out_this.end(); ++ it)
|
||||
|
|
@ -830,8 +891,10 @@ void safety_offset(ClipperLib::Paths* paths)
|
|||
}
|
||||
*paths = std::move(out);
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// unscale output
|
||||
unscaleClipperPolygons(*paths);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
}
|
||||
|
||||
Polygons top_level_islands(const Slic3r::Polygons &polygons)
|
||||
|
|
@ -925,8 +988,10 @@ ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::v
|
|||
|
||||
// Add a new point to the output, scale by CLIPPER_OFFSET_SCALE and round to ClipperLib::cInt.
|
||||
auto add_offset_point = [&out](Vec2d pt) {
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
pt *= double(CLIPPER_OFFSET_SCALE);
|
||||
pt += Vec2d(0.5 - (pt.x() < 0), 0.5 - (pt.y() < 0));
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
pt += Vec2d(0.5 - (pt.x() < 0), 0.5 - (pt.y() < 0));
|
||||
out.emplace_back(ClipperLib::cInt(pt.x()), ClipperLib::cInt(pt.y()));
|
||||
};
|
||||
|
||||
|
|
@ -1075,8 +1140,10 @@ Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::v
|
|||
clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
}
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// 4) Unscale the output.
|
||||
unscaleClipperPolygons(output);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return ClipperPaths_to_Slic3rPolygons(output);
|
||||
}
|
||||
|
||||
|
|
@ -1119,8 +1186,10 @@ for (const std::vector<float>& ds : deltas)
|
|||
clipper.Execute(ClipperLib::ctDifference, output, ClipperLib::pftNonZero, ClipperLib::pftNonZero);
|
||||
}
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// 4) Unscale the output.
|
||||
unscaleClipperPolygons(output);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
return ClipperPaths_to_Slic3rPolygons(output);
|
||||
}
|
||||
|
||||
|
|
@ -1152,7 +1221,9 @@ for (const std::vector<float>& ds : deltas)
|
|||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
unscaleClipperPolygons(contours);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ExPolygons output;
|
||||
if (holes.empty()) {
|
||||
output.reserve(contours.size());
|
||||
|
|
@ -1160,7 +1231,9 @@ for (const std::vector<float>& ds : deltas)
|
|||
output.emplace_back(ClipperPath_to_Slic3rPolygon(path));
|
||||
} else {
|
||||
ClipperLib::Clipper clipper;
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
unscaleClipperPolygons(holes);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
ClipperLib::PolyTree polytree;
|
||||
|
|
@ -1200,7 +1273,9 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
|
|||
#endif /* NDEBUG */
|
||||
|
||||
// 3) Subtract holes from the contours.
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
unscaleClipperPolygons(contours);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
ExPolygons output;
|
||||
if (holes.empty()) {
|
||||
output.reserve(contours.size());
|
||||
|
|
@ -1208,7 +1283,9 @@ ExPolygons variable_offset_inner_ex(const ExPolygon &expoly, const std::vector<s
|
|||
output.emplace_back(ClipperPath_to_Slic3rPolygon(path));
|
||||
} else {
|
||||
ClipperLib::Clipper clipper;
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
unscaleClipperPolygons(holes);
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
clipper.AddPaths(contours, ClipperLib::ptSubject, true);
|
||||
clipper.AddPaths(holes, ClipperLib::ptClip, true);
|
||||
ClipperLib::PolyTree polytree;
|
||||
|
|
|
|||
|
|
@ -12,17 +12,23 @@ using ClipperLib::jtMiter;
|
|||
using ClipperLib::jtRound;
|
||||
using ClipperLib::jtSquare;
|
||||
|
||||
// Factor to convert from coord_t (which is int32) to an int64 type used by the Clipper library
|
||||
// for general offsetting (the offset(), offset2(), offset_ex() functions) and for the safety offset,
|
||||
// which is optionally executed by other functions (union, intersection, diff).
|
||||
// This scaling (cca 130t) is applied over the usual SCALING_FACTOR.
|
||||
// By the way, is the scalling for offset needed at all?
|
||||
// The reason to apply this scaling may be to match the resolution of the double mantissa.
|
||||
#define CLIPPER_OFFSET_POWER_OF_2 17
|
||||
// 2^17=131072
|
||||
#define CLIPPER_OFFSET_SCALE (1 << CLIPPER_OFFSET_POWER_OF_2)
|
||||
#define CLIPPER_OFFSET_SCALE_ROUNDING_DELTA ((1 << (CLIPPER_OFFSET_POWER_OF_2 - 1)) - 1)
|
||||
#define CLIPPER_MAX_COORD_UNSCALED (ClipperLib::hiRange / CLIPPER_OFFSET_SCALE)
|
||||
#define CLIPPERUTILS_UNSAFE_OFFSET
|
||||
|
||||
// #define CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
#ifdef CLIPPERUTILS_OFFSET_SCALE
|
||||
// Factor to convert from coord_t (which is int32) to an int64 type used by the Clipper library
|
||||
// for general offsetting (the offset(), offset2(), offset_ex() functions) and for the safety offset,
|
||||
// which is optionally executed by other functions (union, intersection, diff).
|
||||
// This scaling (cca 130t) is applied over the usual SCALING_FACTOR.
|
||||
// By the way, is the scalling for offset needed at all?
|
||||
// The reason to apply this scaling may be to match the resolution of the double mantissa.
|
||||
#define CLIPPER_OFFSET_POWER_OF_2 17
|
||||
// 2^17=131072
|
||||
#define CLIPPER_OFFSET_SCALE (1 << CLIPPER_OFFSET_POWER_OF_2)
|
||||
#define CLIPPER_OFFSET_SCALE_ROUNDING_DELTA ((1 << (CLIPPER_OFFSET_POWER_OF_2 - 1)) - 1)
|
||||
#define CLIPPER_MAX_COORD_UNSCALED (ClipperLib::hiRange / CLIPPER_OFFSET_SCALE)
|
||||
#endif // CLIPPERUTILS_OFFSET_SCALE
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
|
@ -47,8 +53,11 @@ ClipperLib::Paths _offset(ClipperLib::Path &&input, ClipperLib::EndType endType,
|
|||
ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit);
|
||||
inline Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rPolygons(_offset(Slic3rMultiPoint_to_ClipperPath(polygon), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
|
||||
|
||||
#ifdef CLIPPERUTILS_UNSAFE_OFFSET
|
||||
inline Slic3r::Polygons offset(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rPolygons(_offset(Slic3rMultiPoints_to_ClipperPaths(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
|
||||
#endif // CLIPPERUTILS_UNSAFE_OFFSET
|
||||
|
||||
// offset Polylines
|
||||
inline Slic3r::Polygons offset(const Slic3r::Polyline &polyline, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtSquare, double miterLimit = 3)
|
||||
|
|
@ -65,13 +74,18 @@ inline Slic3r::Polygons offset(const Slic3r::ExPolygons &expolygons, const float
|
|||
{ return ClipperPaths_to_Slic3rPolygons(_offset(expolygons, delta, joinType, miterLimit)); }
|
||||
inline Slic3r::ExPolygons offset_ex(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rExPolygons(_offset(Slic3rMultiPoint_to_ClipperPath(polygon), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
|
||||
|
||||
#ifdef CLIPPERUTILS_UNSAFE_OFFSET
|
||||
inline Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rExPolygons(_offset(Slic3rMultiPoints_to_ClipperPaths(polygons), ClipperLib::etClosedPolygon, delta, joinType, miterLimit)); }
|
||||
#endif // CLIPPERUTILS_UNSAFE_OFFSET
|
||||
|
||||
inline Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygon &expolygon, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rExPolygons(_offset(expolygon, delta, joinType, miterLimit)); }
|
||||
inline Slic3r::ExPolygons offset_ex(const Slic3r::ExPolygons &expolygons, const float delta, ClipperLib::JoinType joinType = ClipperLib::jtMiter, double miterLimit = 3)
|
||||
{ return ClipperPaths_to_Slic3rExPolygons(_offset(expolygons, delta, joinType, miterLimit)); }
|
||||
|
||||
#ifdef CLIPPERUTILS_UNSAFE_OFFSET
|
||||
ClipperLib::Paths _offset2(const Slic3r::Polygons &polygons, const float delta1,
|
||||
const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
|
|
@ -81,6 +95,8 @@ Slic3r::Polygons offset2(const Slic3r::Polygons &polygons, const float delta1,
|
|||
Slic3r::ExPolygons offset2_ex(const Slic3r::Polygons &polygons, const float delta1,
|
||||
const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
#endif // CLIPPERUTILS_UNSAFE_OFFSET
|
||||
|
||||
Slic3r::ExPolygons offset2_ex(const Slic3r::ExPolygons &expolygons, const float delta1,
|
||||
const float delta2, ClipperLib::JoinType joinType = ClipperLib::jtMiter,
|
||||
double miterLimit = 3);
|
||||
|
|
@ -319,6 +335,7 @@ void safety_offset(ClipperLib::Paths* paths);
|
|||
|
||||
Polygons top_level_islands(const Slic3r::Polygons &polygons);
|
||||
|
||||
ClipperLib::Path mittered_offset_path_scaled(const Points &contour, const std::vector<float> &deltas, double miter_limit);
|
||||
Polygons variable_offset_inner(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
|
||||
Polygons variable_offset_outer(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
|
||||
ExPolygons variable_offset_outer_ex(const ExPolygon &expoly, const std::vector<std::vector<float>> &deltas, double miter_limit = 2.);
|
||||
|
|
|
|||
|
|
@ -471,8 +471,8 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src,
|
|||
{
|
||||
t_config_option_key opt_key = opt_key_src;
|
||||
std::string value = value_src;
|
||||
// Both opt_key and value may be modified by _handle_legacy().
|
||||
// If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by _handle_legacy().
|
||||
// Both opt_key and value may be modified by handle_legacy().
|
||||
// If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by handle_legacy().
|
||||
this->handle_legacy(opt_key, value);
|
||||
if (opt_key.empty())
|
||||
// Ignore the option.
|
||||
|
|
|
|||
|
|
@ -1967,8 +1967,9 @@ public:
|
|||
int opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast<const ConfigOptionInts*>(this->option(opt_key))->get_at(idx); }
|
||||
|
||||
// In ConfigManipulation::toggle_print_fff_options, it is called on option with type ConfigOptionEnumGeneric* and also ConfigOptionEnum*.
|
||||
// Thus the virtual method getInt() is used to retrieve the enum value.
|
||||
template<typename ENUM>
|
||||
ENUM opt_enum(const t_config_option_key &opt_key) const { return this->option<ConfigOptionEnum<ENUM>>(opt_key)->value; }
|
||||
ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast<ENUM>(this->option(opt_key)->getInt()); }
|
||||
|
||||
bool opt_bool(const t_config_option_key &opt_key) const { return this->option<ConfigOptionBool>(opt_key)->value != 0; }
|
||||
bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option<ConfigOptionBools>(opt_key)->get_at(idx) != 0; }
|
||||
|
|
|
|||
|
|
@ -217,6 +217,28 @@ inline Polygons to_polygons(const ExPolygons &src)
|
|||
return polygons;
|
||||
}
|
||||
|
||||
inline ConstPolygonPtrs to_polygon_ptrs(const ExPolygon &src)
|
||||
{
|
||||
ConstPolygonPtrs polygons;
|
||||
polygons.reserve(src.holes.size() + 1);
|
||||
polygons.emplace_back(&src.contour);
|
||||
for (const Polygon &hole : src.holes)
|
||||
polygons.emplace_back(&hole);
|
||||
return polygons;
|
||||
}
|
||||
|
||||
inline ConstPolygonPtrs to_polygon_ptrs(const ExPolygons &src)
|
||||
{
|
||||
ConstPolygonPtrs polygons;
|
||||
polygons.reserve(number_polygons(src));
|
||||
for (const ExPolygon &expoly : src) {
|
||||
polygons.emplace_back(&expoly.contour);
|
||||
for (const Polygon &hole : expoly.holes)
|
||||
polygons.emplace_back(&hole);
|
||||
}
|
||||
return polygons;
|
||||
}
|
||||
|
||||
inline Polygons to_polygons(ExPolygon &&src)
|
||||
{
|
||||
Polygons polygons;
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ void FillConcentric::_fill_surface_single(
|
|||
this->spacing = unscale<double>(distance);
|
||||
}
|
||||
|
||||
Polygons loops = to_polygons(std::move(expolygon));
|
||||
Polygons last = loops;
|
||||
Polygons loops = to_polygons(expolygon);
|
||||
ExPolygons last { std::move(expolygon) };
|
||||
while (! last.empty()) {
|
||||
last = offset2(last, -(distance + min_spacing/2), +min_spacing/2);
|
||||
append(loops, last);
|
||||
last = offset2_ex(last, -(distance + min_spacing/2), +min_spacing/2);
|
||||
append(loops, to_polygons(last));
|
||||
}
|
||||
|
||||
// generate paths from the outermost to the innermost, to avoid
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ void FillLine::_fill_surface_single(
|
|||
pts.push_back(it->a);
|
||||
pts.push_back(it->b);
|
||||
}
|
||||
Polylines polylines = intersection_pl(polylines_src, offset(to_polygons(expolygon), scale_(0.02)), false);
|
||||
Polylines polylines = intersection_pl(polylines_src, offset(expolygon, scale_(0.02)), false);
|
||||
|
||||
// FIXME Vojtech: This is only performed for horizontal lines, not for the vertical lines!
|
||||
const float INFILL_OVERLAP_OVER_SPACING = 0.3f;
|
||||
|
|
|
|||
|
|
@ -238,13 +238,14 @@ Flow support_material_flow(const PrintObject *object, float layer_height)
|
|||
|
||||
Flow support_material_1st_layer_flow(const PrintObject *object, float layer_height)
|
||||
{
|
||||
const auto &width = (object->print()->config().first_layer_extrusion_width.value > 0) ? object->print()->config().first_layer_extrusion_width : object->config().support_material_extrusion_width;
|
||||
const PrintConfig &print_config = object->print()->config();
|
||||
const auto &width = (print_config.first_layer_extrusion_width.value > 0) ? print_config.first_layer_extrusion_width : object->config().support_material_extrusion_width;
|
||||
return Flow::new_from_config_width(
|
||||
frSupportMaterial,
|
||||
// The width parameter accepted by new_from_config_width is of type ConfigOptionFloatOrPercent, the Flow class takes care of the percent to value substitution.
|
||||
(width.value > 0) ? width : object->config().extrusion_width,
|
||||
float(object->print()->config().nozzle_diameter.get_at(object->config().support_material_extruder-1)),
|
||||
(layer_height > 0.f) ? layer_height : float(object->config().first_layer_height.get_abs_value(object->config().layer_height.value)));
|
||||
float(print_config.nozzle_diameter.get_at(object->config().support_material_extruder-1)),
|
||||
(layer_height > 0.f) ? layer_height : float(print_config.first_layer_height.get_abs_value(object->config().layer_height.value)));
|
||||
}
|
||||
|
||||
Flow support_material_interface_flow(const PrintObject *object, float layer_height)
|
||||
|
|
|
|||
|
|
@ -1111,7 +1111,7 @@ void GCode::_do_export(Print& print, FILE* file, ThumbnailsGeneratorCallback thu
|
|||
// Write some terse information on the slicing parameters.
|
||||
const PrintObject *first_object = print.objects().front();
|
||||
const double layer_height = first_object->config().layer_height.value;
|
||||
const double first_layer_height = first_object->config().first_layer_height.get_abs_value(layer_height);
|
||||
const double first_layer_height = print.config().first_layer_height.get_abs_value(layer_height);
|
||||
for (const PrintRegion* region : print.regions()) {
|
||||
_write_format(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(*first_object, frExternalPerimeter, layer_height).width());
|
||||
_write_format(file, "; perimeters extrusion width = %.2fmm\n", region->flow(*first_object, frPerimeter, layer_height).width());
|
||||
|
|
@ -1778,6 +1778,10 @@ namespace ProcessLayer
|
|||
else {
|
||||
gcode += gcodegen.placeholder_parser_process("color_change_gcode", config.color_change_gcode, current_extruder_id);
|
||||
gcode += "\n";
|
||||
//FIXME Tell G-code writer that M600 filled the extruder, thus the G-code writer shall reset the extruder to unretracted state after
|
||||
// return from M600. Thus the G-code generated by the following line is ignored.
|
||||
// see GH issue #6362
|
||||
gcodegen.writer().unretract();
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -1087,11 +1087,13 @@ bool
|
|||
MedialAxis::validate_edge(const VD::edge_type* edge)
|
||||
{
|
||||
// prevent overflows and detect almost-infinite edges
|
||||
#ifndef CLIPPERLIB_INT32
|
||||
if (std::abs(edge->vertex0()->x()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
|
||||
std::abs(edge->vertex0()->y()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
|
||||
std::abs(edge->vertex1()->x()) > double(CLIPPER_MAX_COORD_UNSCALED) ||
|
||||
std::abs(edge->vertex1()->y()) > double(CLIPPER_MAX_COORD_UNSCALED))
|
||||
return false;
|
||||
#endif // CLIPPERLIB_INT32
|
||||
|
||||
// construct the line representing this edge of the Voronoi diagram
|
||||
const Line line(
|
||||
|
|
|
|||
|
|
@ -216,7 +216,7 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
|
|||
break;
|
||||
}
|
||||
// Grown by 3mm.
|
||||
Polygons polys = offset(to_polygons(bridges[i].expolygon), margin, EXTERNAL_SURFACES_OFFSET_PARAMETERS);
|
||||
Polygons polys = offset(bridges[i].expolygon, margin, EXTERNAL_SURFACES_OFFSET_PARAMETERS);
|
||||
if (idx_island == -1) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "Bridge did not fall into the source region!";
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@
|
|||
namespace Slic3r {
|
||||
|
||||
class Polygon;
|
||||
typedef std::vector<Polygon> Polygons;
|
||||
using Polygons = std::vector<Polygon>;
|
||||
using PolygonPtrs = std::vector<Polygon*>;
|
||||
using ConstPolygonPtrs = std::vector<const Polygon*>;
|
||||
|
||||
class Polygon : public MultiPoint
|
||||
{
|
||||
|
|
|
|||
|
|
@ -296,6 +296,13 @@ void Preset::normalize(DynamicPrintConfig &config)
|
|||
if (auto *gap_fill_enabled = config.option<ConfigOptionBool>("gap_fill_enabled", false); gap_fill_enabled)
|
||||
gap_fill_enabled->value = false;
|
||||
}
|
||||
if (auto *first_layer_height = config.option<ConfigOptionFloatOrPercent>("first_layer_height", false); first_layer_height && first_layer_height->percent)
|
||||
if (const auto *layer_height = config.option<ConfigOptionFloat>("layer_height", false); layer_height) {
|
||||
// Legacy conversion - first_layer_height moved from PrintObject setting to a Print setting, thus we are getting rid of the dependency
|
||||
// of first_layer_height on PrintObject specific layer_height. Covert the first layer heigth to an absolute value.
|
||||
first_layer_height->value = first_layer_height->get_abs_value(layer_height->value);
|
||||
first_layer_height->percent = false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Preset::remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config)
|
||||
|
|
@ -427,7 +434,7 @@ const std::vector<std::string>& Preset::print_options()
|
|||
"bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield",
|
||||
"min_skirt_length", "brim_width", "brim_offset", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
|
||||
"raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion",
|
||||
"support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_style",
|
||||
"support_material_pattern", "support_material_with_sheath", "support_material_spacing", "support_material_closing_radius", "support_material_style",
|
||||
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers", "support_material_bottom_interface_layers",
|
||||
"support_material_interface_pattern", "support_material_interface_spacing", "support_material_interface_contact_loops",
|
||||
"support_material_contact_distance", "support_material_bottom_contact_distance",
|
||||
|
|
|
|||
|
|
@ -995,10 +995,8 @@ void PrintConfigDef::init_fff_params()
|
|||
def->label = L("First layer height");
|
||||
def->category = L("Layers and Perimeters");
|
||||
def->tooltip = L("When printing with very low layer heights, you might still want to print a thicker "
|
||||
"bottom layer to improve adhesion and tolerance for non perfect build plates. "
|
||||
"This can be expressed as an absolute value or as a percentage (for example: 150%) "
|
||||
"over the default layer height.");
|
||||
def->sidetext = L("mm or %");
|
||||
"bottom layer to improve adhesion and tolerance for non perfect build plates.");
|
||||
def->sidetext = L("mm");
|
||||
def->ratio_over = "layer_height";
|
||||
def->set_default_value(new ConfigOptionFloatOrPercent(0.35, false));
|
||||
|
||||
|
|
@ -2366,6 +2364,16 @@ void PrintConfigDef::init_fff_params()
|
|||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionInt(-1));
|
||||
|
||||
def = this->add("support_material_closing_radius", coFloat);
|
||||
def->label = L("Closing radius");
|
||||
def->category = L("Support material");
|
||||
def->tooltip = L("For snug supports, the support regions will be merged using morphological closing operation."
|
||||
" Gaps smaller than the closing radius will be filled in.");
|
||||
def->sidetext = L("mm");
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(2));
|
||||
|
||||
def = this->add("support_material_interface_spacing", coFloat);
|
||||
def->label = L("Interface pattern spacing");
|
||||
def->category = L("Support material");
|
||||
|
|
@ -3618,7 +3626,7 @@ std::string FullPrintConfig::validate()
|
|||
return "--layer-height must be a multiple of print resolution";
|
||||
|
||||
// --first-layer-height
|
||||
if (this->get_abs_value("first_layer_height") <= 0)
|
||||
if (first_layer_height.value <= 0)
|
||||
return "Invalid value for --first-layer-height";
|
||||
|
||||
// --filament-diameter
|
||||
|
|
|
|||
|
|
@ -496,7 +496,6 @@ public:
|
|||
ConfigOptionBool dont_support_bridges;
|
||||
ConfigOptionFloat elefant_foot_compensation;
|
||||
ConfigOptionFloatOrPercent extrusion_width;
|
||||
ConfigOptionFloatOrPercent first_layer_height;
|
||||
ConfigOptionBool infill_only_where_needed;
|
||||
// Force the generation of solid shells between adjacent materials/volumes.
|
||||
ConfigOptionBool interface_shells;
|
||||
|
|
@ -530,6 +529,8 @@ public:
|
|||
ConfigOptionFloatOrPercent support_material_interface_speed;
|
||||
ConfigOptionEnum<SupportMaterialPattern> support_material_pattern;
|
||||
ConfigOptionEnum<SupportMaterialInterfacePattern> support_material_interface_pattern;
|
||||
// Morphological closing of support areas. Only used for "sung" supports.
|
||||
ConfigOptionFloat support_material_closing_radius;
|
||||
// Spacing between support material lines (the hatching distance).
|
||||
ConfigOptionFloat support_material_spacing;
|
||||
ConfigOptionFloat support_material_speed;
|
||||
|
|
@ -553,7 +554,6 @@ protected:
|
|||
OPT_PTR(dont_support_bridges);
|
||||
OPT_PTR(elefant_foot_compensation);
|
||||
OPT_PTR(extrusion_width);
|
||||
OPT_PTR(first_layer_height);
|
||||
OPT_PTR(infill_only_where_needed);
|
||||
OPT_PTR(interface_shells);
|
||||
OPT_PTR(layer_height);
|
||||
|
|
@ -579,6 +579,7 @@ protected:
|
|||
OPT_PTR(support_material_interface_extruder);
|
||||
OPT_PTR(support_material_interface_layers);
|
||||
OPT_PTR(support_material_bottom_interface_layers);
|
||||
OPT_PTR(support_material_closing_radius);
|
||||
OPT_PTR(support_material_interface_spacing);
|
||||
OPT_PTR(support_material_interface_speed);
|
||||
OPT_PTR(support_material_pattern);
|
||||
|
|
@ -947,6 +948,7 @@ public:
|
|||
ConfigOptionFloat first_layer_acceleration;
|
||||
ConfigOptionInts first_layer_bed_temperature;
|
||||
ConfigOptionFloatOrPercent first_layer_extrusion_width;
|
||||
ConfigOptionFloatOrPercent first_layer_height;
|
||||
ConfigOptionFloatOrPercent first_layer_speed;
|
||||
ConfigOptionInts first_layer_temperature;
|
||||
ConfigOptionInts full_fan_speed_layer;
|
||||
|
|
@ -1022,6 +1024,7 @@ protected:
|
|||
OPT_PTR(first_layer_acceleration);
|
||||
OPT_PTR(first_layer_bed_temperature);
|
||||
OPT_PTR(first_layer_extrusion_width);
|
||||
OPT_PTR(first_layer_height);
|
||||
OPT_PTR(first_layer_speed);
|
||||
OPT_PTR(first_layer_temperature);
|
||||
OPT_PTR(full_fan_speed_layer);
|
||||
|
|
|
|||
|
|
@ -591,6 +591,7 @@ bool PrintObject::invalidate_state_by_config_options(
|
|||
|| opt_key == "support_material_style"
|
||||
|| opt_key == "support_material_xy_spacing"
|
||||
|| opt_key == "support_material_spacing"
|
||||
|| opt_key == "support_material_closing_radius"
|
||||
|| opt_key == "support_material_synchronize_layers"
|
||||
|| opt_key == "support_material_threshold"
|
||||
|| opt_key == "support_material_with_sheath"
|
||||
|
|
|
|||
|
|
@ -64,9 +64,9 @@ SlicingParameters SlicingParameters::create_from_config(
|
|||
coordf_t object_height,
|
||||
const std::vector<unsigned int> &object_extruders)
|
||||
{
|
||||
coordf_t first_layer_height = (object_config.first_layer_height.value <= 0) ?
|
||||
coordf_t first_layer_height = (print_config.first_layer_height.value <= 0) ?
|
||||
object_config.layer_height.value :
|
||||
object_config.first_layer_height.get_abs_value(object_config.layer_height.value);
|
||||
print_config.first_layer_height.get_abs_value(object_config.layer_height.value);
|
||||
// If object_config.support_material_extruder == 0 resp. object_config.support_material_interface_extruder == 0,
|
||||
// print_config.nozzle_diameter.get_at(size_t(-1)) returns the 0th nozzle diameter,
|
||||
// which is consistent with the requirement that if support_material_extruder == 0 resp. support_material_interface_extruder == 0,
|
||||
|
|
|
|||
|
|
@ -672,6 +672,7 @@ struct SupportGridParams {
|
|||
grid_resolution(object_config.support_material_spacing.value + support_material_flow.spacing()),
|
||||
support_angle(Geometry::deg2rad(object_config.support_material_angle.value)),
|
||||
extrusion_width(support_material_flow.spacing()),
|
||||
support_material_closing_radius(object_config.support_material_closing_radius.value),
|
||||
expansion_to_slice(coord_t(support_material_flow.scaled_spacing() / 2 + 5)),
|
||||
expansion_to_propagate(-3) {}
|
||||
|
||||
|
|
@ -679,6 +680,7 @@ struct SupportGridParams {
|
|||
double grid_resolution;
|
||||
double support_angle;
|
||||
double extrusion_width;
|
||||
double support_material_closing_radius;
|
||||
coord_t expansion_to_slice;
|
||||
coord_t expansion_to_propagate;
|
||||
};
|
||||
|
|
@ -694,7 +696,9 @@ public:
|
|||
const SupportGridParams ¶ms) :
|
||||
m_style(params.style),
|
||||
m_support_polygons(support_polygons), m_trimming_polygons(trimming_polygons),
|
||||
m_support_spacing(params.grid_resolution), m_support_angle(params.support_angle)
|
||||
m_support_spacing(params.grid_resolution), m_support_angle(params.support_angle),
|
||||
m_extrusion_width(params.extrusion_width),
|
||||
m_support_material_closing_radius(params.support_material_closing_radius)
|
||||
{
|
||||
switch (m_style) {
|
||||
case smsGrid:
|
||||
|
|
@ -878,9 +882,10 @@ public:
|
|||
return out;
|
||||
}
|
||||
case smsSnug:
|
||||
// Just close the gaps.
|
||||
float thr = scaled<float>(0.5);
|
||||
return smooth_outward(offset(offset_ex(*m_support_polygons, thr), - thr), thr);
|
||||
// Merge the support polygons by applying morphological closing and inwards smoothing.
|
||||
auto closing_distance = scaled<float>(m_support_material_closing_radius);
|
||||
auto smoothing_distance = scaled<float>(m_extrusion_width);
|
||||
return smooth_outward(offset(offset_ex(*m_support_polygons, closing_distance), - closing_distance), smoothing_distance);
|
||||
}
|
||||
assert(false);
|
||||
return Polygons();
|
||||
|
|
@ -1128,6 +1133,9 @@ private:
|
|||
coordf_t m_support_angle;
|
||||
// X spacing of the support lines parallel with the Y axis.
|
||||
coordf_t m_support_spacing;
|
||||
coordf_t m_extrusion_width;
|
||||
// For snug supports: Morphological closing of support areas.
|
||||
coordf_t m_support_material_closing_radius;
|
||||
|
||||
#ifdef SUPPORT_USE_AGG_RASTERIZER
|
||||
Vec2i m_grid_size;
|
||||
|
|
@ -3178,7 +3186,7 @@ struct MyLayerExtruded
|
|||
MyLayerExtruded& operator=(MyLayerExtruded &&rhs) {
|
||||
this->layer = rhs.layer;
|
||||
this->extrusions = std::move(rhs.extrusions);
|
||||
this->m_polygons_to_extrude = std::move(m_polygons_to_extrude);
|
||||
this->m_polygons_to_extrude = std::move(rhs.m_polygons_to_extrude);
|
||||
rhs.layer = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@
|
|||
#define ENABLE_GCODE_WINDOW (1 && ENABLE_2_4_0_ALPHA0)
|
||||
// Enable exporting lines M73 for remaining time to next printer stop to gcode
|
||||
#define ENABLE_EXTENDED_M73_LINES (1 && ENABLE_VALIDATE_CUSTOM_GCODE)
|
||||
// Enable a modified version of automatic downscale on load of objects too big
|
||||
#define ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG (1 && ENABLE_2_4_0_ALPHA0)
|
||||
|
||||
|
||||
#endif // _prusaslicer_technologies_h_
|
||||
|
|
|
|||
|
|
@ -511,20 +511,22 @@ void TriangleMesh::merge(const TriangleMesh &mesh)
|
|||
//FIXME This could be extremely slow! Use it for tiny meshes only!
|
||||
ExPolygons TriangleMesh::horizontal_projection() const
|
||||
{
|
||||
Polygons pp;
|
||||
pp.reserve(this->stl.stats.number_of_facets);
|
||||
ClipperLib::Paths paths;
|
||||
Polygon p;
|
||||
p.points.assign(3, Point());
|
||||
auto delta = scaled<float>(0.01);
|
||||
std::vector<float> deltas { delta, delta, delta };
|
||||
paths.reserve(this->stl.stats.number_of_facets);
|
||||
for (const stl_facet &facet : this->stl.facet_start) {
|
||||
Polygon p;
|
||||
p.points.resize(3);
|
||||
p.points[0] = Point::new_scale(facet.vertex[0](0), facet.vertex[0](1));
|
||||
p.points[1] = Point::new_scale(facet.vertex[1](0), facet.vertex[1](1));
|
||||
p.points[2] = Point::new_scale(facet.vertex[2](0), facet.vertex[2](1));
|
||||
p.make_counter_clockwise(); // do this after scaling, as winding order might change while doing that
|
||||
pp.emplace_back(p);
|
||||
p.make_counter_clockwise();
|
||||
paths.emplace_back(mittered_offset_path_scaled(p.points, deltas, 3.));
|
||||
}
|
||||
|
||||
// the offset factor was tuned using groovemount.stl
|
||||
return union_ex(offset(pp, scale_(0.01)), true);
|
||||
return ClipperPaths_to_Slic3rExPolygons(paths);
|
||||
}
|
||||
|
||||
// 2D convex hull of a 3D mesh projected into the Z=0 plane.
|
||||
|
|
@ -1797,7 +1799,7 @@ void TriangleMeshSlicer::make_expolygons(const Polygons &loops, const float clos
|
|||
|
||||
// append to the supplied collection
|
||||
if (safety_offset > 0)
|
||||
expolygons_append(*slices, offset2_ex(union_(loops, false), +safety_offset, -safety_offset));
|
||||
expolygons_append(*slices, offset2_ex(union_ex(loops, false), +safety_offset, -safety_offset));
|
||||
else
|
||||
expolygons_append(*slices, union_ex(loops, false));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,7 @@ void Bed3D::Axes::render() const
|
|||
glsafe(::glPopMatrix());
|
||||
};
|
||||
|
||||
m_arrow.init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length));
|
||||
const_cast<GLModel*>(&m_arrow)->init_from(stilized_arrow(16, DefaultTipRadius, DefaultTipLength, DefaultStemRadius, m_stem_length));
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader == nullptr)
|
||||
|
|
@ -143,13 +143,6 @@ void Bed3D::Axes::render() const
|
|||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
}
|
||||
|
||||
Bed3D::Bed3D()
|
||||
: m_type(Custom)
|
||||
, m_vbo_id(0)
|
||||
, m_scale_factor(1.0f)
|
||||
{
|
||||
}
|
||||
|
||||
bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom)
|
||||
{
|
||||
auto check_texture = [](const std::string& texture) {
|
||||
|
|
@ -193,7 +186,7 @@ bool Bed3D::set_shape(const Pointfs& shape, const std::string& custom_texture, c
|
|||
|
||||
ExPolygon poly;
|
||||
for (const Vec2d& p : m_shape) {
|
||||
poly.contour.append(Point(scale_(p(0)), scale_(p(1))));
|
||||
poly.contour.append({ scale_(p(0)), scale_(p(1)) });
|
||||
}
|
||||
|
||||
calc_triangles(poly);
|
||||
|
|
@ -228,7 +221,8 @@ Point Bed3D::point_projection(const Point& point) const
|
|||
void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor,
|
||||
bool show_axes, bool show_texture) const
|
||||
{
|
||||
m_scale_factor = scale_factor;
|
||||
float* factor = const_cast<float*>(&m_scale_factor);
|
||||
*factor = scale_factor;
|
||||
|
||||
if (show_axes)
|
||||
render_axes();
|
||||
|
|
@ -247,22 +241,24 @@ void Bed3D::render(GLCanvas3D& canvas, bool bottom, float scale_factor,
|
|||
|
||||
void Bed3D::calc_bounding_boxes() const
|
||||
{
|
||||
m_bounding_box = BoundingBoxf3();
|
||||
BoundingBoxf3* bounding_box = const_cast<BoundingBoxf3*>(&m_bounding_box);
|
||||
*bounding_box = BoundingBoxf3();
|
||||
for (const Vec2d& p : m_shape) {
|
||||
m_bounding_box.merge(Vec3d(p(0), p(1), 0.0));
|
||||
bounding_box->merge({ p(0), p(1), 0.0 });
|
||||
}
|
||||
|
||||
m_extended_bounding_box = m_bounding_box;
|
||||
BoundingBoxf3* extended_bounding_box = const_cast<BoundingBoxf3*>(&m_extended_bounding_box);
|
||||
*extended_bounding_box = m_bounding_box;
|
||||
|
||||
// extend to contain axes
|
||||
m_extended_bounding_box.merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones());
|
||||
m_extended_bounding_box.merge(m_extended_bounding_box.min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, m_extended_bounding_box.max(2)));
|
||||
extended_bounding_box->merge(m_axes.get_origin() + m_axes.get_total_length() * Vec3d::Ones());
|
||||
extended_bounding_box->merge(extended_bounding_box->min + Vec3d(-Axes::DefaultTipRadius, -Axes::DefaultTipRadius, extended_bounding_box->max(2)));
|
||||
|
||||
// extend to contain model, if any
|
||||
BoundingBoxf3 model_bb = m_model.get_bounding_box();
|
||||
if (model_bb.defined) {
|
||||
model_bb.translate(m_model_offset);
|
||||
m_extended_bounding_box.merge(model_bb);
|
||||
extended_bounding_box->merge(model_bb);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -339,21 +335,24 @@ void Bed3D::render_system(GLCanvas3D& canvas, bool bottom, bool show_texture) co
|
|||
|
||||
void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
||||
{
|
||||
GLTexture* texture = const_cast<GLTexture*>(&m_texture);
|
||||
GLTexture* temp_texture = const_cast<GLTexture*>(&m_temp_texture);
|
||||
|
||||
if (m_texture_filename.empty()) {
|
||||
m_texture.reset();
|
||||
texture->reset();
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_texture.get_id() == 0) || (m_texture.get_source() != m_texture_filename)) {
|
||||
m_texture.reset();
|
||||
if (texture->get_id() == 0 || texture->get_source() != m_texture_filename) {
|
||||
texture->reset();
|
||||
|
||||
if (boost::algorithm::iends_with(m_texture_filename, ".svg")) {
|
||||
// use higher resolution images if graphic card and opengl version allow
|
||||
GLint max_tex_size = OpenGLManager::get_gl_info().get_max_tex_size();
|
||||
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename)) {
|
||||
if (temp_texture->get_id() == 0 || temp_texture->get_source() != m_texture_filename) {
|
||||
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
|
||||
if (!m_temp_texture.load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8)) {
|
||||
if (!temp_texture->load_from_svg_file(m_texture_filename, false, false, false, max_tex_size / 8)) {
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
|
|
@ -361,15 +360,15 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
}
|
||||
|
||||
// starts generating the main texture, compression will run asynchronously
|
||||
if (!m_texture.load_from_svg_file(m_texture_filename, true, true, true, max_tex_size)) {
|
||||
if (!texture->load_from_svg_file(m_texture_filename, true, true, true, max_tex_size)) {
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (boost::algorithm::iends_with(m_texture_filename, ".png")) {
|
||||
// generate a temporary lower resolution texture to show while no main texture levels have been compressed
|
||||
if ((m_temp_texture.get_id() == 0) || (m_temp_texture.get_source() != m_texture_filename)) {
|
||||
if (!m_temp_texture.load_from_file(m_texture_filename, false, GLTexture::None, false)) {
|
||||
if (temp_texture->get_id() == 0 || temp_texture->get_source() != m_texture_filename) {
|
||||
if (!temp_texture->load_from_file(m_texture_filename, false, GLTexture::None, false)) {
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
|
|
@ -377,7 +376,7 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
}
|
||||
|
||||
// starts generating the main texture, compression will run asynchronously
|
||||
if (!m_texture.load_from_file(m_texture_filename, true, GLTexture::MultiThreaded, true)) {
|
||||
if (!texture->load_from_file(m_texture_filename, true, GLTexture::MultiThreaded, true)) {
|
||||
render_default(bottom);
|
||||
return;
|
||||
}
|
||||
|
|
@ -387,13 +386,13 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
return;
|
||||
}
|
||||
}
|
||||
else if (m_texture.unsent_compressed_data_available()) {
|
||||
else if (texture->unsent_compressed_data_available()) {
|
||||
// sends to gpu the already available compressed levels of the main texture
|
||||
m_texture.send_compressed_data_to_gpu();
|
||||
texture->send_compressed_data_to_gpu();
|
||||
|
||||
// the temporary texture is not needed anymore, reset it
|
||||
if (m_temp_texture.get_id() != 0)
|
||||
m_temp_texture.reset();
|
||||
if (temp_texture->get_id() != 0)
|
||||
temp_texture->reset();
|
||||
|
||||
canvas.request_extra_frame();
|
||||
|
||||
|
|
@ -406,9 +405,11 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
shader->set_uniform("transparent_background", bottom);
|
||||
shader->set_uniform("svg_source", boost::algorithm::iends_with(m_texture.get_source(), ".svg"));
|
||||
|
||||
if (m_vbo_id == 0) {
|
||||
glsafe(::glGenBuffers(1, &m_vbo_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
||||
unsigned int* vbo_id = const_cast<unsigned int*>(&m_vbo_id);
|
||||
|
||||
if (*vbo_id == 0) {
|
||||
glsafe(::glGenBuffers(1, vbo_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, *vbo_id));
|
||||
glsafe(::glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)m_triangles.get_vertices_data_size(), (const GLvoid*)m_triangles.get_vertices_data(), GL_STATIC_DRAW));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
}
|
||||
|
|
@ -428,12 +429,12 @@ void Bed3D::render_texture(bool bottom, GLCanvas3D& canvas) const
|
|||
GLint tex_coords_id = shader->get_attrib_location("v_tex_coords");
|
||||
|
||||
// show the temporary texture while no compressed data is available
|
||||
GLuint tex_id = (GLuint)m_temp_texture.get_id();
|
||||
GLuint tex_id = (GLuint)temp_texture->get_id();
|
||||
if (tex_id == 0)
|
||||
tex_id = (GLuint)m_texture.get_id();
|
||||
tex_id = (GLuint)texture->get_id();
|
||||
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, tex_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, *vbo_id));
|
||||
|
||||
if (position_id != -1) {
|
||||
glsafe(::glEnableVertexAttribArray(position_id));
|
||||
|
|
@ -471,24 +472,26 @@ void Bed3D::render_model() const
|
|||
if (m_model_filename.empty())
|
||||
return;
|
||||
|
||||
if ((m_model.get_filename() != m_model_filename) && m_model.init_from_file(m_model_filename)) {
|
||||
GLModel* model = const_cast<GLModel*>(&m_model);
|
||||
|
||||
if (model->get_filename() != m_model_filename && model->init_from_file(m_model_filename)) {
|
||||
// move the model so that its origin (0.0, 0.0, 0.0) goes into the bed shape center and a bit down to avoid z-fighting with the texture quad
|
||||
Vec3d shift = m_bounding_box.center();
|
||||
shift(2) = -0.03;
|
||||
m_model_offset = shift;
|
||||
*const_cast<Vec3d*>(&m_model_offset) = shift;
|
||||
|
||||
// update extended bounding box
|
||||
calc_bounding_boxes();
|
||||
}
|
||||
|
||||
if (!m_model.get_filename().empty()) {
|
||||
if (!model->get_filename().empty()) {
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader != nullptr) {
|
||||
shader->start_using();
|
||||
shader->set_uniform("uniform_color", m_model_color);
|
||||
::glPushMatrix();
|
||||
::glTranslated(m_model_offset(0), m_model_offset(1), m_model_offset(2));
|
||||
m_model.render();
|
||||
model->render();
|
||||
::glPopMatrix();
|
||||
shader->stop_using();
|
||||
}
|
||||
|
|
@ -511,7 +514,7 @@ void Bed3D::render_custom(GLCanvas3D& canvas, bool bottom, bool show_texture) co
|
|||
|
||||
void Bed3D::render_default(bool bottom) const
|
||||
{
|
||||
m_texture.reset();
|
||||
const_cast<GLTexture*>(&m_texture)->reset();
|
||||
|
||||
unsigned int triangles_vcount = m_triangles.get_vertices_count();
|
||||
if (triangles_vcount > 0) {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ class Bed3D
|
|||
private:
|
||||
Vec3d m_origin{ Vec3d::Zero() };
|
||||
float m_stem_length{ DefaultStemLength };
|
||||
mutable GLModel m_arrow;
|
||||
GLModel m_arrow;
|
||||
|
||||
public:
|
||||
const Vec3d& get_origin() const { return m_origin; }
|
||||
|
|
@ -67,28 +67,28 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
EType m_type;
|
||||
EType m_type{ Custom };
|
||||
Pointfs m_shape;
|
||||
std::string m_texture_filename;
|
||||
std::string m_model_filename;
|
||||
mutable BoundingBoxf3 m_bounding_box;
|
||||
mutable BoundingBoxf3 m_extended_bounding_box;
|
||||
BoundingBoxf3 m_bounding_box;
|
||||
BoundingBoxf3 m_extended_bounding_box;
|
||||
Polygon m_polygon;
|
||||
GeometryBuffer m_triangles;
|
||||
GeometryBuffer m_gridlines;
|
||||
mutable GLTexture m_texture;
|
||||
mutable GLModel m_model;
|
||||
mutable Vec3d m_model_offset{ Vec3d::Zero() };
|
||||
std::array<float, 4> m_model_color{ 0.235f, 0.235f, 0.235f, 1.0f };
|
||||
GLTexture m_texture;
|
||||
// temporary texture shown until the main texture has still no levels compressed
|
||||
mutable GLTexture m_temp_texture;
|
||||
mutable unsigned int m_vbo_id;
|
||||
GLTexture m_temp_texture;
|
||||
GLModel m_model;
|
||||
Vec3d m_model_offset{ Vec3d::Zero() };
|
||||
std::array<float, 4> m_model_color{ 0.235f, 0.235f, 0.235f, 1.0f };
|
||||
unsigned int m_vbo_id{ 0 };
|
||||
Axes m_axes;
|
||||
|
||||
mutable float m_scale_factor;
|
||||
float m_scale_factor{ 1.0f };
|
||||
|
||||
public:
|
||||
Bed3D();
|
||||
Bed3D() = default;
|
||||
~Bed3D() { reset(); }
|
||||
|
||||
EType get_type() const { return m_type; }
|
||||
|
|
|
|||
|
|
@ -421,20 +421,24 @@ const BoundingBoxf3& GLVolume::transformed_bounding_box() const
|
|||
const BoundingBoxf3& box = bounding_box();
|
||||
assert(box.defined || box.min(0) >= box.max(0) || box.min(1) >= box.max(1) || box.min(2) >= box.max(2));
|
||||
|
||||
if (m_transformed_bounding_box_dirty)
|
||||
{
|
||||
m_transformed_bounding_box = box.transformed(world_matrix());
|
||||
m_transformed_bounding_box_dirty = false;
|
||||
BoundingBoxf3* transformed_bounding_box = const_cast<BoundingBoxf3*>(&m_transformed_bounding_box);
|
||||
bool* transformed_bounding_box_dirty = const_cast<bool*>(&m_transformed_bounding_box_dirty);
|
||||
if (*transformed_bounding_box_dirty) {
|
||||
*transformed_bounding_box = box.transformed(world_matrix());
|
||||
*transformed_bounding_box_dirty = false;
|
||||
}
|
||||
|
||||
return m_transformed_bounding_box;
|
||||
return *transformed_bounding_box;
|
||||
}
|
||||
|
||||
const BoundingBoxf3& GLVolume::transformed_convex_hull_bounding_box() const
|
||||
{
|
||||
if (m_transformed_convex_hull_bounding_box_dirty)
|
||||
m_transformed_convex_hull_bounding_box = this->transformed_convex_hull_bounding_box(world_matrix());
|
||||
return m_transformed_convex_hull_bounding_box;
|
||||
BoundingBoxf3* transformed_convex_hull_bounding_box = const_cast<BoundingBoxf3*>(&m_transformed_convex_hull_bounding_box);
|
||||
bool* transformed_convex_hull_bounding_box_dirty = const_cast<bool*>(&m_transformed_convex_hull_bounding_box_dirty);
|
||||
if (*transformed_convex_hull_bounding_box_dirty) {
|
||||
*transformed_convex_hull_bounding_box = this->transformed_convex_hull_bounding_box(world_matrix());
|
||||
*transformed_convex_hull_bounding_box_dirty = false;
|
||||
}
|
||||
return *transformed_convex_hull_bounding_box;
|
||||
}
|
||||
|
||||
BoundingBoxf3 GLVolume::transformed_convex_hull_bounding_box(const Transform3d &trafo) const
|
||||
|
|
@ -795,7 +799,7 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab
|
|||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state)
|
||||
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const
|
||||
{
|
||||
if (config == nullptr)
|
||||
return false;
|
||||
|
|
@ -805,7 +809,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
|||
return false;
|
||||
|
||||
BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values));
|
||||
BoundingBoxf3 print_volume(Vec3d(unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0), Vec3d(unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config->opt_float("max_print_height")));
|
||||
BoundingBoxf3 print_volume({ unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0 }, { unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config->opt_float("max_print_height") });
|
||||
// Allow the objects to protrude below the print bed
|
||||
print_volume.min(2) = -1e10;
|
||||
print_volume.min(0) -= BedEpsilon;
|
||||
|
|
@ -817,9 +821,8 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
|||
|
||||
bool contained_min_one = false;
|
||||
|
||||
for (GLVolume* volume : this->volumes)
|
||||
{
|
||||
if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled))
|
||||
for (GLVolume* volume : this->volumes) {
|
||||
if (volume == nullptr || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || (volume->composite_id.volume_id < 0 && !volume->shader_outside_printer_detection_enabled))
|
||||
continue;
|
||||
|
||||
const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box();
|
||||
|
|
@ -832,10 +835,10 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
|||
if (contained)
|
||||
contained_min_one = true;
|
||||
|
||||
if ((state == ModelInstancePVS_Inside) && volume->is_outside)
|
||||
if (state == ModelInstancePVS_Inside && volume->is_outside)
|
||||
state = ModelInstancePVS_Fully_Outside;
|
||||
|
||||
if ((state == ModelInstancePVS_Fully_Outside) && volume->is_outside && print_volume.intersects(bb))
|
||||
if (state == ModelInstancePVS_Fully_Outside && volume->is_outside && print_volume.intersects(bb))
|
||||
state = ModelInstancePVS_Partly_Outside;
|
||||
}
|
||||
|
||||
|
|
@ -845,7 +848,7 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
|||
return contained_min_one;
|
||||
}
|
||||
|
||||
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut)
|
||||
bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut) const
|
||||
{
|
||||
if (config == nullptr)
|
||||
return false;
|
||||
|
|
@ -867,9 +870,8 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, b
|
|||
|
||||
partlyOut = false;
|
||||
fullyOut = false;
|
||||
for (GLVolume* volume : this->volumes)
|
||||
{
|
||||
if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled))
|
||||
for (GLVolume* volume : this->volumes) {
|
||||
if (volume == nullptr || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || (volume->composite_id.volume_id < 0 && !volume->shader_outside_printer_detection_enabled))
|
||||
continue;
|
||||
|
||||
const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box();
|
||||
|
|
|
|||
|
|
@ -267,15 +267,15 @@ private:
|
|||
// Shift in z required by sla supports+pad
|
||||
double m_sla_shift_z;
|
||||
// Bounding box of this volume, in unscaled coordinates.
|
||||
mutable BoundingBoxf3 m_transformed_bounding_box;
|
||||
BoundingBoxf3 m_transformed_bounding_box;
|
||||
// Whether or not is needed to recalculate the transformed bounding box.
|
||||
mutable bool m_transformed_bounding_box_dirty;
|
||||
bool m_transformed_bounding_box_dirty;
|
||||
// Convex hull of the volume, if any.
|
||||
std::shared_ptr<const TriangleMesh> m_convex_hull;
|
||||
// Bounding box of this volume, in unscaled coordinates.
|
||||
mutable BoundingBoxf3 m_transformed_convex_hull_bounding_box;
|
||||
BoundingBoxf3 m_transformed_convex_hull_bounding_box;
|
||||
// Whether or not is needed to recalculate the transformed convex hull bounding box.
|
||||
mutable bool m_transformed_convex_hull_bounding_box_dirty;
|
||||
bool m_transformed_convex_hull_bounding_box_dirty;
|
||||
|
||||
public:
|
||||
// Color of the triangles / quads held by this volume.
|
||||
|
|
@ -568,8 +568,8 @@ public:
|
|||
|
||||
// returns true if all the volumes are completely contained in the print volume
|
||||
// returns the containment state in the given out_state, if non-null
|
||||
bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state);
|
||||
bool check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut);
|
||||
bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state) const;
|
||||
bool check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut) const;
|
||||
void reset_outside_state();
|
||||
|
||||
void update_colors_by_extruder(const DynamicPrintConfig* config);
|
||||
|
|
|
|||
|
|
@ -21,12 +21,6 @@ double Camera::FrustrumMinNearZ = 100.0;
|
|||
double Camera::FrustrumZMargin = 10.0;
|
||||
double Camera::MaxFovDeg = 60.0;
|
||||
|
||||
Camera::Camera()
|
||||
: requires_zoom_to_bed(false)
|
||||
{
|
||||
set_default_orientation();
|
||||
}
|
||||
|
||||
std::string Camera::get_type_as_string() const
|
||||
{
|
||||
switch (m_type)
|
||||
|
|
@ -49,11 +43,6 @@ void Camera::set_type(EType type)
|
|||
}
|
||||
}
|
||||
|
||||
void Camera::set_type(const std::string& type)
|
||||
{
|
||||
set_type((type == "1") ? Perspective : Ortho);
|
||||
}
|
||||
|
||||
void Camera::select_next_type()
|
||||
{
|
||||
unsigned char next = (unsigned char)m_type + 1;
|
||||
|
|
@ -65,24 +54,18 @@ void Camera::select_next_type()
|
|||
|
||||
void Camera::set_target(const Vec3d& target)
|
||||
{
|
||||
Vec3d new_target = validate_target(target);
|
||||
Vec3d new_displacement = new_target - m_target;
|
||||
if (!new_displacement.isApprox(Vec3d::Zero()))
|
||||
{
|
||||
const Vec3d new_target = validate_target(target);
|
||||
const Vec3d new_displacement = new_target - m_target;
|
||||
if (!new_displacement.isApprox(Vec3d::Zero())) {
|
||||
m_target = new_target;
|
||||
m_view_matrix.translate(-new_displacement);
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::update_zoom(double delta_zoom)
|
||||
{
|
||||
set_zoom(m_zoom / (1.0 - std::max(std::min(delta_zoom, 4.0), -4.0) * 0.1));
|
||||
}
|
||||
|
||||
void Camera::set_zoom(double zoom)
|
||||
{
|
||||
// Don't allow to zoom too far outside the scene.
|
||||
double zoom_min = min_zoom();
|
||||
const double zoom_min = min_zoom();
|
||||
if (zoom_min > 0.0)
|
||||
zoom = std::max(zoom, zoom_min);
|
||||
|
||||
|
|
@ -123,7 +106,7 @@ double Camera::get_fov() const
|
|||
void Camera::apply_viewport(int x, int y, unsigned int w, unsigned int h) const
|
||||
{
|
||||
glsafe(::glViewport(0, 0, w, h));
|
||||
glsafe(::glGetIntegerv(GL_VIEWPORT, m_viewport.data()));
|
||||
glsafe(::glGetIntegerv(GL_VIEWPORT, const_cast<std::array<int, 4>*>(&m_viewport)->data()));
|
||||
}
|
||||
|
||||
void Camera::apply_view_matrix() const
|
||||
|
|
@ -138,22 +121,23 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
|
|||
double w = 0.0;
|
||||
double h = 0.0;
|
||||
|
||||
double old_distance = m_distance;
|
||||
m_frustrum_zs = calc_tight_frustrum_zs_around(box);
|
||||
const double old_distance = m_distance;
|
||||
std::pair<double, double>* frustrum_zs = const_cast<std::pair<double, double>*>(&m_frustrum_zs);
|
||||
*frustrum_zs = calc_tight_frustrum_zs_around(box);
|
||||
if (m_distance != old_distance)
|
||||
// the camera has been moved re-apply view matrix
|
||||
apply_view_matrix();
|
||||
|
||||
if (near_z > 0.0)
|
||||
m_frustrum_zs.first = std::max(std::min(m_frustrum_zs.first, near_z), FrustrumMinNearZ);
|
||||
frustrum_zs->first = std::max(std::min(frustrum_zs->first, near_z), FrustrumMinNearZ);
|
||||
|
||||
if (far_z > 0.0)
|
||||
m_frustrum_zs.second = std::max(m_frustrum_zs.second, far_z);
|
||||
frustrum_zs->second = std::max(frustrum_zs->second, far_z);
|
||||
|
||||
w = 0.5 * (double)m_viewport[2];
|
||||
h = 0.5 * (double)m_viewport[3];
|
||||
|
||||
double inv_zoom = get_inv_zoom();
|
||||
const double inv_zoom = get_inv_zoom();
|
||||
w *= inv_zoom;
|
||||
h *= inv_zoom;
|
||||
|
||||
|
|
@ -162,16 +146,16 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
|
|||
default:
|
||||
case Ortho:
|
||||
{
|
||||
m_gui_scale = 1.0;
|
||||
*const_cast<double*>(&m_gui_scale) = 1.0;
|
||||
break;
|
||||
}
|
||||
case Perspective:
|
||||
{
|
||||
// scale near plane to keep w and h constant on the plane at z = m_distance
|
||||
double scale = m_frustrum_zs.first / m_distance;
|
||||
const double scale = frustrum_zs->first / m_distance;
|
||||
w *= scale;
|
||||
h *= scale;
|
||||
m_gui_scale = scale;
|
||||
*const_cast<double*>(&m_gui_scale) = scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -184,26 +168,25 @@ void Camera::apply_projection(const BoundingBoxf3& box, double near_z, double fa
|
|||
default:
|
||||
case Ortho:
|
||||
{
|
||||
glsafe(::glOrtho(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second));
|
||||
glsafe(::glOrtho(-w, w, -h, h, frustrum_zs->first, frustrum_zs->second));
|
||||
break;
|
||||
}
|
||||
case Perspective:
|
||||
{
|
||||
glsafe(::glFrustum(-w, w, -h, h, m_frustrum_zs.first, m_frustrum_zs.second));
|
||||
glsafe(::glFrustum(-w, w, -h, h, frustrum_zs->first, frustrum_zs->second));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
glsafe(::glGetDoublev(GL_PROJECTION_MATRIX, m_projection_matrix.data()));
|
||||
glsafe(::glGetDoublev(GL_PROJECTION_MATRIX, const_cast<Transform3d*>(&m_projection_matrix)->data()));
|
||||
glsafe(::glMatrixMode(GL_MODELVIEW));
|
||||
}
|
||||
|
||||
void Camera::zoom_to_box(const BoundingBoxf3& box, double margin_factor)
|
||||
{
|
||||
// Calculate the zoom factor needed to adjust the view around the given box.
|
||||
double zoom = calc_zoom_to_bounding_box_factor(box, margin_factor);
|
||||
if (zoom > 0.0)
|
||||
{
|
||||
const double zoom = calc_zoom_to_bounding_box_factor(box, margin_factor);
|
||||
if (zoom > 0.0) {
|
||||
m_zoom = zoom;
|
||||
// center view around box center
|
||||
set_target(box.center());
|
||||
|
|
@ -213,9 +196,8 @@ void Camera::zoom_to_box(const BoundingBoxf3& box, double margin_factor)
|
|||
void Camera::zoom_to_volumes(const GLVolumePtrs& volumes, double margin_factor)
|
||||
{
|
||||
Vec3d center;
|
||||
double zoom = calc_zoom_to_volumes_factor(volumes, center, margin_factor);
|
||||
if (zoom > 0.0)
|
||||
{
|
||||
const double zoom = calc_zoom_to_volumes_factor(volumes, center, margin_factor);
|
||||
if (zoom > 0.0) {
|
||||
m_zoom = zoom;
|
||||
// center view around the calculated center
|
||||
set_target(center);
|
||||
|
|
@ -289,8 +271,8 @@ void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, b
|
|||
}
|
||||
}
|
||||
|
||||
Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
|
||||
auto rot_z = Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ());
|
||||
const Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
|
||||
const auto rot_z = Eigen::AngleAxisd(delta_azimut_rad, Vec3d::UnitZ());
|
||||
m_view_rotation *= rot_z * Eigen::AngleAxisd(delta_zenit_rad, rot_z.inverse() * get_dir_right());
|
||||
m_view_rotation.normalize();
|
||||
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- m_target) + translation, m_view_rotation, Vec3d(1., 1., 1.));
|
||||
|
|
@ -299,10 +281,10 @@ void Camera::rotate_on_sphere(double delta_azimut_rad, double delta_zenit_rad, b
|
|||
// Virtual trackball, rotate around an axis, where the eucledian norm of the axis gives the rotation angle in radians.
|
||||
void Camera::rotate_local_around_target(const Vec3d& rotation_rad)
|
||||
{
|
||||
double angle = rotation_rad.norm();
|
||||
const double angle = rotation_rad.norm();
|
||||
if (std::abs(angle) > EPSILON) {
|
||||
Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
|
||||
Vec3d axis = m_view_rotation.conjugate() * rotation_rad.normalized();
|
||||
const Vec3d translation = m_view_matrix.translation() + m_view_rotation * m_target;
|
||||
const Vec3d axis = m_view_rotation.conjugate() * rotation_rad.normalized();
|
||||
m_view_rotation *= Eigen::Quaterniond(Eigen::AngleAxisd(angle, axis));
|
||||
m_view_rotation.normalize();
|
||||
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (-m_target) + translation, m_view_rotation, Vec3d(1., 1., 1.));
|
||||
|
|
@ -310,18 +292,13 @@ void Camera::rotate_local_around_target(const Vec3d& rotation_rad)
|
|||
}
|
||||
}
|
||||
|
||||
double Camera::min_zoom() const
|
||||
{
|
||||
return 0.7 * calc_zoom_to_bounding_box_factor(m_scene_box);
|
||||
}
|
||||
|
||||
std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const
|
||||
{
|
||||
std::pair<double, double> ret;
|
||||
auto& [near_z, far_z] = ret;
|
||||
|
||||
// box in eye space
|
||||
BoundingBoxf3 eye_box = box.transformed(m_view_matrix);
|
||||
const BoundingBoxf3 eye_box = box.transformed(m_view_matrix);
|
||||
near_z = -eye_box.max(2);
|
||||
far_z = -eye_box.min(2);
|
||||
|
||||
|
|
@ -330,73 +307,71 @@ std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBo
|
|||
far_z += FrustrumZMargin;
|
||||
|
||||
// ensure min size
|
||||
if (far_z - near_z < FrustrumMinZRange)
|
||||
{
|
||||
double mid_z = 0.5 * (near_z + far_z);
|
||||
double half_size = 0.5 * FrustrumMinZRange;
|
||||
if (far_z - near_z < FrustrumMinZRange) {
|
||||
const double mid_z = 0.5 * (near_z + far_z);
|
||||
const double half_size = 0.5 * FrustrumMinZRange;
|
||||
near_z = mid_z - half_size;
|
||||
far_z = mid_z + half_size;
|
||||
}
|
||||
|
||||
if (near_z < FrustrumMinNearZ)
|
||||
{
|
||||
float delta = FrustrumMinNearZ - near_z;
|
||||
if (near_z < FrustrumMinNearZ) {
|
||||
const double delta = FrustrumMinNearZ - near_z;
|
||||
set_distance(m_distance + delta);
|
||||
near_z += delta;
|
||||
far_z += delta;
|
||||
}
|
||||
else if ((near_z > 2.0 * FrustrumMinNearZ) && (m_distance > DefaultDistance))
|
||||
{
|
||||
float delta = m_distance - DefaultDistance;
|
||||
set_distance(DefaultDistance);
|
||||
near_z -= delta;
|
||||
far_z -= delta;
|
||||
}
|
||||
// The following is commented out because it causes flickering of the 3D scene GUI
|
||||
// when the bounding box of the scene gets large enough
|
||||
// We need to introduce some smarter code to move the camera back and forth in such case
|
||||
// else if (near_z > 2.0 * FrustrumMinNearZ && m_distance > DefaultDistance) {
|
||||
// float delta = m_distance - DefaultDistance;
|
||||
// set_distance(DefaultDistance);
|
||||
// near_z -= delta;
|
||||
// far_z -= delta;
|
||||
// }
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, double margin_factor) const
|
||||
{
|
||||
double max_bb_size = box.max_size();
|
||||
const double max_bb_size = box.max_size();
|
||||
if (max_bb_size == 0.0)
|
||||
return -1.0;
|
||||
|
||||
// project the box vertices on a plane perpendicular to the camera forward axis
|
||||
// then calculates the vertices coordinate on this plane along the camera xy axes
|
||||
|
||||
Vec3d right = get_dir_right();
|
||||
Vec3d up = get_dir_up();
|
||||
Vec3d forward = get_dir_forward();
|
||||
|
||||
Vec3d bb_center = box.center();
|
||||
const Vec3d right = get_dir_right();
|
||||
const Vec3d up = get_dir_up();
|
||||
const Vec3d forward = get_dir_forward();
|
||||
const Vec3d bb_center = box.center();
|
||||
|
||||
// box vertices in world space
|
||||
std::vector<Vec3d> vertices;
|
||||
vertices.reserve(8);
|
||||
vertices.push_back(box.min);
|
||||
vertices.emplace_back(box.max(0), box.min(1), box.min(2));
|
||||
vertices.emplace_back(box.max(0), box.max(1), box.min(2));
|
||||
vertices.emplace_back(box.min(0), box.max(1), box.min(2));
|
||||
vertices.emplace_back(box.min(0), box.min(1), box.max(2));
|
||||
vertices.emplace_back(box.max(0), box.min(1), box.max(2));
|
||||
vertices.push_back(box.max);
|
||||
vertices.emplace_back(box.min(0), box.max(1), box.max(2));
|
||||
const std::vector<Vec3d> vertices = {
|
||||
box.min,
|
||||
{ box.max(0), box.min(1), box.min(2) },
|
||||
{ box.max(0), box.max(1), box.min(2) },
|
||||
{ box.min(0), box.max(1), box.min(2) },
|
||||
{ box.min(0), box.min(1), box.max(2) },
|
||||
{ box.max(0), box.min(1), box.max(2) },
|
||||
box.max,
|
||||
{ box.min(0), box.max(1), box.max(2) }
|
||||
};
|
||||
|
||||
double min_x = DBL_MAX;
|
||||
double min_y = DBL_MAX;
|
||||
double max_x = -DBL_MAX;
|
||||
double max_y = -DBL_MAX;
|
||||
|
||||
for (const Vec3d& v : vertices)
|
||||
{
|
||||
for (const Vec3d& v : vertices) {
|
||||
// project vertex on the plane perpendicular to camera forward axis
|
||||
Vec3d pos = v - bb_center;
|
||||
Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
|
||||
const Vec3d pos = v - bb_center;
|
||||
const Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
|
||||
|
||||
// calculates vertex coordinate along camera xy axes
|
||||
double x_on_plane = proj_on_plane.dot(right);
|
||||
double y_on_plane = proj_on_plane.dot(up);
|
||||
const double x_on_plane = proj_on_plane.dot(right);
|
||||
const double y_on_plane = proj_on_plane.dot(up);
|
||||
|
||||
min_x = std::min(min_x, x_on_plane);
|
||||
min_y = std::min(min_y, y_on_plane);
|
||||
|
|
@ -406,7 +381,7 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, double
|
|||
|
||||
double dx = max_x - min_x;
|
||||
double dy = max_y - min_y;
|
||||
if ((dx <= 0.0) || (dy <= 0.0))
|
||||
if (dx <= 0.0 || dy <= 0.0)
|
||||
return -1.0f;
|
||||
|
||||
dx *= margin_factor;
|
||||
|
|
@ -423,13 +398,12 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& c
|
|||
// project the volumes vertices on a plane perpendicular to the camera forward axis
|
||||
// then calculates the vertices coordinate on this plane along the camera xy axes
|
||||
|
||||
Vec3d right = get_dir_right();
|
||||
Vec3d up = get_dir_up();
|
||||
Vec3d forward = get_dir_forward();
|
||||
const Vec3d right = get_dir_right();
|
||||
const Vec3d up = get_dir_up();
|
||||
const Vec3d forward = get_dir_forward();
|
||||
|
||||
BoundingBoxf3 box;
|
||||
for (const GLVolume* volume : volumes)
|
||||
{
|
||||
for (const GLVolume* volume : volumes) {
|
||||
box.merge(volume->transformed_bounding_box());
|
||||
}
|
||||
center = box.center();
|
||||
|
|
@ -439,24 +413,22 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& c
|
|||
double max_x = -DBL_MAX;
|
||||
double max_y = -DBL_MAX;
|
||||
|
||||
for (const GLVolume* volume : volumes)
|
||||
{
|
||||
for (const GLVolume* volume : volumes) {
|
||||
const Transform3d& transform = volume->world_matrix();
|
||||
const TriangleMesh* hull = volume->convex_hull();
|
||||
if (hull == nullptr)
|
||||
continue;
|
||||
|
||||
for (const Vec3f& vertex : hull->its.vertices)
|
||||
{
|
||||
Vec3d v = transform * vertex.cast<double>();
|
||||
for (const Vec3f& vertex : hull->its.vertices) {
|
||||
const Vec3d v = transform * vertex.cast<double>();
|
||||
|
||||
// project vertex on the plane perpendicular to camera forward axis
|
||||
Vec3d pos = v - center;
|
||||
Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
|
||||
const Vec3d pos = v - center;
|
||||
const Vec3d proj_on_plane = pos - pos.dot(forward) * forward;
|
||||
|
||||
// calculates vertex coordinate along camera xy axes
|
||||
double x_on_plane = proj_on_plane.dot(right);
|
||||
double y_on_plane = proj_on_plane.dot(up);
|
||||
const double x_on_plane = proj_on_plane.dot(right);
|
||||
const double y_on_plane = proj_on_plane.dot(up);
|
||||
|
||||
min_x = std::min(min_x, x_on_plane);
|
||||
min_y = std::min(min_y, y_on_plane);
|
||||
|
|
@ -467,10 +439,10 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& c
|
|||
|
||||
center += 0.5 * (max_x + min_x) * right + 0.5 * (max_y + min_y) * up;
|
||||
|
||||
double dx = margin_factor * (max_x - min_x);
|
||||
double dy = margin_factor * (max_y - min_y);
|
||||
const double dx = margin_factor * (max_x - min_x);
|
||||
const double dy = margin_factor * (max_y - min_y);
|
||||
|
||||
if ((dx <= 0.0) || (dy <= 0.0))
|
||||
if (dx <= 0.0 || dy <= 0.0)
|
||||
return -1.0f;
|
||||
|
||||
return std::min((double)m_viewport[2] / dx, (double)m_viewport[3] / dy);
|
||||
|
|
@ -478,22 +450,21 @@ double Camera::calc_zoom_to_volumes_factor(const GLVolumePtrs& volumes, Vec3d& c
|
|||
|
||||
void Camera::set_distance(double distance) const
|
||||
{
|
||||
if (m_distance != distance)
|
||||
{
|
||||
m_view_matrix.translate((distance - m_distance) * get_dir_forward());
|
||||
m_distance = distance;
|
||||
if (m_distance != distance) {
|
||||
const_cast<Transform3d*>(&m_view_matrix)->translate((distance - m_distance) * get_dir_forward());
|
||||
*const_cast<double*>(&m_distance) = distance;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up)
|
||||
{
|
||||
Vec3d unit_z = (position - target).normalized();
|
||||
Vec3d unit_x = up.cross(unit_z).normalized();
|
||||
Vec3d unit_y = unit_z.cross(unit_x).normalized();
|
||||
const Vec3d unit_z = (position - target).normalized();
|
||||
const Vec3d unit_x = up.cross(unit_z).normalized();
|
||||
const Vec3d unit_y = unit_z.cross(unit_x).normalized();
|
||||
|
||||
m_target = target;
|
||||
m_distance = (position - target).norm();
|
||||
Vec3d new_position = m_target + m_distance * unit_z;
|
||||
const Vec3d new_position = m_target + m_distance * unit_z;
|
||||
|
||||
m_view_matrix(0, 0) = unit_x(0);
|
||||
m_view_matrix(0, 1) = unit_x(1);
|
||||
|
|
@ -525,10 +496,10 @@ void Camera::look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up
|
|||
void Camera::set_default_orientation()
|
||||
{
|
||||
m_zenit = 45.0f;
|
||||
double theta_rad = Geometry::deg2rad(-(double)m_zenit);
|
||||
double phi_rad = Geometry::deg2rad(45.0);
|
||||
double sin_theta = ::sin(theta_rad);
|
||||
Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
|
||||
const double theta_rad = Geometry::deg2rad(-(double)m_zenit);
|
||||
const double phi_rad = Geometry::deg2rad(45.0);
|
||||
const double sin_theta = ::sin(theta_rad);
|
||||
const Vec3d camera_pos = m_target + m_distance * Vec3d(sin_theta * ::sin(phi_rad), sin_theta * ::cos(phi_rad), ::cos(theta_rad));
|
||||
m_view_rotation = Eigen::AngleAxisd(theta_rad, Vec3d::UnitX()) * Eigen::AngleAxisd(phi_rad, Vec3d::UnitZ());
|
||||
m_view_rotation.normalize();
|
||||
m_view_matrix.fromPositionOrientationScale(m_view_rotation * (- camera_pos), m_view_rotation, Vec3d(1., 1., 1.));
|
||||
|
|
@ -543,9 +514,9 @@ Vec3d Camera::validate_target(const Vec3d& target) const
|
|||
test_box.scale(ScaleFactor);
|
||||
test_box.translate(m_scene_box.center());
|
||||
|
||||
return Vec3d(std::clamp(target(0), test_box.min(0), test_box.max(0)),
|
||||
std::clamp(target(1), test_box.min(1), test_box.max(1)),
|
||||
std::clamp(target(2), test_box.min(2), test_box.max(2)));
|
||||
return { std::clamp(target(0), test_box.min(0), test_box.max(0)),
|
||||
std::clamp(target(1), test_box.min(1), test_box.max(1)),
|
||||
std::clamp(target(2), test_box.min(2), test_box.max(2)) };
|
||||
}
|
||||
|
||||
void Camera::update_zenit()
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ struct Camera
|
|||
Num_types
|
||||
};
|
||||
|
||||
bool requires_zoom_to_bed;
|
||||
bool requires_zoom_to_bed{ false };
|
||||
|
||||
private:
|
||||
EType m_type{ Perspective };
|
||||
|
|
@ -35,26 +35,26 @@ private:
|
|||
float m_zenit{ 45.0f };
|
||||
double m_zoom{ 1.0 };
|
||||
// Distance between camera position and camera target measured along the camera Z axis
|
||||
mutable double m_distance{ DefaultDistance };
|
||||
mutable double m_gui_scale{ 1.0 };
|
||||
double m_distance{ DefaultDistance };
|
||||
double m_gui_scale{ 1.0 };
|
||||
|
||||
mutable std::array<int, 4> m_viewport;
|
||||
mutable Transform3d m_view_matrix{ Transform3d::Identity() };
|
||||
std::array<int, 4> m_viewport;
|
||||
Transform3d m_view_matrix{ Transform3d::Identity() };
|
||||
// We are calculating the rotation part of the m_view_matrix from m_view_rotation.
|
||||
mutable Eigen::Quaterniond m_view_rotation{ 1.0, 0.0, 0.0, 0.0 };
|
||||
mutable Transform3d m_projection_matrix{ Transform3d::Identity() };
|
||||
mutable std::pair<double, double> m_frustrum_zs;
|
||||
Eigen::Quaterniond m_view_rotation{ 1.0, 0.0, 0.0, 0.0 };
|
||||
Transform3d m_projection_matrix{ Transform3d::Identity() };
|
||||
std::pair<double, double> m_frustrum_zs;
|
||||
|
||||
BoundingBoxf3 m_scene_box;
|
||||
|
||||
public:
|
||||
Camera();
|
||||
Camera() { set_default_orientation(); }
|
||||
|
||||
EType get_type() const { return m_type; }
|
||||
std::string get_type_as_string() const;
|
||||
void set_type(EType type);
|
||||
// valid values for type: "0" -> ortho, "1" -> perspective
|
||||
void set_type(const std::string& type);
|
||||
void set_type(const std::string& type) { set_type((type == "1") ? Perspective : Ortho); }
|
||||
void select_next_type();
|
||||
|
||||
void enable_update_config_on_type_change(bool enable) { m_update_config_on_type_change_enabled = enable; }
|
||||
|
|
@ -67,7 +67,7 @@ public:
|
|||
|
||||
double get_zoom() const { return m_zoom; }
|
||||
double get_inv_zoom() const { assert(m_zoom != 0.0); return 1.0 / m_zoom; }
|
||||
void update_zoom(double delta_zoom);
|
||||
void update_zoom(double delta_zoom) { set_zoom(m_zoom / (1.0 - std::max(std::min(delta_zoom, 4.0), -4.0) * 0.1)); }
|
||||
void set_zoom(double zoom);
|
||||
|
||||
const BoundingBoxf3& get_scene_box() const { return m_scene_box; }
|
||||
|
|
@ -119,8 +119,7 @@ public:
|
|||
bool is_looking_downward() const { return get_dir_forward().dot(Vec3d::UnitZ()) < 0.0; }
|
||||
|
||||
// forces camera right vector to be parallel to XY plane
|
||||
void recover_from_free_camera()
|
||||
{
|
||||
void recover_from_free_camera() {
|
||||
if (std::abs(get_dir_right()(2)) > EPSILON)
|
||||
look_at(get_position(), m_target, Vec3d::UnitZ());
|
||||
}
|
||||
|
|
@ -128,7 +127,7 @@ public:
|
|||
void look_at(const Vec3d& position, const Vec3d& target, const Vec3d& up);
|
||||
|
||||
double max_zoom() const { return 250.0; }
|
||||
double min_zoom() const;
|
||||
double min_zoom() const { return 0.7 * calc_zoom_to_bounding_box_factor(m_scene_box); }
|
||||
|
||||
private:
|
||||
// returns tight values for nearZ and farZ plane around the given bounding box
|
||||
|
|
|
|||
|
|
@ -278,6 +278,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
|||
bool have_support_material_auto = have_support_material && config->opt_bool("support_material_auto");
|
||||
bool have_support_interface = config->opt_int("support_material_interface_layers") > 0;
|
||||
bool have_support_soluble = have_support_material && config->opt_float("support_material_contact_distance") == 0;
|
||||
auto support_material_style = config->opt_enum<SupportMaterialStyle>("support_material_style");
|
||||
for (auto el : { "support_material_style", "support_material_pattern", "support_material_with_sheath",
|
||||
"support_material_spacing", "support_material_angle",
|
||||
"support_material_interface_pattern", "support_material_interface_layers",
|
||||
|
|
@ -286,6 +287,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config)
|
|||
toggle_field(el, have_support_material);
|
||||
toggle_field("support_material_threshold", have_support_material_auto);
|
||||
toggle_field("support_material_bottom_contact_distance", have_support_material && ! have_support_soluble);
|
||||
toggle_field("support_material_closing_radius", have_support_material && support_material_style == smsSnug);
|
||||
|
||||
for (auto el : { "support_material_bottom_interface_layers", "support_material_interface_spacing", "support_material_interface_extruder",
|
||||
"support_material_interface_speed", "support_material_interface_contact_loops" })
|
||||
|
|
|
|||
|
|
@ -2165,7 +2165,7 @@ static std::string get_custom_code(const std::string& code_in, double height)
|
|||
if (dlg.ShowModal() != wxID_OK)
|
||||
return "";
|
||||
|
||||
value = dlg.GetValue().ToStdString();
|
||||
value = into_u8(dlg.GetValue());
|
||||
valid = GUI::Tab::validate_custom_gcode("Custom G-code", value);
|
||||
} while (!valid);
|
||||
return value;
|
||||
|
|
@ -2173,7 +2173,7 @@ static std::string get_custom_code(const std::string& code_in, double height)
|
|||
if (dlg.ShowModal() != wxID_OK)
|
||||
return "";
|
||||
|
||||
return dlg.GetValue().ToStdString();
|
||||
return into_u8(dlg.GetValue());
|
||||
#endif // ENABLE_VALIDATE_CUSTOM_GCODE
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -508,6 +508,7 @@ void GLCanvas3D::LayersEditing::reset_layer_height_profile(GLCanvas3D& canvas)
|
|||
m_layer_height_profile.clear();
|
||||
m_layers_texture.valid = false;
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
wxGetApp().obj_list()->update_info_items(last_object_id);
|
||||
}
|
||||
|
||||
void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas, float quality_factor)
|
||||
|
|
@ -517,6 +518,7 @@ void GLCanvas3D::LayersEditing::adaptive_layer_height_profile(GLCanvas3D& canvas
|
|||
const_cast<ModelObject*>(m_model_object)->layer_height_profile.set(m_layer_height_profile);
|
||||
m_layers_texture.valid = false;
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
wxGetApp().obj_list()->update_info_items(last_object_id);
|
||||
}
|
||||
|
||||
void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas, const HeightProfileSmoothingParams& smoothing_params)
|
||||
|
|
@ -526,6 +528,7 @@ void GLCanvas3D::LayersEditing::smooth_layer_height_profile(GLCanvas3D& canvas,
|
|||
const_cast<ModelObject*>(m_model_object)->layer_height_profile.set(m_layer_height_profile);
|
||||
m_layers_texture.valid = false;
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
wxGetApp().obj_list()->update_info_items(last_object_id);
|
||||
}
|
||||
|
||||
void GLCanvas3D::LayersEditing::generate_layer_height_texture()
|
||||
|
|
@ -565,6 +568,7 @@ void GLCanvas3D::LayersEditing::accept_changes(GLCanvas3D& canvas)
|
|||
wxGetApp().plater()->take_snapshot(_(L("Variable layer height - Manual edit")));
|
||||
const_cast<ModelObject*>(m_model_object)->layer_height_profile.set(m_layer_height_profile);
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
wxGetApp().obj_list()->update_info_items(last_object_id);
|
||||
}
|
||||
}
|
||||
m_layer_height_profile_modified = false;
|
||||
|
|
@ -3524,7 +3528,7 @@ Vec2d GLCanvas3D::get_local_mouse_position() const
|
|||
void GLCanvas3D::set_tooltip(const std::string& tooltip) const
|
||||
{
|
||||
if (m_canvas != nullptr)
|
||||
m_tooltip.set_text(tooltip);
|
||||
const_cast<Tooltip*>(&m_tooltip)->set_text(tooltip);
|
||||
}
|
||||
|
||||
void GLCanvas3D::do_move(const std::string& snapshot_type)
|
||||
|
|
@ -3541,22 +3545,19 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
|
|||
|
||||
Selection::EMode selection_mode = m_selection.get_mode();
|
||||
|
||||
for (const GLVolume* v : m_volumes.volumes)
|
||||
{
|
||||
for (const GLVolume* v : m_volumes.volumes) {
|
||||
int object_idx = v->object_idx();
|
||||
int instance_idx = v->instance_idx();
|
||||
int volume_idx = v->volume_idx();
|
||||
|
||||
std::pair<int, int> done_id(object_idx, instance_idx);
|
||||
|
||||
if ((0 <= object_idx) && (object_idx < (int)m_model->objects.size()))
|
||||
{
|
||||
if (0 <= object_idx && object_idx < (int)m_model->objects.size()) {
|
||||
done.insert(done_id);
|
||||
|
||||
// Move instances/volumes
|
||||
ModelObject* model_object = m_model->objects[object_idx];
|
||||
if (model_object != nullptr)
|
||||
{
|
||||
if (model_object != nullptr) {
|
||||
if (selection_mode == Selection::Instance)
|
||||
model_object->instances[instance_idx]->set_offset(v->get_instance_offset());
|
||||
else if (selection_mode == Selection::Volume)
|
||||
|
|
@ -3572,8 +3573,7 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
|
|||
}
|
||||
|
||||
// Fixes sinking/flying instances
|
||||
for (const std::pair<int, int>& i : done)
|
||||
{
|
||||
for (const std::pair<int, int>& i : done) {
|
||||
ModelObject* m = m_model->objects[i.first];
|
||||
Vec3d shift(0.0, 0.0, -m->get_instance_min_z(i.second));
|
||||
m_selection.translate(i.first, i.second, shift);
|
||||
|
|
@ -3932,13 +3932,13 @@ bool GLCanvas3D::_render_undo_redo_stack(const bool is_undo, float pos_x) const
|
|||
em *= m_retina_helper->get_scale_factor();
|
||||
#endif
|
||||
|
||||
if (imgui->undo_redo_list(ImVec2(18 * em, 26 * em), is_undo, &string_getter, hovered, selected, m_mouse_wheel))
|
||||
m_imgui_undo_redo_hovered_pos = hovered;
|
||||
int* mouse_wheel = const_cast<int*>(&m_mouse_wheel);
|
||||
if (imgui->undo_redo_list(ImVec2(18 * em, 26 * em), is_undo, &string_getter, hovered, selected, *mouse_wheel))
|
||||
*const_cast<int*>(&m_imgui_undo_redo_hovered_pos) = hovered;
|
||||
else
|
||||
m_imgui_undo_redo_hovered_pos = -1;
|
||||
*const_cast<int*>(&m_imgui_undo_redo_hovered_pos) = -1;
|
||||
|
||||
if (selected >= 0)
|
||||
{
|
||||
if (selected >= 0) {
|
||||
is_undo ? wxGetApp().plater()->undo_to(selected) : wxGetApp().plater()->redo_to(selected);
|
||||
action_taken = true;
|
||||
}
|
||||
|
|
@ -3979,9 +3979,10 @@ bool GLCanvas3D::_render_search_list(float pos_x) const
|
|||
char *s = new char[255];
|
||||
strcpy(s, search_line.empty() ? _u8L("Enter a search term").c_str() : search_line.c_str());
|
||||
|
||||
imgui->search_list(ImVec2(45 * em, 30 * em), &search_string_getter, s,
|
||||
sidebar.get_searcher().view_params,
|
||||
selected, edited, m_mouse_wheel, wxGetApp().is_localized());
|
||||
int* mouse_wheel = const_cast<int*>(&m_mouse_wheel);
|
||||
imgui->search_list(ImVec2(45 * em, 30 * em), &search_string_getter, s,
|
||||
sidebar.get_searcher().view_params,
|
||||
selected, edited, *mouse_wheel, wxGetApp().is_localized());
|
||||
|
||||
search_line = s;
|
||||
delete [] s;
|
||||
|
|
@ -4840,8 +4841,10 @@ void GLCanvas3D::_refresh_if_shown_on_screen()
|
|||
|
||||
void GLCanvas3D::_picking_pass() const
|
||||
{
|
||||
std::vector<int>* hover_volume_idxs = const_cast<std::vector<int>*>(&m_hover_volume_idxs);
|
||||
|
||||
if (m_picking_enabled && !m_mouse.dragging && m_mouse.position != Vec2d(DBL_MAX, DBL_MAX)) {
|
||||
m_hover_volume_idxs.clear();
|
||||
hover_volume_idxs->clear();
|
||||
|
||||
// Render the object for picking.
|
||||
// FIXME This cannot possibly work in a multi - sampled context as the color gets mangled by the anti - aliasing.
|
||||
|
|
@ -4856,9 +4859,10 @@ void GLCanvas3D::_picking_pass() const
|
|||
|
||||
glsafe(::glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
m_camera_clipping_plane = m_gizmos.get_clipping_plane();
|
||||
if (m_camera_clipping_plane.is_active()) {
|
||||
::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)m_camera_clipping_plane.get_data());
|
||||
ClippingPlane* camera_clipping_plane = const_cast<ClippingPlane*>(&m_camera_clipping_plane);
|
||||
*camera_clipping_plane = m_gizmos.get_clipping_plane();
|
||||
if (camera_clipping_plane->is_active()) {
|
||||
::glClipPlane(GL_CLIP_PLANE0, (GLdouble*)camera_clipping_plane->get_data());
|
||||
::glEnable(GL_CLIP_PLANE0);
|
||||
}
|
||||
_render_volumes_for_picking();
|
||||
|
|
@ -4884,11 +4888,11 @@ void GLCanvas3D::_picking_pass() const
|
|||
if (0 <= volume_id && volume_id < (int)m_volumes.volumes.size()) {
|
||||
// do not add the volume id if any gizmo is active and CTRL is pressed
|
||||
if (m_gizmos.get_current_type() == GLGizmosManager::EType::Undefined || !wxGetKeyState(WXK_CONTROL))
|
||||
m_hover_volume_idxs.emplace_back(volume_id);
|
||||
m_gizmos.set_hover_id(-1);
|
||||
hover_volume_idxs->emplace_back(volume_id);
|
||||
const_cast<GLGizmosManager*>(&m_gizmos)->set_hover_id(-1);
|
||||
}
|
||||
else
|
||||
m_gizmos.set_hover_id(inside && (unsigned int)volume_id <= GLGizmoBase::BASE_ID ? ((int)GLGizmoBase::BASE_ID - volume_id) : -1);
|
||||
const_cast<GLGizmosManager*>(&m_gizmos)->set_hover_id(inside && (unsigned int)volume_id <= GLGizmoBase::BASE_ID ? ((int)GLGizmoBase::BASE_ID - volume_id) : -1);
|
||||
|
||||
_update_volumes_hover_state();
|
||||
}
|
||||
|
|
@ -4896,12 +4900,11 @@ void GLCanvas3D::_picking_pass() const
|
|||
|
||||
void GLCanvas3D::_rectangular_selection_picking_pass() const
|
||||
{
|
||||
m_gizmos.set_hover_id(-1);
|
||||
const_cast<GLGizmosManager*>(&m_gizmos)->set_hover_id(-1);
|
||||
|
||||
std::set<int> idxs;
|
||||
|
||||
if (m_picking_enabled)
|
||||
{
|
||||
if (m_picking_enabled) {
|
||||
if (m_multisample_allowed)
|
||||
// This flag is often ignored by NVIDIA drivers if rendering into a screen buffer.
|
||||
glsafe(::glDisable(GL_MULTISAMPLE));
|
||||
|
|
@ -4922,8 +4925,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
|
|||
|
||||
int left = (int)m_rectangle_selection.get_left();
|
||||
int top = get_canvas_size().get_height() - (int)m_rectangle_selection.get_top();
|
||||
if ((left >= 0) && (top >= 0))
|
||||
{
|
||||
if (left >= 0 && top >= 0) {
|
||||
#define USE_PARALLEL 1
|
||||
#if USE_PARALLEL
|
||||
struct Pixel
|
||||
|
|
@ -4943,7 +4945,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
|
|||
for (size_t i = range.begin(); i < range.end(); ++i)
|
||||
if (frame[i].valid()) {
|
||||
int volume_id = frame[i].id();
|
||||
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) {
|
||||
if (0 <= volume_id && volume_id < (int)m_volumes.volumes.size()) {
|
||||
mutex.lock();
|
||||
idxs.insert(volume_id);
|
||||
mutex.unlock();
|
||||
|
|
@ -4958,14 +4960,14 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
|
|||
{
|
||||
int px_id = 4 * i;
|
||||
int volume_id = frame[px_id] + (frame[px_id + 1] << 8) + (frame[px_id + 2] << 16);
|
||||
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
|
||||
if (0 <= volume_id && volume_id < (int)m_volumes.volumes.size())
|
||||
idxs.insert(volume_id);
|
||||
}
|
||||
#endif // USE_PARALLEL
|
||||
}
|
||||
}
|
||||
|
||||
m_hover_volume_idxs.assign(idxs.begin(), idxs.end());
|
||||
const_cast<std::vector<int>*>(&m_hover_volume_idxs)->assign(idxs.begin(), idxs.end());
|
||||
_update_volumes_hover_state();
|
||||
}
|
||||
|
||||
|
|
@ -5059,7 +5061,9 @@ void GLCanvas3D::_render_objects() const
|
|||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
m_camera_clipping_plane = m_gizmos.get_clipping_plane();
|
||||
ClippingPlane* camera_clipping_plane = const_cast<ClippingPlane*>(&m_camera_clipping_plane);
|
||||
GLVolumeCollection* volumes = const_cast<GLVolumeCollection*>(&m_volumes);
|
||||
*camera_clipping_plane = m_gizmos.get_clipping_plane();
|
||||
|
||||
if (m_picking_enabled) {
|
||||
// Update the layer editing selection to the first object selected, update the current object maximum Z.
|
||||
|
|
@ -5067,17 +5071,17 @@ void GLCanvas3D::_render_objects() const
|
|||
|
||||
if (m_config != nullptr) {
|
||||
const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false);
|
||||
m_volumes.set_print_box((float)bed_bb.min(0) - BedEpsilon, (float)bed_bb.min(1) - BedEpsilon, 0.0f, (float)bed_bb.max(0) + BedEpsilon, (float)bed_bb.max(1) + BedEpsilon, (float)m_config->opt_float("max_print_height"));
|
||||
m_volumes.check_outside_state(m_config, nullptr);
|
||||
volumes->set_print_box((float)bed_bb.min(0) - BedEpsilon, (float)bed_bb.min(1) - BedEpsilon, 0.0f, (float)bed_bb.max(0) + BedEpsilon, (float)bed_bb.max(1) + BedEpsilon, (float)m_config->opt_float("max_print_height"));
|
||||
volumes->check_outside_state(m_config, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_use_clipping_planes)
|
||||
m_volumes.set_z_range(-m_clipping_planes[0].get_data()[3], m_clipping_planes[1].get_data()[3]);
|
||||
volumes->set_z_range(-m_clipping_planes[0].get_data()[3], m_clipping_planes[1].get_data()[3]);
|
||||
else
|
||||
m_volumes.set_z_range(-FLT_MAX, FLT_MAX);
|
||||
volumes->set_z_range(-FLT_MAX, FLT_MAX);
|
||||
|
||||
m_volumes.set_clipping_plane(m_camera_clipping_plane.get_data());
|
||||
volumes->set_clipping_plane(camera_clipping_plane->get_data());
|
||||
|
||||
GLShaderProgram* shader = wxGetApp().get_shader("gouraud");
|
||||
if (shader != nullptr) {
|
||||
|
|
@ -5085,16 +5089,16 @@ void GLCanvas3D::_render_objects() const
|
|||
|
||||
if (m_picking_enabled && !m_gizmos.is_dragging() && m_layers_editing.is_enabled() && (m_layers_editing.last_object_id != -1) && (m_layers_editing.object_max_z() > 0.0f)) {
|
||||
int object_id = m_layers_editing.last_object_id;
|
||||
m_volumes.render(GLVolumeCollection::Opaque, false, wxGetApp().plater()->get_camera().get_view_matrix(), [object_id](const GLVolume& volume) {
|
||||
volumes->render(GLVolumeCollection::Opaque, false, wxGetApp().plater()->get_camera().get_view_matrix(), [object_id](const GLVolume& volume) {
|
||||
// Which volume to paint without the layer height profile shader?
|
||||
return volume.is_active && (volume.is_modifier || volume.composite_id.object_id != object_id);
|
||||
});
|
||||
// Let LayersEditing handle rendering of the active object using the layer height profile shader.
|
||||
m_layers_editing.render_volumes(*this, this->m_volumes);
|
||||
m_layers_editing.render_volumes(*this, *volumes);
|
||||
} else {
|
||||
// do not cull backfaces to show broken geometry, if any
|
||||
m_volumes.render(GLVolumeCollection::Opaque, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this](const GLVolume& volume) {
|
||||
return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
|
||||
// do not cull backfaces to show broken geometry, if any
|
||||
volumes->render(GLVolumeCollection::Opaque, m_picking_enabled, wxGetApp().plater()->get_camera().get_view_matrix(), [this](const GLVolume& volume) {
|
||||
return (m_render_sla_auxiliaries || volume.composite_id.volume_id >= 0);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -5112,11 +5116,11 @@ void GLCanvas3D::_render_objects() const
|
|||
}
|
||||
}
|
||||
|
||||
m_volumes.render(GLVolumeCollection::Transparent, false, wxGetApp().plater()->get_camera().get_view_matrix());
|
||||
volumes->render(GLVolumeCollection::Transparent, false, wxGetApp().plater()->get_camera().get_view_matrix());
|
||||
shader->stop_using();
|
||||
}
|
||||
|
||||
m_camera_clipping_plane = ClippingPlane::ClipsNothing();
|
||||
*camera_clipping_plane = ClippingPlane::ClipsNothing();
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_gcode() const
|
||||
|
|
@ -5157,13 +5161,13 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale() const
|
|||
GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar();
|
||||
#if ENABLE_RETINA_GL
|
||||
const float sc = m_retina_helper->get_scale_factor() * scale;
|
||||
m_main_toolbar.set_scale(sc);
|
||||
m_undoredo_toolbar.set_scale(sc);
|
||||
const_cast<GLToolbar*>(&m_main_toolbar)->set_scale(sc);
|
||||
const_cast<GLToolbar*>(&m_undoredo_toolbar)->set_scale(sc);
|
||||
collapse_toolbar.set_scale(sc);
|
||||
size *= m_retina_helper->get_scale_factor();
|
||||
#else
|
||||
m_main_toolbar.set_icons_size(size);
|
||||
m_undoredo_toolbar.set_icons_size(size);
|
||||
const_cast<GLToolbar*>(&m_main_toolbar)->set_icons_size(size);
|
||||
const_cast<GLToolbar*>(&m_undoredo_toolbar)->set_icons_size(size);
|
||||
collapse_toolbar.set_icons_size(size);
|
||||
#endif // ENABLE_RETINA_GL
|
||||
|
||||
|
|
@ -5211,13 +5215,13 @@ void GLCanvas3D::_render_overlays() const
|
|||
// to correctly place them
|
||||
#if ENABLE_RETINA_GL
|
||||
const float scale = m_retina_helper->get_scale_factor() * wxGetApp().toolbar_icon_scale(/*true*/);
|
||||
m_main_toolbar.set_scale(scale);
|
||||
m_undoredo_toolbar.set_scale(scale);
|
||||
const_cast<GLToolbar*>(&m_main_toolbar)->set_scale(scale);
|
||||
const_cast<GLToolbar*>(&m_undoredo_toolbar)->set_scale(scale);
|
||||
wxGetApp().plater()->get_collapse_toolbar().set_scale(scale);
|
||||
#else
|
||||
const float size = int(GLToolbar::Default_Icons_Size * wxGetApp().toolbar_icon_scale(/*true*/));
|
||||
m_main_toolbar.set_icons_size(size);
|
||||
m_undoredo_toolbar.set_icons_size(size);
|
||||
const_cast<GLToolbar*>(&m_main_toolbar)->set_icons_size(size);
|
||||
const_cast<GLToolbar*>(&m_undoredo_toolbar)->set_icons_size(size);
|
||||
wxGetApp().plater()->get_collapse_toolbar().set_icons_size(size);
|
||||
#endif // ENABLE_RETINA_GL
|
||||
|
||||
|
|
@ -5292,12 +5296,12 @@ void GLCanvas3D::_render_gizmos_overlay() const
|
|||
#if ENABLE_RETINA_GL
|
||||
// m_gizmos.set_overlay_scale(m_retina_helper->get_scale_factor());
|
||||
const float scale = m_retina_helper->get_scale_factor()*wxGetApp().toolbar_icon_scale();
|
||||
m_gizmos.set_overlay_scale(scale); //! #ys_FIXME_experiment
|
||||
const_cast<GLGizmosManager*>(&m_gizmos)->set_overlay_scale(scale); //! #ys_FIXME_experiment
|
||||
#else
|
||||
// m_gizmos.set_overlay_scale(m_canvas->GetContentScaleFactor());
|
||||
// m_gizmos.set_overlay_scale(wxGetApp().em_unit()*0.1f);
|
||||
const float size = int(GLGizmosManager::Default_Icons_Size*wxGetApp().toolbar_icon_scale());
|
||||
m_gizmos.set_overlay_icon_size(size); //! #ys_FIXME_experiment
|
||||
const float size = int(GLGizmosManager::Default_Icons_Size * wxGetApp().toolbar_icon_scale());
|
||||
const_cast<GLGizmosManager*>(&m_gizmos)->set_overlay_icon_size(size); //! #ys_FIXME_experiment
|
||||
#endif /* __WXMSW__ */
|
||||
|
||||
m_gizmos.render_overlay();
|
||||
|
|
@ -5316,8 +5320,9 @@ void GLCanvas3D::_render_main_toolbar() const
|
|||
float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f;
|
||||
float left = -0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar_width) * inv_zoom;
|
||||
|
||||
m_main_toolbar.set_position(top, left);
|
||||
m_main_toolbar.render(*this);
|
||||
GLToolbar* main_toolbar = const_cast<GLToolbar*>(&m_main_toolbar);
|
||||
main_toolbar->set_position(top, left);
|
||||
main_toolbar->render(*this);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_undoredo_toolbar() const
|
||||
|
|
@ -5332,8 +5337,10 @@ void GLCanvas3D::_render_undoredo_toolbar() const
|
|||
const GLToolbar& collapse_toolbar = wxGetApp().plater()->get_collapse_toolbar();
|
||||
float collapse_toolbar_width = collapse_toolbar.is_enabled() ? collapse_toolbar.get_width() : 0.0f;
|
||||
float left = (m_main_toolbar.get_width() - 0.5f * (m_main_toolbar.get_width() + m_undoredo_toolbar.get_width() + collapse_toolbar_width)) * inv_zoom;
|
||||
m_undoredo_toolbar.set_position(top, left);
|
||||
m_undoredo_toolbar.render(*this);
|
||||
|
||||
GLToolbar* undoredo_toolbar = const_cast<GLToolbar*>(&m_undoredo_toolbar);
|
||||
undoredo_toolbar->set_position(top, left);
|
||||
undoredo_toolbar->render(*this);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_render_collapse_toolbar() const
|
||||
|
|
@ -5424,20 +5431,21 @@ void GLCanvas3D::_render_sla_slices() const
|
|||
if (!obj->is_step_done(slaposSliceSupports))
|
||||
continue;
|
||||
|
||||
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i);
|
||||
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i);
|
||||
SlaCap* sla_caps = const_cast<SlaCap*>(m_sla_caps);
|
||||
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = sla_caps[0].triangles.find(i);
|
||||
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = sla_caps[1].triangles.find(i);
|
||||
{
|
||||
if (it_caps_bottom == m_sla_caps[0].triangles.end())
|
||||
it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first;
|
||||
if (! m_sla_caps[0].matches(clip_min_z)) {
|
||||
m_sla_caps[0].z = clip_min_z;
|
||||
if (it_caps_bottom == sla_caps[0].triangles.end())
|
||||
it_caps_bottom = sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first;
|
||||
if (!sla_caps[0].matches(clip_min_z)) {
|
||||
sla_caps[0].z = clip_min_z;
|
||||
it_caps_bottom->second.object.clear();
|
||||
it_caps_bottom->second.supports.clear();
|
||||
}
|
||||
if (it_caps_top == m_sla_caps[1].triangles.end())
|
||||
it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
|
||||
if (! m_sla_caps[1].matches(clip_max_z)) {
|
||||
m_sla_caps[1].z = clip_max_z;
|
||||
if (it_caps_top == sla_caps[1].triangles.end())
|
||||
it_caps_top = sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
|
||||
if (!sla_caps[1].matches(clip_max_z)) {
|
||||
sla_caps[1].z = clip_max_z;
|
||||
it_caps_top->second.object.clear();
|
||||
it_caps_top->second.supports.clear();
|
||||
}
|
||||
|
|
@ -5543,7 +5551,7 @@ void GLCanvas3D::_update_volumes_hover_state() const
|
|||
|
||||
if (alt_pressed && (shift_pressed || ctrl_pressed)) {
|
||||
// illegal combinations of keys
|
||||
m_hover_volume_idxs.clear();
|
||||
const_cast<std::vector<int>*>(&m_hover_volume_idxs)->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -5567,7 +5575,7 @@ void GLCanvas3D::_update_volumes_hover_state() const
|
|||
|
||||
if (hover_modifiers_only && !hover_from_single_instance) {
|
||||
// do not allow to select volumes from different instances
|
||||
m_hover_volume_idxs.clear();
|
||||
const_cast<std::vector<int>*>(&m_hover_volume_idxs)->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -5588,23 +5596,15 @@ void GLCanvas3D::_update_volumes_hover_state() const
|
|||
(deselect && !m_selection.is_single_full_instance() && (volume.object_idx() == m_selection.get_object_idx()) && (volume.instance_idx() == m_selection.get_instance_idx()))
|
||||
);
|
||||
|
||||
if (as_volume) {
|
||||
if (deselect)
|
||||
volume.hover = GLVolume::HS_Deselect;
|
||||
else
|
||||
volume.hover = GLVolume::HS_Select;
|
||||
}
|
||||
if (as_volume)
|
||||
volume.hover = deselect ? GLVolume::HS_Deselect : GLVolume::HS_Select;
|
||||
else {
|
||||
int object_idx = volume.object_idx();
|
||||
int instance_idx = volume.instance_idx();
|
||||
|
||||
for (GLVolume* v : m_volumes.volumes) {
|
||||
if (v->object_idx() == object_idx && v->instance_idx() == instance_idx) {
|
||||
if (deselect)
|
||||
v->hover = GLVolume::HS_Deselect;
|
||||
else
|
||||
v->hover = GLVolume::HS_Select;
|
||||
}
|
||||
if (v->object_idx() == object_idx && v->instance_idx() == instance_idx)
|
||||
v->hover = deselect ? GLVolume::HS_Deselect : GLVolume::HS_Select;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6311,31 +6311,47 @@ std::vector<float> GLCanvas3D::_parse_colors(const std::vector<std::string>& col
|
|||
#if ENABLE_WARNING_TEXTURE_REMOVAL
|
||||
void GLCanvas3D::_set_warning_notification(EWarning warning, bool state)
|
||||
{
|
||||
enum ErrorType{
|
||||
PLATER_WARNING,
|
||||
PLATER_ERROR,
|
||||
SLICING_ERROR
|
||||
};
|
||||
std::string text;
|
||||
bool error = false;
|
||||
ErrorType error = ErrorType::PLATER_WARNING;
|
||||
switch (warning) {
|
||||
case EWarning::ObjectOutside: text = _u8L("An object outside the print area was detected."); break;
|
||||
case EWarning::ToolpathOutside: text = _u8L("A toolpath outside the print area was detected."); error = true; break;
|
||||
case EWarning::SlaSupportsOutside: text = _u8L("SLA supports outside the print area were detected."); error = true; break;
|
||||
case EWarning::ToolpathOutside: text = _u8L("A toolpath outside the print area was detected."); error = ErrorType::SLICING_ERROR; break;
|
||||
case EWarning::SlaSupportsOutside: text = _u8L("SLA supports outside the print area were detected."); error = ErrorType::PLATER_ERROR; break;
|
||||
case EWarning::SomethingNotShown: text = _u8L("Some objects are not visible."); break;
|
||||
case EWarning::ObjectClashed:
|
||||
text = _u8L("An object outside the print area was detected.\n"
|
||||
"Resolve the current problem to continue slicing.");
|
||||
error = true;
|
||||
error = ErrorType::PLATER_ERROR;
|
||||
break;
|
||||
}
|
||||
auto& notification_manager = *wxGetApp().plater()->get_notification_manager();
|
||||
if (state) {
|
||||
if (error)
|
||||
notification_manager.push_plater_error_notification(text);
|
||||
else
|
||||
switch (error)
|
||||
{
|
||||
case PLATER_WARNING:
|
||||
if (state)
|
||||
notification_manager.push_plater_warning_notification(text);
|
||||
}
|
||||
else {
|
||||
if (error)
|
||||
notification_manager.close_plater_error_notification(text);
|
||||
else
|
||||
notification_manager.close_plater_warning_notification(text);
|
||||
break;
|
||||
case PLATER_ERROR:
|
||||
if (state)
|
||||
notification_manager.push_plater_error_notification(text);
|
||||
else
|
||||
notification_manager.close_plater_error_notification(text);
|
||||
break;
|
||||
case SLICING_ERROR:
|
||||
if (state)
|
||||
notification_manager.push_slicing_error_notification(text);
|
||||
else
|
||||
notification_manager.close_slicing_error_notification(text);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -449,13 +449,13 @@ private:
|
|||
wxTimer m_timer;
|
||||
LayersEditing m_layers_editing;
|
||||
Mouse m_mouse;
|
||||
mutable GLGizmosManager m_gizmos;
|
||||
mutable GLToolbar m_main_toolbar;
|
||||
mutable GLToolbar m_undoredo_toolbar;
|
||||
GLGizmosManager m_gizmos;
|
||||
GLToolbar m_main_toolbar;
|
||||
GLToolbar m_undoredo_toolbar;
|
||||
ClippingPlane m_clipping_planes[2];
|
||||
mutable ClippingPlane m_camera_clipping_plane;
|
||||
ClippingPlane m_camera_clipping_plane;
|
||||
bool m_use_clipping_planes;
|
||||
mutable SlaCap m_sla_caps[2];
|
||||
SlaCap m_sla_caps[2];
|
||||
std::string m_sidebar_field;
|
||||
// when true renders an extra frame by not resetting m_dirty to false
|
||||
// see request_extra_frame()
|
||||
|
|
@ -463,7 +463,7 @@ private:
|
|||
int m_extra_frame_requested_delayed { std::numeric_limits<int>::max() };
|
||||
bool m_event_handlers_bound{ false };
|
||||
|
||||
mutable GLVolumeCollection m_volumes;
|
||||
GLVolumeCollection m_volumes;
|
||||
GCodeViewer m_gcode_viewer;
|
||||
|
||||
RenderTimer m_render_timer;
|
||||
|
|
@ -478,7 +478,6 @@ private:
|
|||
bool m_dirty;
|
||||
bool m_initialized;
|
||||
bool m_apply_zoom_to_volumes_filter;
|
||||
mutable std::vector<int> m_hover_volume_idxs;
|
||||
bool m_picking_enabled;
|
||||
bool m_moving_enabled;
|
||||
bool m_dynamic_background_enabled;
|
||||
|
|
@ -487,6 +486,7 @@ private:
|
|||
bool m_tab_down;
|
||||
ECursorType m_cursor_type;
|
||||
GLSelectionRectangle m_rectangle_selection;
|
||||
std::vector<int> m_hover_volume_idxs;
|
||||
|
||||
// Following variable is obsolete and it should be safe to remove it.
|
||||
// I just don't want to do it now before a release (Lukas Matena 24.3.2019)
|
||||
|
|
@ -504,13 +504,13 @@ private:
|
|||
RenderStats m_render_stats;
|
||||
#endif // ENABLE_RENDER_STATISTICS
|
||||
|
||||
mutable int m_imgui_undo_redo_hovered_pos{ -1 };
|
||||
mutable int m_mouse_wheel {0};
|
||||
int m_imgui_undo_redo_hovered_pos{ -1 };
|
||||
int m_mouse_wheel{ 0 };
|
||||
int m_selected_extruder;
|
||||
|
||||
Labels m_labels;
|
||||
mutable Tooltip m_tooltip;
|
||||
mutable bool m_tooltip_enabled{ true };
|
||||
Tooltip m_tooltip;
|
||||
bool m_tooltip_enabled{ true };
|
||||
Slope m_slope;
|
||||
|
||||
ArrangeSettings m_arrange_settings_fff, m_arrange_settings_sla,
|
||||
|
|
@ -519,8 +519,7 @@ private:
|
|||
PrinterTechnology current_printer_technology() const;
|
||||
|
||||
template<class Self>
|
||||
static auto & get_arrange_settings(Self *self)
|
||||
{
|
||||
static auto & get_arrange_settings(Self *self) {
|
||||
PrinterTechnology ptech = self->current_printer_technology();
|
||||
|
||||
auto *ptr = &self->m_arrange_settings_fff;
|
||||
|
|
@ -529,11 +528,10 @@ private:
|
|||
ptr = &self->m_arrange_settings_sla;
|
||||
} else if (ptech == ptFFF) {
|
||||
auto co_opt = self->m_config->template option<ConfigOptionBool>("complete_objects");
|
||||
if (co_opt && co_opt->value) {
|
||||
if (co_opt && co_opt->value)
|
||||
ptr = &self->m_arrange_settings_fff_seq_print;
|
||||
} else {
|
||||
else
|
||||
ptr = &self->m_arrange_settings_fff;
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
|
|
@ -715,10 +713,9 @@ public:
|
|||
double m_rotation = 0.;
|
||||
BoundingBoxf m_bb;
|
||||
friend class GLCanvas3D;
|
||||
public:
|
||||
|
||||
inline operator bool() const
|
||||
{
|
||||
|
||||
public:
|
||||
inline operator bool() const {
|
||||
return !std::isnan(m_pos.x()) && !std::isnan(m_pos.y());
|
||||
}
|
||||
|
||||
|
|
@ -763,8 +760,7 @@ public:
|
|||
void use_slope(bool use) { m_slope.use(use); }
|
||||
void set_slope_normal_angle(float angle_in_deg) { m_slope.set_normal_angle(angle_in_deg); }
|
||||
|
||||
ArrangeSettings get_arrange_settings() const
|
||||
{
|
||||
ArrangeSettings get_arrange_settings() const {
|
||||
const ArrangeSettings &settings = get_arrange_settings(this);
|
||||
ArrangeSettings ret = settings;
|
||||
if (&settings == &m_arrange_settings_fff_seq_print) {
|
||||
|
|
|
|||
|
|
@ -428,8 +428,7 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||
bool processed = false;
|
||||
|
||||
// mouse anywhere
|
||||
if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && (m_mouse_capture.parent != nullptr))
|
||||
{
|
||||
if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && m_mouse_capture.parent != nullptr) {
|
||||
if (m_mouse_capture.any() && (evt.LeftUp() || evt.MiddleUp() || evt.RightUp())) {
|
||||
// prevents loosing selection into the scene if mouse down was done inside the toolbar and mouse up was down outside it,
|
||||
// as when switching between views
|
||||
|
|
@ -441,38 +440,31 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||
|
||||
if (evt.Moving())
|
||||
update_hover_state(mouse_pos, parent);
|
||||
else if (evt.LeftUp())
|
||||
{
|
||||
if (m_mouse_capture.left)
|
||||
{
|
||||
else if (evt.LeftUp()) {
|
||||
if (m_mouse_capture.left) {
|
||||
processed = true;
|
||||
m_mouse_capture.left = false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (evt.MiddleUp())
|
||||
{
|
||||
if (m_mouse_capture.middle)
|
||||
{
|
||||
else if (evt.MiddleUp()) {
|
||||
if (m_mouse_capture.middle) {
|
||||
processed = true;
|
||||
m_mouse_capture.middle = false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (evt.RightUp())
|
||||
{
|
||||
if (m_mouse_capture.right)
|
||||
{
|
||||
else if (evt.RightUp()) {
|
||||
if (m_mouse_capture.right) {
|
||||
processed = true;
|
||||
m_mouse_capture.right = false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (evt.Dragging())
|
||||
{
|
||||
else if (evt.Dragging()) {
|
||||
if (m_mouse_capture.any())
|
||||
// if the button down was done on this toolbar, prevent from dragging into the scene
|
||||
processed = true;
|
||||
|
|
@ -481,35 +473,29 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||
}
|
||||
|
||||
int item_id = contains_mouse(mouse_pos, parent);
|
||||
if (item_id != -1)
|
||||
{
|
||||
if (item_id != -1) {
|
||||
// mouse inside toolbar
|
||||
if (evt.LeftDown() || evt.LeftDClick())
|
||||
{
|
||||
if (evt.LeftDown() || evt.LeftDClick()) {
|
||||
m_mouse_capture.left = true;
|
||||
m_mouse_capture.parent = &parent;
|
||||
processed = true;
|
||||
if ((item_id != -2) && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
|
||||
((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)))
|
||||
{
|
||||
if (item_id != -2 && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
|
||||
(m_pressed_toggable_id == -1 || m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)) {
|
||||
// mouse is inside an icon
|
||||
do_action(GLToolbarItem::Left, item_id, parent, true);
|
||||
parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
else if (evt.MiddleDown())
|
||||
{
|
||||
else if (evt.MiddleDown()) {
|
||||
m_mouse_capture.middle = true;
|
||||
m_mouse_capture.parent = &parent;
|
||||
}
|
||||
else if (evt.RightDown())
|
||||
{
|
||||
else if (evt.RightDown()) {
|
||||
m_mouse_capture.right = true;
|
||||
m_mouse_capture.parent = &parent;
|
||||
processed = true;
|
||||
if ((item_id != -2) && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
|
||||
((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)))
|
||||
{
|
||||
if (item_id != -2 && !m_items[item_id]->is_separator() && !m_items[item_id]->is_disabled() &&
|
||||
(m_pressed_toggable_id == -1 || m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)) {
|
||||
// mouse is inside an icon
|
||||
do_action(GLToolbarItem::Right, item_id, parent, true);
|
||||
parent.set_as_dirty();
|
||||
|
|
@ -522,24 +508,26 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||
|
||||
void GLToolbar::calc_layout() const
|
||||
{
|
||||
switch (m_layout.type)
|
||||
Layout* layout = const_cast<Layout*>(&m_layout);
|
||||
|
||||
switch (layout->type)
|
||||
{
|
||||
default:
|
||||
case Layout::Horizontal:
|
||||
{
|
||||
m_layout.width = get_width_horizontal();
|
||||
m_layout.height = get_height_horizontal();
|
||||
layout->width = get_width_horizontal();
|
||||
layout->height = get_height_horizontal();
|
||||
break;
|
||||
}
|
||||
case Layout::Vertical:
|
||||
{
|
||||
m_layout.width = get_width_vertical();
|
||||
m_layout.height = get_height_vertical();
|
||||
layout->width = get_width_vertical();
|
||||
layout->height = get_height_vertical();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_layout.dirty = false;
|
||||
layout->dirty = false;
|
||||
}
|
||||
|
||||
float GLToolbar::get_width_horizontal() const
|
||||
|
|
@ -1196,19 +1184,17 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const
|
|||
left += scaled_border;
|
||||
top -= scaled_border;
|
||||
|
||||
if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0))
|
||||
if (tex_id == 0 || tex_width <= 0 || tex_height <= 0)
|
||||
return;
|
||||
|
||||
// renders icons
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
{
|
||||
for (const GLToolbarItem* item : m_items) {
|
||||
if (!item->is_visible())
|
||||
continue;
|
||||
|
||||
if (item->is_separator())
|
||||
top -= separator_stride;
|
||||
else
|
||||
{
|
||||
else {
|
||||
item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale));
|
||||
top -= icon_stride;
|
||||
}
|
||||
|
|
@ -1219,16 +1205,14 @@ bool GLToolbar::generate_icons_texture() const
|
|||
{
|
||||
std::string path = resources_dir() + "/icons/";
|
||||
std::vector<std::string> filenames;
|
||||
for (GLToolbarItem* item : m_items)
|
||||
{
|
||||
for (GLToolbarItem* item : m_items) {
|
||||
const std::string& icon_filename = item->get_icon_filename();
|
||||
if (!icon_filename.empty())
|
||||
filenames.push_back(path + icon_filename);
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, bool>> states;
|
||||
if (m_type == Normal)
|
||||
{
|
||||
if (m_type == Normal) {
|
||||
states.push_back({ 1, false }); // Normal
|
||||
states.push_back({ 0, false }); // Pressed
|
||||
states.push_back({ 2, false }); // Disabled
|
||||
|
|
@ -1236,8 +1220,7 @@ bool GLToolbar::generate_icons_texture() const
|
|||
states.push_back({ 0, false }); // HoverPressed
|
||||
states.push_back({ 2, false }); // HoverDisabled
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
states.push_back({ 1, false }); // Normal
|
||||
states.push_back({ 1, true }); // Pressed
|
||||
states.push_back({ 1, false }); // Disabled
|
||||
|
|
@ -1251,9 +1234,9 @@ bool GLToolbar::generate_icons_texture() const
|
|||
// if (sprite_size_px % 2 != 0)
|
||||
// sprite_size_px += 1;
|
||||
|
||||
bool res = m_icons_texture.load_from_svg_files_as_sprites_array(filenames, states, sprite_size_px, false);
|
||||
bool res = const_cast<GLTexture*>(&m_icons_texture)->load_from_svg_files_as_sprites_array(filenames, states, sprite_size_px, false);
|
||||
if (res)
|
||||
m_icons_texture_dirty = false;
|
||||
*const_cast<bool*>(&m_icons_texture_dirty) = false;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
@ -1262,8 +1245,7 @@ bool GLToolbar::update_items_visibility()
|
|||
{
|
||||
bool ret = false;
|
||||
|
||||
for (GLToolbarItem* item : m_items)
|
||||
{
|
||||
for (GLToolbarItem* item : m_items) {
|
||||
ret |= item->update_visibility();
|
||||
}
|
||||
|
||||
|
|
@ -1272,12 +1254,10 @@ bool GLToolbar::update_items_visibility()
|
|||
|
||||
// updates separators visibility to avoid having two of them consecutive
|
||||
bool any_item_visible = false;
|
||||
for (GLToolbarItem* item : m_items)
|
||||
{
|
||||
for (GLToolbarItem* item : m_items) {
|
||||
if (!item->is_separator())
|
||||
any_item_visible |= item->is_visible();
|
||||
else
|
||||
{
|
||||
else {
|
||||
item->set_visible(any_item_visible);
|
||||
any_item_visible = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,10 +233,10 @@ private:
|
|||
EType m_type;
|
||||
std::string m_name;
|
||||
bool m_enabled;
|
||||
mutable GLTexture m_icons_texture;
|
||||
mutable bool m_icons_texture_dirty;
|
||||
GLTexture m_icons_texture;
|
||||
bool m_icons_texture_dirty;
|
||||
BackgroundTexture m_background_texture;
|
||||
mutable Layout m_layout;
|
||||
Layout m_layout;
|
||||
|
||||
ItemsList m_items;
|
||||
|
||||
|
|
|
|||
|
|
@ -1525,14 +1525,20 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
|
|||
if (type == itUndef)
|
||||
return;
|
||||
|
||||
wxDataViewItem parent = m_objects_model->GetParent(item);
|
||||
|
||||
if (type & itSettings)
|
||||
del_settings_from_config(m_objects_model->GetParent(item));
|
||||
del_settings_from_config(parent);
|
||||
else if (type & itInstanceRoot && obj_idx != -1)
|
||||
del_instances_from_object(obj_idx);
|
||||
else if (type & itLayerRoot && obj_idx != -1)
|
||||
del_layers_from_object(obj_idx);
|
||||
else if (type & itLayer && obj_idx != -1)
|
||||
del_layer_from_object(obj_idx, m_objects_model->GetLayerRangeByItem(item));
|
||||
else if (type & itInfo && obj_idx != -1) {
|
||||
Unselect(item);
|
||||
Select(parent);
|
||||
}
|
||||
else if (idx == -1)
|
||||
return;
|
||||
else if (!del_subobject_from_object(obj_idx, idx, type))
|
||||
|
|
@ -1540,9 +1546,10 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
|
|||
|
||||
// If last volume item with warning was deleted, unmark object item
|
||||
if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
|
||||
m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item));
|
||||
m_objects_model->DeleteWarningIcon(parent);
|
||||
|
||||
m_objects_model->Delete(item);
|
||||
update_info_items(obj_idx);
|
||||
}
|
||||
|
||||
void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
|
||||
|
|
@ -2118,20 +2125,32 @@ void ObjectList::part_selection_changed()
|
|||
{
|
||||
if (item)
|
||||
{
|
||||
if (m_objects_model->GetParent(item) == wxDataViewItem(nullptr)) {
|
||||
obj_idx = m_objects_model->GetIdByItem(item);
|
||||
const ItemType type = m_objects_model->GetItemType(item);
|
||||
const wxDataViewItem parent = m_objects_model->GetParent(item);
|
||||
const ItemType parent_type = m_objects_model->GetItemType(parent);
|
||||
obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||
|
||||
if (parent == wxDataViewItem(nullptr)
|
||||
|| type == itInfo) {
|
||||
og_name = _(L("Object manipulation"));
|
||||
m_config = &(*m_objects)[obj_idx]->config;
|
||||
update_and_show_manipulations = true;
|
||||
|
||||
if (type == itInfo) {
|
||||
InfoItemType info_type = m_objects_model->GetInfoItemType(item);
|
||||
if (info_type != InfoItemType::VariableLayerHeight) {
|
||||
GLGizmosManager::EType gizmo_type =
|
||||
info_type == InfoItemType::CustomSupports ? GLGizmosManager::EType::FdmSupports
|
||||
: GLGizmosManager::EType::Seam;
|
||||
GLGizmosManager& gizmos_mgr = wxGetApp().plater()->canvas3D()->get_gizmos_manager();
|
||||
if (gizmos_mgr.get_current_type() != gizmo_type)
|
||||
gizmos_mgr.open_gizmo(gizmo_type);
|
||||
} else
|
||||
wxGetApp().plater()->toggle_layers_editing(true);
|
||||
}
|
||||
}
|
||||
else {
|
||||
obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||
|
||||
const ItemType type = m_objects_model->GetItemType(item);
|
||||
if (type & itSettings) {
|
||||
const auto parent = m_objects_model->GetParent(item);
|
||||
const ItemType parent_type = m_objects_model->GetItemType(parent);
|
||||
|
||||
if (parent_type & itObject) {
|
||||
og_name = _(L("Object Settings to modify"));
|
||||
m_config = &(*m_objects)[obj_idx]->config;
|
||||
|
|
@ -2243,6 +2262,52 @@ wxDataViewItem ObjectList::add_settings_item(wxDataViewItem parent_item, const D
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void ObjectList::update_info_items(size_t obj_idx)
|
||||
{
|
||||
const ModelObject* model_object = (*m_objects)[obj_idx];
|
||||
wxDataViewItem item_obj = m_objects_model->GetItemById(obj_idx);
|
||||
assert(item_obj.IsOk());
|
||||
|
||||
for (InfoItemType type : {InfoItemType::CustomSupports,
|
||||
InfoItemType::CustomSeam,
|
||||
InfoItemType::VariableLayerHeight}) {
|
||||
wxDataViewItem item = m_objects_model->GetInfoItemByType(item_obj, type);
|
||||
bool shows = item.IsOk();
|
||||
bool should_show = false;
|
||||
|
||||
switch (type) {
|
||||
case InfoItemType::CustomSupports :
|
||||
case InfoItemType::CustomSeam :
|
||||
should_show = printer_technology() == ptFFF
|
||||
&& std::any_of(model_object->volumes.begin(), model_object->volumes.end(),
|
||||
[type](const ModelVolume* mv) {
|
||||
return ! (type == InfoItemType::CustomSupports
|
||||
? mv->supported_facets.empty()
|
||||
: mv->seam_facets.empty());
|
||||
});
|
||||
break;
|
||||
|
||||
case InfoItemType::VariableLayerHeight :
|
||||
should_show = printer_technology() == ptFFF
|
||||
&& ! model_object->layer_height_profile.empty();
|
||||
break;
|
||||
}
|
||||
|
||||
if (! shows && should_show) {
|
||||
m_objects_model->AddInfoChild(item_obj, type);
|
||||
Expand(item_obj);
|
||||
}
|
||||
else if (shows && ! should_show) {
|
||||
Unselect(item);
|
||||
m_objects_model->Delete(item);
|
||||
Select(item_obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
|
||||
{
|
||||
auto model_object = (*m_objects)[obj_idx];
|
||||
|
|
@ -2251,6 +2316,8 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
|
|||
model_object->config.has("extruder") ? model_object->config.extruder() : 0,
|
||||
get_mesh_errors_count(obj_idx) > 0);
|
||||
|
||||
update_info_items(obj_idx);
|
||||
|
||||
// add volumes to the object
|
||||
if (model_object->volumes.size() > 1) {
|
||||
for (const ModelVolume* volume : model_object->volumes) {
|
||||
|
|
@ -3029,7 +3096,7 @@ void ObjectList::update_selections_on_canvas()
|
|||
|
||||
if (sel_cnt == 1) {
|
||||
wxDataViewItem item = GetSelection();
|
||||
if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer))
|
||||
if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer | itInfo))
|
||||
add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, mode);
|
||||
else
|
||||
add_to_selection(item, selection, instance_idx, mode);
|
||||
|
|
@ -3442,6 +3509,9 @@ void ObjectList::update_object_list_by_printer_technology()
|
|||
m_objects_model->GetChildren(wxDataViewItem(nullptr), object_items);
|
||||
|
||||
for (auto& object_item : object_items) {
|
||||
// update custom supports info
|
||||
update_info_items(m_objects_model->GetObjectIdByItem(object_item));
|
||||
|
||||
// Update Settings Item for object
|
||||
update_settings_item_and_selection(object_item, sel);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
class wxBoxSizer;
|
||||
class wxBitmapComboBox;
|
||||
class wxMenuItem;
|
||||
class ObjectDataViewModel;
|
||||
class MenuWithSeparators;
|
||||
|
||||
namespace Slic3r {
|
||||
|
|
@ -347,6 +346,7 @@ public:
|
|||
void update_and_show_object_settings_item();
|
||||
void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
|
||||
void update_object_list_by_printer_technology();
|
||||
void update_info_items(size_t obj_idx);
|
||||
|
||||
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
|
||||
void instances_to_separated_objects(const int obj_idx);
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
|
@ -316,8 +317,12 @@ void GLGizmoFdmSupports::update_model_object() const
|
|||
updated |= mv->supported_facets.set(*m_triangle_selectors[idx].get());
|
||||
}
|
||||
|
||||
if (updated)
|
||||
if (updated) {
|
||||
const ModelObjectPtrs& mos = wxGetApp().model().objects;
|
||||
wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin());
|
||||
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/ImGuiWrapper.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
|
@ -222,8 +222,12 @@ void GLGizmoSeam::update_model_object() const
|
|||
updated |= mv->seam_facets.set(*m_triangle_selectors[idx].get());
|
||||
}
|
||||
|
||||
if (updated)
|
||||
if (updated) {
|
||||
const ModelObjectPtrs& mos = wxGetApp().model().objects;
|
||||
wxGetApp().obj_list()->update_info_items(std::find(mos.begin(), mos.end(), mo) - mos.begin());
|
||||
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -163,6 +163,17 @@ void GLGizmosManager::reset_all_states()
|
|||
m_hover = Undefined;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::open_gizmo(EType type)
|
||||
{
|
||||
int idx = int(type);
|
||||
if (m_gizmos[idx]->is_selectable() && m_gizmos[idx]->is_activable()) {
|
||||
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
|
||||
update_data();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_hover_id(int id)
|
||||
{
|
||||
if (!m_enabled || m_current == Undefined)
|
||||
|
|
@ -266,24 +277,21 @@ bool GLGizmosManager::is_running() const
|
|||
|
||||
bool GLGizmosManager::handle_shortcut(int key)
|
||||
{
|
||||
if (!m_enabled)
|
||||
if (!m_enabled || m_parent.get_selection().is_empty())
|
||||
return false;
|
||||
|
||||
if (m_parent.get_selection().is_empty())
|
||||
auto it = std::find_if(m_gizmos.begin(), m_gizmos.end(),
|
||||
[key](const std::unique_ptr<GLGizmoBase>& gizmo) {
|
||||
int gizmo_key = gizmo->get_shortcut_key();
|
||||
return gizmo->is_selectable()
|
||||
&& ((gizmo_key == key - 64) || (gizmo_key == key - 96));
|
||||
});
|
||||
|
||||
if (it == m_gizmos.end())
|
||||
return false;
|
||||
|
||||
bool handled = false;
|
||||
|
||||
for (size_t idx : get_selectable_idxs()) {
|
||||
int it_key = m_gizmos[idx]->get_shortcut_key();
|
||||
|
||||
if (m_gizmos[idx]->is_activable() && ((it_key == key - 64) || (it_key == key - 96))) {
|
||||
activate_gizmo(m_current == idx ? Undefined : (EType)idx);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
EType gizmo_type = EType(it - m_gizmos.begin());
|
||||
return open_gizmo(gizmo_type);
|
||||
}
|
||||
|
||||
bool GLGizmosManager::is_dragging() const
|
||||
|
|
@ -814,10 +822,7 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt)
|
|||
if (!processed && !evt.HasModifiers())
|
||||
{
|
||||
if (handle_shortcut(keyCode))
|
||||
{
|
||||
update_data();
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (processed)
|
||||
|
|
@ -1156,5 +1161,11 @@ bool GLGizmosManager::is_in_editing_mode(bool error_notification) const
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
int GLGizmosManager::get_shortcut_key(GLGizmosManager::EType type) const
|
||||
{
|
||||
return m_gizmos[type]->get_shortcut_key();
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
|
|
|||
|
|
@ -171,6 +171,7 @@ public:
|
|||
void refresh_on_off_state();
|
||||
void reset_all_states();
|
||||
bool is_serializing() const { return m_serializing; }
|
||||
bool open_gizmo(EType type);
|
||||
|
||||
void set_hover_id(int id);
|
||||
void enable_grabber(EType type, unsigned int id, bool enable);
|
||||
|
|
@ -228,6 +229,7 @@ public:
|
|||
void update_after_undo_redo(const UndoRedo::Snapshot& snapshot);
|
||||
|
||||
int get_selectable_icons_cnt() const { return get_selectable_idxs().size(); }
|
||||
int get_shortcut_key(GLGizmosManager::EType) const;
|
||||
|
||||
private:
|
||||
void render_background(float left, float top, float right, float bottom, float border) const;
|
||||
|
|
|
|||
|
|
@ -522,8 +522,10 @@ void MainFrame::init_tabpanel()
|
|||
#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
|
||||
m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||
#endif
|
||||
#if wxCHECK_VERSION(3,1,3)
|
||||
if (wxSystemSettings::GetAppearance().IsDark())
|
||||
m_tabpanel->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
#endif
|
||||
m_tabpanel->Hide();
|
||||
m_settings_dialog.set_tabpanel(m_tabpanel);
|
||||
|
||||
|
|
|
|||
|
|
@ -169,13 +169,16 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
|
|||
imgui.set_next_window_pos(win_pos.x, win_pos.y, ImGuiCond_Always, 1.0f, 0.0f);
|
||||
imgui.set_next_window_size(m_window_width, m_window_height, ImGuiCond_Always);
|
||||
|
||||
// find if hovered
|
||||
if (m_state == EState::Hovered)
|
||||
m_state = EState::Shown;
|
||||
|
||||
|
||||
// find if hovered FIXME: do it only in update state?
|
||||
if (m_state == EState::Hovered) {
|
||||
m_state = EState::Unknown;
|
||||
init();
|
||||
}
|
||||
|
||||
if (mouse_pos.x < win_pos.x && mouse_pos.x > win_pos.x - m_window_width && mouse_pos.y > win_pos.y && mouse_pos.y < win_pos.y + m_window_height) {
|
||||
ImGui::SetNextWindowFocus();
|
||||
m_state = EState::Hovered;
|
||||
set_hovered();
|
||||
}
|
||||
|
||||
// color change based on fading out
|
||||
|
|
@ -185,22 +188,8 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
|
|||
fading_pop = true;
|
||||
}
|
||||
|
||||
// background color
|
||||
if (m_is_gray) {
|
||||
ImVec4 backcolor(0.7f, 0.7f, 0.7f, 0.5f);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
}
|
||||
else if (m_data.level == NotificationLevel::ErrorNotification) {
|
||||
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
|
||||
backcolor.x += 0.3f;
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
}
|
||||
else if (m_data.level == NotificationLevel::WarningNotification) {
|
||||
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
|
||||
backcolor.x += 0.3f;
|
||||
backcolor.y += 0.15f;
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
}
|
||||
bool bgrnd_color_pop = push_background_color();
|
||||
|
||||
|
||||
// name of window indentifies window - has to be unique string
|
||||
if (m_id == 0)
|
||||
|
|
@ -219,13 +208,34 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
|
|||
}
|
||||
imgui.end();
|
||||
|
||||
if (m_is_gray || m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification)
|
||||
if (bgrnd_color_pop)
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
if (fading_pop)
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
|
||||
bool NotificationManager::PopNotification::push_background_color()
|
||||
{
|
||||
if (m_is_gray) {
|
||||
ImVec4 backcolor(0.7f, 0.7f, 0.7f, 0.5f);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
return true;
|
||||
}
|
||||
if (m_data.level == NotificationLevel::ErrorNotification) {
|
||||
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
|
||||
backcolor.x += 0.3f;
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
return true;
|
||||
}
|
||||
if (m_data.level == NotificationLevel::WarningNotification) {
|
||||
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
|
||||
backcolor.x += 0.3f;
|
||||
backcolor.y += 0.15f;
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void NotificationManager::PopNotification::count_spaces()
|
||||
{
|
||||
//determine line width
|
||||
|
|
@ -242,34 +252,28 @@ void NotificationManager::PopNotification::count_spaces()
|
|||
m_window_width = m_line_height * 25;
|
||||
}
|
||||
|
||||
void NotificationManager::PopNotification::init()
|
||||
void NotificationManager::PopNotification::count_lines()
|
||||
{
|
||||
// Do not init closing notification
|
||||
if (is_finished())
|
||||
return;
|
||||
|
||||
std::string text = m_text1 + " " + m_hypertext;
|
||||
size_t last_end = 0;
|
||||
m_lines_count = 0;
|
||||
std::string text = m_text1 + " " + m_hypertext;
|
||||
size_t last_end = 0;
|
||||
m_lines_count = 0;
|
||||
|
||||
count_spaces();
|
||||
|
||||
// count lines
|
||||
m_endlines.clear();
|
||||
while (last_end < text.length() - 1)
|
||||
{
|
||||
size_t next_hard_end = text.find_first_of('\n', last_end);
|
||||
if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset) {
|
||||
size_t next_hard_end = text.find_first_of('\n', last_end);
|
||||
if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset) {
|
||||
//next line is ended by '/n'
|
||||
m_endlines.push_back(next_hard_end);
|
||||
last_end = next_hard_end + 1;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// find next suitable endline
|
||||
if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset) {
|
||||
// more than one line till end
|
||||
size_t next_space = text.find_first_of(' ', last_end);
|
||||
size_t next_space = text.find_first_of(' ', last_end);
|
||||
if (next_space > 0) {
|
||||
size_t next_space_candidate = text.find_first_of(' ', next_space + 1);
|
||||
size_t next_space_candidate = text.find_first_of(' ', next_space + 1);
|
||||
while (next_space_candidate > 0 && ImGui::CalcTextSize(text.substr(last_end, next_space_candidate - last_end).c_str()).x < m_window_width - m_window_width_offset) {
|
||||
next_space = next_space_candidate;
|
||||
next_space_candidate = text.find_first_of(' ', next_space + 1);
|
||||
|
|
@ -283,7 +287,8 @@ void NotificationManager::PopNotification::init()
|
|||
}
|
||||
m_endlines.push_back(last_end + letter_count);
|
||||
last_end += letter_count;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
m_endlines.push_back(next_space);
|
||||
last_end = next_space + 1;
|
||||
}
|
||||
|
|
@ -297,11 +302,22 @@ void NotificationManager::PopNotification::init()
|
|||
}
|
||||
m_lines_count++;
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationManager::PopNotification::init()
|
||||
{
|
||||
// Do not init closing notification
|
||||
if (is_finished())
|
||||
return;
|
||||
|
||||
count_spaces();
|
||||
count_lines();
|
||||
|
||||
if (m_lines_count == 3)
|
||||
m_multiline = true;
|
||||
m_notification_start = GLCanvas3D::timestamp_now();
|
||||
//if (m_state != EState::Hidden)
|
||||
// m_state = EState::Shown;
|
||||
if (m_state == EState::Unknown)
|
||||
m_state = EState::Shown;
|
||||
}
|
||||
void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui)
|
||||
{
|
||||
|
|
@ -324,8 +340,8 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons
|
|||
if (m_multiline) {
|
||||
|
||||
int last_end = 0;
|
||||
float starting_y = m_line_height/2;//10;
|
||||
float shift_y = m_line_height;// -m_line_height / 20;
|
||||
float starting_y = m_line_height/2;
|
||||
float shift_y = m_line_height;
|
||||
for (size_t i = 0; i < m_lines_count; i++) {
|
||||
std::string line = m_text1.substr(last_end , m_endlines[i] - last_end);
|
||||
if(i < m_lines_count - 1)
|
||||
|
|
@ -549,7 +565,7 @@ void NotificationManager::PopNotification::update(const NotificationData& n)
|
|||
m_text2 = n.text2;
|
||||
init();
|
||||
}
|
||||
bool NotificationManager::PopNotification::compare_text(const std::string& text)
|
||||
bool NotificationManager::PopNotification::compare_text(const std::string& text) const
|
||||
{
|
||||
std::wstring wt1 = boost::nowide::widen(m_text1);
|
||||
std::wstring wt2 = boost::nowide::widen(text);
|
||||
|
|
@ -579,9 +595,10 @@ bool NotificationManager::PopNotification::update_state(bool paused, const int64
|
|||
// reset timers - hovered state is set in render
|
||||
if (m_state == EState::Hovered) {
|
||||
m_current_fade_opacity = 1.0f;
|
||||
m_notification_start = now;
|
||||
m_state = EState::Unknown;
|
||||
init();
|
||||
// Timers when not fading
|
||||
} else if (m_state != EState::FadingOut && m_data.duration != 0 && !paused) {
|
||||
} else if (m_state != EState::NotFading && m_state != EState::FadingOut && m_data.duration != 0 && !paused) {
|
||||
int64_t up_time = now - m_notification_start;
|
||||
if (up_time >= m_data.duration * 1000) {
|
||||
m_state = EState::FadingOut;
|
||||
|
|
@ -785,53 +802,154 @@ bool NotificationManager::ExportFinishedNotification::on_text_click()
|
|||
void NotificationManager::ProgressBarNotification::init()
|
||||
{
|
||||
PopNotification::init();
|
||||
m_lines_count++;
|
||||
m_endlines.push_back(m_endlines.back());
|
||||
}
|
||||
void NotificationManager::ProgressBarNotification::count_spaces()
|
||||
{
|
||||
//determine line width
|
||||
m_line_height = ImGui::CalcTextSize("A").y;
|
||||
|
||||
m_left_indentation = m_line_height;
|
||||
if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) {
|
||||
std::string text;
|
||||
text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker);
|
||||
float picture_width = ImGui::CalcTextSize(text.c_str()).x;
|
||||
m_left_indentation = picture_width + m_line_height / 2;
|
||||
//m_lines_count++;
|
||||
if(m_lines_count >= 2) {
|
||||
m_lines_count = 3;
|
||||
m_multiline = true;
|
||||
while (m_endlines.size() < 3)
|
||||
m_endlines.push_back(m_endlines.back());
|
||||
} else {
|
||||
m_lines_count = 2;
|
||||
m_endlines.push_back(m_endlines.back());
|
||||
}
|
||||
m_window_width_offset = m_line_height * (m_has_cancel_button ? 6 : 4);
|
||||
m_window_width = m_line_height * 25;
|
||||
if(m_state == EState::Shown)
|
||||
m_state = EState::NotFading;
|
||||
}
|
||||
|
||||
|
||||
void NotificationManager::ProgressBarNotification::count_lines()
|
||||
{
|
||||
std::string text = m_text1 + " " + m_hypertext;
|
||||
size_t last_end = 0;
|
||||
m_lines_count = 0;
|
||||
|
||||
m_endlines.clear();
|
||||
while (last_end < text.length() - 1)
|
||||
{
|
||||
size_t next_hard_end = text.find_first_of('\n', last_end);
|
||||
if (next_hard_end != std::string::npos && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset) {
|
||||
//next line is ended by '/n'
|
||||
m_endlines.push_back(next_hard_end);
|
||||
last_end = next_hard_end + 1;
|
||||
}
|
||||
else {
|
||||
// find next suitable endline
|
||||
if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - m_window_width_offset) {
|
||||
// more than one line till end
|
||||
size_t next_space = text.find_first_of(' ', last_end);
|
||||
if (next_space > 0) {
|
||||
size_t next_space_candidate = text.find_first_of(' ', next_space + 1);
|
||||
while (next_space_candidate > 0 && ImGui::CalcTextSize(text.substr(last_end, next_space_candidate - last_end).c_str()).x < m_window_width - m_window_width_offset) {
|
||||
next_space = next_space_candidate;
|
||||
next_space_candidate = text.find_first_of(' ', next_space + 1);
|
||||
}
|
||||
// when one word longer than line. Or the last space is too early.
|
||||
if (ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x > m_window_width - m_window_width_offset ||
|
||||
ImGui::CalcTextSize(text.substr(last_end, next_space - last_end).c_str()).x < (m_window_width - m_window_width_offset) / 4 * 3
|
||||
) {
|
||||
float width_of_a = ImGui::CalcTextSize("a").x;
|
||||
int letter_count = (int)((m_window_width - m_window_width_offset) / width_of_a);
|
||||
while (last_end + letter_count < text.size() && ImGui::CalcTextSize(text.substr(last_end, letter_count).c_str()).x < m_window_width - m_window_width_offset) {
|
||||
letter_count++;
|
||||
}
|
||||
m_endlines.push_back(last_end + letter_count);
|
||||
last_end += letter_count;
|
||||
}
|
||||
else {
|
||||
m_endlines.push_back(next_space);
|
||||
last_end = next_space + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_endlines.push_back(text.length());
|
||||
last_end = text.length();
|
||||
}
|
||||
|
||||
}
|
||||
m_lines_count++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
|
||||
{
|
||||
// line1 - we do not print any more text than what fits on line 1. Line 2 is bar.
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 - win_size_y / 6 - m_line_height / 2);
|
||||
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
|
||||
if (m_has_cancel_button)
|
||||
render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
if (m_multiline) {
|
||||
// two lines text, one line bar
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(m_line_height / 4);
|
||||
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(m_line_height + m_line_height / 4);
|
||||
std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
|
||||
imgui.text(line.c_str());
|
||||
if (m_has_cancel_button)
|
||||
render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
} else {
|
||||
//one line text, one line bar
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(/*win_size_y / 2 - win_size_y / 6 -*/ m_line_height / 4);
|
||||
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
|
||||
if (m_has_cancel_button)
|
||||
render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
void NotificationManager::ProgressBarNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
|
||||
{
|
||||
ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);
|
||||
ImVec4 gray_color = ImVec4(.34f, .34f, .34f, 1.0f);
|
||||
ImVec2 lineEnd = ImVec2(win_pos_x - m_window_width_offset, win_pos_y + win_size_y / 2 + m_line_height / 4);
|
||||
ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y / 2 + m_line_height / 4);
|
||||
ImVec2 lineEnd = ImVec2(win_pos_x - m_window_width_offset, win_pos_y + win_size_y / 2 + (m_multiline ? m_line_height / 2 : 0));
|
||||
ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y / 2 + (m_multiline ? m_line_height / 2 : 0));
|
||||
ImVec2 midPoint = ImVec2(lineStart.x + (lineEnd.x - lineStart.x) * m_percentage, lineStart.y);
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(gray_color.x * 255), (int)(gray_color.y * 255), (int)(gray_color.z * 255), (1.0f * 255.f)), m_line_height * 0.2f);
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, midPoint, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.2f);
|
||||
}
|
||||
//------PrintHostUploadNotification----------------
|
||||
void NotificationManager::PrintHostUploadNotification::init()
|
||||
{
|
||||
ProgressBarNotification::init();
|
||||
if (m_state == EState::NotFading && m_uj_state == UploadJobState::PB_COMPLETED)
|
||||
m_state = EState::Shown;
|
||||
}
|
||||
void NotificationManager::PrintHostUploadNotification::count_spaces()
|
||||
{
|
||||
//determine line width
|
||||
m_line_height = ImGui::CalcTextSize("A").y;
|
||||
|
||||
m_left_indentation = m_line_height;
|
||||
if (m_uj_state == UploadJobState::PB_ERROR) {
|
||||
std::string text;
|
||||
text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker);
|
||||
float picture_width = ImGui::CalcTextSize(text.c_str()).x;
|
||||
m_left_indentation = picture_width + m_line_height / 2;
|
||||
}
|
||||
m_window_width_offset = m_line_height * 6; //(m_has_cancel_button ? 6 : 4);
|
||||
m_window_width = m_line_height * 25;
|
||||
}
|
||||
bool NotificationManager::PrintHostUploadNotification::push_background_color()
|
||||
{
|
||||
|
||||
if (m_uj_state == UploadJobState::PB_ERROR) {
|
||||
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
|
||||
backcolor.x += 0.3f;
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void NotificationManager::PrintHostUploadNotification::set_percentage(float percent)
|
||||
{
|
||||
m_percentage = percent;
|
||||
if (percent >= 1.0f) {
|
||||
m_uj_state = UploadJobState::PB_COMPLETED;
|
||||
m_has_cancel_button = false;
|
||||
init();
|
||||
} else if (percent < 0.0f) {
|
||||
error();
|
||||
} else {
|
||||
|
|
@ -846,34 +964,44 @@ void NotificationManager::PrintHostUploadNotification::render_bar(ImGuiWrapper&
|
|||
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_PROGRESS:
|
||||
{
|
||||
ProgressBarNotification::render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
float uploaded = m_file_size / 100 * m_percentage;
|
||||
float uploaded = m_file_size * m_percentage;
|
||||
std::stringstream stream;
|
||||
stream << std::fixed << std::setprecision(2) << (int)(m_percentage * 100) << "% - " << uploaded << " of " << m_file_size << "MB uploaded";
|
||||
text = stream.str();
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 /*- m_line_height / 4 * 3*/);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? 0 : m_line_height / 4));
|
||||
break;
|
||||
}
|
||||
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_ERROR:
|
||||
text = _u8L("ERROR");
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? m_line_height / 4 : m_line_height / 2));
|
||||
break;
|
||||
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_CANCELLED:
|
||||
text = _u8L("CANCELED");
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? m_line_height / 4 : m_line_height / 2));
|
||||
break;
|
||||
case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_COMPLETED:
|
||||
text = _u8L("COMPLETED");
|
||||
ImGui::SetCursorPosX(m_left_indentation);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2);
|
||||
ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? m_line_height / 4 : m_line_height / 2));
|
||||
break;
|
||||
}
|
||||
|
||||
imgui.text(text.c_str());
|
||||
|
||||
}
|
||||
void NotificationManager::PrintHostUploadNotification::render_left_sign(ImGuiWrapper& imgui)
|
||||
{
|
||||
if (m_uj_state == UploadJobState::PB_ERROR) {
|
||||
std::string text;
|
||||
text = ImGui::ErrorMarker;
|
||||
ImGui::SetCursorPosX(m_line_height / 3);
|
||||
ImGui::SetCursorPosY(m_window_height / 2 - m_line_height);
|
||||
imgui.text(text.c_str());
|
||||
}
|
||||
}
|
||||
void NotificationManager::PrintHostUploadNotification::render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
|
||||
{
|
||||
ImVec2 win_size(win_size_x, win_size_y);
|
||||
|
|
@ -1059,6 +1187,14 @@ void NotificationManager::close_slicing_errors_and_warnings()
|
|||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::close_slicing_error_notification(const std::string& text)
|
||||
{
|
||||
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::SlicingError && notification->compare_text(_u8L("ERROR:") + "\n" + text)) {
|
||||
notification->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::push_slicing_complete_notification(int timestamp, bool large)
|
||||
{
|
||||
std::string hypertext;
|
||||
|
|
@ -1122,39 +1258,53 @@ void NotificationManager::push_exporting_finished_notification(const std::string
|
|||
|
||||
void NotificationManager::push_upload_job_notification(int id, float filesize, const std::string& filename, const std::string& host, float percentage)
|
||||
{
|
||||
// find if upload with same id was not already in notification
|
||||
// done by compare_jon_id not compare_text thus has to be performed here
|
||||
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PrintHostUpload && dynamic_cast<PrintHostUploadNotification*>(notification.get())->compare_job_id(id)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
|
||||
NotificationData data{ NotificationType::PrintHostUpload, NotificationLevel::ProgressBarNotification, 0, text };
|
||||
NotificationData data{ NotificationType::PrintHostUpload, NotificationLevel::ProgressBarNotification, 10, text };
|
||||
push_notification_data(std::make_unique<NotificationManager::PrintHostUploadNotification>(data, m_id_provider, m_evt_handler, 0, id, filesize), 0);
|
||||
}
|
||||
void NotificationManager::set_upload_job_notification_percentage(int id, const std::string& filename, const std::string& host, float percentage)
|
||||
{
|
||||
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
|
||||
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PrintHostUpload && notification->compare_text(text)) {
|
||||
dynamic_cast<PrintHostUploadNotification*>(notification.get())->set_percentage(percentage);
|
||||
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
|
||||
if (notification->get_type() == NotificationType::PrintHostUpload) {
|
||||
PrintHostUploadNotification* phun = dynamic_cast<PrintHostUploadNotification*>(notification.get());
|
||||
if (phun->compare_job_id(id)) {
|
||||
phun->set_percentage(percentage);
|
||||
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host)
|
||||
{
|
||||
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
|
||||
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PrintHostUpload && notification->compare_text(text)) {
|
||||
dynamic_cast<PrintHostUploadNotification*>(notification.get())->cancel();
|
||||
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
|
||||
break;
|
||||
if (notification->get_type() == NotificationType::PrintHostUpload) {
|
||||
PrintHostUploadNotification* phun = dynamic_cast<PrintHostUploadNotification*>(notification.get());
|
||||
if (phun->compare_job_id(id)) {
|
||||
phun->cancel();
|
||||
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::upload_job_notification_show_error(int id, const std::string& filename, const std::string& host)
|
||||
{
|
||||
std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host);
|
||||
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PrintHostUpload && notification->compare_text(text)) {
|
||||
dynamic_cast<PrintHostUploadNotification*>(notification.get())->error();
|
||||
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
|
||||
break;
|
||||
if (notification->get_type() == NotificationType::PrintHostUpload) {
|
||||
PrintHostUploadNotification* phun = dynamic_cast<PrintHostUploadNotification*>(notification.get());
|
||||
if(phun->compare_job_id(id)) {
|
||||
phun->error();
|
||||
wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ public:
|
|||
// void set_slicing_warning_gray(const std::string& text, bool g);
|
||||
// immediately stops showing slicing errors
|
||||
void close_slicing_errors_and_warnings();
|
||||
void close_slicing_error_notification(const std::string& text);
|
||||
// Release those slicing warnings, which refer to an ObjectID, which is not in the list.
|
||||
// living_oids is expected to be sorted.
|
||||
void remove_slicing_warnings_of_released_objects(const std::vector<ObjectID>& living_oids);
|
||||
|
|
@ -207,6 +208,7 @@ private:
|
|||
Unknown, // NOT initialized
|
||||
Hidden,
|
||||
Shown, // Requesting Render at some time if duration != 0
|
||||
NotFading, // Never jumps to state Fading out even if duration says so
|
||||
FadingOut, // Requesting Render at some time
|
||||
ClosePending, // Requesting Render
|
||||
Finished, // Requesting Render
|
||||
|
|
@ -230,18 +232,17 @@ private:
|
|||
const NotificationData get_data() const { return m_data; }
|
||||
const bool is_gray() const { return m_is_gray; }
|
||||
void set_gray(bool g) { m_is_gray = g; }
|
||||
bool compare_text(const std::string& text);
|
||||
virtual bool compare_text(const std::string& text) const;
|
||||
void hide(bool h) { if (is_finished()) return; m_state = h ? EState::Hidden : EState::Unknown; }
|
||||
// sets m_next_render with time of next mandatory rendering. Delta is time since last render.
|
||||
bool update_state(bool paused, const int64_t delta);
|
||||
int64_t next_render() const { return is_finished() ? 0 : m_next_render; }
|
||||
EState get_state() const { return m_state; }
|
||||
bool is_hovered() const { return m_state == EState::Hovered; }
|
||||
|
||||
void set_hovered() { if (m_state != EState::Finished && m_state != EState::ClosePending && m_state != EState::Hidden && m_state != EState::Unknown) m_state = EState::Hovered; }
|
||||
protected:
|
||||
// Call after every size change
|
||||
virtual void init();
|
||||
// Part of init()
|
||||
virtual void count_spaces();
|
||||
// Calculetes correct size but not se it in imgui!
|
||||
virtual void set_next_window_size(ImGuiWrapper& imgui);
|
||||
virtual void render_text(ImGuiWrapper& imgui,
|
||||
|
|
@ -255,13 +256,20 @@ private:
|
|||
const std::string text,
|
||||
bool more = false);
|
||||
// Left sign could be error or warning sign
|
||||
void render_left_sign(ImGuiWrapper& imgui);
|
||||
virtual void render_left_sign(ImGuiWrapper& imgui);
|
||||
virtual void render_minimize_button(ImGuiWrapper& imgui,
|
||||
const float win_pos_x, const float win_pos_y);
|
||||
// Hypertext action, returns true if notification should close.
|
||||
// Action is stored in NotificationData::callback as std::function<bool(wxEvtHandler*)>
|
||||
virtual bool on_text_click();
|
||||
protected:
|
||||
|
||||
// Part of init(), counts horizontal spacing like left indentation
|
||||
virtual void count_spaces();
|
||||
// Part of init(), counts end lines
|
||||
virtual void count_lines();
|
||||
// returns true if PopStyleColor should be called later to pop this push
|
||||
virtual bool push_background_color();
|
||||
|
||||
const NotificationData m_data;
|
||||
// For reusing ImGUI windows.
|
||||
NotificationIDProvider &m_id_provider;
|
||||
|
|
@ -364,7 +372,8 @@ private:
|
|||
virtual void set_percentage(float percent) { m_percentage = percent; }
|
||||
protected:
|
||||
virtual void init() override;
|
||||
virtual void count_spaces() override;
|
||||
virtual void count_lines() override;
|
||||
|
||||
virtual void render_text(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y) override;
|
||||
|
|
@ -375,6 +384,8 @@ private:
|
|||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y)
|
||||
{}
|
||||
virtual void render_minimize_button(ImGuiWrapper& imgui,
|
||||
const float win_pos_x, const float win_pos_y) override {}
|
||||
float m_percentage;
|
||||
|
||||
bool m_has_cancel_button {false};
|
||||
|
|
@ -401,17 +412,23 @@ private:
|
|||
{
|
||||
m_has_cancel_button = true;
|
||||
}
|
||||
static std::string get_upload_job_text(int id, const std::string& filename, const std::string& host) { return "[" + std::to_string(id) + "] " + filename + " -> " + host; }
|
||||
static std::string get_upload_job_text(int id, const std::string& filename, const std::string& host) { return /*"[" + std::to_string(id) + "] " + */filename + " -> " + host; }
|
||||
virtual void set_percentage(float percent) override;
|
||||
void cancel() { m_uj_state = UploadJobState::PB_CANCELLED; m_has_cancel_button = false; }
|
||||
void error() { m_uj_state = UploadJobState::PB_ERROR; m_has_cancel_button = false; }
|
||||
void error() { m_uj_state = UploadJobState::PB_ERROR; m_has_cancel_button = false; init(); }
|
||||
bool compare_job_id(const int other_id) const { return m_job_id == other_id; }
|
||||
virtual bool compare_text(const std::string& text) const override { return false; }
|
||||
protected:
|
||||
virtual void init() override;
|
||||
virtual void count_spaces() override;
|
||||
virtual bool push_background_color() override;
|
||||
virtual void render_bar(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y) override;
|
||||
virtual void render_cancel_button(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y) override;
|
||||
virtual void render_left_sign(ImGuiWrapper& imgui) override;
|
||||
// Identifies job in cancel callback
|
||||
int m_job_id;
|
||||
// Size of uploaded size to be displayed in MB
|
||||
|
|
|
|||
|
|
@ -47,6 +47,19 @@ void ObjectDataViewModelNode::init_container()
|
|||
static constexpr char LayerRootIcon[] = "edit_layers_all";
|
||||
static constexpr char LayerIcon[] = "edit_layers_some";
|
||||
static constexpr char WarningIcon[] = "exclamation";
|
||||
static constexpr char InfoIcon[] = "info";
|
||||
|
||||
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const InfoItemType info_type) :
|
||||
m_parent(parent),
|
||||
m_type(itInfo),
|
||||
m_extruder(wxEmptyString)
|
||||
{
|
||||
m_name = info_type == InfoItemType::CustomSupports ? _L("Paint-on supports")
|
||||
: info_type == InfoItemType::CustomSeam ? _L("Paint-on seam")
|
||||
: _L("Variable layer height");
|
||||
m_info_item_type = info_type;
|
||||
}
|
||||
|
||||
|
||||
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) :
|
||||
m_parent(parent),
|
||||
|
|
@ -69,6 +82,8 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
|
|||
m_bmp = create_scaled_bitmap(LayerRootIcon); // FIXME: pass window ptr
|
||||
m_name = _(L("Layers"));
|
||||
}
|
||||
else if (type == itInfo)
|
||||
assert(false);
|
||||
|
||||
if (type & (itInstanceRoot | itLayerRoot))
|
||||
init_container();
|
||||
|
|
@ -250,6 +265,7 @@ ObjectDataViewModel::ObjectDataViewModel()
|
|||
|
||||
m_volume_bmps = MenuFactory::get_volume_bitmaps();
|
||||
m_warning_bmp = create_scaled_bitmap(WarningIcon);
|
||||
m_info_bmp = create_scaled_bitmap(InfoIcon);
|
||||
}
|
||||
|
||||
ObjectDataViewModel::~ObjectDataViewModel()
|
||||
|
|
@ -330,12 +346,37 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
|
|||
return child;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddInfoChild(const wxDataViewItem &parent_item, InfoItemType info_type)
|
||||
{
|
||||
ObjectDataViewModelNode *root = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
|
||||
if (!root) return wxDataViewItem(0);
|
||||
|
||||
const auto node = new ObjectDataViewModelNode(root, info_type);
|
||||
|
||||
// The new item should be added according to its order in InfoItemType.
|
||||
// Find last info item with lower index and append after it.
|
||||
const auto& children = root->GetChildren();
|
||||
int idx = -1;
|
||||
for (int i=0; i<int(children.size()); ++i) {
|
||||
if (children[i]->GetType() == itInfo && int(children[i]->GetInfoItemType()) < int(info_type) )
|
||||
idx = i;
|
||||
}
|
||||
|
||||
root->Insert(node, idx+1);
|
||||
node->SetBitmap(m_info_bmp);
|
||||
// notify control
|
||||
const wxDataViewItem child((void*)node);
|
||||
ItemAdded(parent_item, child);
|
||||
return child;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &parent_item)
|
||||
{
|
||||
ObjectDataViewModelNode *root = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
|
||||
if (!root) return wxDataViewItem(0);
|
||||
|
||||
const auto node = new ObjectDataViewModelNode(root, itSettings);
|
||||
|
||||
root->Insert(node, 0);
|
||||
// notify control
|
||||
const wxDataViewItem child((void*)node);
|
||||
|
|
@ -1379,6 +1420,14 @@ ItemType ObjectDataViewModel::GetItemType(const wxDataViewItem &item) const
|
|||
return node->m_type < 0 ? itUndef : node->m_type;
|
||||
}
|
||||
|
||||
InfoItemType ObjectDataViewModel::GetInfoItemType(const wxDataViewItem &item) const
|
||||
{
|
||||
if (!item.IsOk())
|
||||
return InfoItemType::Undef;
|
||||
ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(item.GetID());
|
||||
return node->m_info_item_type;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const
|
||||
{
|
||||
if (!parent_item.IsOk())
|
||||
|
|
@ -1411,6 +1460,21 @@ wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item)
|
|||
return GetItemByType(item, itLayerRoot);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetInfoItemByType(const wxDataViewItem &parent_item, InfoItemType type) const
|
||||
{
|
||||
if (! parent_item.IsOk())
|
||||
return wxDataViewItem(0);
|
||||
|
||||
ObjectDataViewModelNode *node = static_cast<ObjectDataViewModelNode*>(parent_item.GetID());
|
||||
for (size_t i = 0; i < node->GetChildCount(); i++) {
|
||||
const ObjectDataViewModelNode* child_node = node->GetNthChild(i);
|
||||
if (child_node->m_type == itInfo && child_node->m_info_item_type == type)
|
||||
return wxDataViewItem((void*)child_node);
|
||||
}
|
||||
|
||||
return wxDataViewItem(0); // not found
|
||||
}
|
||||
|
||||
bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
|
||||
{
|
||||
if (!item.IsOk())
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ enum ItemType {
|
|||
itSettings = 16,
|
||||
itLayerRoot = 32,
|
||||
itLayer = 64,
|
||||
itInfo = 128
|
||||
};
|
||||
|
||||
enum ColumnNumber
|
||||
|
|
@ -44,6 +45,14 @@ enum PrintIndicator
|
|||
piUnprintable , // unprintable
|
||||
};
|
||||
|
||||
enum class InfoItemType
|
||||
{
|
||||
Undef,
|
||||
CustomSupports,
|
||||
CustomSeam,
|
||||
VariableLayerHeight
|
||||
};
|
||||
|
||||
class ObjectDataViewModelNode;
|
||||
WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray);
|
||||
|
||||
|
|
@ -69,6 +78,7 @@ class ObjectDataViewModelNode
|
|||
|
||||
std::string m_action_icon_name = "";
|
||||
ModelVolumeType m_volume_type;
|
||||
InfoItemType m_info_item_type {InfoItemType::Undef};
|
||||
|
||||
public:
|
||||
ObjectDataViewModelNode(const wxString& name,
|
||||
|
|
@ -104,6 +114,7 @@ public:
|
|||
const wxString& extruder = wxEmptyString );
|
||||
|
||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
|
||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const InfoItemType type);
|
||||
|
||||
~ObjectDataViewModelNode()
|
||||
{
|
||||
|
|
@ -176,6 +187,7 @@ public:
|
|||
const wxBitmap& GetBitmap() const { return m_bmp; }
|
||||
const wxString& GetName() const { return m_name; }
|
||||
ItemType GetType() const { return m_type; }
|
||||
InfoItemType GetInfoItemType() const { return m_info_item_type; }
|
||||
void SetIdx(const int& idx);
|
||||
int GetIdx() const { return m_idx; }
|
||||
ModelVolumeType GetVolumeType() { return m_volume_type; }
|
||||
|
|
@ -244,6 +256,7 @@ class ObjectDataViewModel :public wxDataViewModel
|
|||
std::vector<ObjectDataViewModelNode*> m_objects;
|
||||
std::vector<wxBitmap> m_volume_bmps;
|
||||
wxBitmap m_warning_bmp;
|
||||
wxBitmap m_info_bmp;
|
||||
|
||||
wxDataViewCtrl* m_ctrl { nullptr };
|
||||
|
||||
|
|
@ -261,6 +274,7 @@ public:
|
|||
const int extruder = 0,
|
||||
const bool create_frst_child = true);
|
||||
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
|
||||
wxDataViewItem AddInfoChild(const wxDataViewItem &parent_item, InfoItemType info_type);
|
||||
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
|
||||
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector<bool>& print_indicator);
|
||||
wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
|
||||
|
|
@ -335,12 +349,15 @@ public:
|
|||
// In our case it is an item with all columns
|
||||
bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; }
|
||||
|
||||
ItemType GetItemType(const wxDataViewItem &item) const ;
|
||||
ItemType GetItemType(const wxDataViewItem &item) const;
|
||||
InfoItemType GetInfoItemType(const wxDataViewItem &item) const;
|
||||
wxDataViewItem GetItemByType( const wxDataViewItem &parent_item,
|
||||
ItemType type) const;
|
||||
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
|
||||
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
|
||||
wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
|
||||
wxDataViewItem GetInfoItemByType(const wxDataViewItem &parent_item, InfoItemType type) const;
|
||||
|
||||
bool IsSettingsItem(const wxDataViewItem &item) const;
|
||||
void UpdateSettingsDigest( const wxDataViewItem &item,
|
||||
const std::vector<std::string>& categories);
|
||||
|
|
|
|||
|
|
@ -90,22 +90,24 @@ float OpenGLManager::GLInfo::get_max_anisotropy() const
|
|||
|
||||
void OpenGLManager::GLInfo::detect() const
|
||||
{
|
||||
m_version = gl_get_string_safe(GL_VERSION, "N/A");
|
||||
m_glsl_version = gl_get_string_safe(GL_SHADING_LANGUAGE_VERSION, "N/A");
|
||||
m_vendor = gl_get_string_safe(GL_VENDOR, "N/A");
|
||||
m_renderer = gl_get_string_safe(GL_RENDERER, "N/A");
|
||||
*const_cast<std::string*>(&m_version) = gl_get_string_safe(GL_VERSION, "N/A");
|
||||
*const_cast<std::string*>(&m_glsl_version) = gl_get_string_safe(GL_SHADING_LANGUAGE_VERSION, "N/A");
|
||||
*const_cast<std::string*>(&m_vendor) = gl_get_string_safe(GL_VENDOR, "N/A");
|
||||
*const_cast<std::string*>(&m_renderer) = gl_get_string_safe(GL_RENDERER, "N/A");
|
||||
|
||||
glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_max_tex_size));
|
||||
int* max_tex_size = const_cast<int*>(&m_max_tex_size);
|
||||
glsafe(::glGetIntegerv(GL_MAX_TEXTURE_SIZE, max_tex_size));
|
||||
|
||||
m_max_tex_size /= 2;
|
||||
*max_tex_size /= 2;
|
||||
|
||||
if (Slic3r::total_physical_memory() / (1024 * 1024 * 1024) < 6)
|
||||
m_max_tex_size /= 2;
|
||||
*max_tex_size /= 2;
|
||||
|
||||
if (GLEW_EXT_texture_filter_anisotropic)
|
||||
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &m_max_anisotropy));
|
||||
|
||||
m_detected = true;
|
||||
if (GLEW_EXT_texture_filter_anisotropic) {
|
||||
float* max_anisotropy = const_cast<float*>(&m_max_anisotropy);
|
||||
glsafe(::glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, max_anisotropy));
|
||||
}
|
||||
*const_cast<bool*>(&m_detected) = true;
|
||||
}
|
||||
|
||||
static bool version_greater_or_equal_to(const std::string& version, unsigned int major, unsigned int minor)
|
||||
|
|
@ -174,19 +176,16 @@ std::string OpenGLManager::GLInfo::to_string(bool format_as_html, bool extension
|
|||
out << b_start << "Renderer: " << b_end << m_renderer << line_end;
|
||||
out << b_start << "GLSL version: " << b_end << m_glsl_version << line_end;
|
||||
|
||||
if (extensions)
|
||||
{
|
||||
if (extensions) {
|
||||
std::vector<std::string> extensions_list;
|
||||
std::string extensions_str = gl_get_string_safe(GL_EXTENSIONS, "");
|
||||
boost::split(extensions_list, extensions_str, boost::is_any_of(" "), boost::token_compress_off);
|
||||
|
||||
if (!extensions_list.empty())
|
||||
{
|
||||
if (!extensions_list.empty()) {
|
||||
out << h2_start << "Installed extensions:" << h2_end << line_end;
|
||||
|
||||
std::sort(extensions_list.begin(), extensions_list.end());
|
||||
for (const std::string& ext : extensions_list)
|
||||
{
|
||||
for (const std::string& ext : extensions_list) {
|
||||
out << ext << line_end;
|
||||
}
|
||||
}
|
||||
|
|
@ -252,7 +251,7 @@ bool OpenGLManager::init_gl()
|
|||
message += _L("You may need to update your graphics card driver.");
|
||||
#ifdef _WIN32
|
||||
message += "\n";
|
||||
message += _L("As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw_renderer parameter.");
|
||||
message += _L("As a workaround, you may run PrusaSlicer with a software rendered 3D graphics by running prusa-slicer.exe with the --sw-renderer parameter.");
|
||||
#endif
|
||||
wxMessageBox(message, wxString("PrusaSlicer - ") + _L("Unsupported OpenGL version"), wxOK | wxICON_ERROR);
|
||||
}
|
||||
|
|
@ -304,8 +303,7 @@ wxGLCanvas* OpenGLManager::create_wxglcanvas(wxWindow& parent)
|
|||
0
|
||||
};
|
||||
|
||||
if (s_multisample == EMultisampleState::Unknown)
|
||||
{
|
||||
if (s_multisample == EMultisampleState::Unknown) {
|
||||
detect_multisample(attribList);
|
||||
// // debug output
|
||||
// std::cout << "Multisample " << (can_multisample() ? "enabled" : "disabled") << std::endl;
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@ public:
|
|||
|
||||
class GLInfo
|
||||
{
|
||||
mutable bool m_detected{ false };
|
||||
mutable int m_max_tex_size{ 0 };
|
||||
mutable float m_max_anisotropy{ 0.0f };
|
||||
bool m_detected{ false };
|
||||
int m_max_tex_size{ 0 };
|
||||
float m_max_anisotropy{ 0.0f };
|
||||
|
||||
mutable std::string m_version;
|
||||
mutable std::string m_glsl_version;
|
||||
mutable std::string m_vendor;
|
||||
mutable std::string m_renderer;
|
||||
std::string m_version;
|
||||
std::string m_glsl_version;
|
||||
std::string m_vendor;
|
||||
std::string m_renderer;
|
||||
|
||||
public:
|
||||
GLInfo() = default;
|
||||
|
|
|
|||
|
|
@ -2407,6 +2407,29 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||
#endif /* AUTOPLACEMENT_ON_LOAD */
|
||||
}
|
||||
|
||||
#if ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG
|
||||
for (size_t i = 0; i < object->instances.size(); ++i) {
|
||||
ModelInstance* instance = object->instances[i];
|
||||
const Vec3d size = object->instance_bounding_box(i).size();
|
||||
const Vec3d ratio = size.cwiseQuotient(bed_size);
|
||||
const double max_ratio = std::max(ratio(0), ratio(1));
|
||||
if (max_ratio > 10000) {
|
||||
// the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
|
||||
// so scale down the mesh
|
||||
double inv = 1. / max_ratio;
|
||||
object->scale_mesh_after_creation(inv * Vec3d::Ones());
|
||||
object->origin_translation = Vec3d::Zero();
|
||||
object->center_around_origin();
|
||||
scaled_down = true;
|
||||
break;
|
||||
}
|
||||
else if (max_ratio > 5) {
|
||||
const Vec3d inverse = 1.0 / max_ratio * Vec3d::Ones();
|
||||
instance->set_scaling_factor(inverse.cwiseProduct(instance->get_scaling_factor()));
|
||||
scaled_down = true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
const Vec3d size = object->bounding_box().size();
|
||||
const Vec3d ratio = size.cwiseQuotient(bed_size);
|
||||
const double max_ratio = std::max(ratio(0), ratio(1));
|
||||
|
|
@ -2425,6 +2448,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||
}
|
||||
scaled_down = true;
|
||||
}
|
||||
#endif // ENABLE_MODIFIED_DOWNSCALE_ON_LOAD_OBJECTS_TOO_BIG
|
||||
|
||||
object->ensure_on_bed();
|
||||
}
|
||||
|
|
@ -4943,6 +4967,12 @@ void Plater::convert_unit(ConversionType conv_type)
|
|||
}
|
||||
}
|
||||
|
||||
void Plater::toggle_layers_editing(bool enable)
|
||||
{
|
||||
if (canvas3D()->is_layers_editing_enabled() != enable)
|
||||
wxPostEvent(canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING));
|
||||
}
|
||||
|
||||
void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper, bool keep_lower, bool rotate_lower)
|
||||
{
|
||||
wxCHECK_RET(obj_idx < p->model.objects.size(), "obj_idx out of bounds");
|
||||
|
|
|
|||
|
|
@ -191,6 +191,7 @@ public:
|
|||
bool is_selection_empty() const;
|
||||
void scale_selection_to_fit_print_volume();
|
||||
void convert_unit(ConversionType conv_type);
|
||||
void toggle_layers_editing(bool enable);
|
||||
|
||||
void cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include <wx/dataview.h>
|
||||
#include <wx/wupdlock.h>
|
||||
#include <wx/debug.h>
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
|
@ -68,8 +69,10 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
|
|||
combo_groups->SetValue(recent_group);
|
||||
}
|
||||
|
||||
btn_sizer->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL));
|
||||
|
||||
auto* szr = CreateStdDialogButtonSizer(wxOK | wxCANCEL);
|
||||
auto* btn_ok = szr->GetAffirmativeButton();
|
||||
btn_sizer->Add(szr);
|
||||
|
||||
wxString recent_path = from_u8(app_config->get("recent", CONFIG_KEY_PATH));
|
||||
if (recent_path.Length() > 0 && recent_path[recent_path.Length() - 1] != '/') {
|
||||
recent_path += '/';
|
||||
|
|
@ -82,6 +85,20 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, bool can_start_pr
|
|||
txt_filename->SetValue(recent_path);
|
||||
txt_filename->SetFocus();
|
||||
|
||||
wxString suffix = recent_path.substr(recent_path.find_last_of('.'));
|
||||
|
||||
btn_ok->Bind(wxEVT_BUTTON, [this, suffix](wxCommandEvent&) {
|
||||
wxString path = txt_filename->GetValue();
|
||||
// .gcode suffix control
|
||||
if (!path.Lower().EndsWith(suffix.Lower()))
|
||||
{
|
||||
wxMessageDialog msg_wingow(this, wxString::Format(_L("Upload filename doesn't end with \"%s\". Do you wish to continue?"), suffix), wxString(SLIC3R_APP_NAME), wxYES | wxNO);
|
||||
if (msg_wingow.ShowModal() == wxID_NO)
|
||||
return;
|
||||
}
|
||||
EndDialog(wxID_OK);
|
||||
});
|
||||
|
||||
Fit();
|
||||
CenterOnParent();
|
||||
|
||||
|
|
|
|||
|
|
@ -80,7 +80,9 @@ static void unmount_callback(DADiskRef disk, DADissenterRef dissenter, void *con
|
|||
NSLog(@"-%@",(CFStringRef)deviceModelKey);
|
||||
*/
|
||||
if (mediaEjectableKey != nullptr) {
|
||||
BOOL op = ejectable && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceModelKey, CFSTR("SD Card Reader")) || CFEqual(deviceProtocolName, CFSTR("Secure Digital")));
|
||||
BOOL op = ejectable &&
|
||||
( (deviceProtocolName != nullptr && (CFEqual(deviceProtocolName, CFSTR("USB")) || CFEqual(deviceProtocolName, CFSTR("Secure Digital")))) ||
|
||||
(deviceModelKey != nullptr && CFEqual(deviceModelKey, CFSTR("SD Card Reader"))) );
|
||||
//!CFEqual(deviceModelKey, CFSTR("Disk Image"));
|
||||
if (op)
|
||||
[result addObject:volURL.path];
|
||||
|
|
|
|||
|
|
@ -1102,39 +1102,32 @@ void Selection::erase()
|
|||
|
||||
if (is_single_full_object())
|
||||
wxGetApp().obj_list()->delete_from_model_and_list(ItemType::itObject, get_object_idx(), 0);
|
||||
else if (is_multiple_full_object())
|
||||
{
|
||||
else if (is_multiple_full_object()) {
|
||||
std::vector<ItemForDelete> items;
|
||||
items.reserve(m_cache.content.size());
|
||||
for (ObjectIdxsToInstanceIdxsMap::iterator it = m_cache.content.begin(); it != m_cache.content.end(); ++it)
|
||||
{
|
||||
for (ObjectIdxsToInstanceIdxsMap::iterator it = m_cache.content.begin(); it != m_cache.content.end(); ++it) {
|
||||
items.emplace_back(ItemType::itObject, it->first, 0);
|
||||
}
|
||||
wxGetApp().obj_list()->delete_from_model_and_list(items);
|
||||
}
|
||||
else if (is_multiple_full_instance())
|
||||
{
|
||||
else if (is_multiple_full_instance()) {
|
||||
std::set<std::pair<int, int>> instances_idxs;
|
||||
for (ObjectIdxsToInstanceIdxsMap::iterator obj_it = m_cache.content.begin(); obj_it != m_cache.content.end(); ++obj_it)
|
||||
{
|
||||
for (InstanceIdxsList::reverse_iterator inst_it = obj_it->second.rbegin(); inst_it != obj_it->second.rend(); ++inst_it)
|
||||
{
|
||||
for (ObjectIdxsToInstanceIdxsMap::iterator obj_it = m_cache.content.begin(); obj_it != m_cache.content.end(); ++obj_it) {
|
||||
for (InstanceIdxsList::reverse_iterator inst_it = obj_it->second.rbegin(); inst_it != obj_it->second.rend(); ++inst_it) {
|
||||
instances_idxs.insert(std::make_pair(obj_it->first, *inst_it));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ItemForDelete> items;
|
||||
items.reserve(instances_idxs.size());
|
||||
for (const std::pair<int, int>& i : instances_idxs)
|
||||
{
|
||||
for (const std::pair<int, int>& i : instances_idxs) {
|
||||
items.emplace_back(ItemType::itInstance, i.first, i.second);
|
||||
}
|
||||
wxGetApp().obj_list()->delete_from_model_and_list(items);
|
||||
}
|
||||
else if (is_single_full_instance())
|
||||
wxGetApp().obj_list()->delete_from_model_and_list(ItemType::itInstance, get_object_idx(), get_instance_idx());
|
||||
else if (is_mixed())
|
||||
{
|
||||
else if (is_mixed()) {
|
||||
std::set<ItemForDelete> items_set;
|
||||
std::map<int, int> volumes_in_obj;
|
||||
|
||||
|
|
@ -1186,11 +1179,9 @@ void Selection::erase()
|
|||
|
||||
wxGetApp().obj_list()->delete_from_model_and_list(items);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
std::set<std::pair<int, int>> volumes_idxs;
|
||||
for (unsigned int i : m_list)
|
||||
{
|
||||
for (unsigned int i : m_list) {
|
||||
const GLVolume* v = (*m_volumes)[i];
|
||||
// Only remove volumes associated with ModelVolumes from the object list.
|
||||
// Temporary meshes (SLA supports or pads) are not managed by the object list.
|
||||
|
|
@ -1200,8 +1191,7 @@ void Selection::erase()
|
|||
|
||||
std::vector<ItemForDelete> items;
|
||||
items.reserve(volumes_idxs.size());
|
||||
for (const std::pair<int, int>& v : volumes_idxs)
|
||||
{
|
||||
for (const std::pair<int, int>& v : volumes_idxs) {
|
||||
items.emplace_back(ItemType::itVolume, v.first, v.second);
|
||||
}
|
||||
|
||||
|
|
@ -1214,7 +1204,7 @@ void Selection::render(float scale_factor) const
|
|||
if (!m_valid || is_empty())
|
||||
return;
|
||||
|
||||
m_scale_factor = scale_factor;
|
||||
*const_cast<float*>(&m_scale_factor) = scale_factor;
|
||||
|
||||
// render cumulative bounding box of selected volumes
|
||||
render_selected_volumes();
|
||||
|
|
@ -1224,7 +1214,7 @@ void Selection::render(float scale_factor) const
|
|||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
void Selection::render_center(bool gizmo_is_dragging) const
|
||||
{
|
||||
if (!m_valid || is_empty() || (m_quadric == nullptr))
|
||||
if (!m_valid || is_empty() || m_quadric == nullptr)
|
||||
return;
|
||||
|
||||
Vec3d center = gizmo_is_dragging ? m_cache.dragging_center : get_bounding_box().center();
|
||||
|
|
@ -1250,8 +1240,7 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const
|
|||
|
||||
GLShaderProgram* shader = nullptr;
|
||||
|
||||
if (!boost::starts_with(sidebar_field, "layer"))
|
||||
{
|
||||
if (!boost::starts_with(sidebar_field, "layer")) {
|
||||
shader = wxGetApp().get_shader("gouraud_light");
|
||||
if (shader == nullptr)
|
||||
return;
|
||||
|
|
@ -1735,18 +1724,16 @@ void Selection::do_remove_volume(unsigned int volume_idx)
|
|||
|
||||
void Selection::do_remove_instance(unsigned int object_idx, unsigned int instance_idx)
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) {
|
||||
GLVolume* v = (*m_volumes)[i];
|
||||
if ((v->object_idx() == (int)object_idx) && (v->instance_idx() == (int)instance_idx))
|
||||
if (v->object_idx() == (int)object_idx && v->instance_idx() == (int)instance_idx)
|
||||
do_remove_volume(i);
|
||||
}
|
||||
}
|
||||
|
||||
void Selection::do_remove_object(unsigned int object_idx)
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) {
|
||||
GLVolume* v = (*m_volumes)[i];
|
||||
if (v->object_idx() == (int)object_idx)
|
||||
do_remove_volume(i);
|
||||
|
|
@ -1755,47 +1742,48 @@ void Selection::do_remove_object(unsigned int object_idx)
|
|||
|
||||
void Selection::calc_bounding_box() const
|
||||
{
|
||||
m_bounding_box = BoundingBoxf3();
|
||||
if (m_valid)
|
||||
{
|
||||
for (unsigned int i : m_list)
|
||||
{
|
||||
m_bounding_box.merge((*m_volumes)[i]->transformed_convex_hull_bounding_box());
|
||||
BoundingBoxf3* bounding_box = const_cast<BoundingBoxf3*>(&m_bounding_box);
|
||||
*bounding_box = BoundingBoxf3();
|
||||
if (m_valid) {
|
||||
for (unsigned int i : m_list) {
|
||||
bounding_box->merge((*m_volumes)[i]->transformed_convex_hull_bounding_box());
|
||||
}
|
||||
}
|
||||
m_bounding_box_dirty = false;
|
||||
*const_cast<bool*>(&m_bounding_box_dirty) = false;
|
||||
}
|
||||
|
||||
void Selection::calc_unscaled_instance_bounding_box() const
|
||||
{
|
||||
m_unscaled_instance_bounding_box = BoundingBoxf3();
|
||||
if (m_valid) {
|
||||
for (unsigned int i : m_list) {
|
||||
const GLVolume &volume = *(*m_volumes)[i];
|
||||
BoundingBoxf3* unscaled_instance_bounding_box = const_cast<BoundingBoxf3*>(&m_unscaled_instance_bounding_box);
|
||||
*unscaled_instance_bounding_box = BoundingBoxf3();
|
||||
if (m_valid) {
|
||||
for (unsigned int i : m_list) {
|
||||
const GLVolume& volume = *(*m_volumes)[i];
|
||||
if (volume.is_modifier)
|
||||
continue;
|
||||
Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, true, false) * volume.get_volume_transformation().get_matrix();
|
||||
trafo.translation()(2) += volume.get_sla_shift_z();
|
||||
m_unscaled_instance_bounding_box.merge(volume.transformed_convex_hull_bounding_box(trafo));
|
||||
}
|
||||
}
|
||||
m_unscaled_instance_bounding_box_dirty = false;
|
||||
Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, true, false) * volume.get_volume_transformation().get_matrix();
|
||||
trafo.translation()(2) += volume.get_sla_shift_z();
|
||||
unscaled_instance_bounding_box->merge(volume.transformed_convex_hull_bounding_box(trafo));
|
||||
}
|
||||
}
|
||||
*const_cast<bool*>(&m_unscaled_instance_bounding_box_dirty) = false;
|
||||
}
|
||||
|
||||
void Selection::calc_scaled_instance_bounding_box() const
|
||||
{
|
||||
m_scaled_instance_bounding_box = BoundingBoxf3();
|
||||
BoundingBoxf3* scaled_instance_bounding_box = const_cast<BoundingBoxf3*>(&m_scaled_instance_bounding_box);
|
||||
*scaled_instance_bounding_box = BoundingBoxf3();
|
||||
if (m_valid) {
|
||||
for (unsigned int i : m_list) {
|
||||
const GLVolume &volume = *(*m_volumes)[i];
|
||||
const GLVolume& volume = *(*m_volumes)[i];
|
||||
if (volume.is_modifier)
|
||||
continue;
|
||||
Transform3d trafo = volume.get_instance_transformation().get_matrix(false, false, false, false) * volume.get_volume_transformation().get_matrix();
|
||||
trafo.translation()(2) += volume.get_sla_shift_z();
|
||||
m_scaled_instance_bounding_box.merge(volume.transformed_convex_hull_bounding_box(trafo));
|
||||
scaled_instance_bounding_box->merge(volume.transformed_convex_hull_bounding_box(trafo));
|
||||
}
|
||||
}
|
||||
m_scaled_instance_bounding_box_dirty = false;
|
||||
*const_cast<bool*>(&m_scaled_instance_bounding_box_dirty) = false;
|
||||
}
|
||||
|
||||
void Selection::render_selected_volumes() const
|
||||
|
|
|
|||
|
|
@ -206,14 +206,14 @@ private:
|
|||
IndicesList m_list;
|
||||
Cache m_cache;
|
||||
Clipboard m_clipboard;
|
||||
mutable BoundingBoxf3 m_bounding_box;
|
||||
mutable bool m_bounding_box_dirty;
|
||||
BoundingBoxf3 m_bounding_box;
|
||||
bool m_bounding_box_dirty;
|
||||
// Bounding box of a selection, with no instance scaling applied. This bounding box
|
||||
// is useful for absolute scaling of tilted objects in world coordinate space.
|
||||
mutable BoundingBoxf3 m_unscaled_instance_bounding_box;
|
||||
mutable bool m_unscaled_instance_bounding_box_dirty;
|
||||
mutable BoundingBoxf3 m_scaled_instance_bounding_box;
|
||||
mutable bool m_scaled_instance_bounding_box_dirty;
|
||||
BoundingBoxf3 m_unscaled_instance_bounding_box;
|
||||
bool m_unscaled_instance_bounding_box_dirty;
|
||||
BoundingBoxf3 m_scaled_instance_bounding_box;
|
||||
bool m_scaled_instance_bounding_box_dirty;
|
||||
|
||||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
GLUquadricObj* m_quadric;
|
||||
|
|
@ -222,7 +222,7 @@ private:
|
|||
GLModel m_arrow;
|
||||
GLModel m_curved_arrow;
|
||||
|
||||
mutable float m_scale_factor;
|
||||
float m_scale_factor;
|
||||
|
||||
public:
|
||||
Selection();
|
||||
|
|
|
|||
|
|
@ -1515,6 +1515,7 @@ void TabPrint::build()
|
|||
optgroup->append_single_option_line("support_material_with_sheath", category_path + "with-sheath-around-the-support");
|
||||
optgroup->append_single_option_line("support_material_spacing", category_path + "pattern-spacing-0-inf");
|
||||
optgroup->append_single_option_line("support_material_angle", category_path + "pattern-angle");
|
||||
optgroup->append_single_option_line("support_material_closing_radius", category_path + "pattern-angle");
|
||||
optgroup->append_single_option_line("support_material_interface_layers", category_path + "interface-layers");
|
||||
optgroup->append_single_option_line("support_material_bottom_interface_layers", category_path + "interface-layers");
|
||||
optgroup->append_single_option_line("support_material_interface_pattern", category_path + "interface-pattern");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue