mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-18 22:42:37 +00:00
Mate connectors: draw the dashed pair line between the two origins
The last unbuilt element of snaporca-wgsc. Two connectors a mate binds are one object with a gap still in it; drawn as two separate frames they read as unrelated, and "which two of these five frames are the mate?" had no answer on screen at all. Dashed, grey, drawn IN WORLD along the segment joining the origins -- so it foreshortens with the model and its length is the gap the mate has left to close. A Fastened mate therefore draws nothing, which is correct: the gap is zero. Screen-constant dash pitch (6 px dash, 4 px gap) like every other gizmo here, with the pitch opening up beyond 400 dashes so a mate across a large assembly cannot emit thousands of segments. Depth test off: the line's job is to say "these two belong together", and it has to say it even when a part sits between the camera and one end. Fed from BOTH sources of polarity truth, the same two the role colours already use: every committed Mate feature (connectors named by feature index), and the live pick of an open Mate card (named by combo ordinal). Only resolved frames are eligible, so an unresolved end draws no line rather than a line to the origin of the world. RIG-VERIFIED on :10 with the fresh binary (/OrcaSlicer/build/src/Release, 2026-08-17 12:43): two imported bodies, a face-and-direction connector on each, Planar mate offset 40. Sampling the segment between the two origins gives a regular dash/gap alternation of 13:10 sample units -- the 6:4 px pitch -- in the stroke grey (107,117,133), over both solids. The grey end keeps its open collar head and the blue end its filled one, so polarity and pair now read together. Refs snaporca-wgsc
This commit is contained in:
@@ -1001,6 +1001,12 @@ void DesignCanvas::set_mate_connectors(std::vector<DesignSketchTool::MateConnect
|
||||
request_repaint();
|
||||
}
|
||||
|
||||
void DesignCanvas::set_mate_links(std::vector<std::pair<Vec3d, Vec3d>> l)
|
||||
{
|
||||
m_sketch_tool.set_mate_links(std::move(l));
|
||||
request_repaint();
|
||||
}
|
||||
|
||||
bool DesignCanvas::toggle_planes()
|
||||
{
|
||||
const bool on = m_sketch_tool.toggle_show_planes();
|
||||
|
||||
@@ -197,6 +197,7 @@ public:
|
||||
std::vector<Vec2d> sizes = {}); // draw datum/reference planes (u/v extents)
|
||||
// Mate connectors, drawn as frames so their verse and polarity are visible (snaporca-wgsc).
|
||||
void set_mate_connectors(std::vector<DesignSketchTool::MateConnectorGlyph> g);
|
||||
void set_mate_links(std::vector<std::pair<Vec3d, Vec3d>> l);
|
||||
void set_body_highlight(bool on); // tint the solid when its feature is tree-selected
|
||||
// The status line, shown along the BASE OF THE VIEWPORT rather than in the side panel:
|
||||
// the panel clips it at ~73 characters with no warning (snaporca-8cc), the viewport's
|
||||
|
||||
@@ -9728,6 +9728,10 @@ void DesignPanel::refresh_mate_connectors()
|
||||
const int cs_b = (m_active == Tool::Mate && m_mate_cs_b) ? m_mate_cs_b->GetSelection() : -1;
|
||||
|
||||
std::vector<DesignSketchTool::MateConnectorGlyph> out;
|
||||
// Origins, keyed both ways: a committed mate names its connectors by FEATURE index, the open
|
||||
// card's combos by ordinal. Only resolved frames land here, so an unresolved end simply draws
|
||||
// no pair line rather than a line to the origin of the world.
|
||||
std::map<int, Vec3d> origin_by_feature, origin_by_ordinal;
|
||||
const auto frames = m_doc.resolve_datum_coordsys();
|
||||
size_t k = 0;
|
||||
for (size_t i = 0; i < m_doc.features.size() && k < frames.size(); ++i) {
|
||||
@@ -9748,9 +9752,24 @@ void DesignPanel::refresh_mate_connectors()
|
||||
// is the case the glyph has to confess rather than absorb.
|
||||
g.roll_undefined = (f.coordsys_type == CoordSysType::FaceAndDirection
|
||||
&& f.coordsys_edge < 0);
|
||||
origin_by_feature[int(i)] = g.origin;
|
||||
origin_by_ordinal[ordinal] = g.origin;
|
||||
out.push_back(g);
|
||||
}
|
||||
|
||||
std::vector<std::pair<Vec3d, Vec3d>> links;
|
||||
auto add_link = [&links](const std::map<int, Vec3d>& m, int a, int b) {
|
||||
const auto ia = m.find(a), ib = m.find(b);
|
||||
if (ia != m.end() && ib != m.end()) links.emplace_back(ia->second, ib->second);
|
||||
};
|
||||
for (const CadFeature& mf : m_doc.features)
|
||||
if (mf.type == CadFeatureType::Mate && mf.enabled)
|
||||
add_link(origin_by_feature, mf.mate_cs_a, mf.mate_cs_b);
|
||||
if (cs_a >= 0 && cs_b >= 0 && cs_a != cs_b)
|
||||
add_link(origin_by_ordinal, cs_a, cs_b); // the live pick, not yet committed
|
||||
|
||||
m_viewport->set_mate_connectors(std::move(out));
|
||||
m_viewport->set_mate_links(std::move(links));
|
||||
}
|
||||
|
||||
void DesignPanel::update_datum_gizmo()
|
||||
|
||||
@@ -3680,6 +3680,35 @@ void DesignSketchTool::render_mate_connectors()
|
||||
arrow(Z, R * 2.10, body, g.role == 2); // +Z only. Nothing is ever drawn on -Z.
|
||||
}
|
||||
}
|
||||
|
||||
// ---- the pair line. Dashed, drawn IN WORLD along the segment joining the two origins, so it
|
||||
// foreshortens with the model and its length is the gap the mate has still to close. Screen-
|
||||
// constant dashes like everything else here; the dash pitch opens up on a long span so a mate
|
||||
// across a large assembly cannot emit thousands of segments.
|
||||
for (const auto& lnk : m_mate_links) {
|
||||
const Vec3d d = lnk.second - lnk.first;
|
||||
const double L = d.norm();
|
||||
if (L < 1e-9) continue;
|
||||
SketchPlane lp;
|
||||
lp.origin = lnk.first;
|
||||
lp.x_axis = d / L;
|
||||
lp.y_axis = lp.x_axis.cross(cam.get_dir_forward().normalized());
|
||||
if (lp.y_axis.norm() < 1e-6) lp.y_axis = lp.x_axis.cross(up); // link along the view axis
|
||||
lp.y_axis.normalize();
|
||||
lp.normal = lp.x_axis.cross(lp.y_axis);
|
||||
m_plane = lp;
|
||||
|
||||
std::vector<std::pair<Vec2d, Vec2d>> segs;
|
||||
const double dash = 6.0 * upp;
|
||||
const double step = std::max(dash + 4.0 * upp, L / 400.0);
|
||||
for (double t = 0.0; t < L; t += step)
|
||||
segs.emplace_back(Vec2d(t, 0.0), Vec2d(std::min(t + dash, L), 0.0));
|
||||
// Depth off: the line's job is to say "these two belong together", and it has to say it
|
||||
// even when the parts it spans are between the camera and one of the ends.
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
draw_strokes(m_mc_stroke_model, segs, lw, grey);
|
||||
}
|
||||
|
||||
m_plane = saved;
|
||||
}
|
||||
|
||||
|
||||
@@ -337,7 +337,11 @@ public:
|
||||
bool roll_undefined{false};
|
||||
};
|
||||
void set_mate_connectors(std::vector<MateConnectorGlyph> g) { m_mate_connectors = std::move(g); }
|
||||
void clear_mate_connectors() { m_mate_connectors.clear(); }
|
||||
// The pair line: the two origins of every mate — committed ones, plus the live pick of an open
|
||||
// Mate card. Two connectors a mate binds are ONE object with a gap still in it; drawn as two
|
||||
// separate frames they read as unrelated.
|
||||
void set_mate_links(std::vector<std::pair<Vec3d, Vec3d>> l) { m_mate_links = std::move(l); }
|
||||
void clear_mate_connectors() { m_mate_connectors.clear(); m_mate_links.clear(); }
|
||||
|
||||
// Visual Revolve gizmo. The panel feeds the sketch plane + profile centroid + axis (0=plane X,
|
||||
// 1=plane Y) + angle + flip while its Revolve card is open; an angle-arc is drawn in the
|
||||
@@ -1085,6 +1089,7 @@ private:
|
||||
void render_mate_face(const Vec3d& origin, const Vec3d& X, const Vec3d& Y, const Vec3d& Z,
|
||||
double R, const ColorRGBA& body);
|
||||
std::vector<MateConnectorGlyph> m_mate_connectors;
|
||||
std::vector<std::pair<Vec3d, Vec3d>> m_mate_links;
|
||||
GLModel m_mc_stroke_model;
|
||||
GLModel m_mc_fill_model; // the face treatment's shaded facets
|
||||
GLModel m_solid_face_model;
|
||||
|
||||
Reference in New Issue
Block a user