mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-05 14:51:06 +00:00
The MachineKinematics comments pointed at docs/superpowers plan files, which are gitignored working notes.
107 lines
4.7 KiB
C++
107 lines
4.7 KiB
C++
#ifndef slic3r_MachineKinematics_hpp_
|
|
#define slic3r_MachineKinematics_hpp_
|
|
|
|
#include "../Point.hpp"
|
|
|
|
namespace Slic3r {
|
|
|
|
// The frame contract for emitted movement.
|
|
//
|
|
// GCodeWriter produces points in the *logical placed* frame: plate offsets have
|
|
// already been subtracted, but no machine-specific mapping has been applied.
|
|
// A MachineKinematics turns that into the coordinates actually written to
|
|
// G-code, and answers the two structural questions the writer needs in order to
|
|
// decide which axis words it may omit.
|
|
//
|
|
// This is a seam for writer-generated movement only. Start/end/custom G-code,
|
|
// classic wipe-tower output and GCodeWriter::extrude_arc_to_xy() do NOT pass
|
|
// through it: they write machine coordinates directly.
|
|
class MachineKinematics
|
|
{
|
|
public:
|
|
virtual ~MachineKinematics() = default;
|
|
|
|
// Logical placed point -> emitted machine point.
|
|
virtual Vec3d to_machine(const Vec3d &p) const = 0;
|
|
|
|
// Inverse of to_machine(), back to the logical placed frame. Intended for
|
|
// consumers that must reconstruct model coordinates from emitted G-code
|
|
// (the G-code viewer's upright preview).
|
|
virtual Vec3d to_logical(const Vec3d &machine) const = 0;
|
|
|
|
// Machine point -> build-volume frame, for bounds validation only. This is
|
|
// deliberately NOT to_logical(): the build-volume check wants the physical
|
|
// frame the printable area is expressed in, not the model frame. Keeping
|
|
// them separate stops the two contracts from being confused.
|
|
virtual Vec3d to_build_volume(const Vec3d &machine) const = 0;
|
|
|
|
// True when a move must emit X, Y and Z because omitting a word would be
|
|
// wrong under this mapping. Deliberately not called "couples_axes": a pure
|
|
// axis permutation forces full emission without physically coupling axes.
|
|
virtual bool must_emit_all_axes() const = 0;
|
|
|
|
// True when a lift must be suppressed while the current position is unknown,
|
|
// because _travel_to_z() re-emits the logical X/Y through this mapping and an
|
|
// uninitialised position would map to a bogus machine point -- for a reverse
|
|
// mapping, the far corner of the bed.
|
|
virtual bool suppress_lift_at_unknown_position() const = 0;
|
|
|
|
// True when a G2/G3 arc in the logical XY plane is still the same arc in the
|
|
// machine frame. Arc moves emit only X, Y, I and J, so this asks a narrower
|
|
// question than must_emit_all_axes(): whether logical X and Y reach the
|
|
// machine unchanged. A mapping that only negates or reverses Z keeps its
|
|
// arcs; one that permutes X or Y moves the arc out of the plane that I/J
|
|
// describes, and a shear turns the circle into an ellipse G2/G3 cannot
|
|
// express at all.
|
|
virtual bool supports_arc_moves() const = 0;
|
|
|
|
// Configuration. GCodeWriter forwards its setters here so that the state
|
|
// lives with the strategy and a strategy installed before the setters run
|
|
// still receives it.
|
|
virtual void set_axis_remap(int rx, int ry, int rz) = 0;
|
|
virtual void set_build_volume_max(const Vec3d &max) = 0;
|
|
};
|
|
|
|
// Axis remap only -- the historical GCodeWriter behaviour, moved verbatim.
|
|
//
|
|
// The remap encodes, per output axis, which source axis feeds it and how:
|
|
// r < 3 : source axis r, unchanged
|
|
// r < 6 : source axis r-3, negated
|
|
// else : source axis r-6, reversed within the build volume
|
|
class CartesianKinematics : public MachineKinematics
|
|
{
|
|
public:
|
|
Vec3d to_machine(const Vec3d &p) const override;
|
|
Vec3d to_logical(const Vec3d &machine) const override;
|
|
Vec3d to_build_volume(const Vec3d &machine) const override { return machine; }
|
|
|
|
bool must_emit_all_axes() const override { return this->has_axis_remap(); }
|
|
bool suppress_lift_at_unknown_position() const override { return this->has_axis_remap(); }
|
|
|
|
// X and Y must reach the machine untouched. Because the remap is a
|
|
// permutation, pinning those two also pins Z to Z, so a mapping that only
|
|
// negates or reverses Z still supports arcs -- every word a G2/G3 emits is
|
|
// unchanged by it.
|
|
bool supports_arc_moves() const override { return m_remap_x == 0 && m_remap_y == 1; }
|
|
|
|
void set_axis_remap(int rx, int ry, int rz) override
|
|
{ m_remap_x = rx; m_remap_y = ry; m_remap_z = rz; }
|
|
void set_build_volume_max(const Vec3d &max) override { m_build_vol_max = max; }
|
|
|
|
bool has_axis_remap() const
|
|
{ return m_remap_x != 0 || m_remap_y != 1 || m_remap_z != 2; }
|
|
|
|
protected:
|
|
Vec3d apply_axis_remap(const Vec3d &pos) const;
|
|
Vec3d apply_axis_remap_inverse(const Vec3d &pos) const;
|
|
|
|
int m_remap_x { 0 };
|
|
int m_remap_y { 1 };
|
|
int m_remap_z { 2 };
|
|
Vec3d m_build_vol_max { Vec3d::Zero() };
|
|
};
|
|
|
|
} // namespace Slic3r
|
|
|
|
#endif // slic3r_MachineKinematics_hpp_
|