OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GUI::DesignSketchTool Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/GUI/CAD/DesignSketchTool.hpp>

Collaboration diagram for Slic3r::GUI::DesignSketchTool:

Classes

struct  DisplaySketch
struct  MateConnectorGlyph
struct  LoopInfo
struct  LoopReport
struct  DimAnnot
struct  Handle
struct  Feature
struct  RegionLoop
struct  AutoEditStep
struct  SketchSnap
struct  GlyphHit
struct  LabelRect
struct  SolidPick
struct  FaceHighlight

Public Types

enum class  Mode {
  Select , Dimension , Polyline , Line ,
  CornerRect , CenterRect , ObliqueRect , RoundedRect ,
  CenterCircle , TwoPointCircle , Point , ThreePointCircle ,
  ThreePointArc , TangentArc , CenterArc , Slot ,
  ArcSlot , Polygon , Ellipse , EllipseArc ,
  BSpline , Fillet , Chamfer , Offset ,
  Mirror , Trim , Extend , Move ,
  Rotate , Scale , Array , PolarArray ,
  TransformArt , Constrain
}
enum class  SolidSel {
  None , Whole , Face , Edge ,
  Vertex
}
enum class  DimType {
  None , Length , Diameter , Radius ,
  Angle , Distance , DistanceToLine
}

Public Member Functions

Mode mode () const
int pending_points () const
bool has_pending_picks () const
bool gesture_pending () const
bool confirm_pending ()
bool end_chain ()
void emit_step_hint ()
bool value_field_open () const
bool is_edit_op_mode () const
bool is_transform_mode () const
bool is_creation_autoedit_mode () const
void set_inline_busy (bool b)
bool inline_busy () const
bool live_sketch_has_work () const
void set_escalate_on_repick (bool on)
bool constrain_value_anchor (wxPoint &out) const
void begin (const SketchPlane &plane, Mode mode=Mode::Polyline)
void begin_edit (const std::vector< SketchEntity > &entities, const std::vector< SketchEntityConstraintDef > &constraints, const SketchPlane &plane)
bool add_imported_regions (const std::vector< std::vector< std::vector< Vec2d > > > &regions)
void set_tool (Mode mode)
void set_construction (bool c)
void set_polygon_sides (int n)
void set_polygon_circumscribed (bool c)
void finish ()
void cancel ()
bool is_active () const
bool has_entities () const
bool on_mouse (wxMouseEvent &evt, GLCanvas3D &canvas)
bool right_abandon ()
bool take_right_click (GLCanvas3D &canvas)
void drop_right_click ()
void render (GLCanvas3D &canvas)
void set_display_sketches (std::vector< DisplaySketch > ds)
void set_highlight_sketches (std::vector< std::pair< int, ColorRGBA > > hl)
bool has_display () const
void set_show_planes (bool s)
void set_show_axes (bool s)
bool toggle_show_planes ()
bool toggle_show_axes ()
void set_solid_pick (const std::vector< CadBody > *bodies, const TriangleMesh *mesh, const std::vector< int > *tri_face, const std::vector< int > *tri_body, const std::vector< bool > *visible=nullptr, const std::vector< Transform3d > *xform=nullptr)
void set_pick_only_body (int b)
void set_body_edges_hidden (bool h)
void clear_solid_selection ()
void refresh_body_edges ()
bool has_solid_selection () const
std::vector< int > selected_edges () const
void select_body (int body)
void set_highlight_faces (const std::vector< std::pair< int, int > > &faces)
std::vector< std::pair< int, int > > selected_faces () const
BoundingBoxf3 fit_box (const GLVolumeCollection &volumes) const
BoundingBoxf3 selection_box () const
BoundingBoxf3 faces_box (std::vector< std::pair< int, int > > faces) const
void set_move_gizmo (int body, const Vec3d &pivot, const Transform3d &base_xform, double body_radius=0.0)
void clear_move_gizmo ()
int move_body_index () const
void grab_move_arrow (int axis, const Linef3 &ray)
void drag_move_arrow (const Linef3 &ray)
std::vector< SketchEntity > selected_loop_entities () const
std::vector< std::vector< int > > region_entity_indices (const std::vector< SketchEntity > &ents) const
std::vector< std::vector< int > > region_entity_indices_with_holes (const std::vector< SketchEntity > &ents) const
void clear_display_pick ()
void set_display_pick (int feature, int region)
int display_pick () const
int display_pick_region () const
void set_extrude_gizmo (const SketchPlane &plane, const Vec2d &centroid, double depth, double depth2, bool two_sided, bool flip)
void clear_extrude_gizmo ()
void set_datum_gizmo (const SketchPlane &plane, double usize, double vsize, const Vec3d &base_origin, const Vec3d &base_normal, double offset, bool offset_on)
void clear_datum_gizmo ()
void set_helix_gizmo (const SketchPlane &plane, double radius, double pitch, double height, double taper, bool left_handed)
void clear_helix_gizmo ()
void set_rib_gizmo (const SketchPlane &plane, const Vec2d &p0, const Vec2d &p1, double thickness)
void clear_rib_gizmo ()
void set_base_pick (std::vector< SketchPlane > planes, std::vector< int > bases, std::vector< std::string > labels={})
void clear_base_pick ()
bool draws_reference_axes () const
bool set_fillet_gizmo (const Vec3d &body_centroid, double radius)
void clear_fillet_gizmo ()
bool filleting () const
void set_hole_gizmo (const SketchPlane &plane, double x, double y, double diameter, double depth, bool through)
void set_hole_face_bounds (bool has, double umin, double umax, double vmin, double vmax)
void clear_hole_gizmo ()
bool holing () const
void set_thread_gizmo (const SketchPlane &plane, double x, double y, double radius, double height)
void clear_thread_gizmo ()
bool threading () const
void set_shell_gizmo (const Vec3d &face_centroid, const Vec3d &inward_dir, double thickness)
void clear_shell_gizmo ()
bool shelling () const
void set_datum_planes (std::vector< SketchPlane > planes, std::vector< Vec2d > sizes={})
void set_mate_connectors (std::vector< MateConnectorGlyph > g)
void set_mate_links (std::vector< std::pair< Vec3d, Vec3d > > l)
void clear_mate_connectors ()
void set_revolve_gizmo (const SketchPlane &plane, const Vec2d &centroid, const Vec3d &axis_origin, const Vec3d &axis_dir, double angle, bool flip)
void clear_revolve_gizmo ()
bool revolving () const
void set_draft_gizmo (const Vec3d &face_centroid, const Vec3d &face_normal, double angle)
void clear_draft_gizmo ()
bool drafting () const
void set_on_draft_angle_changed (std::function< void(double)> cb)
void set_cut_gizmo (const SketchPlane &plane, double offset, const Vec3d &body_center, double half_extent)
void clear_cut_gizmo ()
bool cutting () const
void set_on_cut_offset_changed (std::function< void(double)> cb)
void set_pattern_gizmo (const SketchPlane &plane, const Vec3d &body_centroid, bool circular, int count, int dir, double spacing, double angle)
void clear_pattern_gizmo ()
bool patterning () const
void begin_constrain (const SketchProfile &prof, const SketchPlane &plane)
bool is_constraining () const
void set_profile_points (const std::vector< Vec2d > &pts)
bool selected_segment (int &a, int &b) const
void begin_constrain_entities (const std::vector< SketchEntity > &ents, const SketchPlane &plane)
bool is_constraining_entities () const
void begin_imported_transform (int feat, const std::vector< std::vector< std::vector< Vec2d > > > &base_regions, const SketchPlane &plane, const Vec2d &offset, double scale_x, double scale_y)
bool selected_constrain_entities (int &e0, int &e1) const
int pick2 () const
bool pick0_point (Vec2d &out) const
void set_constrain_entities (const std::vector< SketchEntity > &ents)
void set_constraint_highlight (std::vector< int > v)
void set_constraint_glyphs (std::vector< SketchEntityConstraintDef > v)
void apply_segment_length (double len)
void keep_segment_as_drawn ()
const std::vector< int > & selection () const
bool sketch_has_selection () const
bool first_selected_type (SketchEntity::Type &out) const
bool select_at_screen (GLCanvas3D &canvas, int sx, int sy)
bool open_selection_dimension_editor ()
const std::vector< SketchEntity > & entities () const
const SketchPlane & plane () const
int dof () const
bool solve_ok () const
int add_entities_scripted (const std::vector< SketchEntity > &ents)
bool select_indices (const std::vector< int > &idx)
bool try_add_constraints (const std::vector< SketchEntityConstraintDef > &cands)
bool remove_constraint_near (const Vec2d &p)
bool remove_constraint (int idx)
LoopReport loop_report () const
int heal_coincidences (double tol, bool ignore_construction)
void clear_selection ()
int toggle_selection_construction ()
void delete_selected ()
void reset_autoedit ()
void close_session_chrome ()
bool undo_last_entity ()
bool redo_last_entity ()
bool can_undo_entity () const
bool can_redo_entity () const
DimType dimension_kind () const
double dimension_current () const
void apply_dimension (double v)
DimType pending_dimension_type () const
void set_dimension_value (double v)
void cancel_dimension_value ()
void notify (const std::string &msg, bool error=true)
void show_refusal (const std::string &why)
const std::vector< SketchEntityConstraintDef > & constraints () const
bool abort_gesture ()
bool disarm_tool ()
void request_exit ()

Static Public Member Functions

static BoundingBoxf3 sketch_box (const std::vector< SketchEntity > &entities, const SketchPlane &plane)
static void pad_box (BoundingBoxf3 &box)

Public Attributes

class SketchInlineEditor * inline_editor {nullptr}
std::function< void()> render_overlays
int m_pick_press_x = 0
int m_pick_press_y = 0
bool m_pick_pending = false
std::function< void(int body, const Transform3d &xform)> on_body_move_changed
std::function< void(int level, int body, int face, int edge)> on_solid_selection_changed
std::function< void()> on_empty_pick
std::function< void(int feature, int region, int entity)> on_display_sketch_selected
std::function< void(int feature)> on_display_sketch_activated
std::function< void(double depth, bool second)> on_extrude_depth_changed
std::function< void(double usize, double vsize)> on_datum_size_changed
std::function< void(double offset)> on_datum_offset_changed
std::function< void(double radius, double pitch, double height)> on_helix_changed
std::function< void(double thickness)> on_rib_thickness_changed
std::function< void(int base)> on_datum_base_picked
std::function< int()> selected_base
std::function< void(double radius)> on_fillet_radius_changed
std::function< void(double x, double y, double diameter, double depth)> on_hole_changed
std::function< void(double x, double y, double radius, double height)> on_thread_changed
std::function< void(double thickness)> on_shell_thickness_changed
std::function< void(double angle)> on_revolve_angle_changed
std::function< void(double value)> on_pattern_changed
std::function< void(int feat, Vec2d offset, double scale_x, double scale_y)> on_imported_transform
std::function< void(double length, double angle_deg)> on_segment_drawn
std::function< void(double length, double angle_deg, bool locked)> on_cursor_metrics
std::function< void(Mode mode, int step, int picks)> on_step_changed
std::function< void()> on_constraints_changed
std::function< void(int dof, bool ok, bool has_constraints)> on_solve_state
std::function< void(int count)> on_selection_changed
std::function< void(double current)> on_dimension_pick_complete
std::function< void(wxPoint screen_px, double current, const std::string &title, std::function< void(double)> commit, std::function< void()> cancel)> on_inline_edit
std::function< void()> on_inline_dismiss
std::function< void()> on_inline_commit
std::function< void(const std::string &)> on_readout
std::function< void(const std::string &msg, bool error)> on_notice
std::function< void(const std::vector< SketchEntity > &, const std::vector< SketchEntityConstraintDef > &, const SketchPlane &)> on_commit_entities
std::function< void(const SketchProfile &, const SketchPlane &)> on_commit
std::function< void(int)> on_face_selected
std::function< void()> on_exit
std::function< void()> on_exit_refused

Private Types

enum class  HandleRole {
  P0 , P1 , Center , RadiusHandle ,
  SlotCenter0 , SlotCenter1 , SlotWidth , RectCorner ,
  PolygonVertex , MajorAxis , MinorAxis , BSplineCtrl
}
enum class  FeatureKind {
  Free , Line , Circle , Arc ,
  CornerRect , CenterRect , Slot , ArcSlot ,
  Polygon , Ellipse , RoundedRect , BSpline
}

Private Member Functions

bool screen_to_plane (GLCanvas3D &canvas, const wxMouseEvent &evt, Vec2d &out) const
bool snap_chain_start (GLCanvas3D &canvas, const wxMouseEvent &evt, Vec2d &p) const
Vec2d snap_dir (const Vec2d &anchor, const Vec2d &raw, bool &locked) const
Vec2d snap_vertex (GLCanvas3D &canvas, const wxMouseEvent &evt, const Vec2d &raw, bool &snapped) const
bool click_snaps () const
double screen_tol (GLCanvas3D &canvas, const wxMouseEvent &evt, const Vec2d &at, double px=kPickPx) const
InferenceSnap infer_at (GLCanvas3D &canvas, const wxMouseEvent &evt, const Vec2d &raw) const
bool has_coincident (int ea, SketchPointRole ra, int eb, SketchPointRole rb) const
void infer_auto_constraints (int base, double ang_tol_rad=3.0 *M_PI/180.0, double weld_tol=1e-3)
int hit_test (const Vec2d &p, double tol) const
std::vector< int > connected_loop (int seed) const
void apply_angle_between (int ia, int ib, double deg)
bool selection_valid () const
void record_dimension_constraint (double v)
void resolve_live ()
void announce_loop_defects ()
void resolve_live_drag (int dragged_ei, SketchPointRole dragged_role)
std::vector< Handle > build_handles () const
bool hit_test_handle (const Vec2d &p, double tol, Handle &out) const
void set_handle (const Handle &h, const Vec2d &target)
bool update_hover (GLCanvas3D &canvas, wxMouseEvent &evt)
int feature_of (int ei) const
void rebuild_features_from_entities ()
void begin_feature (FeatureKind kind)
void end_feature (const Vec2d &c0=Vec2d(0, 0), const Vec2d &c1=Vec2d(0, 0), double param=0.0, int sides=0)
bool point_at (int ei, SketchPointRole role, Vec2d &out) const
void set_point (int ei, SketchPointRole role, const Vec2d &v)
bool hit_test_point (const Vec2d &p, double tol, int &ei, SketchPointRole &role) const
int hit_test_dimension (const Vec2d &p, double tol) const
void edit_dimension (int di)
Vec2d dim_anchor (const DimAnnot &a) const
void open_value_editor (int di)
void open_angle_editor (int ei)
void set_line_angle (int ei, double deg)
void open_primary_autoedit ()
std::string build_readout () const
void open_next_autoedit_dim ()
void arm_polyline_segment_edit ()
void open_polygon_side_editor (int fi)
void open_polygon_angle_editor (int fi)
void set_polygon_side (int fi, double side)
void set_polygon_angle (int fi, double deg)
void set_polygon_radius (int fi, double R)
void open_arc_angle_editor (int ei)
void set_arc_sweep (int ei, double deg)
void drag_arc_handle (int ei, SketchPointRole role, const Vec2d &target)
void open_ellipse_axis_editor (int ei, bool major)
void set_ellipse_axis (int ei, bool major, double v)
void set_ellipsearc_sweep (int ei, double deg)
void set_rect_angle (int fi, double deg)
void drag_ellipsearc_handle (int ei, SketchPointRole role, const Vec2d &target)
int erase_constraints (const std::function< bool(int, const SketchEntityConstraintDef &)> &drop)
void drop_orientation_constraints (int begin, int end)
void drop_constraints_referencing (int ei)
bool apply_live_trim (const Vec2d &p, double tol, bool extend)
bool compute_trim_preview (const Vec2d &p, double tol, bool extend, int &subject_ei, std::vector< Vec2d > &removed_poly) const
void drag_polygon_vertex (int fi, int ei, SketchPointRole role, const Vec2d &target)
double measure_dim (const DimAnnot &a) const
std::string dimtype_title (DimType k) const
SketchEntityConstraintDef constraint_for (const DimAnnot &a) const
int upsert_constraint (const SketchEntityConstraintDef &c)
int upsert_dimension (const DimAnnot &a)
int upsert_dimension_constraint (const SketchEntityConstraintDef &c)
int place_dimension (DimAnnot a)
std::string dim_text (const DimAnnot &a) const
void render_dimensions (double unit_per_px)
bool draw_dim_quote (const DimAnnot &a, double th, const ColorRGBA &col, Vec2d &out_label)
void render_live_quotes (double unit_per_px)
void build_constraint_glyphs (double unit_per_px, const std::vector< SketchEntityConstraintDef > &cons, std::vector< std::pair< Vec2d, Vec2d > > &out)
void draw_strokes (GLModel &model, const std::vector< std::pair< Vec2d, Vec2d > > &segs, double hw, const ColorRGBA &color)
void draw_text (GLModel &model, const std::string &s, const Vec2d &center, double height, const ColorRGBA &color)
void draw_dim_label (const std::string &txt, const Vec2d &plane_center)
void push_line (const Vec2d &a, const Vec2d &b)
void push_closed_lines (const std::vector< Vec2d > &corners)
void push_open_chain (const std::vector< Vec2d > &pts)
void push_circle (const Vec2d &center, double radius)
void push_point (const Vec2d &p)
std::vector< SketchEntity > make_three_point_circle (const Vec2d &a, const Vec2d &b, const Vec2d &c) const
std::vector< SketchEntity > make_three_point_arc (const Vec2d &start, const Vec2d &end, const Vec2d &on_arc) const
std::vector< SketchEntity > make_tangent_arc (const Vec2d &start, const Vec2d &end) const
std::vector< SketchEntity > make_center_arc (const Vec2d &center, const Vec2d &start, const Vec2d &end_dir) const
std::vector< SketchEntity > make_slot (const Vec2d &c0, const Vec2d &c1, double half_width) const
std::vector< SketchEntity > make_arc_slot (const Vec2d &center, const Vec2d &start, const Vec2d &end_dir, double half_width) const
std::vector< SketchEntity > make_rounded_rect (const Vec2d &a, const Vec2d &b, const Vec2d &radius_pt) const
std::vector< SketchEntity > rounded_rect_entities (double xmin, double ymin, double xmax, double ymax, double r) const
void open_rounded_rect_editor (int fi, int which)
void set_rounded_rect (int fi, double w, double h, double r)
void open_arc_slot_editor (int fi, bool radius)
void set_arc_slot (int fi, double Rc, double w)
void open_slot_editor (int fi, int which)
void set_slot (int fi, double length, double w)
void set_slot_angle (int fi, double deg)
void drag_rect_corner (int fi, const Vec2d &cursor)
void drag_slot_handle (int fi, const Vec2d &cursor)
std::vector< SketchEntity > make_polygon (const Vec2d &center, const Vec2d &vertex, int sides) const
std::vector< SketchEntity > make_ellipse (const Vec2d &center, const Vec2d &major_end, const Vec2d &minor_pt) const
std::vector< SketchEntity > make_bspline (const std::vector< Vec2d > &ctrl) const
std::vector< SketchEntity > make_ellipse_arc (const Vec2d &center, const Vec2d &major_end, const Vec2d &minor_pt, const Vec2d &start_pt, const Vec2d &end_pt) const
void append_entities (const std::vector< SketchEntity > &ents)
void draw_entities_preview (const std::vector< SketchEntity > &ents, const ColorRGBA &color)
bool op_corner (int a, int b, Vec2d &C, Vec2d &bis, double &theta) const
void op_pick (int ei)
void recompute_op_ghost ()
void render_op_gizmo (double unit_per_px)
bool hit_test_op_arrow (const Vec2d &p, double tol) const
void drag_op_arrow (const Vec2d &target)
void open_op_editor ()
void confirm_op ()
void reset_op ()
bool op_ready () const
std::vector< std::vector< Vec2d > > closed_regions () const
std::vector< std::vector< Vec2d > > closed_regions (const std::vector< SketchEntity > &ents) const
std::vector< RegionLoop > region_loops (const std::vector< SketchEntity > &ents) const
int region_at (const Vec2d &p) const
void draw_quad_strip (GLModel &model, const std::vector< Vec2d > &pts, bool closed, const ColorRGBA &color)
void draw_vertices (GLModel &model, const std::vector< Vec2d > &pts, const ColorRGBA &color, double half_size=1.3)
void draw_fill (GLModel &model, const std::vector< Vec2d > &poly, const ColorRGBA &color)
void draw_fill_holed (GLModel &model, const std::vector< Vec2d > &outer, const std::vector< std::vector< Vec2d > > &holes, const ColorRGBA &color)
const ColorRGBA * sketch_hl_color (int feature) const
std::vector< SketchEntity > op_chain_entities () const
void xform_world_corners (Vec2d out[4]) const
int hit_test_xform_handle (const Vec2d &p, double tol) const
void drag_xform_handle (const Vec2d &target)
void render_xform_gizmo ()
void emit_xform ()
void reset_xform ()
bool tf_ready () const
void tf_pick (int ei)
void compute_tf_pivot ()
void recompute_tf_ghost ()
Vec2d tf_handle_pos () const
bool hit_test_tf_handle (const Vec2d &p, double tol) const
void drag_tf_handle (const Vec2d &target)
void render_tf_gizmo (double unit_per_px)
void open_tf_editor_a ()
void open_tf_editor_count ()
void confirm_transform ()
void reset_tf ()
Vec3d body_xform_pt (int body, const Vec3d &p) const
void render_body_edges ()
const TopoDS_Shape * body_shape (int body) const
bool is_current_shape (int body, const TopoDS_Shape &sampled) const
void append_ribbons (GLModel::Geometry &g, int body, const std::vector< std::vector< Vec3d > > &polylines, const Vec3d &vd, const Vec3d &pull, double hw) const
bool body_pickable (int b) const
bool handle_solid_click (GLCanvas3D &canvas, const wxMouseEvent &evt)
bool resolve_solid_pick (GLCanvas3D &canvas, int mx, int my, SolidPick &out) const
bool update_solid_hover (GLCanvas3D &canvas, const wxMouseEvent &evt)
void pick_bodies_in_rectangle ()
bool on_mouse_impl (wxMouseEvent &evt, GLCanvas3D &canvas)
void hit_display_sketch (const DisplaySketch &d, const Vec2d &p, double tol, int &edge_feat, int &edge_reg, int &edge_ent, double &edge_d, int &face_feat, int &face_reg) const
void render_solid_highlight ()
void render_solid_sel (SolidSel kind, const std::vector< Vec3d > &edge_pts, const Vec3d &vertex_pt, const ColorRGBA &rgb)
FaceHighlight make_face_highlight (int body, std::vector< int > faces) const
std::vector< std::pair< int, int > > picked_faces () const
const FaceHighlight & cached_face_highlight (FaceHighlight &cache, int body, std::vector< int > faces) const
void render_face_outline (const FaceHighlight &h, bool quiet)
void render_datum_planes ()
void render_view_helpers ()
void render_mate_connectors ()
void render_mate_face (const Vec3d &origin, const Vec3d &X, const Vec3d &Y, const Vec3d &Z, double R, const ColorRGBA &body)
void render_extrude_gizmo ()
bool hit_test_extrude_arrow (GLCanvas3D &canvas, const wxMouseEvent &evt, int &which) const
void drag_extrude_arrow (GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
void open_extrude_editor (int which)
void render_datum_gizmo ()
bool hit_test_datum_handle (GLCanvas3D &canvas, const wxMouseEvent &evt, int &which) const
void drag_datum_handle (GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
Vec3d helix_point (double t) const
void render_helix_gizmo ()
bool hit_test_helix_handle (GLCanvas3D &canvas, const wxMouseEvent &evt, int &which) const
void drag_helix_handle (GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
void render_rib_gizmo ()
bool hit_test_rib_handle (GLCanvas3D &canvas, const wxMouseEvent &evt, int &which) const
void drag_rib_handle (GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
double dbp_half_extent () const
std::vector< SketchPlane > dbp_squares (double half) const
void render_reference_axes (const Vec3d &origin, double half)
void render_base_pick ()
int hit_test_base_pick (GLCanvas3D &canvas, const wxMouseEvent &evt) const
Transform3d compose_move_xform () const
void ring_basis (int axis, Vec3d &e, Vec3d &u, Vec3d &v) const
void render_move_gizmo ()
double move_gizmo_arm (const Camera &cam) const
bool hit_test_move_arrow (GLCanvas3D &canvas, const wxMouseEvent &evt, int &axis) const
bool hit_test_move_arc (GLCanvas3D &canvas, const wxMouseEvent &evt, int &axis) const
void drag_move_arc (GLCanvas3D &canvas, const wxMouseEvent &evt, int axis)
bool arc_mouse_angle (GLCanvas3D &canvas, const wxMouseEvent &evt, int axis, double &ang) const
void open_move_editor (int axis)
void render_fillet_gizmo ()
bool hit_test_fillet_arrow (GLCanvas3D &canvas, const wxMouseEvent &evt) const
double fillet_axis_proj (GLCanvas3D &canvas, const wxMouseEvent &evt) const
void start_fillet_drag (GLCanvas3D &canvas, const wxMouseEvent &evt)
void drag_fillet_arrow (GLCanvas3D &canvas, const wxMouseEvent &evt)
void open_fillet_editor ()
void render_hole_gizmo ()
int hit_test_hole_handle (GLCanvas3D &canvas, const wxMouseEvent &evt) const
double hole_axis_proj (GLCanvas3D &canvas, const wxMouseEvent &evt, const Vec3d &anchor, const Vec3d &dir) const
void start_hole_drag (GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
void drag_hole_handle (GLCanvas3D &canvas, const wxMouseEvent &evt)
void open_hole_editor (int which)
void render_thread_gizmo ()
int hit_test_thread_handle (GLCanvas3D &canvas, const wxMouseEvent &evt) const
void start_thread_drag (GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
void drag_thread_handle (GLCanvas3D &canvas, const wxMouseEvent &evt)
void open_thread_editor (int which)
void render_shell_gizmo ()
bool hit_test_shell_arrow (GLCanvas3D &canvas, const wxMouseEvent &evt) const
void start_shell_drag (GLCanvas3D &canvas, const wxMouseEvent &evt)
void drag_shell_arrow (GLCanvas3D &canvas, const wxMouseEvent &evt)
void open_shell_editor ()
void render_revolve_gizmo ()
bool hit_test_revolve_handle (GLCanvas3D &canvas, const wxMouseEvent &evt) const
void drag_revolve_arc (GLCanvas3D &canvas, const wxMouseEvent &evt)
void open_revolve_editor ()
void render_draft_gizmo ()
bool hit_test_draft_handle (GLCanvas3D &canvas, const wxMouseEvent &evt) const
void drag_draft_arc (GLCanvas3D &canvas, const wxMouseEvent &evt)
void render_cut_gizmo ()
bool hit_test_cut_arrow (GLCanvas3D &canvas, const wxMouseEvent &evt) const
void start_cut_drag (GLCanvas3D &canvas, const wxMouseEvent &evt)
void drag_cut_arrow (GLCanvas3D &canvas, const wxMouseEvent &evt)
void render_pattern_gizmo ()
bool hit_test_pattern_handle (GLCanvas3D &canvas, const wxMouseEvent &evt) const
void drag_pattern_handle (GLCanvas3D &canvas, const wxMouseEvent &evt)
void open_pattern_editor ()

Static Private Member Functions

static std::vector< Vec2d > entity_polyline (const SketchEntity &e, bool &closed)

Private Attributes

bool m_loop_defect_shown {false}
bool m_active {false}
SketchPlane m_plane
std::vector< Vec2d > m_points
std::vector< SketchEntity > m_entities
bool m_construction {false}
int m_polygon_sides {6}
bool m_polygon_circumscribed {false}
Vec2d m_cursor {0,0}
bool m_has_cursor {false}
bool m_snap_off {false}
InferenceSnap m_cursor_snap
bool m_cursor_locked {false}
bool m_awaiting_length {false}
int m_autoedit_seen {-1}
bool m_autoedit_pending {false}
std::vector< AutoEditStep > m_autoedit_dims
int m_autoedit_dim_idx {-1}
Vec2d m_autoedit_label_pos {1e18, 1e18}
std::vector< int > m_selection
std::vector< std::pair< int, SketchPointRole > > m_point_sel
int m_last_mouse_x {0}
int m_last_mouse_y {0}
bool m_dragging_point {false}
int m_drag_ei {-1}
int m_drag_poly_fi {-1}
int m_drag_rect_fi {-1}
Vec2d m_drag_rect_anchor {0,0}
int m_drag_slot_fi {-1}
bool m_drag_slot_c1 {false}
SketchPointRole m_drag_role {SketchPointRole::P0}
std::vector< SketchEntityConstraintDef > m_constraints
bool m_show_handles {false}
bool m_dragging_handle {false}
Handle m_drag_handle
bool m_has_hover_handle {false}
Handle m_hover_handle
std::vector< DimAnnot > m_live_quotes
Vec2d m_live_poly_side_label {0,0}
Vec2d m_live_poly_angle_label {0,0}
int m_live_poly_fi {-1}
Vec2d m_live_arc_angle_label {0,0}
int m_live_arc_ei {-1}
Vec2d m_live_ellipse_major_label {0,0}
Vec2d m_live_ellipse_minor_label {0,0}
Vec2d m_live_ellipsearc_sweep_label {0,0}
int m_live_ellipse_ei {-1}
Vec2d m_live_obrect_angle_label {0,0}
int m_live_obrect_fi {-1}
Vec2d m_live_rrect_w_label {0,0}
Vec2d m_live_rrect_h_label {0,0}
Vec2d m_live_rrect_r_label {0,0}
int m_live_rrect_fi {-1}
Vec2d m_live_aslot_r_label {0,0}
Vec2d m_live_aslot_w_label {0,0}
int m_live_aslot_fi {-1}
Vec2d m_live_slot_len_label {0,0}
Vec2d m_live_slot_w_label {0,0}
Vec2d m_live_slot_angle_label {0,0}
int m_live_slot_fi {-1}
std::vector< Feature > m_features
std::vector< SketchSnap > m_sketch_redo
int m_skipped_last {0}
double m_chain_dup_tol {1e-9}
int m_open_feature {-1}
int m_step_mode_last {-1}
int m_step_last {-1}
int m_step_picks_last {-1}
int m_op_a {-1}
int m_op_b {-1}
double m_op_value {0.0}
Vec2d m_op_anchor {0,0}
Vec2d m_op_dir {0,0}
Vec2d m_op_label {1e18,1e18}
std::vector< SketchEntity > m_op_ghost
bool m_op_dragging_arrow {false}
std::vector< int > m_mirror_targets
std::vector< int > m_op_chain
std::vector< std::vector< std::vector< Vec2d > > > m_xform_base
int m_xform_feat {-1}
Vec2d m_xform_min {0,0}
Vec2d m_xform_max {0,0}
Vec2d m_xform_offset {0,0}
double m_xform_sx {1.0}
double m_xform_sy {1.0}
int m_xform_handle {-1}
Vec2d m_xform_anchor {0,0}
std::vector< int > m_tf_targets
Vec2d m_tf_pivot {0,0}
Vec2d m_tf_delta {0,0}
double m_tf_angle {0.0}
double m_tf_scale {1.0}
int m_tf_count {3}
double m_tf_handle_r {1.0}
std::vector< SketchEntity > m_tf_ghost
int m_tf_handle {-1}
bool m_tf_dragging {false}
Vec2d m_tf_label_a {1e18,1e18}
Vec2d m_tf_label_b {1e18,1e18}
int m_dof {-1}
bool m_solve_ok {true}
std::vector< char > m_entity_conflict
std::vector< DimAnnot > m_dimensions
std::vector< int > m_bad_dims
int m_dim_e0 {-1}
SketchPointRole m_dim_r0 {SketchPointRole::P0}
bool m_dim_has0 {false}
int m_pending_dim {-1}
Mode m_mode {Mode::Polyline}
int m_sel_a {-1}
int m_sel_b {-1}
bool m_constrain_entities {false}
int m_pick0 {-1}
int m_pick1 {-1}
int m_pick2 {-1}
Vec2d m_pick0_pt {0,0}
std::vector< int > m_constraint_hl
std::vector< SketchEntityConstraintDef > m_constrain_cons
std::vector< GlyphHit > m_glyph_hits
double m_glyph_r {0.0}
GLModel m_line_model
GLModel m_vertex_model
GLModel m_highlight_model
int m_dim_label_seq {0}
std::vector< LabelRect > m_label_rects
float m_render_scale {1.0f}
GLModel m_fill_model
std::vector< DisplaySketch > m_display_sketches
std::vector< std::pair< int, ColorRGBA > > m_hl_sketches
int m_display_pick {-1}
const std::vector< CadBody > * m_solid_bodies {nullptr}
const TriangleMesh * m_solid_mesh {nullptr}
const std::vector< int > * m_solid_tri_face {nullptr}
const std::vector< int > * m_solid_tri_body {nullptr}
const std::vector< bool > * m_solid_visible {nullptr}
int m_pick_only_body {-1}
const std::vector< Transform3d > * m_solid_xform {nullptr}
std::vector< std::vector< std::vector< Vec3d > > > m_body_edges
std::vector< TopoDS_Shape > m_body_edges_shape
std::vector< double > m_body_edges_tol
bool m_body_edges_hidden {false}
SolidSel m_solid_sel {SolidSel::None}
int m_sel_body {-1}
TopoDS_Shape m_sel_shape
int m_sel_face {-1}
int m_sel_edge {-1}
std::vector< Vec3d > m_sel_edge_pts
std::vector< int > m_sel_edges_more
std::vector< std::vector< Vec3d > > m_sel_edges_more_pts
Vec3d m_sel_vertex_pt {Vec3d::Zero()}
SolidPick m_pre
GLSelectionRectangle m_rubber
std::optional< wxMouseEvent > m_right_press
bool m_escalate_repick {true}
std::vector< FaceHighlight > m_hl_faces
FaceHighlight m_sel_hl
FaceHighlight m_pre_hl
bool m_show_planes {false}
bool m_show_axes {false}
std::vector< SketchPlane > m_datum_planes
std::vector< Vec2d > m_datum_sizes
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
GLModel m_solid_edge_model
GLModel m_body_edges_model
GLModel m_solid_vertex_model
int m_display_pick_region {-1}
bool m_ex_active {false}
SketchPlane m_ex_plane
Vec2d m_ex_centroid {0,0}
double m_ex_depth {0.0}
double m_ex_depth2 {0.0}
bool m_ex_two_sided {false}
bool m_ex_flip {false}
int m_ex_drag {-1}
int m_ex_press_x {0}
int m_ex_press_y {0}
GLModel m_ex_arrow_model
bool m_dz_active {false}
SketchPlane m_dz_plane
double m_dz_usize {60.0}
double m_dz_vsize {60.0}
int m_dz_drag {-1}
int m_dz_press_x {0}
int m_dz_press_y {0}
Vec3d m_dz_anchor {Vec3d::Zero()}
Vec3d m_dz_normal {0.0, 0.0, 1.0}
double m_dz_offset {0.0}
bool m_dz_offset_on {false}
bool m_hx_active {false}
SketchPlane m_hx_plane
double m_hx_radius {10.0}
double m_hx_pitch {2.0}
double m_hx_height {20.0}
double m_hx_taper {0.0}
bool m_hx_left {false}
int m_hx_drag {-1}
int m_hx_press_x {0}
int m_hx_press_y {0}
bool m_rb_active {false}
SketchPlane m_rb_plane
Vec2d m_rb_p0 {Vec2d::Zero()}
Vec2d m_rb_p1 {Vec2d::Zero()}
double m_rb_thickness {2.0}
int m_rb_drag {-1}
bool m_dbp_active {false}
std::vector< SketchPlane > m_dbp_planes
std::vector< int > m_dbp_base
std::vector< std::string > m_dbp_labels
int m_dbp_hover {-1}
bool m_mv_active {false}
int m_mv_body {-1}
Vec3d m_mv_base {Vec3d::Zero()}
Vec3d m_mv_offset {Vec3d::Zero()}
Transform3d m_mv_base_xform {Transform3d::Identity()}
Eigen::Matrix3d m_mv_rot {Eigen::Matrix3d::Identity()}
Eigen::Matrix3d m_mv_rot_start {Eigen::Matrix3d::Identity()}
double m_mv_arc_a0 {0.0}
int m_mv_drag {-1}
double m_mv_radius {0.0}
int m_mv_press_x {0}
int m_mv_press_y {0}
double m_mv_grab_along {0.0}
GLModel m_mv_arrow_model
bool m_fl_active {false}
Vec3d m_fl_anchor {Vec3d::Zero()}
Vec3d m_fl_dir {Vec3d::UnitZ()}
double m_fl_radius {1.0}
bool m_fl_drag {false}
int m_fl_press_x {0}
int m_fl_press_y {0}
double m_fl_grab_proj {0.0}
double m_fl_grab_radius {1.0}
GLModel m_fl_arrow_model
bool m_hl_active {false}
SketchPlane m_hl_plane
double m_hl_x {0.0}
double m_hl_y {0.0}
double m_hl_diameter {6.0}
double m_hl_depth {10.0}
bool m_hl_through {true}
bool m_hl_has_bounds {false}
double m_hl_umin {0}
double m_hl_umax {0}
double m_hl_vmin {0}
double m_hl_vmax {0}
int m_hl_drag {-1}
int m_hl_press_x {0}
int m_hl_press_y {0}
double m_hl_grab_proj {0.0}
double m_hl_grab_val {0.0}
Vec2d m_hl_grab_uv {0.0, 0.0}
double m_hl_grab_x {0.0}
double m_hl_grab_y {0.0}
GLModel m_hl_stroke_model
bool m_th_active {false}
SketchPlane m_th_plane
double m_th_x {0.0}
double m_th_y {0.0}
double m_th_radius {5.0}
double m_th_height {10.0}
int m_th_drag {-1}
int m_th_press_x {0}
int m_th_press_y {0}
double m_th_grab_proj {0.0}
double m_th_grab_val {0.0}
Vec2d m_th_grab_uv {0.0, 0.0}
double m_th_grab_x {0.0}
double m_th_grab_y {0.0}
GLModel m_th_stroke_model
bool m_sh_active {false}
Vec3d m_sh_anchor {Vec3d::Zero()}
Vec3d m_sh_dir {Vec3d::UnitZ()}
double m_sh_thickness {2.0}
bool m_sh_drag {false}
int m_sh_press_x {0}
int m_sh_press_y {0}
double m_sh_grab_proj {0.0}
double m_sh_grab_val {2.0}
GLModel m_sh_stroke_model
bool m_rv_active {false}
Vec3d m_rv_center {Vec3d::Zero()}
Vec3d m_rv_axis {Vec3d::UnitX()}
Vec3d m_rv_ref {Vec3d::UnitY()}
double m_rv_radius {10.0}
double m_rv_angle {360.0}
bool m_rv_flip {false}
bool m_rv_drag {false}
int m_rv_press_x {0}
int m_rv_press_y {0}
GLModel m_rv_stroke_model
bool m_dr_active {false}
Vec3d m_dr_center {Vec3d::Zero()}
Vec3d m_dr_axis {Vec3d::UnitZ()}
Vec3d m_dr_ref {Vec3d::UnitX()}
double m_dr_radius {10.0}
double m_dr_angle {5.0}
bool m_dr_drag {false}
int m_dr_press_x {0}
int m_dr_press_y {0}
GLModel m_dr_stroke_model
std::function< void(double)> m_on_draft_angle_changed
bool m_ct_active {false}
Vec3d m_ct_base {Vec3d::Zero()}
Vec3d m_ct_n {Vec3d::UnitZ()}
Vec3d m_ct_u {Vec3d::UnitX()}
Vec3d m_ct_v {Vec3d::UnitY()}
double m_ct_offset {0.0}
double m_ct_half {10.0}
bool m_ct_drag {false}
double m_ct_grab_val {0.0}
double m_ct_grab_proj {0.0}
GLModel m_ct_stroke_model
GLModel m_ct_rect_model
std::function< void(double)> m_on_cut_offset_changed
bool m_pt_active {false}
bool m_pt_circular {false}
Vec3d m_pt_base {Vec3d::Zero()}
Vec3d m_pt_dirw {Vec3d::UnitX()}
Vec3d m_pt_origin {Vec3d::Zero()}
Vec3d m_pt_normal {Vec3d::UnitZ()}
Vec3d m_pt_cref {Vec3d::UnitX()}
Vec3d m_pt_ccenter {Vec3d::Zero()}
double m_pt_radius {10.0}
int m_pt_count {3}
double m_pt_spacing {20.0}
double m_pt_angle {360.0}
bool m_pt_drag {false}
int m_pt_press_x {0}
int m_pt_press_y {0}
GLModel m_pt_stroke_model

Static Private Attributes

static constexpr double kPickPx = 8.0
static constexpr double kToolPickPx = 24.0
static constexpr double kLabelPx = 24.0

Detailed Description


Class Documentation

◆ Slic3r::GUI::DesignSketchTool::DisplaySketch

struct Slic3r::GUI::DesignSketchTool::DisplaySketch
Collaboration diagram for Slic3r::GUI::DesignSketchTool::DisplaySketch:
Class Members
vector< SketchEntity > entities
int feature {-1}
SketchPlane plane

◆ Slic3r::GUI::DesignSketchTool::MateConnectorGlyph

struct Slic3r::GUI::DesignSketchTool::MateConnectorGlyph
Class Members
Vec3d origin {0, 0, 0}
int role {0}
bool roll_undefined {false}
Vec3d x {1, 0, 0}
Vec3d y {0, 1, 0}

◆ Slic3r::GUI::DesignSketchTool::LoopInfo

struct Slic3r::GUI::DesignSketchTool::LoopInfo
Collaboration diagram for Slic3r::GUI::DesignSketchTool::LoopInfo:
Class Members
double area {0.0}
bool closed {false}
bool defect {false}
Vec2d defect_at {0, 0}
vector< int > ents
vector< int > holes

◆ Slic3r::GUI::DesignSketchTool::LoopReport

struct Slic3r::GUI::DesignSketchTool::LoopReport
Collaboration diagram for Slic3r::GUI::DesignSketchTool::LoopReport:
Class Members
vector< LoopInfo > loops
vector< Vec2d > open_ends

◆ Slic3r::GUI::DesignSketchTool::DimAnnot

struct Slic3r::GUI::DesignSketchTool::DimAnnot
Class Members
int con {-1}
int ea {-1}
int eb {-1}
DimType kind {DimType::None}
Vec2d label_pos {0, 0}
SketchPointRole ra {SketchPointRole::P0}
SketchPointRole rb {SketchPointRole::P0}
double side {1.0}
double value {0.0}

◆ Slic3r::GUI::DesignSketchTool::Handle

struct Slic3r::GUI::DesignSketchTool::Handle
Class Members
int ctrl_index {-1}
int ei {-1}
int group {-1}
bool hovered {false}
Vec2d pos {0, 0}
HandleRole role {HandleRole::P0}

◆ Slic3r::GUI::DesignSketchTool::Feature

struct Slic3r::GUI::DesignSketchTool::Feature
Class Members
int begin {0}
Vec2d c0 {0, 0}
Vec2d c1 {0, 0}
int end {0}
FeatureKind kind {FeatureKind::Free}
double param {0.0}
int sides {0}

◆ Slic3r::GUI::DesignSketchTool::RegionLoop

struct Slic3r::GUI::DesignSketchTool::RegionLoop
Collaboration diagram for Slic3r::GUI::DesignSketchTool::RegionLoop:
Class Members
bool defect {false}
Vec2d defect_at {0, 0}
vector< int > ents
vector< int > holes
vector< Vec2d > poly

◆ Slic3r::GUI::DesignSketchTool::AutoEditStep

struct Slic3r::GUI::DesignSketchTool::AutoEditStep
Collaboration diagram for Slic3r::GUI::DesignSketchTool::AutoEditStep:
Class Members
function< void(double)> apply
vector< int > hi
Vec2d label
string title
double value

◆ Slic3r::GUI::DesignSketchTool::SketchSnap

struct Slic3r::GUI::DesignSketchTool::SketchSnap
Collaboration diagram for Slic3r::GUI::DesignSketchTool::SketchSnap:
Class Members
size_t after_constraints {0}
size_t after_entities {0}
vector< SketchEntityConstraintDef > constraints
vector< DimAnnot > dimensions
vector< SketchEntity > entities
vector< Feature > features

◆ Slic3r::GUI::DesignSketchTool::GlyphHit

struct Slic3r::GUI::DesignSketchTool::GlyphHit
Class Members
Vec2d c {0,0}
int con {-1}

◆ Slic3r::GUI::DesignSketchTool::LabelRect

struct Slic3r::GUI::DesignSketchTool::LabelRect
Class Members
double h {0}
double w {0}
double x {0}
double y {0}

◆ Slic3r::GUI::DesignSketchTool::SolidPick

struct Slic3r::GUI::DesignSketchTool::SolidPick
Collaboration diagram for Slic3r::GUI::DesignSketchTool::SolidPick:
Class Members
int body {-1}
int edge {-1}
vector< Vec3d > edge_pts
int face {-1}
SolidSel kind {SolidSel::None}
Vec3d vertex_pt {Vec3d::Zero()}

◆ Slic3r::GUI::DesignSketchTool::FaceHighlight

struct Slic3r::GUI::DesignSketchTool::FaceHighlight
Collaboration diagram for Slic3r::GUI::DesignSketchTool::FaceHighlight:
Class Members
int body {-1}
vector< vector< Vec3d > > edges
vector< int > faces
TopoDS_Shape shape

Member Enumeration Documentation

◆ DimType

Enumerator
None 
Length 
Diameter 
Radius 
Angle 
Distance 
DistanceToLine 
663{ None, Length, Diameter, Radius, Angle, Distance, DistanceToLine };
@ Distance
Definition SketchEngine.hpp:101
@ Diameter
Definition SketchEngine.hpp:105
@ Radius
Definition SketchEngine.hpp:105
@ Angle
Definition CadDocument.hpp:28
@ None
Definition SketchEngine.hpp:180

◆ FeatureKind

Enumerator
Free 
Line 
Circle 
Arc 
CornerRect 
CenterRect 
Slot 
ArcSlot 
Polygon 
Ellipse 
RoundedRect 
BSpline 
825 { Free, Line, Circle, Arc, CornerRect, CenterRect,
826 Slot, ArcSlot, Polygon, Ellipse, RoundedRect, BSpline };
@ Circle
Definition Button.hpp:37
Slic3r::Polygon Polygon
Definition Emboss.cpp:101

◆ HandleRole

Enumerator
P0 
P1 
Center 
RadiusHandle 
SlotCenter0 
SlotCenter1 
SlotWidth 
RectCorner 
PolygonVertex 
MajorAxis 
MinorAxis 
BSplineCtrl 
810 { P0, P1, Center, RadiusHandle,
811 SlotCenter0, SlotCenter1, SlotWidth,
812 RectCorner, PolygonVertex, MajorAxis, MinorAxis, BSplineCtrl };
@ P0
Definition SketchEngine.hpp:131
@ Center
Definition SketchEngine.hpp:131
@ P1
Definition SketchEngine.hpp:131

◆ Mode

Enumerator
Select 
Dimension 
Polyline 
Line 
CornerRect 
CenterRect 
ObliqueRect 
RoundedRect 
CenterCircle 
TwoPointCircle 
Point 
ThreePointCircle 
ThreePointArc 
TangentArc 
CenterArc 
Slot 
ArcSlot 
Polygon 
Ellipse 
EllipseArc 
BSpline 
Fillet 
Chamfer 
Offset 
Mirror 
Trim 
Extend 
Move 
Rotate 
Scale 
Array 
PolarArray 
TransformArt 
Constrain 
91 { Select, Dimension, Polyline, Line, CornerRect, CenterRect, ObliqueRect,
92 RoundedRect, CenterCircle, TwoPointCircle, Point,
93 ThreePointCircle, ThreePointArc, TangentArc, CenterArc, Slot, ArcSlot, Polygon,
94 Ellipse, EllipseArc, BSpline,
95 // In-canvas edit-op TOOLBAR tools (drag-arrow + label, no numeric card):
97 // Standalone scissors: click a segment to trim/extend it (immediate, no card):
98 Trim, Extend,
99 // In-canvas transform TOOLBAR tools (pick targets + drag handle/label, no card):
100 Move, Rotate, Scale, Array, PolarArray,
101 // In-canvas bounding-box transform for imported Text/SVG art:
102 TransformArt,
103 Constrain };
Kernel::Point_3 Point
Definition MeshRepair.cpp:81
@ Offset
Definition CadDocument.hpp:28
@ Fillet
Definition CadDocument.hpp:26
@ Mirror
Definition CadDocument.hpp:26
@ Chamfer
Definition CadDocument.hpp:26

◆ SolidSel

Enumerator
None 
Whole 
Face 
Edge 
Vertex 
229{ None, Whole, Face, Edge, Vertex };
@ Edge
Definition Measure.hpp:26
Mesh::Vertex_index Vertex
Definition MeshRepair.cpp:84
Mesh::Face_index Face
Definition MeshRepair.cpp:86

Member Function Documentation

◆ abort_gesture()

bool Slic3r::GUI::DesignSketchTool::abort_gesture ( )
411{
412 if (!gesture_pending()) return false;
413 m_points.clear();
414 m_has_cursor = false;
415 // Picks are a gesture too: drop them, never apply them, and keep the tool armed.
416 if (has_pending_picks()) {
417 reset_op();
418 reset_tf();
419 m_dim_has0 = false;
420 m_dim_e0 = -1;
422 m_pick0 = m_pick1 = m_pick2 = -1;
423 m_sel_a = m_sel_b = -1;
424 m_selection.clear();
425 m_point_sel.clear();
427 }
429 return true;
430}
std::vector< int > m_selection
Definition DesignSketchTool.hpp:1105
std::function< void(int count)> on_selection_changed
Definition DesignSketchTool.hpp:655
void emit_step_hint()
Definition DesignSketchTool.cpp:9510
int m_pick2
Definition DesignSketchTool.hpp:1249
SketchPointRole m_dim_r0
Definition DesignSketchTool.hpp:1240
int m_pick0
Definition DesignSketchTool.hpp:1247
bool has_pending_picks() const
Definition DesignSketchTool.hpp:112
int m_sel_a
Definition DesignSketchTool.hpp:1244
int m_sel_b
Definition DesignSketchTool.hpp:1245
void reset_op()
Definition DesignSketchTool.cpp:8549
bool m_has_cursor
Definition DesignSketchTool.hpp:1081
int m_dim_e0
Definition DesignSketchTool.hpp:1239
std::vector< Vec2d > m_points
Definition DesignSketchTool.hpp:1075
void reset_tf()
Definition DesignSketchTool.cpp:9112
bool gesture_pending() const
Definition DesignSketchTool.hpp:115
std::vector< std::pair< int, SketchPointRole > > m_point_sel
Definition DesignSketchTool.hpp:1106
int m_pick1
Definition DesignSketchTool.hpp:1248
bool m_dim_has0
Definition DesignSketchTool.hpp:1241

References emit_step_hint(), gesture_pending(), has_pending_picks(), m_dim_e0, m_dim_has0, m_dim_r0, m_has_cursor, m_pick0, m_pick1, m_pick2, m_point_sel, m_points, m_sel_a, m_sel_b, m_selection, on_selection_changed, Slic3r::P0, reset_op(), and reset_tf().

Referenced by request_exit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_entities_scripted()

int Slic3r::GUI::DesignSketchTool::add_entities_scripted ( const std::vector< SketchEntity > & ents)
10441{
10442 if (ents.empty()) return -1;
10443 const int base = int(m_entities.size());
10444 for (const SketchEntity& e : ents) m_entities.push_back(e);
10445 // Auto-constrain, but do NOT let the inference move what the caller specified. A gesture
10446 // gets 3 degrees of slack because a hand cannot click an exact horizontal; a scripted add
10447 // has already said exactly what it means, and snapping a segment 2 degrees off to exactly
10448 // horizontal silently rewrites it. Measured on a real drawing: feeding the 64 flattened
10449 // segments of one circle moved vertices by up to 0.058 mm and shrank the enclosed area by
10450 // 0.067%, because several segments of the polygon fell inside that 3 degree window. Exact
10451 // coincidence inference is unaffected — it already tests to 1e-6 — so chains still weld
10452 // and genuinely axis-aligned scripted geometry still gets its Horizontal/Vertical.
10453 //
10454 // ZERO, not 1e-4. Any window at all is a window that moves the caller's points, and 1e-4 rad
10455 // was still wide enough to catch the short chords of a small flattened circle: on four of
10456 // the 39 corpus drawings the loops that came back wrong were all TINY (1.4 to 13 mm^2), out
10457 // by up to 7e-4 relative, because a 0.005 degree tilt on a 0.3 mm chord is inside 1e-4.
10458 // With zero, only a segment that is EXACTLY axis-aligned is constrained, and constraining
10459 // something already true cannot move it. 8xg1.
10460 // The weld window closes too. Two endpoints a micron apart are not the same point when a
10461 // caller typed both of them: on MPD681, 20 of 363 scripted segments were dragged onto a
10462 // common point up to 0.0021 mm away, because welding is TRANSITIVE and three vertices near
10463 // the origin chained into one. Exactly-equal endpoints still weld, which is what keeps a
10464 // scripted profile closed — a ring's last point IS its first point.
10465 infer_auto_constraints(base, 0.0, 0.0);
10466 resolve_live();
10467 // A scripted add is not a drawn gesture, and draw-then-edit must not fire for it. The render
10468 // pass arms that on a jump in the entity count (see the m_autoedit_seen block in render()),
10469 // so a bulk load made while a creation tool is armed selected the last scripted entity and
10470 // opened that tool's value field — which freezes the canvas (on_mouse_impl returns early
10471 // while m_awaiting_length) and swallows every letter (in_text includes inline_busy()). The
10472 // symptom was that the first key and click after sketch_add did nothing until one Escape had
10473 // dismissed the field. Resyncing the baseline here leaves an ALREADY open field alone; it
10474 // only stops this add from being read as something the user just drew. j7gc.
10475 m_autoedit_seen = int(m_entities.size());
10476 return base;
10477}
void resolve_live()
Definition DesignSketchTool.cpp:868
int m_autoedit_seen
Definition DesignSketchTool.hpp:1086
void infer_auto_constraints(int base, double ang_tol_rad=3.0 *M_PI/180.0, double weld_tol=1e-3)
Definition DesignSketchTool.cpp:2718
std::vector< SketchEntity > m_entities
Definition DesignSketchTool.hpp:1076

References add_entities_scripted(), infer_auto_constraints(), m_autoedit_seen, m_entities, and resolve_live().

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_add(), Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_mirror(), Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_offset(), and add_entities_scripted().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_imported_regions()

bool Slic3r::GUI::DesignSketchTool::add_imported_regions ( const std::vector< std::vector< std::vector< Vec2d > > > & regions)
2898{
2899 if (!m_active) return false; // no session to draw into; caller makes a feature
2900 const bool saved = m_construction;
2901 m_construction = false; // art is real geometry, never construction lines
2902 size_t before = m_entities.size();
2903 for (const auto& region : regions)
2904 for (const auto& loop : region)
2905 push_closed_lines(loop); // every glyph contour, holes included
2906 m_construction = saved;
2907 if (m_entities.size() == before) return false; // nothing importable — say so, do not lie
2908 // Art is not "just drawn", so it must NOT enter the draw-then-edit queue. Without this the
2909 // glyph contours are treated as fresh entities and a Length field opens on the first of
2910 // them — on a word, that is one value editor per segment, and an open field freezes the
2911 // canvas (yce). reset_autoedit() marks every entity as already seen.
2913 // The new lines carry no constraints, so the solver has nothing to move; resolve anyway so
2914 // the degrees-of-freedom readout counts them instead of going stale.
2915 resolve_live();
2916 return true;
2917}
void push_closed_lines(const std::vector< Vec2d > &corners)
Definition DesignSketchTool.cpp:2919
bool m_active
Definition DesignSketchTool.hpp:1073
bool m_construction
Definition DesignSketchTool.hpp:1077
void reset_autoedit()
Definition DesignSketchTool.hpp:628

References add_imported_regions(), m_active, m_construction, m_entities, push_closed_lines(), reset_autoedit(), and resolve_live().

Referenced by add_imported_regions().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ announce_loop_defects()

void Slic3r::GUI::DesignSketchTool::announce_loop_defects ( )
private
937{
938 bool any = false;
939 for (const RegionLoop& r : region_loops(m_entities))
940 if (r.defect) { any = true; break; }
941 if (any && !m_loop_defect_shown)
942 notify(_u8L("This profile crosses or folds back on itself at the red mark, so it does not bound one region"));
944}
std::vector< RegionLoop > region_loops(const std::vector< SketchEntity > &ents) const
Definition DesignSketchTool.cpp:7276
bool m_loop_defect_shown
Definition DesignSketchTool.hpp:786
void notify(const std::string &msg, bool error=true)
Definition DesignSketchTool.hpp:702
Definition DesignSketchTool.hpp:1047
#define _u8L(s)
Definition I18N.hpp:11

References _u8L, m_entities, m_loop_defect_shown, notify(), and region_loops().

Referenced by resolve_live_drag().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ append_entities()

void Slic3r::GUI::DesignSketchTool::append_entities ( const std::vector< SketchEntity > & ents)
private
2956{
2957 for (const SketchEntity& e : ents)
2958 m_entities.push_back(e);
2959}

References append_entities(), and m_entities.

Referenced by append_entities(), end_chain(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ append_ribbons()

void Slic3r::GUI::DesignSketchTool::append_ribbons ( GLModel::Geometry & g,
int body,
const std::vector< std::vector< Vec3d > > & polylines,
const Vec3d & vd,
const Vec3d & pull,
double hw ) const
private
3540{
3542 unsigned int base = unsigned(g.vertices_count());
3543 for (const std::vector<Vec3d>& pl : polylines)
3544 for (size_t s = 1; s < pl.size(); ++s) {
3545 const Vec3d a = body_xform_pt(body, pl[s - 1]) + pull, c = body_xform_pt(body, pl[s]) + pull;
3546 Vec3d dir = c - a; if (dir.norm() < 1e-9) continue; dir.normalize();
3547 Vec3d off = dir.cross(vd);
3548 if (off.norm() < 1e-9) continue; // edge seen end-on: a point, nothing to draw
3549 off = off.normalized() * hw;
3550 g.add_vertex((Vec3f)(a + off).cast<float>());
3551 g.add_vertex((Vec3f)(c + off).cast<float>());
3552 g.add_vertex((Vec3f)(c - off).cast<float>());
3553 g.add_vertex((Vec3f)(a - off).cast<float>());
3554 g.add_triangle(base, base + 1, base + 2);
3555 g.add_triangle(base, base + 2, base + 3); base += 4;
3556 }
3557}
Vec3d body_xform_pt(int body, const Vec3d &p) const
Definition DesignSketchTool.cpp:3607
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
Eigen::Matrix< float, 3, 1, Eigen::DontAlign > Vec3f
Definition Point.hpp:65
@ pull
On-demand fetch via REST API (blocking call).
Definition IPrinterAgent.hpp:59
auto cast(const BoundingBoxBase< Tin > &b)
Definition BoundingBox.hpp:299

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), append_ribbons(), body_xform_pt(), Slic3r::cast(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::GLModel::Geometry::P3, Slic3r::pull, Slic3r::GUI::GLModel::Geometry::Triangles, and Slic3r::GUI::GLModel::Geometry::vertices_count().

Referenced by append_ribbons(), render_body_edges(), render_face_outline(), and render_reference_axes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ apply_angle_between()

void Slic3r::GUI::DesignSketchTool::apply_angle_between ( int ia,
int ib,
double deg )
private
706{
707 SketchEntity& A = m_entities[ia];
708 SketchEntity& B = m_entities[ib];
709 const Vec2d aE[2] = { A.p0, A.p1 };
710 const Vec2d bE[2] = { B.p0, B.p1 };
711 int si = -1, sj = -1;
712 double best = 1e-6;
713 for (int i = 0; i < 2; ++i)
714 for (int j = 0; j < 2; ++j) {
715 const double d = (aE[i] - bE[j]).squaredNorm();
716 if (d < best) { best = d; si = i; sj = j; }
717 }
718 Vec2d pivot, refDir, bMoving;
719 bool moveP1;
720 if (si >= 0) { // shared vertex: pivot there, A's arm is the reference
721 pivot = aE[si];
722 refDir = aE[1 - si] - pivot;
723 moveP1 = (sj == 0); // move the B end that is NOT at the pivot
724 bMoving = moveP1 ? B.p1 : B.p0;
725 } else { // no shared vertex: pivot B.p0, A's direction is reference
726 pivot = B.p0;
727 refDir = A.p1 - A.p0;
728 moveP1 = true;
729 bMoving = B.p1;
730 }
731 double nr = refDir.norm();
732 if (nr < 1e-9) return;
733 refDir /= nr;
734 const Vec2d db = bMoving - pivot;
735 const double Lb = db.norm();
736 if (Lb < 1e-9) return;
737 const double cross = refDir.x() * db.y() - refDir.y() * db.x();
738 const double sign = (cross >= 0.0) ? 1.0 : -1.0; // keep B on its current side
739 const double rad = sign * deg * M_PI / 180.0;
740 const Vec2d ndir(refDir.x() * std::cos(rad) - refDir.y() * std::sin(rad),
741 refDir.x() * std::sin(rad) + refDir.y() * std::cos(rad));
742 const Vec2d nb = pivot + Lb * ndir;
743 if (moveP1) B.p1 = nb; else B.p0 = nb;
744}
#define M_PI
Definition ExtrusionSimulator.cpp:31
double rad(double deg)
Definition DesignSketchTool.cpp:7748
T cross(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:168
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67

References Slic3r::cross(), m_entities, M_PI, Slic3r::SketchEntity::p0, and Slic3r::SketchEntity::p1.

Referenced by apply_dimension().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ apply_dimension()

void Slic3r::GUI::DesignSketchTool::apply_dimension ( double v)
747{
748 // Refuse BEFORE moving or recording. Each case below has its own threshold (positive for
749 // length / radius / diameter, non-negative for a distance) and the constraint used to be
750 // recorded UNCONDITIONALLY after them — so a value that moved nothing was still handed to
751 // the solver, which then had to satisfy something it never could. The socket guarded against
752 // this and said so; now the tool does too, and it says why.
753 const DimType kind = dimension_kind();
754 const bool needs_positive = (kind == DimType::Length || kind == DimType::Radius ||
755 kind == DimType::Diameter);
756 if (!std::isfinite(v) || (needs_positive && v <= 0.0) ||
757 (!needs_positive && kind != DimType::Angle && kind != DimType::None && v < 0.0)) {
758 show_refusal(needs_positive ? _u8L("The value must be greater than zero")
759 : _u8L("The value must not be negative (zero means coincident)"));
760 return;
761 }
762 switch (dimension_kind()) {
763 case DimType::Length: {
764 SketchEntity& e = m_entities[m_selection[0]];
765 const Vec2d d = e.p1 - e.p0;
766 const double r = d.norm();
767 if (r > 1e-9 && v > 1e-9) e.p1 = e.p0 + (v / r) * d;
768 break;
769 }
770 case DimType::Diameter: if (v > 1e-9) m_entities[m_selection[0]].radius = 0.5 * v; break;
771 case DimType::Radius: if (v > 1e-9) m_entities[m_selection[0]].radius = v; break;
773 case DimType::Distance: {
774 // Move the 2nd selection so its reference point sits at distance v from the
775 // 1st (v == 0 -> coincident / concentric). Translate the whole entity.
776 if (v < 0.0) break;
777 Vec2d ra(0, 0), rb(0, 0);
779 SketchEntity& b = m_entities[m_selection[1]];
780 entity_ref_point(b, rb);
781 const Vec2d d = rb - ra;
782 const double r = d.norm();
783 Vec2d target = ra;
784 if (r > 1e-9) target = ra + (v / r) * d;
785 else target = ra + Vec2d(v, 0.0);
786 translate_entity(b, target - rb);
787 break;
788 }
790 // Move the point-like selection perpendicular to the line so its reference
791 // point is at distance v (v == 0 -> on the line / on the axis).
792 if (v < 0.0) break;
793 const bool aLine = (m_entities[m_selection[0]].type == SketchEntity::Type::Line);
794 const SketchEntity& L = m_entities[m_selection[aLine ? 0 : 1]];
795 SketchEntity& P = m_entities[m_selection[aLine ? 1 : 0]];
796 Vec2d rp(0, 0); entity_ref_point(P, rp);
797 Vec2d dir = L.p1 - L.p0;
798 const double n = dir.norm();
799 if (n < 1e-9) break;
800 const Vec2d nrm(-dir.y() / n, dir.x() / n);
801 const double d0 = (rp - L.p0).dot(nrm); // current signed distance
802 const double sign = (d0 >= 0.0) ? 1.0 : -1.0; // keep the point on its side
803 translate_entity(P, (sign * v - d0) * nrm);
804 break;
805 }
806 default: break;
807 }
808 record_dimension_constraint(v); // store a driving constraint for this dimension
809 resolve_live(); // live-solve so the viewport shows the solved sketch
810 if (!m_solve_ok) // the number on screen is not the geometry's number
811 notify(_u8L("That dimension cannot be satisfied — the sketch is over-constrained"));
812 m_selection.clear();
814}
#define L(s)
Definition ExtrusionEntity.cpp:25
DimType dimension_kind() const
Definition DesignSketchTool.cpp:640
bool m_solve_ok
Definition DesignSketchTool.hpp:1235
DimType
Definition DesignSketchTool.hpp:663
@ Distance
Definition DesignSketchTool.hpp:663
@ DistanceToLine
Definition DesignSketchTool.hpp:663
@ Angle
Definition DesignSketchTool.hpp:663
@ None
Definition DesignSketchTool.hpp:663
@ Diameter
Definition DesignSketchTool.hpp:663
@ Length
Definition DesignSketchTool.hpp:663
@ Radius
Definition DesignSketchTool.hpp:663
void record_dimension_constraint(double v)
Definition DesignSketchTool.cpp:819
void show_refusal(const std::string &why)
Definition DesignSketchTool.cpp:403
void apply_angle_between(int ia, int ib, double deg)
Definition DesignSketchTool.cpp:705
static bool entity_ref_point(const SketchEntity &e, Vec2d &out)
Definition DesignSketchTool.cpp:10408
static void translate_entity(SketchEntity &e, const Vec2d &d)
Definition DesignSketchTool.cpp:10421
T dot(const boost::geometry::model::d2::point_xy< T > &v1, const boost::geometry::model::d2::point_xy< T > &v2)
Definition ExtrusionSimulator.cpp:154
@ P
Definition libslic3r.h:149
@ Line
Definition SketchEngine.hpp:31

References _u8L, Angle, apply_angle_between(), Diameter, dimension_kind(), Distance, DistanceToLine, Slic3r::dot(), Slic3r::GUI::entity_ref_point(), L, Length, Slic3r::SketchEntity::Line, m_entities, m_selection, m_solve_ok, None, notify(), on_selection_changed, Slic3r::P, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Radius, record_dimension_constraint(), resolve_live(), show_refusal(), and Slic3r::GUI::translate_entity().

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_set_value(), and open_selection_dimension_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ apply_live_trim()

bool Slic3r::GUI::DesignSketchTool::apply_live_trim ( const Vec2d & p,
double tol,
bool extend )
private
1811{
1812 double best = 1e30; int bi = -1;
1813 for (size_t i = 0; i < m_entities.size(); ++i) {
1814 const double d = entity_pick_dist(p, m_entities[i]);
1815 if (d < best) { best = d; bi = int(i); }
1816 }
1817 if (bi < 0 || best > tol) return false;
1818 using Ty = SketchEntity::Type;
1819 const Ty st = m_entities[bi].type;
1820 const bool subject_ok = extend ? (st == Ty::Line || st == Ty::Arc)
1821 : (st == Ty::Line || st == Ty::Arc || st == Ty::Circle);
1822 if (!subject_ok) return false;
1823 std::vector<SketchEntity> others;
1824 others.reserve(m_entities.size());
1825 for (size_t i = 0; i < m_entities.size(); ++i)
1826 if (int(i) != bi) others.push_back(m_entities[i]);
1827 const bool ok = extend ? SketchEngine::extend_entity(m_entities[bi], others, p)
1828 : SketchEngine::trim_entity(m_entities[bi], others, p);
1829 if (!ok) return false;
1830 drop_constraints_referencing(bi); // the slid endpoint invalidates this entity's constraints
1831 return true;
1832}
void drop_constraints_referencing(int ei)
Definition DesignSketchTool.cpp:1800
@ Arc
Definition DesignSketchTool.hpp:825
@ Circle
Definition DesignSketchTool.hpp:825
@ Line
Definition DesignSketchTool.hpp:91
static bool extend_entity(SketchEntity &e, const std::vector< SketchEntity > &others, const Vec2d &pick)
Definition SketchEngine.cpp:2008
static bool trim_entity(SketchEntity &e, const std::vector< SketchEntity > &others, const Vec2d &pick)
Definition SketchEngine.cpp:1898
static double entity_pick_dist(const Vec2d &p, const SketchEntity &e)
Definition DesignSketchTool.cpp:10353
Type
Definition SketchEngine.hpp:31

References apply_live_trim(), drop_constraints_referencing(), Slic3r::GUI::entity_pick_dist(), Slic3r::SketchEngine::extend_entity(), m_entities, and Slic3r::SketchEngine::trim_entity().

Referenced by apply_live_trim(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ apply_segment_length()

void Slic3r::GUI::DesignSketchTool::apply_segment_length ( double len)
2432{
2433 if (m_points.size() == 2 && len > 1e-9) {
2434 const Vec2d d = m_points[1] - m_points[0];
2435 const double r = d.norm();
2436 if (r > 1e-9)
2437 m_points[1] = m_points[0] + (len / r) * d;
2438 }
2440 // Driving length constraint on the just-committed Line entity.
2441 if (len > 1e-9 && !m_entities.empty()) {
2442 const int i = int(m_entities.size()) - 1;
2443 if (m_entities[i].type == SketchEntity::Type::Line) {
2444 SketchEntityConstraintDef c;
2446 c.ea = i; c.ra = SketchPointRole::P0;
2447 c.eb = i; c.rb = SketchPointRole::P1;
2448 c.value = len;
2449 m_constraints.push_back(c);
2450 }
2451 }
2452 resolve_live(); // live-solve the in-session sketch
2453}
void keep_segment_as_drawn()
Definition DesignSketchTool.cpp:2455
std::vector< SketchEntityConstraintDef > m_constraints
Definition DesignSketchTool.hpp:1118

References apply_segment_length(), Slic3r::Distance, Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, keep_segment_as_drawn(), Slic3r::SketchEntity::Line, m_constraints, m_entities, m_points, Slic3r::P0, Slic3r::P1, Slic3r::SketchEntityConstraintDef::ra, Slic3r::SketchEntityConstraintDef::rb, resolve_live(), Slic3r::SketchEntityConstraintDef::type, and Slic3r::SketchEntityConstraintDef::value.

Referenced by apply_segment_length().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ arc_mouse_angle()

bool Slic3r::GUI::DesignSketchTool::arc_mouse_angle ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int axis,
double & ang ) const
private
6008{
6009 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6010 const Vec3d ro = r.a, rd = r.b - r.a;
6011 Vec3d e, u, v; ring_basis(axis, e, u, v);
6012 const Vec3d p = m_mv_base + m_mv_offset;
6013 const double denom = rd.dot(e);
6014 if (std::abs(denom) < 1e-9) return false; // ray ∥ ring plane
6015 const Vec3d hit = ro + ((p - ro).dot(e) / denom) * rd;
6016 const Vec3d d = hit - p;
6017 ang = std::atan2(d.dot(v), d.dot(u));
6018 return true;
6019}
Vec3d m_mv_base
Definition DesignSketchTool.hpp:1460
Vec3d m_mv_offset
Definition DesignSketchTool.hpp:1461
void ring_basis(int axis, Vec3d &e, Vec3d &u, Vec3d &v) const
Definition DesignSketchTool.cpp:5854
@ Point
Definition DesignSketchTool.hpp:92

References Slic3r::Linef3::a, arc_mouse_angle(), Slic3r::Linef3::b, m_mv_base, m_mv_offset, Slic3r::GUI::GLCanvas3D::mouse_ray(), ring_basis(), and Slic3r::GUI::wxMouseEvent.

Referenced by arc_mouse_angle(), drag_move_arc(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ arm_polyline_segment_edit()

void Slic3r::GUI::DesignSketchTool::arm_polyline_segment_edit ( )
private
1544{
1545 const int k = int(m_points.size()) - 1; // index of the just-placed vertex
1546 if (k < 1 || !on_inline_edit) return;
1547 const Vec2d a = m_points[k - 1]; // segment anchor (previous vertex)
1548 const Vec2d mid = 0.5 * (a + m_points[k]); // label anchor = segment midpoint
1549 const Vec2d d = m_points[k] - a;
1550 const double L = d.norm();
1551 if (L < 1e-9) return;
1552 double deg = std::atan2(d.y(), d.x()) * 180.0 / M_PI; if (deg < 0.0) deg += 360.0;
1553
1554 m_autoedit_dims.clear();
1555 m_autoedit_dims.push_back({ mid, L, [this, k, a](double len) { // Length
1556 if (k < int(m_points.size())) {
1557 if (!(len > 0.0)) { show_refusal(_u8L("The value must be greater than zero")); return; }
1558 Vec2d dd = m_points[k] - a; const double n = dd.norm();
1559 if (n > 1e-9) m_points[k] = a + (len / n) * dd;
1560 }
1561 }, {}, _u8L("Length") });
1562 m_autoedit_dims.push_back({ mid, deg, [this, k, a](double dg) { // Angle
1563 if (k < int(m_points.size())) {
1564 const double len = (m_points[k] - a).norm();
1565 const double r = dg * M_PI / 180.0;
1566 m_points[k] = a + len * Vec2d(std::cos(r), std::sin(r));
1567 }
1568 }, {}, _u8L("Angle (°)") });
1570 wxGetApp().CallAfter([this] { open_next_autoedit_dim(); });
1571}
std::vector< AutoEditStep > m_autoedit_dims
Definition DesignSketchTool.hpp:1097
int m_autoedit_dim_idx
Definition DesignSketchTool.hpp:1098
std::function< void(wxPoint screen_px, double current, const std::string &title, std::function< void(double)> commit, std::function< void()> cancel)> on_inline_edit
Definition DesignSketchTool.hpp:685
void open_next_autoedit_dim()
Definition DesignSketchTool.cpp:1504

References _u8L, arm_polyline_segment_edit(), L, m_autoedit_dim_idx, m_autoedit_dims, M_PI, m_points, on_inline_edit, open_next_autoedit_dim(), and show_refusal().

Referenced by arm_polyline_segment_edit(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ begin()

void Slic3r::GUI::DesignSketchTool::begin ( const SketchPlane & plane,
Mode mode = Mode::Polyline )
104{
105 m_sketch_redo.clear();
106
107 m_plane = plane;
108 m_mode = mode;
109 m_step_mode_last = -1; // a new session re-announces its step, even if it repeats the last
110 m_points.clear();
111 m_entities.clear();
112 m_construction = false;
113 m_has_cursor = false;
114 m_sel_a = m_sel_b = -1;
115 m_constrain_entities = false;
116 m_pick0 = m_pick1 = m_pick2 = -1;
117 m_constraint_hl.clear();
118 m_constrain_cons.clear();
119 m_awaiting_length = false;
120 m_autoedit_seen = 0; // baseline: no entities yet; first commit triggers edit
121 m_autoedit_pending = false;
122 m_selection.clear();
123 m_point_sel.clear();
124 m_constraints.clear();
125 m_dimensions.clear();
126 m_dim_has0 = false;
127 m_pending_dim = -1;
128 m_dof = -1; m_solve_ok = true; m_entity_conflict.clear();
129 m_features.clear();
130 m_open_feature = -1;
131 m_active = true;
132}
bool m_constrain_entities
Definition DesignSketchTool.hpp:1246
int m_dof
Definition DesignSketchTool.hpp:1234
bool m_autoedit_pending
Definition DesignSketchTool.hpp:1087
int m_pending_dim
Definition DesignSketchTool.hpp:1242
std::vector< int > m_constraint_hl
Definition DesignSketchTool.hpp:1251
const SketchPlane & plane() const
Definition DesignSketchTool.hpp:579
Mode m_mode
Definition DesignSketchTool.hpp:1243
std::vector< Feature > m_features
Definition DesignSketchTool.hpp:1150
std::vector< char > m_entity_conflict
Definition DesignSketchTool.hpp:1236
SketchPlane m_plane
Definition DesignSketchTool.hpp:1074
std::vector< DimAnnot > m_dimensions
Definition DesignSketchTool.hpp:1237
int m_open_feature
Definition DesignSketchTool.hpp:1161
std::vector< SketchEntityConstraintDef > m_constrain_cons
Definition DesignSketchTool.hpp:1252
Mode mode() const
Definition DesignSketchTool.hpp:107
bool m_awaiting_length
Definition DesignSketchTool.hpp:1085
int m_step_mode_last
Definition DesignSketchTool.hpp:1167
std::vector< SketchSnap > m_sketch_redo
Definition DesignSketchTool.hpp:1158

References m_active, m_autoedit_pending, m_autoedit_seen, m_awaiting_length, m_constrain_cons, m_constrain_entities, m_constraint_hl, m_constraints, m_construction, m_dim_has0, m_dimensions, m_dof, m_entities, m_entity_conflict, m_features, m_has_cursor, m_mode, m_open_feature, m_pending_dim, m_pick0, m_pick1, m_pick2, m_plane, m_point_sel, m_points, m_sel_a, m_sel_b, m_selection, m_sketch_redo, m_solve_ok, m_step_mode_last, mode(), and plane().

Referenced by begin_edit(), drop_orientation_constraints(), feature_of(), open_primary_autoedit(), toggle_selection_construction(), and undo_last_entity().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ begin_constrain()

void Slic3r::GUI::DesignSketchTool::begin_constrain ( const SketchProfile & prof,
const SketchPlane & plane )
2496{
2497 m_plane = plane;
2499 m_points = prof.points;
2500 m_entities.clear();
2501 m_has_cursor = false;
2502 m_sel_a = m_sel_b = -1;
2503 m_constrain_entities = false;
2504 m_pick0 = m_pick1 = m_pick2 = -1;
2505 m_active = true;
2506}
@ Constrain
Definition DesignSketchTool.hpp:103

References begin_constrain(), Constrain, m_active, m_constrain_entities, m_entities, m_has_cursor, m_mode, m_pick0, m_pick1, m_pick2, m_plane, m_points, m_sel_a, m_sel_b, plane(), and Slic3r::SketchProfile::points.

Referenced by begin_constrain().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ begin_constrain_entities()

void Slic3r::GUI::DesignSketchTool::begin_constrain_entities ( const std::vector< SketchEntity > & ents,
const SketchPlane & plane )
2510{
2511 m_plane = plane;
2513 m_constrain_entities = true;
2514 m_points.clear();
2515 m_entities = ents;
2516 m_has_cursor = false;
2517 m_sel_a = m_sel_b = -1;
2518 m_pick0 = m_pick1 = m_pick2 = -1;
2519 m_active = true;
2520}

References begin_constrain_entities(), Constrain, m_active, m_constrain_entities, m_entities, m_has_cursor, m_mode, m_pick0, m_pick1, m_pick2, m_plane, m_points, m_sel_a, m_sel_b, and plane().

Referenced by begin_constrain_entities().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ begin_edit()

void Slic3r::GUI::DesignSketchTool::begin_edit ( const std::vector< SketchEntity > & entities,
const std::vector< SketchEntityConstraintDef > & constraints,
const SketchPlane & plane )
140{
145 resolve_live();
146}
void rebuild_features_from_entities()
Definition DesignSketchTool.cpp:154
const std::vector< SketchEntityConstraintDef > & constraints() const
Definition DesignSketchTool.hpp:710
const std::vector< SketchEntity > & entities() const
Definition DesignSketchTool.hpp:578
@ Select
Definition DesignSketchTool.hpp:91
void begin(const SketchPlane &plane, Mode mode=Mode::Polyline)
Definition DesignSketchTool.cpp:103

References begin(), constraints(), entities(), m_constraints, m_entities, plane(), rebuild_features_from_entities(), resolve_live(), and Select.

Here is the call graph for this function:

◆ begin_feature()

void Slic3r::GUI::DesignSketchTool::begin_feature ( FeatureKind kind)
private
960{
961 Feature f;
962 f.kind = kind;
963 f.begin = int(m_entities.size());
964 f.end = f.begin;
965 m_features.push_back(f);
966 m_open_feature = int(m_features.size()) - 1;
967}
FeatureKind kind
Definition DesignSketchTool.hpp:828
Definition DesignSketchTool.hpp:827
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:124

References Slic3r::f(), m_entities, m_features, and m_open_feature.

Referenced by on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ begin_imported_transform()

void Slic3r::GUI::DesignSketchTool::begin_imported_transform ( int feat,
const std::vector< std::vector< std::vector< Vec2d > > > & base_regions,
const SketchPlane & plane,
const Vec2d & offset,
double scale_x,
double scale_y )
8585{
8586 cancel(); // drop any prior session, clears state
8587 m_plane = plane;
8589 m_xform_base = base_regions;
8590 m_xform_feat = feat;
8592 m_xform_sx = (std::abs(sx) > 1e-6) ? sx : 1.0;
8593 m_xform_sy = (std::abs(sy) > 1e-6) ? sy : 1.0;
8594 m_xform_handle = -1;
8595 Vec2d mn(1e30, 1e30), mx(-1e30, -1e30);
8596 for (const auto& region : m_xform_base)
8597 for (const auto& contour : region)
8598 for (const Vec2d& p : contour) {
8599 mn.x() = std::min(mn.x(), p.x()); mn.y() = std::min(mn.y(), p.y());
8600 mx.x() = std::max(mx.x(), p.x()); mx.y() = std::max(mx.y(), p.y());
8601 }
8602 if (mx.x() < mn.x()) { mn = Vec2d(0, 0); mx = Vec2d(0, 0); }
8603 m_xform_min = mn; m_xform_max = mx;
8604 m_active = true;
8605 m_has_cursor = false;
8606}
Vec2d m_xform_min
Definition DesignSketchTool.hpp:1190
std::vector< std::vector< std::vector< Vec2d > > > m_xform_base
Definition DesignSketchTool.hpp:1188
Vec2d m_xform_max
Definition DesignSketchTool.hpp:1190
Vec2d m_xform_offset
Definition DesignSketchTool.hpp:1191
double m_xform_sx
Definition DesignSketchTool.hpp:1192
int m_xform_handle
Definition DesignSketchTool.hpp:1193
@ TransformArt
Definition DesignSketchTool.hpp:102
double m_xform_sy
Definition DesignSketchTool.hpp:1192
int m_xform_feat
Definition DesignSketchTool.hpp:1189
void cancel()
Definition DesignSketchTool.cpp:345
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582
const Polygon & contour(const ExPolygon &p)
Definition AGGRaster.hpp:30

References begin_imported_transform(), cancel(), Slic3r::contour(), m_active, m_has_cursor, m_mode, m_plane, m_xform_base, m_xform_feat, m_xform_handle, m_xform_max, m_xform_min, m_xform_offset, m_xform_sx, m_xform_sy, Slic3r::offset(), plane(), and TransformArt.

Referenced by begin_imported_transform().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ body_pickable()

bool Slic3r::GUI::DesignSketchTool::body_pickable ( int b) const
private
3616{
3617 if (b < 0) return false;
3618 // Body-focus mode. The focus is an INDEX held by the panel across recomputes, so it can
3619 // outlive the body it names — delete a body and the stored index may point past the end.
3620 // A restriction to a body that no longer exists rejects EVERY body, which is a viewport
3621 // that silently accepts no clicks at all: the worst possible failure for a picking mode,
3622 // because nothing on screen says why. Out of range therefore means NO restriction — fail
3623 // open, never dead.
3624 const bool focus_live = m_pick_only_body >= 0 && m_solid_bodies != nullptr
3625 && m_pick_only_body < int(m_solid_bodies->size());
3626 if (focus_live && b != m_pick_only_body) return false;
3627 if (m_solid_visible == nullptr || b >= int(m_solid_visible->size())) return true;
3628 return (*m_solid_visible)[b];
3629}
int m_pick_only_body
Definition DesignSketchTool.hpp:1283
const std::vector< CadBody > * m_solid_bodies
Definition DesignSketchTool.hpp:1278
const std::vector< bool > * m_solid_visible
Definition DesignSketchTool.hpp:1282

References body_pickable(), m_pick_only_body, m_solid_bodies, and m_solid_visible.

Referenced by body_pickable(), pick_bodies_in_rectangle(), render_face_outline(), resolve_solid_pick(), and select_body().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ body_shape()

const TopoDS_Shape * Slic3r::GUI::DesignSketchTool::body_shape ( int body) const
private
3519{
3520 if (m_solid_bodies == nullptr || body < 0 || body >= int(m_solid_bodies->size()))
3521 return nullptr;
3522 const TopoDS_Shape& shape = (*m_solid_bodies)[body].shape;
3523 return shape.IsNull() ? nullptr : &shape;
3524}

References body_shape(), and m_solid_bodies.

Referenced by body_shape(), is_current_shape(), make_face_highlight(), picked_faces(), and set_highlight_faces().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ body_xform_pt()

Vec3d Slic3r::GUI::DesignSketchTool::body_xform_pt ( int body,
const Vec3d & p ) const
private
3608{
3609 if (m_solid_xform != nullptr && body >= 0 && body < int(m_solid_xform->size()))
3610 return (*m_solid_xform)[body] * p;
3611 return p;
3612}
const std::vector< Transform3d > * m_solid_xform
Definition DesignSketchTool.hpp:1284

References body_xform_pt(), and m_solid_xform.

Referenced by append_ribbons(), body_xform_pt(), and resolve_solid_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ build_constraint_glyphs()

void Slic3r::GUI::DesignSketchTool::build_constraint_glyphs ( double unit_per_px,
const std::vector< SketchEntityConstraintDef > & cons,
std::vector< std::pair< Vec2d, Vec2d > > & out )
private
8449{
8450 m_glyph_hits.clear();
8451 if (cons.empty() || m_entities.empty()) return;
8452 using T = SketchConstraintType;
8453 const double s = std::max(11.0 * unit_per_px, 1e-4); // glyph cell size in plane units
8454 const double step = s * 1.5; // vertical stacking step
8455
8456 // Representative anchor point on an entity (line midpoint, round-entity centre).
8457 auto anchor_of = [&](int ei) -> Vec2d {
8458 if (ei < 0 || ei >= int(m_entities.size())) return Vec2d(0, 0);
8459 const SketchEntity& e = m_entities[ei];
8460 switch (e.type) {
8461 case SketchEntity::Type::Line: return 0.5 * (e.p0 + e.p1);
8465 case SketchEntity::Type::EllipseArc: return e.center;
8466 case SketchEntity::Type::BSpline: return 0.5 * (e.p0 + e.p1);
8467 case SketchEntity::Type::Point: return e.p0;
8468 }
8469 return e.p0;
8470 };
8471
8472 // Unit-cell stroke authoring helpers (cell centred on origin).
8473 auto seg = [&](std::vector<std::pair<Vec2d, Vec2d>>& v, Vec2d a, Vec2d b) { v.emplace_back(a, b); };
8474 auto circ = [&](std::vector<std::pair<Vec2d, Vec2d>>& v, Vec2d c, double r) {
8475 const int n = 12; Vec2d prev(c.x() + r, c.y());
8476 for (int i = 1; i <= n; ++i) {
8477 const double t = 2.0 * 3.14159265358979 * i / n;
8478 Vec2d cur(c.x() + r * std::cos(t), c.y() + r * std::sin(t));
8479 v.emplace_back(prev, cur); prev = cur;
8480 }
8481 };
8482 // Author one glyph type into a unit-cell stroke list.
8483 auto unit_glyph = [&](T type, std::vector<std::pair<Vec2d, Vec2d>>& v) {
8484 switch (type) {
8485 case T::Horizontal: seg(v, {-0.5, 0}, {0.5, 0}); break;
8486 case T::Vertical: seg(v, {0, -0.5}, {0, 0.5}); break;
8487 case T::Parallel: seg(v, {-0.35, -0.5}, {0.0, 0.5}); seg(v, {0.05, -0.5}, {0.4, 0.5}); break;
8488 case T::Perpendicular: seg(v, {-0.4, 0.5}, {-0.4, -0.4}); seg(v, {-0.4, -0.4}, {0.5, -0.4}); break;
8489 case T::Coincident: circ(v, {0, 0}, 0.42); break;
8490 case T::Concentric: circ(v, {0, 0}, 0.5); circ(v, {0, 0}, 0.24); break;
8491 case T::EqualLength:seg(v, {-0.4, 0.16}, {0.4, 0.16}); seg(v, {-0.4, -0.16}, {0.4, -0.16}); break;
8492 case T::Tangent: circ(v, {0, -0.1}, 0.35); seg(v, {-0.5, 0.42}, {0.5, 0.42}); break;
8493 case T::Midpoint: seg(v, {-0.4, 0}, {0.4, 0}); seg(v, {0, -0.18}, {0, 0.18}); break;
8494 case T::Symmetric: seg(v, {0, -0.5}, {0, 0.5});
8495 seg(v, {-0.5, 0.4}, {-0.15, 0}); seg(v, {-0.5, -0.4}, {-0.15, 0});
8496 seg(v, {0.5, 0.4}, {0.15, 0}); seg(v, {0.5, -0.4}, {0.15, 0}); break;
8497 case T::Fix: seg(v, {-0.4, -0.4}, {0.4, -0.4}); seg(v, {0.4, -0.4}, {0.4, 0.4});
8498 seg(v, {0.4, 0.4}, {-0.4, 0.4}); seg(v, {-0.4, 0.4}, {-0.4, -0.4}); break;
8499 case T::Angle: seg(v, {-0.4, -0.4}, {0.4, -0.4}); seg(v, {-0.4, -0.4}, {0.3, 0.4}); break;
8500 case T::Radius: circ(v, {0, 0}, 0.45); seg(v, {0, 0}, {0.45, 0}); break;
8501 case T::Diameter: circ(v, {0, 0}, 0.45); seg(v, {-0.45, 0}, {0.45, 0}); break;
8502 case T::PointOnLine:
8503 case T::PointOnObject: seg(v, {-0.5, -0.3}, {0.5, -0.3}); circ(v, {0, 0.05}, 0.16); break;
8504 case T::Distance:
8505 case T::LockX:
8506 case T::LockY: seg(v, {-0.4, 0}, {0.4, 0}); break; // generic tick
8507 }
8508 };
8509
8510 // Stack count per entity so successive badges step upward.
8511 std::vector<int> stack(m_entities.size(), 0);
8512 const Vec2d up(0.0, 1.0); // plane-space up; offset so badge sits off the geometry
8513 m_glyph_r = 0.6 * s;
8514 for (size_t ci = 0; ci < cons.size(); ++ci) {
8515 const SketchEntityConstraintDef& d = cons[ci];
8516 if (d.ea < 0 || d.ea >= int(m_entities.size())) continue;
8517 const int k = stack[d.ea]++;
8518 const Vec2d center = anchor_of(d.ea) + up * (step * (1.0 + k));
8519 m_glyph_hits.push_back({center, int(ci)});
8520 std::vector<std::pair<Vec2d, Vec2d>> cell;
8521 unit_glyph(d.type, cell);
8522 for (auto& sgp : cell)
8523 out.emplace_back(center + sgp.first * s, center + sgp.second * s);
8524 }
8525}
std::vector< GlyphHit > m_glyph_hits
Definition DesignSketchTool.hpp:1256
double m_glyph_r
Definition DesignSketchTool.hpp:1257
SketchConstraintType
Definition SketchEngine.hpp:100
void center(ExPolygonsWithIds &e)
Definition Emboss.cpp:1382
void step(Coord &crd, const Dir d, const long n=1)
Definition MarchingSquares.hpp:213
@ up
Definition MarchingSquares.hpp:192
@ Ellipse
Definition SketchEngine.hpp:31
@ EllipseArc
Definition SketchEngine.hpp:31
@ Point
Definition SketchEngine.hpp:31
@ Arc
Definition SketchEngine.hpp:31
@ Circle
Definition SketchEngine.hpp:31
@ BSpline
Definition SketchEngine.hpp:31

References Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::BSpline, build_constraint_glyphs(), Slic3r::center(), Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntity::Ellipse, Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::Line, m_entities, m_glyph_hits, m_glyph_r, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::Point, Slic3r::SketchEntity::type, and Slic3r::SketchEntityConstraintDef::type.

Referenced by build_constraint_glyphs(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ build_handles()

std::vector< DesignSketchTool::Handle > Slic3r::GUI::DesignSketchTool::build_handles ( ) const
private
997{
998 std::vector<Handle> hs;
999 hs.reserve(m_entities.size() * 2);
1000 for (size_t i = 0; i < m_entities.size(); ++i) {
1001 const SketchEntity& e = m_entities[i];
1002 switch (e.type) {
1004 Handle a; a.role = HandleRole::P0; a.ei = int(i); a.pos = e.p0; hs.push_back(a);
1005 Handle b; b.role = HandleRole::P1; b.ei = int(i); b.pos = e.p1; hs.push_back(b);
1006 break;
1007 }
1009 Handle c; c.role = HandleRole::Center; c.ei = int(i); c.pos = e.center; hs.push_back(c);
1010 // RadiusHandle sits on the circle to the +x side of its centre; dragging it
1011 // (A4) edits the radius. Pure geometry, no constraint of its own.
1012 Handle r; r.role = HandleRole::RadiusHandle; r.ei = int(i);
1013 r.pos = e.center + Vec2d(e.radius, 0.0); hs.push_back(r);
1014 break;
1015 }
1018 // 3 grips: centre (translate), major-axis end (semi-major a + orientation phi),
1019 // minor-axis end (semi-minor b). a=e.radius, b=e.rminor, phi=e.rotation.
1020 // (EllipseArc also exposes its two endpoints via hit_test_point for sweep.)
1021 const Vec2d um(std::cos(e.rotation), std::sin(e.rotation)); // major dir
1022 const Vec2d un(-um.y(), um.x()); // minor dir
1023 Handle c; c.role = HandleRole::Center; c.ei = int(i); c.pos = e.center; hs.push_back(c);
1024 Handle ma; ma.role = HandleRole::MajorAxis; ma.ei = int(i);
1025 ma.pos = e.center + um * e.radius; hs.push_back(ma);
1026 Handle mi; mi.role = HandleRole::MinorAxis; mi.ei = int(i);
1027 mi.pos = e.center + un * e.rminor; hs.push_back(mi);
1028 break;
1029 }
1031 // One draggable grip per control pole; dragging a pole reshapes the curve.
1032 for (size_t k = 0; k < e.ctrl.size(); ++k) {
1033 Handle h; h.role = HandleRole::BSplineCtrl; h.ei = int(i);
1034 h.ctrl_index = int(k); h.pos = e.ctrl[k]; hs.push_back(h);
1035 }
1036 break;
1037 }
1038 default: break; // Arc derived handles land in later chunks
1039 }
1040 }
1041 return hs;
1042}
HandleRole role
Definition DesignSketchTool.hpp:814
@ MajorAxis
Definition DesignSketchTool.hpp:812
@ BSplineCtrl
Definition DesignSketchTool.hpp:812
@ P0
Definition DesignSketchTool.hpp:810
@ Center
Definition DesignSketchTool.hpp:810
@ P1
Definition DesignSketchTool.hpp:810
@ RadiusHandle
Definition DesignSketchTool.hpp:810
@ MinorAxis
Definition DesignSketchTool.hpp:812
Definition DesignSketchTool.hpp:813

References Slic3r::SketchEntity::BSpline, BSplineCtrl, Center, Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::SketchEntity::ctrl, Slic3r::GUI::DesignSketchTool::Handle::ctrl_index, Slic3r::GUI::DesignSketchTool::Handle::ei, Slic3r::SketchEntity::Ellipse, Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::Line, m_entities, MajorAxis, MinorAxis, P0, Slic3r::SketchEntity::p0, P1, Slic3r::SketchEntity::p1, Slic3r::GUI::DesignSketchTool::Handle::pos, Slic3r::SketchEntity::radius, RadiusHandle, Slic3r::SketchEntity::rminor, Slic3r::GUI::DesignSketchTool::Handle::role, Slic3r::SketchEntity::rotation, and Slic3r::SketchEntity::type.

Referenced by hit_test_handle(), and render().

Here is the caller graph for this function:

◆ build_readout()

std::string Slic3r::GUI::DesignSketchTool::build_readout ( ) const
private
10252{
10253 auto en = [](char* b) { for (char* c = b; *c; ++c) if (*c == ',') *c = '.'; };
10254 if (m_active && (m_mode == Mode::Line || m_mode == Mode::Polyline) &&
10255 !m_points.empty() && m_has_cursor) {
10256 const Vec2d d = m_cursor - m_points.back();
10257 double ang = std::atan2(d.y(), d.x()) * 180.0 / M_PI; if (ang < 0.0) ang += 360.0;
10258 char b[80]; std::snprintf(b, sizeof(b), "L %.2f mm %.1f\xC2\xB0", d.norm(), ang);
10259 en(b);
10260 std::string out = b;
10261 // Tell the user how to end a polyline chain — there's no other affordance for it.
10262 if (m_mode == Mode::Polyline && m_points.size() >= 2)
10263 out += " " + _u8L("right-click or double-click to finish, click start to close");
10264 return out;
10265 }
10266 if (!m_active) return std::string();
10267 std::string out;
10268 for (const DimAnnot& q : m_live_quotes) { // selection's Length/Radius/Width/… quotes
10269 if (!out.empty()) out += " ";
10270 out += dim_text(q);
10271 }
10272 return out;
10273}
std::string dim_text(const DimAnnot &a) const
Definition DesignSketchTool.cpp:2407
Vec2d m_cursor
Definition DesignSketchTool.hpp:1080
std::vector< DimAnnot > m_live_quotes
Definition DesignSketchTool.hpp:1126
@ Polyline
Definition DesignSketchTool.hpp:91
Definition DesignSketchTool.hpp:794

References _u8L, build_readout(), dim_text(), Line, m_active, m_cursor, m_has_cursor, m_live_quotes, m_mode, M_PI, m_points, and Polyline.

Referenced by build_readout(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cached_face_highlight()

const DesignSketchTool::FaceHighlight & Slic3r::GUI::DesignSketchTool::cached_face_highlight ( FaceHighlight & cache,
int body,
std::vector< int > faces ) const
private
3840{
3841 std::sort(faces.begin(), faces.end());
3842 faces.erase(std::unique(faces.begin(), faces.end()), faces.end());
3843 if (cache.body != body || cache.faces != faces || !is_current_shape(body, cache.shape))
3844 cache = make_face_highlight(body, std::move(faces));
3845 return cache;
3846}
bool is_current_shape(int body, const TopoDS_Shape &sampled) const
Definition DesignSketchTool.cpp:3529
FaceHighlight make_face_highlight(int body, std::vector< int > faces) const
Definition DesignSketchTool.cpp:3690

References Slic3r::GUI::DesignSketchTool::FaceHighlight::body, cached_face_highlight(), Slic3r::GUI::DesignSketchTool::FaceHighlight::faces, is_current_shape(), make_face_highlight(), and Slic3r::GUI::DesignSketchTool::FaceHighlight::shape.

Referenced by cached_face_highlight(), render_solid_highlight(), and set_highlight_faces().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ can_redo_entity()

bool Slic3r::GUI::DesignSketchTool::can_redo_entity ( ) const
473{
474 return m_active && !m_sketch_redo.empty()
475 && m_sketch_redo.back().after_entities == m_entities.size()
476 && m_sketch_redo.back().after_constraints == m_constraints.size();
477}

References m_active, m_constraints, m_entities, and m_sketch_redo.

Referenced by redo_last_entity(), and undo_last_entity().

Here is the caller graph for this function:

◆ can_undo_entity()

bool Slic3r::GUI::DesignSketchTool::can_undo_entity ( ) const
inline
653{ return m_active && !m_entities.empty(); }

References m_active, and m_entities.

◆ cancel()

void Slic3r::GUI::DesignSketchTool::cancel ( )
346{
347 m_sketch_redo.clear();
348 close_session_chrome(); // same orphaned-field freeze as finish() — see yce
349 m_active = false;
350 m_step_mode_last = -1;
351 m_points.clear();
352 m_entities.clear();
353 m_construction = false;
354 m_has_cursor = false;
355 m_sel_a = m_sel_b = -1;
356 m_constrain_entities = false;
357 m_pick0 = m_pick1 = m_pick2 = -1;
358 m_constraint_hl.clear();
359 m_constrain_cons.clear();
360 m_awaiting_length = false;
361 m_selection.clear();
362 m_point_sel.clear();
363 m_constraints.clear();
364 m_dimensions.clear();
365 m_dim_has0 = false;
366 m_pending_dim = -1;
367 m_dof = -1; m_solve_ok = true; m_entity_conflict.clear();
368 m_features.clear();
369 m_open_feature = -1;
370 reset_op();
371 reset_xform();
372 reset_tf();
373}
void reset_xform()
Definition DesignSketchTool.cpp:8572
void close_session_chrome()
Definition DesignSketchTool.hpp:641

References close_session_chrome(), m_active, m_awaiting_length, m_constrain_cons, m_constrain_entities, m_constraint_hl, m_constraints, m_construction, m_dim_has0, m_dimensions, m_dof, m_entities, m_entity_conflict, m_features, m_has_cursor, m_open_feature, m_pending_dim, m_pick0, m_pick1, m_pick2, m_point_sel, m_points, m_sel_a, m_sel_b, m_selection, m_sketch_redo, m_solve_ok, m_step_mode_last, reset_op(), reset_tf(), and reset_xform().

Referenced by begin_imported_transform(), and request_exit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ cancel_dimension_value()

void Slic3r::GUI::DesignSketchTool::cancel_dimension_value ( )
2403{
2404 m_pending_dim = -1; // keep the placed dimension at its measured value
2405}

References cancel_dimension_value(), and m_pending_dim.

Referenced by cancel_dimension_value().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_base_pick()

void Slic3r::GUI::DesignSketchTool::clear_base_pick ( )
5562{
5563 m_dbp_active = false;
5564 m_dbp_planes.clear();
5565 m_dbp_base.clear();
5566 m_dbp_labels.clear();
5567 m_dbp_hover = -1;
5568}
int m_dbp_hover
Definition DesignSketchTool.hpp:1448
std::vector< SketchPlane > m_dbp_planes
Definition DesignSketchTool.hpp:1445
std::vector< std::string > m_dbp_labels
Definition DesignSketchTool.hpp:1447
std::vector< int > m_dbp_base
Definition DesignSketchTool.hpp:1446
bool m_dbp_active
Definition DesignSketchTool.hpp:1444

References clear_base_pick(), m_dbp_active, m_dbp_base, m_dbp_hover, m_dbp_labels, and m_dbp_planes.

Referenced by clear_base_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_cut_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_cut_gizmo ( )
6845{
6846 m_ct_active = false;
6847 m_ct_drag = false;
6848}
bool m_ct_active
Definition DesignSketchTool.hpp:1596
bool m_ct_drag
Definition DesignSketchTool.hpp:1603

References clear_cut_gizmo(), m_ct_active, and m_ct_drag.

Referenced by clear_cut_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_datum_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_datum_gizmo ( )
4949{
4950 m_dz_active = false;
4951 m_dz_drag = -1;
4952}
int m_dz_drag
Definition DesignSketchTool.hpp:1405
bool m_dz_active
Definition DesignSketchTool.hpp:1401

References clear_datum_gizmo(), m_dz_active, and m_dz_drag.

Referenced by clear_datum_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_display_pick()

void Slic3r::GUI::DesignSketchTool::clear_display_pick ( )
inline
int m_display_pick
Definition DesignSketchTool.hpp:1273
int m_display_pick_region
Definition DesignSketchTool.hpp:1382

References m_display_pick, and m_display_pick_region.

◆ clear_draft_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_draft_gizmo ( )
6729{
6730 m_dr_active = false;
6731 m_dr_drag = false;
6732}
bool m_dr_drag
Definition DesignSketchTool.hpp:1587
bool m_dr_active
Definition DesignSketchTool.hpp:1581

References clear_draft_gizmo(), m_dr_active, and m_dr_drag.

Referenced by clear_draft_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_extrude_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_extrude_gizmo ( )
4437{
4438 m_ex_active = false;
4439 m_ex_drag = -1;
4440}
bool m_ex_active
Definition DesignSketchTool.hpp:1385
int m_ex_drag
Definition DesignSketchTool.hpp:1392

References clear_extrude_gizmo(), m_ex_active, and m_ex_drag.

Referenced by clear_extrude_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_fillet_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_fillet_gizmo ( )
6074{
6075 m_fl_active = false;
6076 m_fl_drag = false;
6077}
bool m_fl_drag
Definition DesignSketchTool.hpp:1487
bool m_fl_active
Definition DesignSketchTool.hpp:1483

References clear_fillet_gizmo(), m_fl_active, and m_fl_drag.

Referenced by clear_fillet_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_helix_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_helix_gizmo ( )
5114{
5115 m_hx_active = false;
5116 m_hx_drag = -1;
5117}
int m_hx_drag
Definition DesignSketchTool.hpp:1424
bool m_hx_active
Definition DesignSketchTool.hpp:1417

References clear_helix_gizmo(), m_hx_active, and m_hx_drag.

Referenced by clear_helix_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_hole_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_hole_gizmo ( )
6192{
6193 m_hl_active = false;
6194 m_hl_drag = -1;
6195}
bool m_hl_active
Definition DesignSketchTool.hpp:1503
int m_hl_drag
Definition DesignSketchTool.hpp:1513

References clear_hole_gizmo(), m_hl_active, and m_hl_drag.

Referenced by clear_hole_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_mate_connectors()

void Slic3r::GUI::DesignSketchTool::clear_mate_connectors ( )
inline
451{ m_mate_connectors.clear(); m_mate_links.clear(); }
std::vector< MateConnectorGlyph > m_mate_connectors
Definition DesignSketchTool.hpp:1375
std::vector< std::pair< Vec3d, Vec3d > > m_mate_links
Definition DesignSketchTool.hpp:1376

References m_mate_connectors, and m_mate_links.

◆ clear_move_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_move_gizmo ( )
5834{
5835 m_mv_active = false;
5836 m_mv_drag = -1;
5837 m_mv_body = -1;
5838 m_mv_offset = Vec3d::Zero();
5839 m_mv_rot = Eigen::Matrix3d::Identity();
5840}
Eigen::Matrix3d m_mv_rot
Definition DesignSketchTool.hpp:1463
int m_mv_body
Definition DesignSketchTool.hpp:1459
bool m_mv_active
Definition DesignSketchTool.hpp:1458
int m_mv_drag
Definition DesignSketchTool.hpp:1466

References clear_move_gizmo(), m_mv_active, m_mv_body, m_mv_drag, m_mv_offset, and m_mv_rot.

Referenced by clear_move_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_pattern_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_pattern_gizmo ( )
7112{
7113 m_pt_active = false;
7114 m_pt_drag = false;
7115}
bool m_pt_active
Definition DesignSketchTool.hpp:1616
bool m_pt_drag
Definition DesignSketchTool.hpp:1628

References clear_pattern_gizmo(), m_pt_active, and m_pt_drag.

Referenced by clear_pattern_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_revolve_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_revolve_gizmo ( )
6958{
6959 m_rv_active = false;
6960 m_rv_drag = false;
6961}
bool m_rv_active
Definition DesignSketchTool.hpp:1565
bool m_rv_drag
Definition DesignSketchTool.hpp:1572

References clear_revolve_gizmo(), m_rv_active, and m_rv_drag.

Referenced by clear_revolve_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_rib_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_rib_gizmo ( )
5288{
5289 m_rb_active = false;
5290 m_rb_drag = -1;
5291}
bool m_rb_active
Definition DesignSketchTool.hpp:1434
int m_rb_drag
Definition DesignSketchTool.hpp:1439

References clear_rib_gizmo(), m_rb_active, and m_rb_drag.

Referenced by clear_rib_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_selection()

void Slic3r::GUI::DesignSketchTool::clear_selection ( )
465{
466 if (m_selection.empty() && m_point_sel.empty()) return;
467 m_selection.clear();
468 m_point_sel.clear();
470}

References m_point_sel, m_selection, and on_selection_changed.

◆ clear_shell_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_shell_gizmo ( )
6613{
6614 m_sh_active = false;
6615 m_sh_drag = false;
6616}
bool m_sh_active
Definition DesignSketchTool.hpp:1549
bool m_sh_drag
Definition DesignSketchTool.hpp:1553

References clear_shell_gizmo(), m_sh_active, and m_sh_drag.

Referenced by clear_shell_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_solid_selection()

void Slic3r::GUI::DesignSketchTool::clear_solid_selection ( )
3632{
3635 m_sel_shape = TopoDS_Shape();
3636 m_sel_edge_pts.clear();
3637 m_sel_edges_more.clear();
3638 m_sel_edges_more_pts.clear();
3639 // The pre-highlight names a face/edge/vertex by index into a shape that a recompute has just
3640 // rebuilt, so it expires with the selection it was a promise about. Left behind it would keep
3641 // glowing on whatever now sits at those indices — a real entity, but not the one meant.
3642 m_pre = SolidPick{};
3643}
int m_sel_face
Definition DesignSketchTool.hpp:1302
std::vector< Vec3d > m_sel_edge_pts
Definition DesignSketchTool.hpp:1304
TopoDS_Shape m_sel_shape
Definition DesignSketchTool.hpp:1301
int m_sel_body
Definition DesignSketchTool.hpp:1300
@ None
Definition DesignSketchTool.hpp:229
int m_sel_edge
Definition DesignSketchTool.hpp:1303
SolidPick m_pre
Definition DesignSketchTool.hpp:1326
std::vector< std::vector< Vec3d > > m_sel_edges_more_pts
Definition DesignSketchTool.hpp:1309
std::vector< int > m_sel_edges_more
Definition DesignSketchTool.hpp:1308
SolidSel m_solid_sel
Definition DesignSketchTool.hpp:1299
Definition DesignSketchTool.hpp:1315

References clear_solid_selection(), m_pre, m_sel_body, m_sel_edge, m_sel_edge_pts, m_sel_edges_more, m_sel_edges_more_pts, m_sel_face, m_sel_shape, m_solid_sel, and None.

Referenced by clear_solid_selection(), handle_solid_click(), on_mouse_impl(), pick_bodies_in_rectangle(), refresh_body_edges(), select_body(), and set_solid_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ clear_thread_gizmo()

void Slic3r::GUI::DesignSketchTool::clear_thread_gizmo ( )
6434{
6435 m_th_active = false;
6436 m_th_drag = -1;
6437}
int m_th_drag
Definition DesignSketchTool.hpp:1535
bool m_th_active
Definition DesignSketchTool.hpp:1530

References clear_thread_gizmo(), m_th_active, and m_th_drag.

Referenced by clear_thread_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ click_snaps()

bool Slic3r::GUI::DesignSketchTool::click_snaps ( ) const
private
2612{
2613 const size_t n = m_points.size();
2614 switch (m_mode) {
2618 return true;
2620 return n < 2;
2621 case Mode::CenterArc: case Mode::ArcSlot:
2622 return n == 1;
2624 return n == 0;
2625 default:
2626 return false;
2627 }
2628}
@ Ellipse
Definition DesignSketchTool.hpp:94
@ EllipseArc
Definition DesignSketchTool.hpp:94
@ ThreePointCircle
Definition DesignSketchTool.hpp:93
@ RoundedRect
Definition DesignSketchTool.hpp:92
@ Polygon
Definition DesignSketchTool.hpp:93
@ ArcSlot
Definition DesignSketchTool.hpp:93
@ BSpline
Definition DesignSketchTool.hpp:94
@ CenterArc
Definition DesignSketchTool.hpp:93
@ Slot
Definition DesignSketchTool.hpp:93
@ CenterCircle
Definition DesignSketchTool.hpp:92
@ TangentArc
Definition DesignSketchTool.hpp:93
@ CornerRect
Definition DesignSketchTool.hpp:91
@ TwoPointCircle
Definition DesignSketchTool.hpp:92
@ CenterRect
Definition DesignSketchTool.hpp:91
@ ObliqueRect
Definition DesignSketchTool.hpp:91
@ ThreePointArc
Definition DesignSketchTool.hpp:93

References ArcSlot, BSpline, CenterArc, CenterCircle, CenterRect, click_snaps(), CornerRect, Ellipse, EllipseArc, Line, m_mode, m_points, ObliqueRect, Point, Polygon, Polyline, RoundedRect, Slot, TangentArc, ThreePointArc, ThreePointCircle, and TwoPointCircle.

Referenced by click_snaps(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ close_session_chrome()

void Slic3r::GUI::DesignSketchTool::close_session_chrome ( )
inline
641 {
642 if (on_inline_dismiss) on_inline_dismiss(); // no-op when no field is open
644 if (on_readout) on_readout(std::string()); // the HUD is not redrawn once the tool stops
645 }
std::function< void()> on_inline_dismiss
Definition DesignSketchTool.hpp:688
std::function< void(const std::string &)> on_readout
Definition DesignSketchTool.hpp:697

References on_inline_dismiss, on_readout, and reset_autoedit().

Referenced by cancel(), and finish().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ closed_regions() [1/2]

std::vector< std::vector< Vec2d > > Slic3r::GUI::DesignSketchTool::closed_regions ( ) const
private
3329{
3330 return closed_regions(m_entities);
3331}
std::vector< std::vector< Vec2d > > closed_regions() const
Definition DesignSketchTool.cpp:3328

References closed_regions(), and m_entities.

Referenced by closed_regions(), and closed_regions().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ closed_regions() [2/2]

std::vector< std::vector< Vec2d > > Slic3r::GUI::DesignSketchTool::closed_regions ( const std::vector< SketchEntity > & ents) const
private
3334{
3335 std::vector<std::vector<Vec2d>> out;
3336 for (RegionLoop& r : region_loops(ents)) out.push_back(std::move(r.poly));
3337 return out;
3338}

References closed_regions(), and region_loops().

Here is the call graph for this function:

◆ compose_move_xform()

Transform3d Slic3r::GUI::DesignSketchTool::compose_move_xform ( ) const
private
5844{
5845 const Vec3d p = m_mv_base;
5846 Transform3d R = Transform3d::Identity();
5847 R.linear() = m_mv_rot;
5848 const Transform3d rot_about_pivot =
5849 Transform3d(Eigen::Translation3d(p)) * R * Transform3d(Eigen::Translation3d(-p));
5850 return Transform3d(Eigen::Translation3d(m_mv_offset)) * rot_about_pivot * m_mv_base_xform;
5851}
Transform3d m_mv_base_xform
Definition DesignSketchTool.hpp:1462
Eigen::Transform< double, 3, Eigen::Affine, Eigen::DontAlign > Transform3d
Definition Point.hpp:96

References compose_move_xform(), m_mv_base, m_mv_base_xform, m_mv_offset, and m_mv_rot.

Referenced by compose_move_xform(), drag_move_arc(), drag_move_arrow(), and open_move_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_tf_pivot()

void Slic3r::GUI::DesignSketchTool::compute_tf_pivot ( )
private
9134{
9135 using T = SketchEntity::Type;
9136 auto cen = [](const SketchEntity& e) -> Vec2d {
9137 switch (e.type) {
9138 case T::Line: return 0.5 * (e.p0 + e.p1);
9139 case T::Arc: case T::Circle: case T::Ellipse: case T::EllipseArc: return e.center;
9140 case T::BSpline:
9141 if (!e.ctrl.empty()) { Vec2d s(0, 0); for (const auto& p : e.ctrl) s += p; return s / double(e.ctrl.size()); }
9142 return 0.5 * (e.p0 + e.p1);
9143 default: return e.p0;
9144 }
9145 };
9146 Vec2d c(0, 0); int n = 0;
9147 for (int ti : m_tf_targets)
9148 if (ti >= 0 && ti < int(m_entities.size())) { c += cen(m_entities[ti]); ++n; }
9149 if (n == 0) { m_tf_pivot = Vec2d(0, 0); m_tf_handle_r = 1.0; return; }
9150 m_tf_pivot = c / double(n);
9151 double r = 0.0;
9152 for (int ti : m_tf_targets) {
9153 if (ti < 0 || ti >= int(m_entities.size())) continue;
9154 const SketchEntity& e = m_entities[ti];
9155 auto upd = [&](const Vec2d& p) { r = std::max(r, (p - m_tf_pivot).norm()); };
9156 switch (e.type) {
9157 case T::Line: upd(e.p0); upd(e.p1); break;
9158 case T::Arc: case T::Circle: case T::Ellipse: case T::EllipseArc:
9159 upd(e.center + Vec2d(e.radius, 0)); upd(e.center - Vec2d(e.radius, 0)); break;
9160 case T::BSpline: for (const auto& p : e.ctrl) upd(p); break;
9161 default: upd(e.p0); break;
9162 }
9163 }
9164 m_tf_handle_r = std::max(r, 1.0);
9165}
Vec2d m_tf_pivot
Definition DesignSketchTool.hpp:1209
double m_tf_handle_r
Definition DesignSketchTool.hpp:1214
std::vector< int > m_tf_targets
Definition DesignSketchTool.hpp:1208

References Slic3r::SketchEntity::center, compute_tf_pivot(), Slic3r::SketchEntity::ctrl, m_entities, m_tf_handle_r, m_tf_pivot, m_tf_targets, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::radius, and Slic3r::SketchEntity::type.

Referenced by compute_tf_pivot(), and tf_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ compute_trim_preview()

bool Slic3r::GUI::DesignSketchTool::compute_trim_preview ( const Vec2d & p,
double tol,
bool extend,
int & subject_ei,
std::vector< Vec2d > & removed_poly ) const
private
1839{
1840 subject_ei = -1;
1841 removed_poly.clear();
1842
1843 double best = 1e30; int bi = -1;
1844 for (size_t i = 0; i < m_entities.size(); ++i) {
1845 const double d = entity_pick_dist(p, m_entities[i]);
1846 if (d < best) { best = d; bi = int(i); }
1847 }
1848 if (bi < 0 || best > tol) return false;
1849
1850 using Ty = SketchEntity::Type;
1851 const Ty st = m_entities[bi].type;
1852 const bool subject_ok = extend ? (st == Ty::Line || st == Ty::Arc)
1853 : (st == Ty::Line || st == Ty::Arc || st == Ty::Circle);
1854 if (!subject_ok) return false;
1855
1856 std::vector<SketchEntity> others;
1857 others.reserve(m_entities.size());
1858 for (size_t i = 0; i < m_entities.size(); ++i)
1859 if (int(i) != bi) others.push_back(m_entities[i]);
1860
1861 const SketchEntity& orig = m_entities[bi];
1862 SketchEntity trimmed = orig; // cut on the copy, never the live entity
1863 const bool ok = extend ? SketchEngine::extend_entity(trimmed, others, p)
1864 : SketchEngine::trim_entity(trimmed, others, p);
1865 if (!ok) return false;
1866
1867 // The highlighted portion is where `trimmed` differs from `orig`: the dropped sub-segment
1868 // (Trim) or the grown one (Extend). Rebuild it as a temp entity and sample its polyline.
1869 const double EPS2 = 1e-14; // squared plane-unit endpoint tolerance
1870 const double AEPS = 1e-7; // radian tolerance
1871 bool closed = false;
1872
1873 if (orig.type == Ty::Line) {
1874 SketchEntity seg = orig;
1875 if ((trimmed.p0 - orig.p0).squaredNorm() > EPS2) {
1876 seg.p0 = orig.p0; seg.p1 = trimmed.p0; // start endpoint moved
1877 } else if ((trimmed.p1 - orig.p1).squaredNorm() > EPS2) {
1878 seg.p0 = trimmed.p1; seg.p1 = orig.p1; // end endpoint moved
1879 } else {
1880 return false; // nothing changed
1881 }
1882 removed_poly = entity_polyline(seg, closed);
1883 } else if (orig.type == Ty::Arc) {
1884 SketchEntity arc = orig; // same centre/radius
1885 if (std::abs(trimmed.start_angle - orig.start_angle) > AEPS) {
1886 arc.start_angle = orig.start_angle; arc.end_angle = trimmed.start_angle;
1887 } else if (std::abs(trimmed.end_angle - orig.end_angle) > AEPS) {
1888 arc.start_angle = trimmed.end_angle; arc.end_angle = orig.end_angle;
1889 } else {
1890 return false;
1891 }
1892 removed_poly = entity_polyline(arc, closed);
1893 } else if (orig.type == Ty::Circle) {
1894 // Trim opens the Circle into the kept Arc [start,end]; the removed gap is its
1895 // complement, swept from the kept arc's end round to its start.
1896 if (trimmed.type != Ty::Arc) return false;
1897 SketchEntity gap = orig;
1898 gap.type = Ty::Arc;
1899 gap.start_angle = trimmed.end_angle;
1900 gap.end_angle = trimmed.start_angle + 2.0 * M_PI;
1901 removed_poly = entity_polyline(gap, closed);
1902 } else {
1903 return false;
1904 }
1905
1906 if (removed_poly.size() < 2) return false;
1907 subject_ei = bi;
1908 return true;
1909}
static std::vector< Vec2d > entity_polyline(const SketchEntity &e, bool &closed)
Definition DesignSketchTool.cpp:3296
void arc(std::vector< std::pair< Vec2d, Vec2d > > &out, double cx, double cy, double rx, double ry, double a0, double a1, int n=14)
Definition DesignSketchTool.cpp:7759

References compute_trim_preview(), Slic3r::SketchEntity::end_angle, Slic3r::GUI::entity_pick_dist(), entity_polyline(), Slic3r::SketchEngine::extend_entity(), m_entities, M_PI, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::start_angle, Slic3r::SketchEngine::trim_entity(), and Slic3r::SketchEntity::type.

Referenced by compute_trim_preview(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ confirm_op()

void Slic3r::GUI::DesignSketchTool::confirm_op ( )
private
8948{
8949 if (!op_ready()) return;
8950 using R = SketchPointRole;
8951 using CT = SketchConstraintType;
8952
8953 if (m_mode == Mode::Fillet || m_mode == Mode::Chamfer) {
8954 const bool fillet = (m_mode == Mode::Fillet);
8955 SketchEntity a_out, b_out, extra;
8956 const bool ok = fillet
8958 : SketchEngine::chamfer_lines(m_entities[m_op_a], m_entities[m_op_b], m_op_value, a_out, b_out, extra);
8959 if (!ok) {
8960 notify(fillet
8961 ? _u8L("Fillet: the radius overruns a leg, or the two lines do not meet at a corner")
8962 : _u8L("Chamfer: the distance overruns a leg, or the two lines do not meet at a corner"));
8963 reset_op();
8964 return;
8965 }
8966 const int a = m_op_a, b = m_op_b;
8967 m_entities[a] = a_out; m_entities[b] = b_out;
8968 const int xi = int(m_entities.size());
8969 m_entities.push_back(extra); // fillet arc / chamfer segment
8970 auto role_near = [](const SketchEntity& ln, const Vec2d& q) -> R {
8971 return ((ln.p0 - q).squaredNorm() <= (ln.p1 - q).squaredNorm()) ? R::P0 : R::P1; };
8972 const R ra = role_near(m_entities[a], extra.p0);
8973 const R rb = role_near(m_entities[b], extra.p1);
8974 // Drop the now-stale corner Coincident + each line's own length Distance (the op
8975 // trimmed both legs back), then bind the new entity onto the trimmed endpoints.
8976 auto refs = [](const SketchEntityConstraintDef& d, int e, R r) {
8977 return (d.ea == e && d.ra == r) || (d.eb == e && d.rb == r); };
8978 auto self_len = [](const SketchEntityConstraintDef& d, int e) {
8979 return d.type == CT::Distance && d.ea == e && d.eb == e; };
8980 const int released = erase_constraints([&](int, const SketchEntityConstraintDef& d) {
8981 return (d.type == CT::Coincident && refs(d, a, ra) && refs(d, b, rb))
8982 || self_len(d, a) || self_len(d, b);
8983 });
8984 if (released > 0)
8985 notify(format(into_u8(_L_PLURAL("%1% constraint the fillet/chamfer invalidated was removed",
8986 "%1% constraints the fillet/chamfer invalidated were removed", released)), released), false);
8987 auto coin = [&](R xr, int ln, R lr) {
8988 SketchEntityConstraintDef d; d.type = CT::Coincident; d.ea = xi; d.ra = xr; d.eb = ln; d.rb = lr; return d; };
8989 if (fillet) {
8990 auto tang = [&](int ln) {
8991 SketchEntityConstraintDef d; d.type = CT::Tangent; d.ea = xi; d.eb = ln; return d; };
8992 const std::vector<std::vector<SketchEntityConstraintDef>> ladder = {
8993 { coin(R::P0, a, ra), coin(R::P1, b, rb), tang(a), tang(b) },
8994 { coin(R::P0, a, ra), coin(R::P1, b, rb), tang(a) },
8995 { coin(R::P0, a, ra), coin(R::P1, b, rb) },
8996 };
8997 for (const auto& set : ladder) if (try_add_constraints(set)) break;
8998 } else {
8999 try_add_constraints({ coin(R::P0, a, ra), coin(R::P1, b, rb) });
9000 }
9001 } else if (m_mode == Mode::Offset) {
9002 const int a = m_op_a;
9004 if (out.empty()) {
9005 notify(_u8L("Offset: an ellipse or a spline has no parallel of its own kind — pick lines, arcs or circles"));
9006 reset_op();
9007 return;
9008 }
9009 const int ni = int(m_entities.size());
9010 const bool single = m_op_chain.size() <= 1;
9011 for (auto& o : out) m_entities.push_back(o);
9012 const SketchEntity::Type st = m_entities[a].type;
9013 SketchEntityConstraintDef d; d.ea = a; d.eb = ni;
9014 // A chain's offset is joined and trimmed at its seams, so its entities no longer map one
9015 // to one onto the originals: it is placed as geometry, without per-entity constraints.
9016 bool emit = single;
9017 if (st == SketchEntity::Type::Line) d.type = CT::Parallel;
9018 else if (st == SketchEntity::Type::Arc || st == SketchEntity::Type::Circle) d.type = CT::Concentric;
9019 else emit = false;
9020 if (emit) try_add_constraints({ d });
9021 } else if (m_mode == Mode::Mirror) {
9022 const SketchEntity axis = m_entities[m_op_a]; // by value (m_entities grows below)
9023 // The sources as they stand BEFORE any of this op's constraints exist. Two jobs: every
9024 // copy is reflected from the untouched original (so a batch that moves the sketch cannot
9025 // feed a later copy moved geometry), and the invariant at the bottom has something to
9026 // compare against. mirror-slot.
9027 const std::vector<SketchEntity> before = m_entities;
9028 const size_t cmark = m_constraints.size();
9029 std::vector<std::pair<int, SketchEntity>> fresh; // copy index -> its pristine reflection
9030 for (int ti : m_mirror_targets) {
9031 if (ti < 0 || ti >= int(before.size())) continue;
9032 auto out = SketchEngine::mirror_entities({ before[ti] }, axis.p0, axis.p1);
9033 if (out.empty()) continue;
9034 const int mi = int(m_entities.size());
9035 for (auto& m : out) { fresh.emplace_back(int(m_entities.size()), m); m_entities.push_back(m); }
9036 SketchEntityConstraintDef d; d.type = CT::Symmetric; d.ea = ti; d.eb = mi; d.ec = m_op_a;
9037 const SketchEntity::Type st = before[ti].type;
9038 std::vector<std::vector<SketchEntityConstraintDef>> ladder;
9039 if (st == SketchEntity::Type::Line) {
9040 d.ra = R::P0; d.rb = R::P0; auto p0 = d;
9041 d.ra = R::P1; d.rb = R::P1; auto p1 = d;
9042 ladder = { { p0, p1 }, { p0 } };
9043 } else if (st == SketchEntity::Type::Arc) {
9044 // BOTH ENDS AND THE CENTRE. Binding only the centre — which is all this did —
9045 // leaves the copy's endpoints and sweep free while the shape's own coincidences
9046 // still tie them to its neighbours, and the solver then answers with a wildly
9047 // different, internally consistent sketch: a slot's caps came back at r=32.2 and
9048 // a 237 deg sweep, one rail collapsed from 62.9 mm to 2.1 mm, and the ORIGINAL
9049 // moved with them. A circle survived the same code only because a circle has no
9050 // endpoints to leave free, which is why the bug reads as "circles fine, rounded
9051 // rectangles and slots destroyed".
9052 d.ra = R::Center; d.rb = R::Center; auto ct = d;
9053 d.ra = R::P0; d.rb = R::P0; auto p0 = d;
9054 d.ra = R::P1; d.rb = R::P1; auto p1 = d;
9055 // Endpoints BEFORE centre: an arc is five DoF, so {centre, p0, p1} is six
9056 // equations and is refused; {p0, p1} is four and pins the sweep, which is the
9057 // half that was going wild. The postcondition below is what makes the ladder
9058 // safe — any rung that does not reproduce the preview is thrown away whole.
9059 ladder = { { p0, p1 }, { ct, p0 }, { ct } };
9060 } else if (st == SketchEntity::Type::Circle) {
9061 d.ra = R::Center; d.rb = R::Center; ladder = { { d } };
9062 } else if (st == SketchEntity::Type::Point) {
9063 d.ra = R::P0; d.rb = R::P0; ladder = { { d } };
9064 }
9065 for (const auto& set : ladder) if (try_add_constraints(set)) break;
9066 }
9067 // A MIRROR MAY NOT MOVE WHAT IT COPIED. try_add_constraints only rolls back when the
9068 // solve FAILS, and the failure here is a solve that succeeds at something else: the
9069 // numbers above came out of a solver that was perfectly happy. So the op checks its own
9070 // postcondition on the geometry, and if a source moved it keeps the copies — which are
9071 // exactly what the preview showed — and drops the whole constraint web that moved them.
9072 // Restoring the sources needs no re-solve: the pre-batch state was itself solved, and a
9073 // failed solve does not write back (pl5).
9074 // BOTH HALVES. Watching only the sources caught the slot (whose web dragged everything)
9075 // and missed the rounded rectangle, where the solver held the sources still and put the
9076 // COPIES somewhere else: an arc has five degrees of freedom and Symmetric on centre plus
9077 // both endpoints is six equations, so that batch is refused and the ladder degrades to a
9078 // set that leaves the sweep free. The rule that covers both, and that is what the user
9079 // actually asked for, is: THE APPLIED RESULT IS THE PREVIEW. Anything else drops the web.
9080 bool disturbed = false;
9081 for (size_t i = 0; i < before.size() && !disturbed; ++i)
9082 disturbed = entity_moved(before[i], m_entities[i], 1e-6);
9083 for (const auto& f : fresh)
9084 if (!disturbed && f.first < int(m_entities.size()))
9085 disturbed = entity_moved(f.second, m_entities[f.first], 1e-6);
9086 if (disturbed) {
9087 m_constraints.resize(cmark);
9088 for (size_t i = 0; i < before.size(); ++i) m_entities[i] = before[i];
9089 // The copies too, and for the same reason: a batch that moved the sketch moved them
9090 // as well, so the ones sitting in m_entities are the solver's answer, not the
9091 // reflection. Restoring only the sources left a slot whose copy came back with a
9092 // 13.8 mm rail and a 308 deg cap — the original was safe and the copy was still
9093 // wrong, which is half a fix. `fresh` is what the preview drew.
9094 for (const auto& f : fresh)
9095 if (f.first < int(m_entities.size())) m_entities[f.first] = f.second;
9096 }
9097 }
9098 reset_op();
9099 m_selection.clear();
9100 resolve_live();
9102}
bool try_add_constraints(const std::vector< SketchEntityConstraintDef > &cands)
Definition DesignSketchTool.cpp:2652
int m_op_b
Definition DesignSketchTool.hpp:1171
std::vector< int > m_op_chain
Definition DesignSketchTool.hpp:1181
std::vector< SketchEntity > op_chain_entities() const
Definition DesignSketchTool.cpp:8562
std::vector< int > m_mirror_targets
Definition DesignSketchTool.hpp:1178
double m_op_value
Definition DesignSketchTool.hpp:1172
@ Fillet
Definition DesignSketchTool.hpp:96
@ Mirror
Definition DesignSketchTool.hpp:96
@ Offset
Definition DesignSketchTool.hpp:96
@ Chamfer
Definition DesignSketchTool.hpp:96
int erase_constraints(const std::function< bool(int, const SketchEntityConstraintDef &)> &drop)
Definition DesignSketchTool.cpp:1768
bool op_ready() const
Definition DesignSketchTool.cpp:8692
int m_op_a
Definition DesignSketchTool.hpp:1170
static std::vector< SketchEntity > mirror_entities(const std::vector< SketchEntity > &src, const Vec2d &a, const Vec2d &b)
Definition SketchEngine.cpp:1008
static std::vector< SketchEntity > offset_entities(const std::vector< SketchEntity > &src, double d)
Definition SketchEngine.cpp:1329
static bool fillet_lines(const SketchEntity &a, const SketchEntity &b, double r, SketchEntity &a_out, SketchEntity &b_out, SketchEntity &arc_out)
Definition SketchEngine.cpp:1560
static bool entity_moved(const SketchEntity &a, const SketchEntity &b, double tol)
Definition DesignSketchTool.cpp:8922
std::string format(const char *fmt, TArgs &&... args)
Definition format.hpp:36
std::string into_u8(const wxString &str)
Definition GUI.cpp:549
@ Tangent
Definition SketchEngine.hpp:104
@ Coincident
Definition SketchEngine.hpp:101
@ Parallel
Definition SketchEngine.hpp:102
@ Concentric
Definition SketchEngine.hpp:103
@ Symmetric
Definition SketchEngine.hpp:104
SketchConstraintType CT
Definition SketchSolver.cpp:19
SketchPointRole
Definition SketchEngine.hpp:131
#define _L_PLURAL(s, plural, n)
Definition I18N.hpp:96

References _L_PLURAL, _u8L, Slic3r::SketchEntity::Arc, Chamfer, Slic3r::SketchEngine::chamfer_lines(), Slic3r::SketchEntity::Circle, Slic3r::Coincident, Slic3r::Concentric, confirm_op(), Slic3r::Distance, Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, Slic3r::SketchEntityConstraintDef::ec, Slic3r::GUI::entity_moved(), erase_constraints(), Slic3r::f(), Fillet, Slic3r::SketchEngine::fillet_lines(), Slic3r::format(), Slic3r::into_u8(), Slic3r::SketchEntity::Line, m_constraints, m_entities, m_mirror_targets, m_mode, m_op_a, m_op_b, m_op_chain, m_op_value, m_selection, Mirror, Slic3r::SketchEngine::mirror_entities(), notify(), Offset, Slic3r::SketchEngine::offset_entities(), on_selection_changed, op_chain_entities(), op_ready(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::Parallel, Slic3r::SketchEntity::Point, Slic3r::SketchEntityConstraintDef::ra, Slic3r::SketchEntityConstraintDef::rb, reset_op(), resolve_live(), Slic3r::Symmetric, Slic3r::Tangent, try_add_constraints(), and Slic3r::SketchEntityConstraintDef::type.

Referenced by confirm_op(), confirm_pending(), finish(), open_op_editor(), and set_tool().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ confirm_pending()

bool Slic3r::GUI::DesignSketchTool::confirm_pending ( )
376{
377 if (op_ready()) { confirm_op(); return true; }
378 if (tf_ready()) { confirm_transform(); return true; }
379 if (!m_points.empty() && end_chain()) return true;
380 return false;
381}
void confirm_op()
Definition DesignSketchTool.cpp:8947
bool tf_ready() const
Definition DesignSketchTool.cpp:9128
void confirm_transform()
Definition DesignSketchTool.cpp:9384
bool end_chain()
Definition DesignSketchTool.cpp:386

References confirm_op(), confirm_transform(), end_chain(), m_points, op_ready(), and tf_ready().

Here is the call graph for this function:

◆ confirm_transform()

void Slic3r::GUI::DesignSketchTool::confirm_transform ( )
private
9385{
9386 if (!tf_ready()) { reset_tf(); return; }
9387 using CT = SketchConstraintType;
9388 const std::vector<int> targets = m_tf_targets; // snapshot by value (m_entities grows)
9389 auto is_target = [&](int e) {
9390 return e >= 0 && std::find(targets.begin(), targets.end(), e) != targets.end();
9391 };
9392
9394 // MUTATING: map every subject in place, then drop the constraint classes the map
9395 // invalidates for any constraint touching a subject. Surviving classes are
9396 // satisfied by construction; the re-solve folds in the new placement.
9397 const Mode mode = m_mode;
9398 for (int ti : targets) {
9399 if (ti < 0 || ti >= int(m_entities.size())) continue;
9400 std::vector<SketchEntity> out;
9401 if (mode == Mode::Move)
9402 out = SketchEngine::transform_entities({ m_entities[ti] }, m_tf_delta, 0.0, 1.0, Vec2d(0, 0));
9403 else if (mode == Mode::Rotate)
9405 else
9407 if (!out.empty()) m_entities[ti] = out[0];
9408 }
9409 const int released = erase_constraints([&](int, const SketchEntityConstraintDef& d) {
9410 if (!(is_target(d.ea) || is_target(d.eb) || is_target(d.ec))) return false;
9411 const bool self = (d.ea == d.eb); // self-length Distance survives translate/rotate
9412 if (mode == Mode::Move) {
9413 switch (d.type) {
9415 case CT::Concentric: case CT::Symmetric: case CT::Midpoint:
9416 case CT::Fix: case CT::LockX: case CT::LockY: return true;
9417 case CT::Distance: return !self;
9418 default: return false; // orientation/length preserved by translation
9419 }
9420 } else if (mode == Mode::Rotate) {
9421 switch (d.type) {
9422 case CT::EqualLength: case CT::Radius: case CT::Diameter: return false;
9423 case CT::Distance: return !self;
9424 default: return true; // orientation + position broken by rotation
9425 }
9426 } else { // Scale (uniform / conformal)
9427 switch (d.type) {
9428 case CT::Horizontal: case CT::Vertical: case CT::Parallel:
9429 case CT::Perpendicular: case CT::Angle: return false;
9430 default: return true; // size + position broken
9431 }
9432 }
9433 });
9434 if (released > 0)
9435 notify(format(into_u8(_L_PLURAL("%1% constraint released by the transform",
9436 "%1% constraints released by the transform", released)), released), false);
9437 } else if (m_mode == Mode::Array || m_mode == Mode::PolarArray) {
9438 // ADDITIVE: append copies of each subject, then bind each copy to its source. Lines
9439 // get Parallel+EqualLength (linear) or EqualLength only (polar — rotation breaks
9440 // Parallel); arc/circle copies get a per-copy Radius (equal-radius under any rigid
9441 // map) plus Concentric when the polar pivot is the source's own centre. Emit each
9442 // web as a degrade ladder (try_add_constraints keeps the first set the solver
9443 // accepts, else the geometry stays unconstrained).
9444 const bool polar = (m_mode == Mode::PolarArray);
9445 const int count = std::max(2, m_tf_count);
9446 for (int ti : targets) {
9447 if (ti < 0 || ti >= int(m_entities.size())) continue;
9448 const SketchEntity src = m_entities[ti]; // by value (m_entities grows below)
9449 std::vector<SketchEntity> copies = polar
9450 ? SketchEngine::array_entities({ src }, count, Vec2d(0, 0), m_tf_angle / double(count), m_tf_pivot)
9451 : SketchEngine::array_entities({ src }, count, m_tf_delta, 0.0, m_tf_pivot);
9452 if (copies.empty()) continue;
9453 const int base = int(m_entities.size());
9454 for (auto& c : copies) m_entities.push_back(c);
9455 const int nc = int(copies.size());
9456 const SketchEntity::Type st = src.type;
9457 std::vector<std::vector<SketchEntityConstraintDef>> ladder;
9458 if (st == SketchEntity::Type::Line) {
9459 auto mk = [&](bool eq, bool par) {
9460 std::vector<SketchEntityConstraintDef> w;
9461 for (int k = 0; k < nc; ++k) {
9462 const int ci = base + k;
9463 if (par) { SketchEntityConstraintDef dp; dp.type = CT::Parallel; dp.ea = ti; dp.eb = ci; w.push_back(dp); }
9464 if (eq) { SketchEntityConstraintDef de; de.type = CT::EqualLength; de.ea = ti; de.eb = ci; w.push_back(de); }
9465 }
9466 return w;
9467 };
9468 if (polar) ladder = { mk(true, false) };
9469 else ladder = { mk(true, true), mk(false, true) };
9470 } else if (st == SketchEntity::Type::Arc || st == SketchEntity::Type::Circle) {
9471 const bool can_conc = polar && (m_tf_pivot - src.center).norm() < 1e-6;
9472 auto mk = [&](bool conc) {
9473 std::vector<SketchEntityConstraintDef> w;
9474 for (int k = 0; k < nc; ++k) {
9475 const int ci = base + k;
9476 SketchEntityConstraintDef dr; dr.type = CT::Radius; dr.ea = ci; dr.value = src.radius; w.push_back(dr);
9477 if (conc) {
9478 SketchEntityConstraintDef dco; dco.type = CT::Concentric;
9479 dco.ea = ti; dco.ra = SketchPointRole::Center; dco.eb = ci; dco.rb = SketchPointRole::Center;
9480 w.push_back(dco);
9481 }
9482 }
9483 return w;
9484 };
9485 ladder = can_conc ? std::vector<std::vector<SketchEntityConstraintDef>>{ mk(true), mk(false) }
9486 : std::vector<std::vector<SketchEntityConstraintDef>>{ mk(false) };
9487 }
9488 bool bound = false;
9489 for (auto& w : ladder) if (!w.empty() && try_add_constraints(w)) { bound = true; break; }
9490 if (!bound)
9491 notify(_u8L("The array copies are unconstrained — the solver refused every binding"), false);
9492 }
9493 }
9494 reset_tf();
9495 m_selection.clear();
9496 resolve_live();
9497 if (on_selection_changed) on_selection_changed(0);
9498}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
Vec2d m_tf_delta
Definition DesignSketchTool.hpp:1210
double m_tf_angle
Definition DesignSketchTool.hpp:1211
double m_tf_scale
Definition DesignSketchTool.hpp:1212
int m_tf_count
Definition DesignSketchTool.hpp:1213
Mode
Definition DesignSketchTool.hpp:91
@ Array
Definition DesignSketchTool.hpp:100
@ PolarArray
Definition DesignSketchTool.hpp:100
@ Move
Definition DesignSketchTool.hpp:100
@ Scale
Definition DesignSketchTool.hpp:100
@ Rotate
Definition DesignSketchTool.hpp:100
static std::vector< SketchEntity > transform_entities(const std::vector< SketchEntity > &src, const Vec2d &move, double angle, double scale, const Vec2d &pivot)
Definition SketchEngine.cpp:1498
static std::vector< SketchEntity > array_entities(const std::vector< SketchEntity > &src, int count, const Vec2d &step, double angle_step, const Vec2d &pivot)
Definition SketchEngine.cpp:1438
@ PointOnObject
Definition SketchEngine.hpp:107
@ Vertical
Definition SketchEngine.hpp:101
@ LockY
Definition SketchEngine.hpp:102
@ Fix
Definition SketchEngine.hpp:101
@ Angle
Definition SketchEngine.hpp:104
@ PointOnLine
Definition SketchEngine.hpp:106
@ EqualLength
Definition SketchEngine.hpp:102
@ Midpoint
Definition SketchEngine.hpp:104
@ Horizontal
Definition SketchEngine.hpp:101
@ Perpendicular
Definition SketchEngine.hpp:102
@ LockX
Definition SketchEngine.hpp:102

References _L_PLURAL, _u8L, Slic3r::Angle, Slic3r::SketchEntity::Arc, Array, Slic3r::SketchEngine::array_entities(), Slic3r::Center, Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::Coincident, Slic3r::Concentric, confirm_transform(), count, Slic3r::Diameter, Slic3r::Distance, Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, Slic3r::SketchEntityConstraintDef::ec, Slic3r::EqualLength, erase_constraints(), Slic3r::Fix, Slic3r::format(), Slic3r::Horizontal, Slic3r::into_u8(), Slic3r::SketchEntity::Line, Slic3r::LockX, Slic3r::LockY, m_entities, m_mode, m_selection, m_tf_angle, m_tf_count, m_tf_delta, m_tf_pivot, m_tf_scale, m_tf_targets, Slic3r::Midpoint, mode(), Move, notify(), on_selection_changed, Slic3r::Parallel, Slic3r::Perpendicular, Slic3r::PointOnLine, Slic3r::PointOnObject, PolarArray, Slic3r::SketchEntityConstraintDef::ra, Slic3r::Radius, Slic3r::SketchEntity::radius, Slic3r::SketchEntityConstraintDef::rb, reset_tf(), resolve_live(), Rotate, Scale, Slic3r::Symmetric, tf_ready(), Slic3r::SketchEngine::transform_entities(), try_add_constraints(), Slic3r::SketchEntity::type, Slic3r::SketchEntityConstraintDef::type, Slic3r::SketchEntityConstraintDef::value, and Slic3r::Vertical.

Referenced by confirm_pending(), confirm_transform(), finish(), open_tf_editor_a(), open_tf_editor_count(), and set_tool().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ connected_loop()

std::vector< int > Slic3r::GUI::DesignSketchTool::connected_loop ( int seed) const
private
10716{
10717 std::vector<int> out;
10718 if (seed < 0 || seed >= int(m_entities.size())) return out;
10719 const double eps2 = sketch_join_tol() * sketch_join_tol();
10720 std::vector<bool> vis(m_entities.size(), false);
10721 std::vector<int> stack = { seed };
10722 vis[seed] = true;
10723 while (!stack.empty()) {
10724 const int cur = stack.back();
10725 stack.pop_back();
10726 out.push_back(cur);
10727 std::vector<Vec2d> ce;
10728 entity_endpoints(m_entities[cur], ce);
10729 if (ce.empty()) continue; // circle/point: not part of a chain
10730 for (size_t j = 0; j < m_entities.size(); ++j) {
10731 if (vis[j]) continue;
10732 std::vector<Vec2d> je;
10734 if (je.empty()) continue;
10735 bool adj = false;
10736 for (const Vec2d& a : ce)
10737 for (const Vec2d& b : je)
10738 if ((a - b).squaredNorm() < eps2) { adj = true; break; }
10739 if (adj) { vis[j] = true; stack.push_back(int(j)); }
10740 }
10741 }
10742 return out;
10743}
static void entity_endpoints(const SketchEntity &e, std::vector< Vec2d > &out)
Definition DesignSketchTool.cpp:10394
double sketch_join_tol()
Definition SketchEngine.cpp:80

References connected_loop(), Slic3r::GUI::entity_endpoints(), m_entities, and Slic3r::sketch_join_tol().

Referenced by connected_loop(), on_mouse_impl(), and op_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ constrain_value_anchor()

bool Slic3r::GUI::DesignSketchTool::constrain_value_anchor ( wxPoint & out) const
2163{
2164 if (m_pick0 < 0 || m_pick0 >= int(m_entities.size())) return false;
2165 auto rep = [](const SketchEntity& e) -> Vec2d {
2166 using T = SketchEntity::Type;
2167 if (e.type == T::Circle || e.type == T::Arc ||
2168 e.type == T::Ellipse || e.type == T::EllipseArc) return e.center;
2169 return 0.5 * (e.p0 + e.p1);
2170 };
2171 Vec2d p = rep(m_entities[m_pick0]);
2172 if (m_pick1 >= 0 && m_pick1 < int(m_entities.size()))
2173 p = 0.5 * (p + rep(m_entities[m_pick1]));
2174 const Camera& cam = wxGetApp().plater()->get_camera();
2175 const wxPoint sp = world_to_screen_px(cam, m_plane.to_world(p));
2176 const std::array<int, 4>& vp = cam.get_viewport();
2177 if (sp.x < vp[0] || sp.y < vp[1] || sp.x > vp[0] + vp[2] || sp.y > vp[1] + vp[3]) return false;
2178 out = sp;
2179 return true;
2180}
@ Camera
Definition Shortcuts.hpp:72
static wxPoint world_to_screen_px(const Camera &cam, const Vec3d &world)
Definition DesignSketchTool.cpp:89

References constrain_value_anchor(), Slic3r::GUI::Camera::get_viewport(), m_entities, m_pick0, m_pick1, m_plane, and Slic3r::GUI::world_to_screen_px().

Referenced by constrain_value_anchor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ constraint_for()

SketchEntityConstraintDef Slic3r::GUI::DesignSketchTool::constraint_for ( const DimAnnot & a) const
private
1341{
1342 SketchEntityConstraintDef c;
1343 switch (a.kind) {
1344 case DimType::Length:
1346 c.ea = a.ea; c.ra = SketchPointRole::P0;
1347 c.eb = a.ea; c.rb = SketchPointRole::P1; c.value = a.value;
1348 break;
1349 case DimType::Diameter: c.type = SketchConstraintType::Diameter; c.ea = a.ea; c.value = a.value; break;
1350 case DimType::Radius: c.type = SketchConstraintType::Radius; c.ea = a.ea; c.value = a.value; break;
1351 case DimType::Distance:
1352 if (a.value < 1e-9) c.type = SketchConstraintType::Coincident;
1353 else { c.type = SketchConstraintType::Distance; c.value = a.value; }
1354 c.ea = a.ea; c.ra = a.ra; c.eb = a.eb; c.rb = a.rb;
1355 break;
1358 c.ea = a.ea; c.ra = a.ra; c.eb = a.eb; c.value = a.value;
1359 break;
1360 default: break;
1361 }
1362 return c;
1363}

References Slic3r::Coincident, Diameter, Slic3r::Diameter, Distance, Slic3r::Distance, DistanceToLine, Slic3r::GUI::DesignSketchTool::DimAnnot::ea, Slic3r::SketchEntityConstraintDef::ea, Slic3r::GUI::DesignSketchTool::DimAnnot::eb, Slic3r::SketchEntityConstraintDef::eb, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, Length, Slic3r::P0, Slic3r::P1, Slic3r::PointOnLine, Slic3r::GUI::DesignSketchTool::DimAnnot::ra, Slic3r::SketchEntityConstraintDef::ra, Radius, Slic3r::Radius, Slic3r::GUI::DesignSketchTool::DimAnnot::rb, Slic3r::SketchEntityConstraintDef::rb, Slic3r::SketchEntityConstraintDef::type, Slic3r::GUI::DesignSketchTool::DimAnnot::value, and Slic3r::SketchEntityConstraintDef::value.

Referenced by open_primary_autoedit(), place_dimension(), and set_dimension_value().

Here is the caller graph for this function:

◆ constraints()

const std::vector< SketchEntityConstraintDef > & Slic3r::GUI::DesignSketchTool::constraints ( ) const
inline
710{ return m_constraints; }

References m_constraints.

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_describe(), and begin_edit().

Here is the caller graph for this function:

◆ cutting()

bool Slic3r::GUI::DesignSketchTool::cutting ( ) const
inline
472{ return m_ct_active; }

References m_ct_active.

◆ dbp_half_extent()

double Slic3r::GUI::DesignSketchTool::dbp_half_extent ( ) const
private
5574{
5575 double half = 20.0;
5576 if (auto* pl = wxGetApp().plater()) {
5577 const BoundingBoxf bb = pl->build_volume().bounding_volume2d();
5578 const double w = bb.max.x() - bb.min.x(), d = bb.max.y() - bb.min.y();
5579 if (w > 1.0 && d > 1.0) half = 0.08 * std::max(w, d);
5580 }
5581 return half;
5582}
static Plater * plater()
Definition GUI_Factories.cpp:400

References dbp_half_extent(), Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::min, and Slic3r::GUI::plater().

Referenced by dbp_half_extent(), hit_test_base_pick(), and render_base_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dbp_squares()

std::vector< SketchPlane > Slic3r::GUI::DesignSketchTool::dbp_squares ( double half) const
private
5585{
5586 std::vector<SketchPlane> squares;
5587 for (size_t i = 0; i < m_dbp_planes.size(); ++i)
5588 squares.push_back(reference_square(m_dbp_planes[i], i < m_dbp_base.size() ? m_dbp_base[i] : -1, half));
5589 return squares;
5590}
SketchPlane reference_square(const SketchPlane &plane, int base, double half)
Definition DesignSketchTool.cpp:5508

References dbp_squares(), m_dbp_base, m_dbp_planes, and Slic3r::GUI::reference_square().

Referenced by dbp_squares(), hit_test_base_pick(), and render_base_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ delete_selected()

void Slic3r::GUI::DesignSketchTool::delete_selected ( )
516{
517 if (m_selection.empty()) return;
518 const int n = int(m_entities.size());
519 std::vector<bool> del(n, false);
520 for (int i : m_selection)
521 if (i >= 0 && i < n) del[i] = true;
522 // old index -> new index (or -1 if deleted), to fix up constraint references.
523 std::vector<int> remap(n, -1);
524 int next = 0;
525 for (int i = 0; i < n; ++i)
526 if (!del[i]) remap[i] = next++;
527 for (int i = n - 1; i >= 0; --i)
528 if (del[i]) m_entities.erase(m_entities.begin() + i);
529 // Drop constraints touching a deleted entity; remap the survivors. A negative reference is
530 // not "no entity" but a sentinel (origin, X axis, Y axis — kSketchRef*) and passes through
531 // unchanged: mapping it to -1 silently cut every constraint onto the origin or an axis.
532 std::vector<SketchEntityConstraintDef> kept;
533 std::vector<int> con_remap(m_constraints.size(), -1);
534 auto live = [&](int e) { return e < 0 || (e < n && remap[e] >= 0); };
535 auto map = [&](int e) { return e < 0 ? e : remap[e]; };
536 for (int ci = 0; ci < int(m_constraints.size()); ++ci) {
537 SketchEntityConstraintDef c = m_constraints[ci];
538 if (!live(c.ea) || !live(c.eb) || !live(c.ec)) continue;
539 c.ea = map(c.ea); c.eb = map(c.eb); c.ec = map(c.ec);
540 con_remap[ci] = int(kept.size());
541 kept.push_back(c);
542 }
543 m_constraints.swap(kept);
544 m_selection.clear();
545 m_point_sel.clear();
546 // Placed quotes follow their geometry and their driving constraint: a quote whose entity or
547 // constraint went away goes with it, the others are reindexed. Clearing them all made one
548 // Delete hide every label while the constraints they showed kept driving the sketch.
549 {
550 std::vector<DimAnnot> kept_d;
551 for (DimAnnot a : m_dimensions) {
552 if (!live(a.ea) || !live(a.eb)) continue;
553 if (a.con >= 0) {
554 if (a.con >= int(con_remap.size()) || con_remap[a.con] < 0) continue;
555 a.con = con_remap[a.con];
556 }
557 a.ea = map(a.ea); a.eb = map(a.eb);
558 kept_d.push_back(a);
559 }
560 m_dimensions.swap(kept_d);
561 }
562 m_dim_has0 = false;
563 m_pending_dim = -1;
564 // The Dimension tool's pending FIRST pick is the same dangling-reference hazard as the placed
565 // quotes just cleared above: it references an entity index that has shifted or gone away, and
566 // a stale m_dim_e0 would dereference out of range on the next click. Drop it too.
567 m_dim_e0 = -1;
569
570 // FEATURE GROUPS hold [begin,end) ranges into m_entities, and every index past a deletion has
571 // just moved. Left alone they point at other people's geometry: feature_of() then answers with
572 // a group the user never drew, and the rect/slot/polygon handles and live quotes follow it.
573 // Survivors are remapped (a contiguous range stays contiguous, since the remap preserves
574 // order); a group that lost any member is dropped, the same rule the placed quotes above
575 // already follow — dangling is worse than absent.
576 {
577 std::vector<Feature> kept_f;
578 for (const Feature& f : m_features) {
579 if (f.begin < 0 || f.end > n || f.end <= f.begin) continue;
580 bool whole = true;
581 for (int k = f.begin; k < f.end; ++k)
582 if (del[k]) { whole = false; break; }
583 if (!whole) continue;
584 Feature g = f;
585 g.begin = remap[f.begin];
586 g.end = remap[f.end - 1] + 1;
587 kept_f.push_back(g);
588 }
589 m_features.swap(kept_f);
590 m_open_feature = -1;
591 }
592
593 // The draw-then-edit QUEUE outlives the entities it was queued for. Its own helper says so:
594 // "Removing an entity that still has a deferred auto-edit would otherwise open a field on a
595 // now-deleted entity and freeze the flow" — it was simply never called from here. Measured:
596 // delete a rectangle whose Width/Height were still queued, draw a circle, type its radius —
597 // the field opens, the digits go in, and the radius does not move, because the field belongs
598 // to a rectangle that no longer exists. ua9g.
600
601 // And re-solve, so the sketch's reported degrees of freedom describe the sketch that is
602 // actually there. Without this, sketch_describe answered dof=16 for a document holding one
603 // circle — the DoF of the geometry that had just been deleted.
604 resolve_live();
606}
int begin
Definition DesignSketchTool.hpp:829

References Slic3r::GUI::DesignSketchTool::Feature::begin, Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, Slic3r::SketchEntityConstraintDef::ec, Slic3r::GUI::DesignSketchTool::Feature::end, Slic3r::f(), m_constraints, m_dim_e0, m_dim_has0, m_dim_r0, m_dimensions, m_entities, m_features, m_open_feature, m_pending_dim, m_point_sel, m_selection, on_selection_changed, Slic3r::P0, reset_autoedit(), and resolve_live().

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_delete(), and undo_last_entity().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dim_anchor()

Vec2d Slic3r::GUI::DesignSketchTool::dim_anchor ( const DimAnnot & a) const
private
1400{
1401 if (a.label_pos.squaredNorm() > 1e-12) return a.label_pos;
1402 Vec2d pa, pb;
1403 if ((a.kind == DimType::Radius || a.kind == DimType::Diameter) &&
1405 return pa;
1406 const bool ga = point_at(a.ea, a.ra, pa);
1407 const bool gb = point_at(a.eb, a.rb, pb);
1408 if (ga && gb) return 0.5 * (pa + pb);
1409 if (ga) return pa;
1410 if (gb) return pb;
1411 return Vec2d(0, 0);
1412}
bool point_at(int ei, SketchPointRole role, Vec2d &out) const
Definition DesignSketchTool.cpp:1144

References Slic3r::Center, Diameter, Slic3r::GUI::DesignSketchTool::DimAnnot::ea, Slic3r::GUI::DesignSketchTool::DimAnnot::eb, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, Slic3r::GUI::DesignSketchTool::DimAnnot::label_pos, point_at(), Slic3r::GUI::DesignSketchTool::DimAnnot::ra, Radius, and Slic3r::GUI::DesignSketchTool::DimAnnot::rb.

Referenced by open_selection_dimension_editor(), and open_value_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dim_text()

std::string Slic3r::GUI::DesignSketchTool::dim_text ( const DimAnnot & a) const
private
2408{
2409 char buf[32];
2410 const char* prefix = (a.kind == DimType::Diameter) ? "\xC3\x98" // 'Ø'
2411 : (a.kind == DimType::Radius) ? "R" : "";
2412 // Two decimals, trailing zeros dropped: the same precision the HUD readout uses, so a label
2413 // and the readout never show the same length two ways.
2414 std::snprintf(buf, sizeof(buf), "%.2f", a.value);
2415 // Force the international (en) decimal point: wx sets LC_NUMERIC to the user
2416 // locale at startup, so snprintf can emit a comma. Normalise it.
2417 for (char& ch : buf)
2418 if (ch == ',') ch = '.';
2419 std::string num(buf);
2420 if (num.find('.') != std::string::npos) {
2421 while (num.back() == '0') num.pop_back();
2422 if (num.back() == '.') num.pop_back();
2423 }
2424 if (num == "-0") num = "0";
2425 // The Design tab models in millimetres whatever the slicer's inch preference says: the
2426 // kernel, the value fields and the readouts are all mm. The suffix used to follow that
2427 // preference while the number did not, so an inch user read "25.4 in" for one inch.
2428 return std::string(prefix) + num + (a.kind == DimType::Angle ? "\xC2\xB0" : " mm");
2429}

References Angle, Diameter, dim_text(), Slic3r::GUI::DesignSketchTool::DimAnnot::kind, Radius, and Slic3r::GUI::DesignSketchTool::DimAnnot::value.

Referenced by build_readout(), dim_text(), draw_dim_quote(), render_cut_gizmo(), render_draft_gizmo(), render_extrude_gizmo(), render_fillet_gizmo(), render_hole_gizmo(), render_live_quotes(), render_move_gizmo(), render_op_gizmo(), render_pattern_gizmo(), render_revolve_gizmo(), render_shell_gizmo(), render_tf_gizmo(), and render_thread_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dimension_current()

double Slic3r::GUI::DesignSketchTool::dimension_current ( ) const
668{
669 switch (dimension_kind()) {
670 case DimType::Length: { const auto& e = m_entities[m_selection[0]]; return (e.p1 - e.p0).norm(); }
671 case DimType::Diameter: return 2.0 * m_entities[m_selection[0]].radius;
672 case DimType::Radius: return m_entities[m_selection[0]].radius;
673 case DimType::Angle: {
674 const auto& a = m_entities[m_selection[0]];
675 const auto& b = m_entities[m_selection[1]];
676 const Vec2d da = a.p1 - a.p0, db = b.p1 - b.p0;
677 const double na = da.norm(), nb = db.norm();
678 if (na < 1e-9 || nb < 1e-9) return 0.0;
679 const double c = std::max(-1.0, std::min(1.0, da.dot(db) / (na * nb)));
680 return std::acos(c) * 180.0 / M_PI;
681 }
682 case DimType::Distance: {
683 Vec2d ra(0, 0), rb(0, 0);
686 return (rb - ra).norm();
687 }
689 const SketchEntity& a = m_entities[m_selection[0]];
690 const SketchEntity& b = m_entities[m_selection[1]];
691 const bool aLine = (a.type == SketchEntity::Type::Line);
692 const SketchEntity& L = aLine ? a : b;
693 const SketchEntity& P = aLine ? b : a;
694 Vec2d rp(0, 0); entity_ref_point(P, rp);
695 Vec2d dir = L.p1 - L.p0;
696 const double n = dir.norm();
697 if (n < 1e-9) return 0.0;
698 const Vec2d nrm(-dir.y() / n, dir.x() / n); // unit normal to the line
699 return std::abs((rp - L.p0).dot(nrm));
700 }
701 default: return 0.0;
702 }
703}

References Angle, Diameter, dimension_kind(), Distance, DistanceToLine, Slic3r::GUI::entity_ref_point(), L, Length, Slic3r::SketchEntity::Line, m_entities, M_PI, m_selection, Slic3r::P, Radius, and Slic3r::SketchEntity::type.

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_set_value(), and open_selection_dimension_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dimension_kind()

DesignSketchTool::DimType Slic3r::GUI::DesignSketchTool::dimension_kind ( ) const
641{
642 if (!selection_valid()) return DimType::None;
643 if (m_selection.size() == 1) {
644 switch (m_entities[m_selection[0]].type) {
648 default: return DimType::None;
649 }
650 }
651 if (m_selection.size() == 2) {
652 const SketchEntity& a = m_entities[m_selection[0]];
653 const SketchEntity& b = m_entities[m_selection[1]];
654 const bool aLine = (a.type == SketchEntity::Type::Line);
655 const bool bLine = (b.type == SketchEntity::Type::Line);
656 Vec2d tmp(0, 0);
657 if (aLine && bLine) return DimType::Angle;
658 // one line + one point-like (point / circle-centre / arc-centre)
659 if (aLine && entity_ref_point(b, tmp)) return DimType::DistanceToLine;
660 if (bLine && entity_ref_point(a, tmp)) return DimType::DistanceToLine;
661 // two point-likes -> centre/point distance (0 = coincident/concentric)
662 if (entity_ref_point(a, tmp) && entity_ref_point(b, tmp)) return DimType::Distance;
663 }
664 return DimType::None;
665}
bool selection_valid() const
Definition DesignSketchTool.cpp:633

References Angle, Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::Circle, Diameter, Distance, DistanceToLine, Slic3r::GUI::entity_ref_point(), Length, Slic3r::SketchEntity::Line, m_entities, m_selection, None, Radius, selection_valid(), and Slic3r::SketchEntity::type.

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_set_value(), apply_dimension(), dimension_current(), open_selection_dimension_editor(), and record_dimension_constraint().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dimtype_title()

std::string Slic3r::GUI::DesignSketchTool::dimtype_title ( DimType k) const
private
1573 {
1574 switch (k) {
1575 case DimType::Length: return _u8L("Length");
1576 case DimType::Diameter: return _u8L("Diameter");
1577 case DimType::Radius: return _u8L("Radius");
1578 case DimType::Angle: return _u8L("Angle (°)");
1579 case DimType::Distance: return _u8L("Distance");
1580 case DimType::DistanceToLine: return _u8L("Distance");
1581 default: return _u8L("Value");
1582 }
1583}

References _u8L, Angle, Diameter, dimtype_title(), Distance, DistanceToLine, Length, and Radius.

Referenced by dimtype_title(), open_primary_autoedit(), open_selection_dimension_editor(), open_value_editor(), and set_dimension_value().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ disarm_tool()

bool Slic3r::GUI::DesignSketchTool::disarm_tool ( )
436{
437 if (m_mode == Mode::Select) return false;
438 reset_op();
439 reset_tf();
441 return true;
442}
void set_tool(Mode mode)
Definition DesignSketchTool.cpp:255

References m_mode, reset_op(), reset_tf(), Select, and set_tool().

Referenced by request_exit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ display_pick()

int Slic3r::GUI::DesignSketchTool::display_pick ( ) const
inline
320{ return m_display_pick; }

References m_display_pick.

◆ display_pick_region()

int Slic3r::GUI::DesignSketchTool::display_pick_region ( ) const
inline
321{ return m_display_pick_region; }

References m_display_pick_region.

◆ dof()

◆ drafting()

bool Slic3r::GUI::DesignSketchTool::drafting ( ) const
inline
466{ return m_dr_active; }

References m_dr_active.

◆ drag_arc_handle()

void Slic3r::GUI::DesignSketchTool::drag_arc_handle ( int ei,
SketchPointRole role,
const Vec2d & target )
private
2031{
2032 if (ei < 0 || ei >= int(m_entities.size())) return;
2033 SketchEntity& e = m_entities[ei];
2034 if (e.type != SketchEntity::Type::Arc) return;
2035 if (role == SketchPointRole::Center) {
2036 const Vec2d d = target - e.center; // rigid translate, keep R + angles
2037 e.center = target; e.p0 += d; e.p1 += d;
2038 } else if (role == SketchPointRole::P0) { // start = RADIUS handle (keep angles)
2039 const double R = (target - e.center).norm();
2040 if (R < 1e-6) return;
2041 e.radius = R;
2042 e.p0 = e.center + R * Vec2d(std::cos(e.start_angle), std::sin(e.start_angle));
2043 e.p1 = e.center + R * Vec2d(std::cos(e.end_angle), std::sin(e.end_angle));
2044 } else if (role == SketchPointRole::P1) { // end = ANGLE handle (keep radius)
2045 const Vec2d d = target - e.center;
2046 if (d.squaredNorm() < 1e-12) return;
2047 // Keep the CCW sweep continuous (0,2pi) so the arc never flips to its complement.
2048 double da = std::atan2(d.y(), d.x()) - e.start_angle;
2049 while (da < 0.0) da += 2.0 * M_PI;
2050 while (da >= 2.0 * M_PI) da -= 2.0 * M_PI;
2051 e.end_angle = e.start_angle + da;
2052 e.p1 = e.center + e.radius * Vec2d(std::cos(e.end_angle), std::sin(e.end_angle));
2053 }
2054 resolve_live();
2055}

References Slic3r::SketchEntity::Arc, Slic3r::Center, Slic3r::SketchEntity::center, drag_arc_handle(), Slic3r::SketchEntity::end_angle, m_entities, M_PI, Slic3r::P0, Slic3r::SketchEntity::p0, Slic3r::P1, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::radius, resolve_live(), Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by drag_arc_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_cut_arrow()

void Slic3r::GUI::DesignSketchTool::drag_cut_arrow ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
6930{
6931 const double proj = hole_axis_proj(canvas, evt, m_ct_base, m_ct_n);
6932 if (std::isnan(proj)) return;
6935}
std::function< void(double)> m_on_cut_offset_changed
Definition DesignSketchTool.hpp:1612
Vec3d m_ct_n
Definition DesignSketchTool.hpp:1598
double m_ct_grab_proj
Definition DesignSketchTool.hpp:1605
double hole_axis_proj(GLCanvas3D &canvas, const wxMouseEvent &evt, const Vec3d &anchor, const Vec3d &dir) const
Definition DesignSketchTool.cpp:6333
Vec3d m_ct_base
Definition DesignSketchTool.hpp:1597
double m_ct_offset
Definition DesignSketchTool.hpp:1601
double m_ct_grab_val
Definition DesignSketchTool.hpp:1604

References drag_cut_arrow(), hole_axis_proj(), m_ct_base, m_ct_grab_proj, m_ct_grab_val, m_ct_n, m_ct_offset, m_on_cut_offset_changed, and Slic3r::GUI::wxMouseEvent.

Referenced by drag_cut_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_datum_handle()

void Slic3r::GUI::DesignSketchTool::drag_datum_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int which )
private
5073{
5074 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
5075 const Vec3d ro = r.a, rd = r.b - r.a;
5076 if (which == 4) { // offset arrow: drag along base normal
5077 const Vec3d e = m_dz_normal; // signed offset, may go negative
5078 const Vec3d w0 = m_dz_anchor - ro;
5079 const double a = e.dot(e), b = e.dot(rd), c = rd.dot(rd), dd = e.dot(w0), ee = rd.dot(w0);
5080 const double denom = a * c - b * b;
5081 if (std::abs(denom) < 1e-7) return; // camera ∥ normal: leave offset as-is
5082 m_dz_offset = (b * ee - c * dd) / denom; // signed distance along the normal
5083 m_dz_plane.origin = m_dz_anchor + m_dz_normal * m_dz_offset; // rectangle follows live
5085 return;
5086 }
5087 const bool uaxis = (which == 0 || which == 1);
5088 const Vec3d e = (uaxis ? m_dz_plane.x_axis : m_dz_plane.y_axis).normalized();
5089 const Vec3d base = m_dz_plane.origin;
5090 const Vec3d w0 = base - ro;
5091 const double a = e.dot(e), b = e.dot(rd), c = rd.dot(rd), dd = e.dot(w0), ee = rd.dot(w0);
5092 const double denom = a * c - b * b;
5093 if (std::abs(denom) < 1e-7) return; // camera ∥ axis: leave size as-is
5094 const double s = (b * ee - c * dd) / denom; // signed coord along e of closest pt
5095 const double size = std::max(2.0, 2.0 * std::abs(s));
5096 if (uaxis) m_dz_usize = size; else m_dz_vsize = size;
5098}
SketchPlane m_dz_plane
Definition DesignSketchTool.hpp:1402
double m_dz_vsize
Definition DesignSketchTool.hpp:1404
Vec3d m_dz_normal
Definition DesignSketchTool.hpp:1408
double m_dz_usize
Definition DesignSketchTool.hpp:1403
double m_dz_offset
Definition DesignSketchTool.hpp:1409
std::function< void(double offset)> on_datum_offset_changed
Definition DesignSketchTool.hpp:345
Vec3d m_dz_anchor
Definition DesignSketchTool.hpp:1407
std::function< void(double usize, double vsize)> on_datum_size_changed
Definition DesignSketchTool.hpp:344

References Slic3r::Linef3::a, Slic3r::Linef3::b, drag_datum_handle(), m_dz_anchor, m_dz_normal, m_dz_offset, m_dz_plane, m_dz_usize, m_dz_vsize, Slic3r::GUI::GLCanvas3D::mouse_ray(), on_datum_offset_changed, on_datum_size_changed, and Slic3r::GUI::wxMouseEvent.

Referenced by drag_datum_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_draft_arc()

void Slic3r::GUI::DesignSketchTool::drag_draft_arc ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
6810{
6811 const Linef3 ray = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6812 const Vec3d ro = ray.a, rd = ray.b - ray.a;
6813 const double denom = rd.dot(m_dr_axis);
6814 if (std::abs(denom) < 1e-9) return;
6815 const double t = (m_dr_center - ro).dot(m_dr_axis) / denom;
6816 const Vec3d p = ro + t * rd;
6817 const Vec3d yax = dr_yaxis(m_dr_axis, m_dr_ref);
6818 const double u = (p - m_dr_center).dot(m_dr_ref);
6819 const double v = (p - m_dr_center).dot(yax);
6820 double deg = std::atan2(v, u) * 180.0 / M_PI;
6821 deg = std::min(89.0, std::max(-89.0, deg));
6822 m_dr_angle = deg;
6824}
std::function< void(double)> m_on_draft_angle_changed
Definition DesignSketchTool.hpp:1593
Vec3d m_dr_ref
Definition DesignSketchTool.hpp:1584
Vec3d m_dr_axis
Definition DesignSketchTool.hpp:1583
Vec3d m_dr_center
Definition DesignSketchTool.hpp:1582
double m_dr_angle
Definition DesignSketchTool.hpp:1586
static Vec3d dr_yaxis(const Vec3d &axis, const Vec3d &ref)
Definition DesignSketchTool.cpp:6707

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::dot(), Slic3r::GUI::dr_yaxis(), drag_draft_arc(), m_dr_angle, m_dr_axis, m_dr_center, m_dr_ref, m_on_draft_angle_changed, M_PI, Slic3r::GUI::GLCanvas3D::mouse_ray(), and Slic3r::GUI::wxMouseEvent.

Referenced by drag_draft_arc(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_ellipsearc_handle()

void Slic3r::GUI::DesignSketchTool::drag_ellipsearc_handle ( int ei,
SketchPointRole role,
const Vec2d & target )
private
2061{
2062 if (ei < 0 || ei >= int(m_entities.size())) return;
2063 SketchEntity& e = m_entities[ei];
2064 if (e.type != SketchEntity::Type::EllipseArc) return;
2065 if (role == SketchPointRole::Center) {
2066 const Vec2d d = target - e.center;
2067 e.center = target; e.p0 += d; e.p1 += d;
2068 } else if (role == SketchPointRole::P0 || role == SketchPointRole::P1) {
2069 const double t = ellipse_param_of(e.center, e.radius, e.rminor, e.rotation, target);
2070 if (role == SketchPointRole::P0) {
2071 e.start_angle = t;
2072 e.p0 = ellipse_point(e.center, e.radius, e.rminor, e.rotation, t);
2073 } else {
2074 // Keep the CCW sweep (end strictly after start) so the arc never inverts.
2075 double t1 = t; while (t1 <= e.start_angle) t1 += 2.0 * M_PI;
2076 e.end_angle = t1;
2077 e.p1 = ellipse_point(e.center, e.radius, e.rminor, e.rotation, t1);
2078 }
2079 }
2080 resolve_live();
2081}
static double ellipse_param_of(const Vec2d &center, double a, double b, double phi, const Vec2d &q)
Definition DesignSketchTool.cpp:3238
static Vec2d ellipse_point(const Vec2d &c, double a, double b, double phi, double t)
Definition DesignSketchTool.cpp:2817

References Slic3r::Center, Slic3r::SketchEntity::center, drag_ellipsearc_handle(), Slic3r::GUI::ellipse_param_of(), Slic3r::GUI::ellipse_point(), Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::end_angle, m_entities, M_PI, Slic3r::P0, Slic3r::SketchEntity::p0, Slic3r::P1, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::radius, resolve_live(), Slic3r::SketchEntity::rminor, Slic3r::SketchEntity::rotation, Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by drag_ellipsearc_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_extrude_arrow()

void Slic3r::GUI::DesignSketchTool::drag_extrude_arrow ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int which )
private
4904{
4905 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
4906 const Vec3d ro = r.a, rd = r.b - r.a;
4907 const Vec3d nd = (m_ex_flip ? -1.0 : 1.0) * m_ex_plane.normal.normalized();
4908 const Vec3d e = (which == 1 ? -1.0 : 1.0) * nd; // axis dir for this arrow
4909 const Vec3d base = m_ex_plane.to_world(m_ex_centroid);
4910 const Vec3d w0 = base - ro;
4911 const double a = e.dot(e), b = e.dot(rd), c = rd.dot(rd), dd = e.dot(w0), ee = rd.dot(w0);
4912 const double denom = a * c - b * b;
4913 if (std::abs(denom) < 1e-7) return; // camera ∥ axis: leave depth as-is
4914 const double depth = std::max(0.01, (b * ee - c * dd) / denom);
4915 if (which == 1) m_ex_depth2 = depth; else m_ex_depth = depth;
4916 if (on_extrude_depth_changed) on_extrude_depth_changed(depth, which == 1);
4917}
double m_ex_depth2
Definition DesignSketchTool.hpp:1389
std::function< void(double depth, bool second)> on_extrude_depth_changed
Definition DesignSketchTool.hpp:333
double m_ex_depth
Definition DesignSketchTool.hpp:1388
Vec2d m_ex_centroid
Definition DesignSketchTool.hpp:1387
SketchPlane m_ex_plane
Definition DesignSketchTool.hpp:1386
bool m_ex_flip
Definition DesignSketchTool.hpp:1391

References Slic3r::Linef3::a, Slic3r::Linef3::b, drag_extrude_arrow(), m_ex_centroid, m_ex_depth, m_ex_depth2, m_ex_flip, m_ex_plane, Slic3r::GUI::GLCanvas3D::mouse_ray(), on_extrude_depth_changed, and Slic3r::GUI::wxMouseEvent.

Referenced by drag_extrude_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_fillet_arrow()

void Slic3r::GUI::DesignSketchTool::drag_fillet_arrow ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
6154{
6155 const double proj = fillet_axis_proj(canvas, evt);
6156 if (std::isnan(proj)) return; // camera ∥ axis: leave radius as-is
6157 m_fl_radius = std::max(0.01, m_fl_grab_radius + (proj - m_fl_grab_proj));
6159}
double m_fl_radius
Definition DesignSketchTool.hpp:1486
std::function< void(double radius)> on_fillet_radius_changed
Definition DesignSketchTool.hpp:390
double fillet_axis_proj(GLCanvas3D &canvas, const wxMouseEvent &evt) const
Definition DesignSketchTool.cpp:6129
double m_fl_grab_radius
Definition DesignSketchTool.hpp:1490
double m_fl_grab_proj
Definition DesignSketchTool.hpp:1489

References drag_fillet_arrow(), fillet_axis_proj(), m_fl_grab_proj, m_fl_grab_radius, m_fl_radius, on_fillet_radius_changed, and Slic3r::GUI::wxMouseEvent.

Referenced by drag_fillet_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_helix_handle()

void Slic3r::GUI::DesignSketchTool::drag_helix_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int which )
private
5254{
5255 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
5256 const Vec3d ro = r.a, rd = r.b - r.a;
5257 const SketchPlane& p = m_hx_plane;
5258 const Vec3d O = p.origin, n = p.normal.normalized();
5259
5260 if (which == 0) { // radius: in-plane distance from O
5261 const Vec2d lp = p.project(ro, rd);
5262 m_hx_radius = std::max(0.01, lp.norm());
5263 } else { // height/pitch: signed distance along n
5264 const Vec3d e = n;
5265 const Vec3d w0 = O - ro;
5266 const double a = e.dot(e), b = e.dot(rd), c = rd.dot(rd), dd = e.dot(w0), ee = rd.dot(w0);
5267 const double denom = a * c - b * b;
5268 if (std::abs(denom) < 1e-7) return; // camera ∥ axis: leave value as-is
5269 const double s = (b * ee - c * dd) / denom; // signed distance along the axis
5270 if (which == 1) m_hx_height = std::max(0.0, s);
5271 else m_hx_pitch = std::max(0.01, s); // zero/negative pitch divides by zero
5272 }
5274}
double m_hx_height
Definition DesignSketchTool.hpp:1421
double m_hx_pitch
Definition DesignSketchTool.hpp:1420
SketchPlane m_hx_plane
Definition DesignSketchTool.hpp:1418
std::function< void(double radius, double pitch, double height)> on_helix_changed
Definition DesignSketchTool.hpp:355
double m_hx_radius
Definition DesignSketchTool.hpp:1419

References Slic3r::Linef3::a, Slic3r::Linef3::b, drag_helix_handle(), m_hx_height, m_hx_pitch, m_hx_plane, m_hx_radius, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::SketchPlane::normal, on_helix_changed, Slic3r::SketchPlane::origin, Slic3r::SketchPlane::project(), and Slic3r::GUI::wxMouseEvent.

Referenced by drag_helix_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_hole_handle()

void Slic3r::GUI::DesignSketchTool::drag_hole_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
6360{
6361 if (m_hl_drag >= 3) return; // X/Y dim labels are click-to-edit, not drag
6362 if (m_hl_drag == 0) { // reposition centre on the plane
6363 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6364 const Vec2d uv = m_hl_plane.project(r.a, r.b - r.a);
6365 m_hl_x = m_hl_grab_x + (uv.x() - m_hl_grab_uv.x());
6366 m_hl_y = m_hl_grab_y + (uv.y() - m_hl_grab_uv.y());
6367 } else { // diameter (1) or depth (2): relative axis drag
6368 const Vec3d centre = m_hl_plane.to_world(Vec2d(m_hl_x, m_hl_y));
6369 const Vec3d dir = (m_hl_drag == 1) ? m_hl_plane.x_axis.normalized() : m_hl_plane.normal.normalized();
6370 const double proj = hole_axis_proj(canvas, evt, centre, dir);
6371 if (std::isnan(proj)) return; // camera ∥ axis: leave value as-is
6372 const double v = std::max(0.01, m_hl_grab_val + (proj - m_hl_grab_proj));
6373 if (m_hl_drag == 1) m_hl_diameter = 2.0 * v;
6374 else m_hl_depth = v;
6375 }
6377}
double m_hl_grab_val
Definition DesignSketchTool.hpp:1516
double m_hl_diameter
Definition DesignSketchTool.hpp:1506
SketchPlane m_hl_plane
Definition DesignSketchTool.hpp:1504
double m_hl_grab_x
Definition DesignSketchTool.hpp:1518
double m_hl_grab_proj
Definition DesignSketchTool.hpp:1515
Vec2d m_hl_grab_uv
Definition DesignSketchTool.hpp:1517
double m_hl_x
Definition DesignSketchTool.hpp:1505
std::function< void(double x, double y, double diameter, double depth)> on_hole_changed
Definition DesignSketchTool.hpp:405
double m_hl_y
Definition DesignSketchTool.hpp:1505
double m_hl_grab_y
Definition DesignSketchTool.hpp:1518
double m_hl_depth
Definition DesignSketchTool.hpp:1507

References Slic3r::Linef3::a, Slic3r::Linef3::b, drag_hole_handle(), hole_axis_proj(), m_hl_depth, m_hl_diameter, m_hl_drag, m_hl_grab_proj, m_hl_grab_uv, m_hl_grab_val, m_hl_grab_x, m_hl_grab_y, m_hl_plane, m_hl_x, m_hl_y, Slic3r::GUI::GLCanvas3D::mouse_ray(), on_hole_changed, and Slic3r::GUI::wxMouseEvent.

Referenced by drag_hole_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_move_arc()

void Slic3r::GUI::DesignSketchTool::drag_move_arc ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int axis )
private
6023{
6024 double ang;
6025 if (!arc_mouse_angle(canvas, evt, axis, ang)) return;
6026 Vec3d e, u, v; ring_basis(axis, e, u, v);
6027 const double delta = ang - m_mv_arc_a0;
6028 m_mv_rot = Eigen::AngleAxisd(delta, e).toRotationMatrix() * m_mv_rot_start;
6030}
Eigen::Matrix3d m_mv_rot_start
Definition DesignSketchTool.hpp:1464
Transform3d compose_move_xform() const
Definition DesignSketchTool.cpp:5843
std::function< void(int body, const Transform3d &xform)> on_body_move_changed
Definition DesignSketchTool.hpp:289
double m_mv_arc_a0
Definition DesignSketchTool.hpp:1465
bool arc_mouse_angle(GLCanvas3D &canvas, const wxMouseEvent &evt, int axis, double &ang) const
Definition DesignSketchTool.cpp:6007

References arc_mouse_angle(), compose_move_xform(), drag_move_arc(), m_mv_arc_a0, m_mv_body, m_mv_rot, m_mv_rot_start, on_body_move_changed, ring_basis(), and Slic3r::GUI::wxMouseEvent.

Referenced by drag_move_arc(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_move_arrow()

void Slic3r::GUI::DesignSketchTool::drag_move_arrow ( const Linef3 & ray)
5958{
5959 if (m_mv_drag < 0 || m_mv_drag > 2) return;
5960 const double proj = ray_axis_proj(ray, m_mv_base + m_mv_offset, Vec3d::Unit(m_mv_drag));
5961 if (std::isnan(proj)) return; // camera ∥ axis: leave offset as-is
5962 if (std::isnan(m_mv_grab_along)) { m_mv_grab_along = proj; return; }
5965}
double m_mv_grab_along
Definition DesignSketchTool.hpp:1469
static double ray_axis_proj(const Linef3 &ray, const Vec3d &anchor, const Vec3d &dir)
Definition DesignSketchTool.cpp:10338

References compose_move_xform(), drag_move_arrow(), m_mv_base, m_mv_body, m_mv_drag, m_mv_grab_along, m_mv_offset, on_body_move_changed, and Slic3r::GUI::ray_axis_proj().

Referenced by drag_move_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_op_arrow()

void Slic3r::GUI::DesignSketchTool::drag_op_arrow ( const Vec2d & target)
private
8862{
8863 const double v = (target - m_op_anchor).dot(m_op_dir); // project onto the arrow axis
8864 if (m_mode == Mode::Offset) m_op_value = v; // signed: chooses the side
8865 else m_op_value = std::max(0.001, v);// fillet/chamfer: positive
8867}
Vec2d m_op_anchor
Definition DesignSketchTool.hpp:1173
Vec2d m_op_dir
Definition DesignSketchTool.hpp:1174
void recompute_op_ghost()
Definition DesignSketchTool.cpp:8729

References Slic3r::dot(), drag_op_arrow(), m_mode, m_op_anchor, m_op_dir, m_op_value, Offset, and recompute_op_ghost().

Referenced by drag_op_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_pattern_handle()

void Slic3r::GUI::DesignSketchTool::drag_pattern_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
7231{
7232 const Linef3 ray = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
7233 const Vec3d ro = ray.a, rd = ray.b - ray.a;
7234 if (!m_pt_circular) {
7235 // Skew-line closest point of the mouse ray to the march axis -> span -> spacing.
7236 const Vec3d e = m_pt_dirw;
7237 const Vec3d w0 = m_pt_base - ro;
7238 const double a = e.dot(e), b = e.dot(rd), c = rd.dot(rd), dd = e.dot(w0), ee = rd.dot(w0);
7239 const double denom = a * c - b * b;
7240 if (std::abs(denom) < 1e-7) return; // camera ∥ axis: leave spacing as-is
7241 const double span = std::max(0.01, (b * ee - c * dd) / denom);
7242 const int div = std::max(1, m_pt_count - 1);
7243 m_pt_spacing = std::max(0.1, span / double(div));
7245 return;
7246 }
7247 const double denom = rd.dot(m_pt_normal);
7248 if (std::abs(denom) < 1e-9) return; // ray ∥ rotation plane: leave angle as-is
7249 const double t = (m_pt_ccenter - ro).dot(m_pt_normal) / denom;
7250 const Vec3d p = ro + t * rd;
7251 const Vec3d yax = m_pt_normal.cross(m_pt_cref).normalized();
7252 double deg = std::atan2((p - m_pt_ccenter).dot(yax), (p - m_pt_ccenter).dot(m_pt_cref)) * 180.0 / M_PI;
7253 if (deg < 0.0) deg += 360.0;
7254 m_pt_angle = std::min(360.0, std::max(1.0, deg));
7256}
Vec3d m_pt_normal
Definition DesignSketchTool.hpp:1621
int m_pt_count
Definition DesignSketchTool.hpp:1625
double m_pt_angle
Definition DesignSketchTool.hpp:1627
std::function< void(double value)> on_pattern_changed
Definition DesignSketchTool.hpp:483
Vec3d m_pt_cref
Definition DesignSketchTool.hpp:1622
Vec3d m_pt_ccenter
Definition DesignSketchTool.hpp:1623
double m_pt_spacing
Definition DesignSketchTool.hpp:1626
Vec3d m_pt_dirw
Definition DesignSketchTool.hpp:1619
Vec3d m_pt_base
Definition DesignSketchTool.hpp:1618
bool m_pt_circular
Definition DesignSketchTool.hpp:1617

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::dot(), drag_pattern_handle(), M_PI, m_pt_angle, m_pt_base, m_pt_ccenter, m_pt_circular, m_pt_count, m_pt_cref, m_pt_dirw, m_pt_normal, m_pt_spacing, Slic3r::GUI::GLCanvas3D::mouse_ray(), on_pattern_changed, and Slic3r::GUI::wxMouseEvent.

Referenced by drag_pattern_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_polygon_vertex()

void Slic3r::GUI::DesignSketchTool::drag_polygon_vertex ( int fi,
int ei,
SketchPointRole role,
const Vec2d & target )
private
1944{
1945 if (fi < 0 || fi >= int(m_features.size())) return;
1946 Feature& f = m_features[fi];
1947 if (f.begin < 0 || f.end > int(m_entities.size())) return;
1948 // Centroid of the loop = the regular polygon's centre (robust if it was moved).
1949 Vec2d c(0, 0); int n = 0;
1950 for (int i = f.begin; i < f.end; ++i)
1951 if (m_entities[i].type == SketchEntity::Type::Line) { c += m_entities[i].p0; ++n; }
1952 if (n == 0) return;
1953 c /= double(n);
1954 Vec2d vpos;
1955 if (!point_at(ei, role, vpos)) return;
1956 const Vec2d cur = vpos - c; // current grabbed-vertex spoke
1957 const Vec2d tgt = target - c; // desired spoke
1958 const double curR = cur.norm(), newR = tgt.norm();
1959 if (curR < 1e-9 || newR < 1e-6) return;
1960 const double s = newR / curR;
1961 const double da = std::atan2(tgt.y(), tgt.x()) - std::atan2(cur.y(), cur.x());
1962 const double ca = std::cos(da), sa = std::sin(da);
1963 auto tf = [&](const Vec2d& p) -> Vec2d { const Vec2d r = (p - c) * s; // -> Vec2d: avoid
1964 return c + Vec2d(r.x() * ca - r.y() * sa, r.x() * sa + r.y() * ca); }; // Eigen dangling
1965
1966 for (int i = f.begin; i < f.end; ++i) {
1967 SketchEntity& e = m_entities[i];
1968 if (e.type != SketchEntity::Type::Line) continue;
1969 e.p0 = tf(e.p0); e.p1 = tf(e.p1);
1970 }
1971 f.c0 = c; f.param = newR;
1972 drop_orientation_constraints(f.begin, f.end); // the drag rotates -> edge H/V invalid
1973 // No re-solve (see set_polygon_angle): the transformed geometry is already a correct
1974 // regular polygon; solving the anchorless redundant loop would collapse it.
1975}
void drop_orientation_constraints(int begin, int end)
Definition DesignSketchTool.cpp:1787

References drag_polygon_vertex(), drop_orientation_constraints(), Slic3r::f(), Slic3r::SketchEntity::Line, m_entities, m_features, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, point_at(), and Slic3r::SketchEntity::type.

Referenced by drag_polygon_vertex(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_rect_corner()

void Slic3r::GUI::DesignSketchTool::drag_rect_corner ( int fi,
const Vec2d & cursor )
private
2343{
2344 if (fi < 0 || fi >= int(m_features.size())) return;
2345 Feature& f = m_features[fi];
2346 if (f.end - f.begin != 4) return;
2347 const Vec2d A = m_drag_rect_anchor, B = cursor;
2348 if (std::abs(B.x() - A.x()) < 1e-4 || std::abs(B.y() - A.y()) < 1e-4) return; // degenerate
2349 const Vec2d corners[4] = { A, Vec2d(B.x(), A.y()), B, Vec2d(A.x(), B.y()) };
2350 for (int i = 0; i < 4; ++i) {
2351 SketchEntity e; e.type = SketchEntity::Type::Line;
2352 e.p0 = corners[i]; e.p1 = corners[(i + 1) % 4];
2353 e.construction = m_entities[f.begin + i].construction;
2354 m_entities[f.begin + i] = e;
2355 }
2356 f.c0 = A; f.c1 = B;
2357}
Vec2d m_drag_rect_anchor
Definition DesignSketchTool.hpp:1114

References Slic3r::SketchEntity::construction, drag_rect_corner(), Slic3r::f(), Slic3r::SketchEntity::Line, m_drag_rect_anchor, m_entities, m_features, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, and Slic3r::SketchEntity::type.

Referenced by drag_rect_corner(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_revolve_arc()

void Slic3r::GUI::DesignSketchTool::drag_revolve_arc ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
7056{
7057 const Linef3 ray = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
7058 const Vec3d ro = ray.a, rd = ray.b - ray.a;
7059 const double denom = rd.dot(m_rv_axis);
7060 if (std::abs(denom) < 1e-9) return; // ray ∥ revolve plane: leave angle as-is
7061 const double t = (m_rv_center - ro).dot(m_rv_axis) / denom;
7062 const Vec3d p = ro + t * rd;
7063 const Vec3d yax = rv_yaxis(m_rv_axis, m_rv_ref, m_rv_flip);
7064 const double u = (p - m_rv_center).dot(m_rv_ref);
7065 const double v = (p - m_rv_center).dot(yax);
7066 double deg = std::atan2(v, u) * 180.0 / M_PI;
7067 if (deg < 0.0) deg += 360.0;
7068 deg = std::min(360.0, std::max(1.0, deg));
7069 m_rv_angle = deg;
7071}
Vec3d m_rv_ref
Definition DesignSketchTool.hpp:1568
double m_rv_angle
Definition DesignSketchTool.hpp:1570
bool m_rv_flip
Definition DesignSketchTool.hpp:1571
std::function< void(double angle)> on_revolve_angle_changed
Definition DesignSketchTool.hpp:461
Vec3d m_rv_axis
Definition DesignSketchTool.hpp:1567
Vec3d m_rv_center
Definition DesignSketchTool.hpp:1566
static Vec3d rv_yaxis(const Vec3d &axis, const Vec3d &ref, bool flip)
Definition DesignSketchTool.cpp:6697

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::dot(), drag_revolve_arc(), M_PI, m_rv_angle, m_rv_axis, m_rv_center, m_rv_flip, m_rv_ref, Slic3r::GUI::GLCanvas3D::mouse_ray(), on_revolve_angle_changed, Slic3r::GUI::rv_yaxis(), and Slic3r::GUI::wxMouseEvent.

Referenced by drag_revolve_arc(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_rib_handle()

void Slic3r::GUI::DesignSketchTool::drag_rib_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int which )
private
5396{
5397 (void)which; // both handles behave identically: a drag on either sets the full thickness
5398 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
5399 const Vec3d ro = r.a, rd = r.b - r.a;
5400 Vec2d d, perp, mid; double half;
5401 if (!rib_frame(m_rb_p0, m_rb_p1, m_rb_thickness, d, perp, mid, half)) return;
5402 const Vec2d lp = m_rb_plane.project(ro, rd);
5403 const Vec2d w = lp - m_rb_p0;
5404 const double dist = std::abs(w.x() * d.y() - w.y() * d.x()); // |cross(w, d)| = perp distance
5405 m_rb_thickness = std::max(0.01, 2.0 * dist); // ×2: centred slab, handle at half
5407}
SketchPlane m_rb_plane
Definition DesignSketchTool.hpp:1435
Vec2d m_rb_p0
Definition DesignSketchTool.hpp:1436
double m_rb_thickness
Definition DesignSketchTool.hpp:1438
std::function< void(double thickness)> on_rib_thickness_changed
Definition DesignSketchTool.hpp:364
Vec2d m_rb_p1
Definition DesignSketchTool.hpp:1437
static bool rib_frame(const Vec2d &p0, const Vec2d &p1, double thickness, Vec2d &d, Vec2d &perp, Vec2d &mid, double &half)
Definition DesignSketchTool.cpp:5296
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:298
Eigen::Matrix< typename Derived::Scalar, 2, 1, Eigen::DontAlign > perp(const Eigen::MatrixBase< Derived > &v)
Definition Point.hpp:130

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::Geometry::dist(), drag_rib_handle(), m_rb_p0, m_rb_p1, m_rb_plane, m_rb_thickness, Slic3r::GUI::GLCanvas3D::mouse_ray(), on_rib_thickness_changed, Slic3r::perp(), Slic3r::GUI::rib_frame(), and Slic3r::GUI::wxMouseEvent.

Referenced by drag_rib_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_shell_arrow()

void Slic3r::GUI::DesignSketchTool::drag_shell_arrow ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
6674{
6675 const double proj = hole_axis_proj(canvas, evt, m_sh_anchor, m_sh_dir);
6676 if (std::isnan(proj)) return;
6677 m_sh_thickness = std::max(0.01, m_sh_grab_val + (proj - m_sh_grab_proj));
6679}
double m_sh_thickness
Definition DesignSketchTool.hpp:1552
double m_sh_grab_val
Definition DesignSketchTool.hpp:1556
Vec3d m_sh_dir
Definition DesignSketchTool.hpp:1551
std::function< void(double thickness)> on_shell_thickness_changed
Definition DesignSketchTool.hpp:425
Vec3d m_sh_anchor
Definition DesignSketchTool.hpp:1550
double m_sh_grab_proj
Definition DesignSketchTool.hpp:1555

References drag_shell_arrow(), hole_axis_proj(), m_sh_anchor, m_sh_dir, m_sh_grab_proj, m_sh_grab_val, m_sh_thickness, on_shell_thickness_changed, and Slic3r::GUI::wxMouseEvent.

Referenced by drag_shell_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_slot_handle()

void Slic3r::GUI::DesignSketchTool::drag_slot_handle ( int fi,
const Vec2d & cursor )
private
2362{
2363 if (fi < 0 || fi >= int(m_features.size())) return;
2364 Feature& f = m_features[fi];
2365 if (f.end - f.begin != 4) return;
2366 const Vec2d c0 = m_drag_slot_c1 ? f.c0 : cursor;
2367 const Vec2d c1 = m_drag_slot_c1 ? cursor : f.c1;
2368 std::vector<SketchEntity> rebuilt = make_slot(c0, c1, f.param);
2369 if (int(rebuilt.size()) != 4) return;
2370 for (int i = 0; i < 4; ++i) {
2371 rebuilt[i].construction = m_entities[f.begin + i].construction;
2372 m_entities[f.begin + i] = rebuilt[i];
2373 }
2374 f.c0 = c0; f.c1 = c1;
2375}
std::vector< SketchEntity > make_slot(const Vec2d &c0, const Vec2d &c1, double half_width) const
Definition DesignSketchTool.cpp:3090
bool m_drag_slot_c1
Definition DesignSketchTool.hpp:1116

References drag_slot_handle(), Slic3r::f(), m_drag_slot_c1, m_entities, m_features, and make_slot().

Referenced by drag_slot_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_tf_handle()

void Slic3r::GUI::DesignSketchTool::drag_tf_handle ( const Vec2d & target)
private
9258{
9259 switch (m_mode) {
9260 case Mode::Move:
9261 case Mode::Array:
9262 m_tf_delta = target - m_tf_pivot;
9263 break;
9264 case Mode::Rotate:
9265 case Mode::PolarArray: {
9266 const Vec2d d = target - m_tf_pivot;
9267 if (d.norm() > 1e-9) m_tf_angle = std::atan2(d.y(), d.x());
9268 break;
9269 }
9270 case Mode::Scale: {
9271 const double r = (target - m_tf_pivot).norm();
9272 m_tf_scale = std::max(1e-3, r / std::max(m_tf_handle_r, 1e-9));
9273 break;
9274 }
9275 default: break;
9276 }
9278}
void recompute_tf_ghost()
Definition DesignSketchTool.cpp:9207

References Array, drag_tf_handle(), m_mode, m_tf_angle, m_tf_delta, m_tf_handle_r, m_tf_pivot, m_tf_scale, Move, PolarArray, recompute_tf_ghost(), Rotate, and Scale.

Referenced by drag_tf_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_thread_handle()

void Slic3r::GUI::DesignSketchTool::drag_thread_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
6560{
6561 if (m_th_drag == 0) {
6562 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6563 const Vec2d uv = m_th_plane.project(r.a, r.b - r.a);
6564 m_th_x = m_th_grab_x + (uv.x() - m_th_grab_uv.x());
6565 m_th_y = m_th_grab_y + (uv.y() - m_th_grab_uv.y());
6566 } else {
6567 const Vec3d centre = m_th_plane.to_world(Vec2d(m_th_x, m_th_y));
6568 const Vec3d dir = (m_th_drag == 1) ? m_th_plane.x_axis.normalized() : m_th_plane.normal.normalized();
6569 const double proj = hole_axis_proj(canvas, evt, centre, dir);
6570 if (std::isnan(proj)) return;
6571 const double v = std::max(0.01, m_th_grab_val + (proj - m_th_grab_proj));
6572 if (m_th_drag == 1) m_th_radius = v;
6573 else m_th_height = v;
6574 }
6576}
SketchPlane m_th_plane
Definition DesignSketchTool.hpp:1531
std::function< void(double x, double y, double radius, double height)> on_thread_changed
Definition DesignSketchTool.hpp:416
double m_th_grab_x
Definition DesignSketchTool.hpp:1540
double m_th_grab_proj
Definition DesignSketchTool.hpp:1537
Vec2d m_th_grab_uv
Definition DesignSketchTool.hpp:1539
double m_th_radius
Definition DesignSketchTool.hpp:1533
double m_th_x
Definition DesignSketchTool.hpp:1532
double m_th_grab_val
Definition DesignSketchTool.hpp:1538
double m_th_grab_y
Definition DesignSketchTool.hpp:1540
double m_th_height
Definition DesignSketchTool.hpp:1534
double m_th_y
Definition DesignSketchTool.hpp:1532

References Slic3r::Linef3::a, Slic3r::Linef3::b, drag_thread_handle(), hole_axis_proj(), m_th_drag, m_th_grab_proj, m_th_grab_uv, m_th_grab_val, m_th_grab_x, m_th_grab_y, m_th_height, m_th_plane, m_th_radius, m_th_x, m_th_y, Slic3r::GUI::GLCanvas3D::mouse_ray(), on_thread_changed, and Slic3r::GUI::wxMouseEvent.

Referenced by drag_thread_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drag_xform_handle()

void Slic3r::GUI::DesignSketchTool::drag_xform_handle ( const Vec2d & target)
private
8631{
8632 if (m_xform_handle < 0) return;
8633 if (m_xform_handle == 4) { // centre move: translate by cursor delta
8634 m_xform_offset += (target - m_xform_anchor);
8635 m_xform_anchor = target;
8636 emit_xform();
8637 return;
8638 }
8639 // Corner scale: hold the opposite corner (fixed world anchor O), send the grabbed
8640 // corner to the cursor. base coords of grabbed (bg) and opposite (ba) corners.
8641 auto base_corner = [&](int i) {
8642 return Vec2d((i == 1 || i == 2) ? m_xform_max.x() : m_xform_min.x(),
8643 (i == 2 || i == 3) ? m_xform_max.y() : m_xform_min.y());
8644 };
8645 const int h = m_xform_handle;
8646 const Vec2d bg = base_corner(h);
8647 const Vec2d ba = base_corner((h + 2) % 4);
8648 const Vec2d O = m_xform_anchor;
8649 const double dbx = bg.x() - ba.x(), dby = bg.y() - ba.y();
8650 if (std::abs(dbx) > 1e-9) {
8651 double nsx = (target.x() - O.x()) / dbx;
8652 if (std::abs(nsx) < 1e-4) nsx = (nsx < 0 ? -1e-4 : 1e-4);
8653 m_xform_sx = nsx;
8654 m_xform_offset.x() = O.x() - ba.x() * nsx;
8655 }
8656 if (std::abs(dby) > 1e-9) {
8657 double nsy = (target.y() - O.y()) / dby;
8658 if (std::abs(nsy) < 1e-4) nsy = (nsy < 0 ? -1e-4 : 1e-4);
8659 m_xform_sy = nsy;
8660 m_xform_offset.y() = O.y() - ba.y() * nsy;
8661 }
8662 emit_xform();
8663}
void emit_xform()
Definition DesignSketchTool.cpp:8665
Vec2d m_xform_anchor
Definition DesignSketchTool.hpp:1194

References drag_xform_handle(), emit_xform(), m_xform_anchor, m_xform_handle, m_xform_max, m_xform_min, m_xform_offset, m_xform_sx, and m_xform_sy.

Referenced by drag_xform_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draw_dim_label()

void Slic3r::GUI::DesignSketchTool::draw_dim_label ( const std::string & txt,
const Vec2d & plane_center )
private
7888{
7889 if (txt.empty()) return;
7890 const Camera& cam = wxGetApp().plater()->get_camera();
7891 const wxPoint sp = world_to_screen_px(cam, m_plane.to_world(plane_center));
7892 if (sp.x < 0 && sp.y < 0) return;
7893 ImGuiWrapper* imgui = wxGetApp().imgui();
7894 // Identical to the Prepare/Preview Measure gizmo label (GLGizmoMeasure::render_dimensioning):
7895 // push_common_window_style sets the white text colour + font/scale (without it the text is
7896 // invisible); BringWindowToDisplayFront keeps the per-frame label window on top.
7898 imgui->set_next_window_pos((float)sp.x, (float)sp.y, ImGuiCond_Always, 0.5f, 0.5f);
7899 imgui->set_next_window_bg_alpha(0.0f);
7900 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
7901 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
7902 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(1.0f, 1.0f));
7903 const std::string win = "##sketchdim" + std::to_string(m_dim_label_seq++);
7904 imgui->begin(win, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration
7905 | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoFocusOnAppearing
7906 | ImGuiWindowFlags_NoNav);
7907 ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
7908 ImGui::AlignTextToFramePadding();
7909 ImDrawList* dl = ImGui::GetWindowDrawList();
7910 const ImVec2 ts = ImGui::CalcTextSize(txt.c_str());
7911 // Push this label clear of any already drawn this frame (see m_label_rects).
7912 {
7913 ImVec2 wp = ImGui::GetWindowPos();
7914 const ImVec2 ws = ImGui::GetWindowSize();
7915 for (int guard = 0; guard < 8; ++guard) {
7916 bool hit = false;
7917 for (const LabelRect& r : m_label_rects) {
7918 const double ix = std::min(double(wp.x) + ws.x, r.x + r.w) - std::max(double(wp.x), r.x);
7919 const double iy = std::min(double(wp.y) + ws.y, r.y + r.h) - std::max(double(wp.y), r.y);
7920 if (ix > 2.0 && iy > 2.0) { hit = true; break; }
7921 }
7922 if (!hit) break;
7923 wp.y += ws.y + 2.0f; // straight down, one label per step
7924 ImGui::SetWindowPos(wp, ImGuiCond_Always);
7925 }
7926 m_label_rects.push_back({double(wp.x), double(wp.y), double(ws.x), double(ws.y)});
7927 }
7928 const ImVec2 pos = ImGui::GetCursorScreenPos();
7929 const ImGuiStyle& st = ImGui::GetStyle();
7930 dl->AddRectFilled(ImVec2(pos.x - st.FramePadding.x, pos.y + st.FramePadding.y),
7931 ImVec2(pos.x + ts.x + 2.0f * st.FramePadding.x,
7932 pos.y + ts.y + 2.0f * st.FramePadding.y),
7933 ImGuiWrapper::to_ImU32(ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f)));
7934 ImGui::SetCursorScreenPos(ImVec2(pos.x + st.FramePadding.x, pos.y));
7935 imgui->text(txt);
7936 imgui->end();
7937 ImGui::PopStyleVar(3);
7939}
std::vector< LabelRect > m_label_rects
Definition DesignSketchTool.hpp:1268
int m_dim_label_seq
Definition DesignSketchTool.hpp:1261
float m_render_scale
Definition DesignSketchTool.hpp:1269
Definition DesignSketchTool.hpp:1267
static ImU32 to_ImU32(const ColorRGBA &color)
Definition ImGuiWrapper.cpp:2239
static void pop_common_window_style()
Definition ImGuiWrapper.cpp:2839
static void push_common_window_style(const float scale)
Definition ImGuiWrapper.cpp:2794
Vec3d pos(const Pt &p)
Definition ReprojectPointsOnMesh.hpp:16

References Slic3r::GUI::ImGuiWrapper::begin(), draw_dim_label(), Slic3r::GUI::ImGuiWrapper::end(), m_dim_label_seq, m_label_rects, m_plane, m_render_scale, Slic3r::GUI::ImGuiWrapper::pop_common_window_style(), Slic3r::GUI::ImGuiWrapper::push_common_window_style(), Slic3r::GUI::ImGuiWrapper::set_next_window_bg_alpha(), Slic3r::GUI::ImGuiWrapper::set_next_window_pos(), Slic3r::GUI::ImGuiWrapper::text(), Slic3r::GUI::ImGuiWrapper::to_ImU32(), and Slic3r::GUI::world_to_screen_px().

Referenced by draw_dim_label(), and draw_text().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draw_dim_quote()

bool Slic3r::GUI::DesignSketchTool::draw_dim_quote ( const DimAnnot & a,
double th,
const ColorRGBA & col,
Vec2d & out_label )
private
7967{
7968 std::vector<std::pair<Vec2d, Vec2d>> segs;
7969 if (a.kind == DimType::Length || a.kind == DimType::Distance) {
7970 Vec2d pa, pb;
7971 if (a.kind == DimType::Length) {
7972 if (a.ea < 0 || a.ea >= int(m_entities.size())) return false;
7973 pa = m_entities[a.ea].p0; pb = m_entities[a.ea].p1;
7974 } else if (!point_at(a.ea, a.ra, pa) || !point_at(a.eb, a.rb, pb)) {
7975 return false;
7976 }
7977 const Vec2d d = pb - pa;
7978 const double L = d.norm();
7979 if (L < 1e-6) return false;
7980 const Vec2d u = d / L;
7981 const Vec2d nrm(-u.y(), u.x());
7982 const double side = (a.side != 0.0) ? a.side : 1.0;
7983 const double off = side * std::max(L * 0.18, 8.0);
7984 const Vec2d A2 = pa + nrm * off, B2 = pb + nrm * off; // offset clear of the sketch line
7985 segs.emplace_back(A2, B2); // dimension line (not on the geometry)
7986 const double as = std::max(L * 0.04, 2.0);
7987 auto arrow = [&](const Vec2d& tip, const Vec2d& dir) {
7988 const Vec2d back = tip + dir * as;
7989 segs.emplace_back(tip, back + nrm * (as * 0.5));
7990 segs.emplace_back(tip, back - nrm * (as * 0.5));
7991 };
7992 arrow(A2, u); arrow(B2, -u);
7993 out_label = (A2 + B2) * 0.5 + nrm * (side * (th * 0.7 + 1.5));
7994 } else if (a.kind == DimType::Diameter || a.kind == DimType::Radius) {
7995 if (a.ea < 0 || a.ea >= int(m_entities.size())) return false;
7996 const SketchEntity& e = m_entities[a.ea];
7997 const Vec2d c = e.center;
7998 const double r = e.radius;
7999 if (r < 1e-6) return false;
8000 const Vec2d u(1.0, 0.0);
8001 const double as = std::max(r * 0.12, 2.0);
8002 if (a.kind == DimType::Diameter) {
8003 const Vec2d p1 = c - u * r, p2 = c + u * r;
8004 segs.emplace_back(p1, p2);
8005 segs.emplace_back(p1, p1 + u * as + Vec2d(0, 1) * (as * 0.5));
8006 segs.emplace_back(p1, p1 + u * as - Vec2d(0, 1) * (as * 0.5));
8007 segs.emplace_back(p2, p2 - u * as + Vec2d(0, 1) * (as * 0.5));
8008 segs.emplace_back(p2, p2 - u * as - Vec2d(0, 1) * (as * 0.5));
8009 out_label = c + Vec2d(0, 1) * (th * 0.8);
8010 } else {
8011 const Vec2d p2 = c + u * r;
8012 segs.emplace_back(c, p2);
8013 segs.emplace_back(p2, p2 - u * as + Vec2d(0, 1) * (as * 0.5));
8014 segs.emplace_back(p2, p2 - u * as - Vec2d(0, 1) * (as * 0.5));
8015 out_label = (c + p2) * 0.5 + Vec2d(0, 1) * (th * 0.8);
8016 }
8017 } else if (a.kind == DimType::DistanceToLine) {
8018 Vec2d pa;
8019 if (!point_at(a.ea, a.ra, pa) || a.eb < 0 || a.eb >= int(m_entities.size())) return false;
8020 const SketchEntity& Ln = m_entities[a.eb];
8021 const Vec2d ld = Ln.p1 - Ln.p0;
8022 const double n = ld.norm();
8023 if (n < 1e-9) return false;
8024 const Vec2d u = ld / n;
8025 const double t = (pa - Ln.p0).dot(u);
8026 const Vec2d foot = Ln.p0 + u * t; // perpendicular foot on the line
8027 segs.emplace_back(pa, foot);
8028 out_label = (pa + foot) * 0.5 + u * (th * 0.7 + 1.5);
8029 } else if (a.kind == DimType::Angle) {
8030 if (a.ea < 0 || a.ea >= int(m_entities.size())) return false;
8031 const SketchEntity& e = m_entities[a.ea];
8032 if (e.type != SketchEntity::Type::Line) return false;
8033 const Vec2d d = e.p1 - e.p0;
8034 const double L = d.norm();
8035 if (L < 1e-6) return false;
8036 double ang = std::atan2(d.y(), d.x()); // signed, matches measure_dim sweep
8037 const double rr = std::max(std::min(L * 0.35, 40.0), th * 1.6); // arc radius
8038 segs.emplace_back(e.p0, e.p0 + Vec2d(rr * 1.15, 0.0)); // horizontal reference leg
8039 const int N = 20; // arc 0 -> ang about p0
8040 Vec2d prev = e.p0 + Vec2d(rr, 0.0);
8041 for (int i = 1; i <= N; ++i) {
8042 const double t = ang * double(i) / N;
8043 const Vec2d cur = e.p0 + Vec2d(rr * std::cos(t), rr * std::sin(t));
8044 segs.emplace_back(prev, cur); prev = cur;
8045 }
8046 const double mid = ang * 0.5;
8047 out_label = e.p0 + Vec2d(std::cos(mid), std::sin(mid)) * (rr + th * 1.1);
8048 } else {
8049 return false;
8050 }
8051 draw_strokes(m_highlight_model, segs, 0.2, dimcol);
8052 draw_text(m_line_model, dim_text(a), out_label, th, dimcol);
8053 return true;
8054}
void draw_strokes(GLModel &model, const std::vector< std::pair< Vec2d, Vec2d > > &segs, double hw, const ColorRGBA &color)
Definition DesignSketchTool.cpp:7713
void draw_text(GLModel &model, const std::string &s, const Vec2d &center, double height, const ColorRGBA &color)
Definition DesignSketchTool.cpp:7941
GLModel m_highlight_model
Definition DesignSketchTool.hpp:1260
GLModel m_line_model
Definition DesignSketchTool.hpp:1258
@ N
Definition CalibrationWizardSavePage.cpp:124

References Angle, Slic3r::SketchEntity::center, Diameter, dim_text(), Distance, DistanceToLine, Slic3r::dot(), draw_dim_quote(), draw_strokes(), draw_text(), Slic3r::GUI::DesignSketchTool::DimAnnot::ea, Slic3r::GUI::DesignSketchTool::DimAnnot::eb, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, L, Length, Slic3r::SketchEntity::Line, m_entities, m_highlight_model, m_line_model, Slic3r::GUI::N, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, point_at(), Slic3r::GUI::DesignSketchTool::DimAnnot::ra, Radius, Slic3r::SketchEntity::radius, Slic3r::GUI::DesignSketchTool::DimAnnot::rb, Slic3r::GUI::DesignSketchTool::DimAnnot::side, and Slic3r::SketchEntity::type.

Referenced by draw_dim_quote(), render_dimensions(), and render_live_quotes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draw_entities_preview()

void Slic3r::GUI::DesignSketchTool::draw_entities_preview ( const std::vector< SketchEntity > & ents,
const ColorRGBA & color )
private
8528{
8529 std::vector<Vec2d> point_markers;
8530 for (const SketchEntity& e : ents) {
8531 // A Point has no polyline (entity_polyline returns nothing), so the strip path below
8532 // cannot draw it; render it as a vertex marker, the same way the live session does.
8533 if (e.type == SketchEntity::Type::Point) { point_markers.push_back(e.p0); continue; }
8534 bool closed = false;
8535 std::vector<Vec2d> poly = entity_polyline(e, closed);
8536 draw_quad_strip(m_highlight_model, poly, closed, color);
8537 }
8538 if (!point_markers.empty())
8539 draw_vertices(m_highlight_model, point_markers, color);
8540}
void draw_quad_strip(GLModel &model, const std::vector< Vec2d > &pts, bool closed, const ColorRGBA &color)
Definition DesignSketchTool.cpp:7494
void draw_vertices(GLModel &model, const std::vector< Vec2d > &pts, const ColorRGBA &color, double half_size=1.3)
Definition DesignSketchTool.cpp:7685
void poly(std::vector< std::pair< Vec2d, Vec2d > > &out, std::initializer_list< Vec2d > p)
Definition DesignSketchTool.cpp:7751

References draw_entities_preview(), draw_quad_strip(), draw_vertices(), entity_polyline(), m_highlight_model, and Slic3r::SketchEntity::Point.

Referenced by draw_entities_preview(), render(), render_op_gizmo(), and render_tf_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draw_fill()

void Slic3r::GUI::DesignSketchTool::draw_fill ( GLModel & model,
const std::vector< Vec2d > & poly,
const ColorRGBA & color )
private
7669{
7670 if (poly.size() < 3) return;
7671 const auto tris = ear_clip(poly);
7672 if (tris.empty()) return;
7673 GLModel::Geometry g;
7675 for (const Vec2d& p : poly)
7676 g.add_vertex((Vec3f)m_plane.to_world(p).cast<float>());
7677 for (const auto& t : tris)
7678 g.add_triangle(t[0], t[1], t[2]);
7679 model.reset();
7680 model.init_from(std::move(g));
7681 model.set_color(color);
7682 model.render();
7683}
void ear_clip(const std::vector< Vec2f > &pts, std::vector< int > poly, const std::function< void(int, int, int)> &emit)
Definition TextureDisplacement.cpp:4562

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), draw_fill(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::GLModel::init_from(), m_plane, Slic3r::GUI::GLModel::Geometry::P3, Slic3r::GUI::GLModel::render(), Slic3r::GUI::GLModel::reset(), Slic3r::GUI::GLModel::set_color(), and Slic3r::GUI::GLModel::Geometry::Triangles.

Referenced by draw_fill(), draw_fill_holed(), render_mate_face(), render_tf_gizmo(), and render_xform_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draw_fill_holed()

void Slic3r::GUI::DesignSketchTool::draw_fill_holed ( GLModel & model,
const std::vector< Vec2d > & outer,
const std::vector< std::vector< Vec2d > > & holes,
const ColorRGBA & color )
private
7603{
7604 if (outer.size() < 3) return;
7605 if (holes.empty()) { draw_fill(model, outer, color); return; }
7606
7607 // EVEN-ODD SCANLINE, not a triangulation. The previous version spliced each hole into the
7608 // outer contour through a keyhole corridor and ear-clipped the result; the corridor did not
7609 // collapse to zero width and was drawn as a visible triangle running from the bore to the
7610 // nearest rectangle corner. Rather than tune a bridge that can always find a new shape to
7611 // fail on, this fills the region the way a rasteriser would: for each horizontal band, cross
7612 // EVERY contour, sort the crossings, and fill between alternate pairs. A hole is simply two
7613 // more crossings, so any number of holes and any concavity fall out of the same rule and no
7614 // corridor exists to leak.
7615 std::vector<const std::vector<Vec2d>*> contours;
7616 contours.push_back(&outer);
7617 for (const auto& h : holes) if (h.size() >= 3) contours.push_back(&h);
7618
7619 double ymin = outer[0].y(), ymax = ymin, xmin = outer[0].x(), xmax = xmin;
7620 for (const auto* c : contours)
7621 for (const Vec2d& v : *c) {
7622 ymin = std::min(ymin, v.y()); ymax = std::max(ymax, v.y());
7623 xmin = std::min(xmin, v.x()); xmax = std::max(xmax, v.x());
7624 }
7625 if (ymax - ymin < 1e-9) return;
7626
7627 // Enough bands that the step is far below a pixel at any sane zoom, cheap enough to rebuild
7628 // every frame: this is a translucent highlight, not geometry.
7629 const int ROWS = 256;
7630 const double dy = (ymax - ymin) / ROWS;
7631
7632 GLModel::Geometry g;
7634 unsigned base = 0;
7635 std::vector<double> xs;
7636 for (int row = 0; row < ROWS; ++row) {
7637 const double y0 = ymin + dy * row, y1 = y0 + dy, ym = 0.5 * (y0 + y1);
7638 xs.clear();
7639 for (const auto* c : contours) {
7640 const std::vector<Vec2d>& q = *c;
7641 for (size_t i = 0, j = q.size() - 1; i < q.size(); j = i++) {
7642 const Vec2d& A = q[i]; const Vec2d& B = q[j];
7643 if ((A.y() > ym) == (B.y() > ym)) continue; // edge does not cross this row
7644 xs.push_back(A.x() + (ym - A.y()) * (B.x() - A.x()) / (B.y() - A.y()));
7645 }
7646 }
7647 if (xs.size() < 2) continue;
7648 std::sort(xs.begin(), xs.end());
7649 for (size_t k = 0; k + 1 < xs.size(); k += 2) { // even-odd: fill alternate spans
7650 const double xa = xs[k], xb = xs[k + 1];
7651 if (xb - xa < 1e-9) continue;
7652 g.add_vertex((Vec3f)m_plane.to_world(Vec2d(xa, y0)).cast<float>());
7653 g.add_vertex((Vec3f)m_plane.to_world(Vec2d(xb, y0)).cast<float>());
7654 g.add_vertex((Vec3f)m_plane.to_world(Vec2d(xb, y1)).cast<float>());
7655 g.add_vertex((Vec3f)m_plane.to_world(Vec2d(xa, y1)).cast<float>());
7656 g.add_triangle(base, base + 1, base + 2);
7657 g.add_triangle(base, base + 2, base + 3);
7658 base += 4;
7659 }
7660 }
7661 if (base == 0) return;
7662 model.reset();
7663 model.init_from(std::move(g));
7664 model.set_color(color);
7665 model.render();
7666}
void draw_fill(GLModel &model, const std::vector< Vec2d > &poly, const ColorRGBA &color)
Definition DesignSketchTool.cpp:7668
const Polygons & holes(const ExPolygon &p)
Definition AGGRaster.hpp:31

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::cast(), draw_fill(), draw_fill_holed(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::holes(), Slic3r::GUI::GLModel::init_from(), m_plane, Slic3r::GUI::GLModel::Geometry::P3, Slic3r::GUI::GLModel::render(), Slic3r::GUI::GLModel::reset(), Slic3r::GUI::GLModel::set_color(), and Slic3r::GUI::GLModel::Geometry::Triangles.

Referenced by draw_fill_holed(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draw_quad_strip()

void Slic3r::GUI::DesignSketchTool::draw_quad_strip ( GLModel & model,
const std::vector< Vec2d > & pts,
bool closed,
const ColorRGBA & color )
private
7495{
7496 if (pts.size() < 2)
7497 return;
7498
7499 // Half-width in WORLD units, so a stroke is 2*hw mm wide on the plane. Halved from 0.6 on
7500 // user report 2026-08-23: at 1.2 mm the orange under-constrained line was heavy enough to
7501 // swallow a short segment and to hide which of two near-parallel lines the cursor was on.
7502 // Every one of this function's call sites is a sketch stroke (entities, previews, rubber
7503 // bands), which is why the constant is here and not a parameter at twenty call sites.
7504 const double hw = 0.3;
7505 GLModel::Geometry g;
7507 unsigned int base = 0;
7508
7509 const size_t segs = closed ? pts.size() : pts.size() - 1;
7510 for (size_t i = 0; i < segs; ++i) {
7511 const Vec2d a = pts[i];
7512 const Vec2d b = pts[(i + 1) % pts.size()];
7513 const Vec2d d = b - a;
7514 const double len = d.norm();
7515 if (len < 1e-6)
7516 continue;
7517 const Vec2d n(-d.y() / len, d.x() / len);
7518 const Vec2d o = n * hw;
7519 g.add_vertex((Vec3f)m_plane.to_world(a + o).cast<float>());
7520 g.add_vertex((Vec3f)m_plane.to_world(b + o).cast<float>());
7521 g.add_vertex((Vec3f)m_plane.to_world(b - o).cast<float>());
7522 g.add_vertex((Vec3f)m_plane.to_world(a - o).cast<float>());
7523 g.add_triangle(base, base + 1, base + 2);
7524 g.add_triangle(base, base + 2, base + 3);
7525 base += 4;
7526 }
7527
7528 if (base > 0) {
7529 model.reset();
7530 model.init_from(std::move(g));
7531 model.set_color(color);
7532 model.render();
7533 }
7534}

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), draw_quad_strip(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::GLModel::init_from(), m_plane, Slic3r::GUI::GLModel::Geometry::P3, Slic3r::GUI::GLModel::render(), Slic3r::GUI::GLModel::reset(), Slic3r::GUI::GLModel::set_color(), and Slic3r::GUI::GLModel::Geometry::Triangles.

Referenced by draw_entities_preview(), draw_quad_strip(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draw_strokes()

void Slic3r::GUI::DesignSketchTool::draw_strokes ( GLModel & model,
const std::vector< std::pair< Vec2d, Vec2d > > & segs,
double hw,
const ColorRGBA & color )
private
7715{
7716 GLModel::Geometry g;
7718 unsigned int base = 0;
7719 for (const auto& s : segs) {
7720 const Vec2d a = s.first, b = s.second;
7721 const Vec2d d = b - a;
7722 const double len = d.norm();
7723 if (len < 1e-6) continue;
7724 const Vec2d n(-d.y() / len, d.x() / len);
7725 const Vec2d o = n * hw;
7726 g.add_vertex((Vec3f)m_plane.to_world(a + o).cast<float>());
7727 g.add_vertex((Vec3f)m_plane.to_world(b + o).cast<float>());
7728 g.add_vertex((Vec3f)m_plane.to_world(b - o).cast<float>());
7729 g.add_vertex((Vec3f)m_plane.to_world(a - o).cast<float>());
7730 g.add_triangle(base, base + 1, base + 2);
7731 g.add_triangle(base, base + 2, base + 3);
7732 base += 4;
7733 }
7734 if (base > 0) {
7735 model.reset();
7736 model.init_from(std::move(g));
7737 model.set_color(color);
7738 model.render();
7739 }
7740}

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), draw_strokes(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::GLModel::init_from(), m_plane, Slic3r::GUI::GLModel::Geometry::P3, Slic3r::GUI::GLModel::render(), Slic3r::GUI::GLModel::reset(), Slic3r::GUI::GLModel::set_color(), and Slic3r::GUI::GLModel::Geometry::Triangles.

Referenced by draw_dim_quote(), draw_strokes(), render(), render_base_pick(), render_cut_gizmo(), render_draft_gizmo(), render_extrude_gizmo(), render_fillet_gizmo(), render_hole_gizmo(), render_live_quotes(), render_mate_connectors(), render_move_gizmo(), render_op_gizmo(), render_pattern_gizmo(), render_revolve_gizmo(), render_shell_gizmo(), render_tf_gizmo(), render_thread_gizmo(), and render_xform_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draw_text()

void Slic3r::GUI::DesignSketchTool::draw_text ( GLModel & model,
const std::string & s,
const Vec2d & center,
double height,
const ColorRGBA & color )
private
7943{
7944 // ponytail: all sketch labels now render as Measure-gizmo-style ImGui labels for visual
7945 // parity with the Prepare/Preview tabs; the vector font (glyph_strokes/draw_strokes) is kept
7946 // only for text lying in a plane, the reference planes' names. Leader lines/arrows still draw
7947 // via draw_strokes at the call sites.
7948 //
7949 // The one label we do NOT draw is the one under an OPEN value field: the field is anchored
7950 // over it and carries the same number plus its title, so leaving the label in place shows
7951 // every value twice while the auto-edit chain runs (confirmed for rounded rect W/H/R, and
7952 // the chain is shared, so Rect/Circle/Slot/Polygon/ArcSlot behave identically). Position
7953 // compare is exact — the chain stores the very same Vec2d the label draws from.
7954 if ((center - m_autoedit_label_pos).squaredNorm() < 1e-9) return;
7956}
Vec2d m_autoedit_label_pos
Definition DesignSketchTool.hpp:1104
void draw_dim_label(const std::string &txt, const Vec2d &plane_center)
Definition DesignSketchTool.cpp:7887

References Slic3r::center(), draw_dim_label(), draw_text(), and m_autoedit_label_pos.

Referenced by draw_dim_quote(), draw_text(), render_base_pick(), render_cut_gizmo(), render_draft_gizmo(), render_extrude_gizmo(), render_fillet_gizmo(), render_hole_gizmo(), render_live_quotes(), render_move_gizmo(), render_op_gizmo(), render_pattern_gizmo(), render_revolve_gizmo(), render_shell_gizmo(), render_tf_gizmo(), and render_thread_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draw_vertices()

void Slic3r::GUI::DesignSketchTool::draw_vertices ( GLModel & model,
const std::vector< Vec2d > & pts,
const ColorRGBA & color,
double half_size = 1.3 )
private
7687{
7688 if (pts.empty())
7689 return;
7690
7691 const double hs = half_size;
7692 GLModel::Geometry g;
7694 unsigned int base = 0;
7695 for (const Vec2d& p : pts) {
7696 g.add_vertex((Vec3f)m_plane.to_world(p + Vec2d(-hs, -hs)).cast<float>());
7697 g.add_vertex((Vec3f)m_plane.to_world(p + Vec2d( hs, -hs)).cast<float>());
7698 g.add_vertex((Vec3f)m_plane.to_world(p + Vec2d( hs, hs)).cast<float>());
7699 g.add_vertex((Vec3f)m_plane.to_world(p + Vec2d(-hs, hs)).cast<float>());
7700 g.add_triangle(base, base + 1, base + 2);
7701 g.add_triangle(base, base + 2, base + 3);
7702 base += 4;
7703 }
7704
7705 model.reset();
7706 model.init_from(std::move(g));
7707 model.set_color(color);
7708 model.render();
7709}

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::cast(), draw_vertices(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::GLModel::init_from(), m_plane, Slic3r::GUI::GLModel::Geometry::P3, Slic3r::GUI::GLModel::render(), Slic3r::GUI::GLModel::reset(), Slic3r::GUI::GLModel::set_color(), and Slic3r::GUI::GLModel::Geometry::Triangles.

Referenced by draw_entities_preview(), draw_vertices(), render(), and render_tf_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ draws_reference_axes()

bool Slic3r::GUI::DesignSketchTool::draws_reference_axes ( ) const
inline
378{ return m_dbp_active && !m_active; }

References m_active, and m_dbp_active.

Referenced by render().

Here is the caller graph for this function:

◆ drop_constraints_referencing()

void Slic3r::GUI::DesignSketchTool::drop_constraints_referencing ( int ei)
private
1801{
1802 erase_constraints([&](int, const SketchEntityConstraintDef& c) {
1803 return c.ea == ei || c.eb == ei || c.ec == ei; // refs to the cut entity
1804 });
1805}

References drop_constraints_referencing(), Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, Slic3r::SketchEntityConstraintDef::ec, and erase_constraints().

Referenced by apply_live_trim(), and drop_constraints_referencing().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drop_orientation_constraints()

void Slic3r::GUI::DesignSketchTool::drop_orientation_constraints ( int begin,
int end )
private
1788{
1789 using CT = SketchConstraintType;
1790 auto orient = [](CT t) {
1791 return t == CT::Horizontal || t == CT::Vertical || t == CT::Parallel ||
1792 t == CT::Perpendicular || t == CT::Angle || t == CT::LockX || t == CT::LockY;
1793 };
1794 auto in = [&](int e) { return e >= begin && e < end; };
1795 erase_constraints([&](int, const SketchEntityConstraintDef& c) {
1796 return orient(c.type) && (in(c.ea) || in(c.eb));
1797 });
1798}
T * end(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:841
static Orientation orient(const Point &a, const Point &b, const Point &c)
Definition Geometry.hpp:44

References Slic3r::Angle, begin(), drop_orientation_constraints(), Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, erase_constraints(), Slic3r::Horizontal, Slic3r::LockX, Slic3r::LockY, Slic3r::Geometry::orient(), Slic3r::Parallel, Slic3r::Perpendicular, Slic3r::SketchEntityConstraintDef::type, and Slic3r::Vertical.

Referenced by drag_polygon_vertex(), drop_orientation_constraints(), set_line_angle(), set_polygon_angle(), and set_rect_angle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ drop_right_click()

void Slic3r::GUI::DesignSketchTool::drop_right_click ( )
inline
190{ m_right_press.reset(); }
std::optional< wxMouseEvent > m_right_press
Definition DesignSketchTool.hpp:1338

References m_right_press.

◆ edit_dimension()

void Slic3r::GUI::DesignSketchTool::edit_dimension ( int di)
private
1391{
1392 if (di < 0 || di >= int(m_dimensions.size())) return;
1394}
void open_value_editor(int di)
Definition DesignSketchTool.cpp:1418

References m_dimensions, and open_value_editor().

Referenced by on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ emit_step_hint()

void Slic3r::GUI::DesignSketchTool::emit_step_hint ( )
9511{
9512 // No session, no step. render() also runs while only the reference planes are up, and m_mode
9513 // then holds the last session's tool (Polyline before the first), whose prompt used to replace
9514 // the panel's own line — "click a reference plane" while Sketch waits for one.
9515 if (!on_step_changed || !m_active) return;
9516 int step = 0, picks = 0;
9517 if (is_edit_op_mode()) {
9518 picks = (m_mode == Mode::Mirror) ? int(m_mirror_targets.size())
9519 : int(m_op_a >= 0) + int(m_op_b >= 0);
9520 step = (m_op_a < 0) ? 0 : (op_ready() ? 2 : 1);
9521 } else if (is_transform_mode()) {
9522 picks = int(m_tf_targets.size());
9523 step = m_tf_targets.empty() ? 0 : 1;
9524 } else if (m_mode == Mode::Constrain && m_constrain_entities) {
9525 picks = int(m_pick0 >= 0) + int(m_pick1 >= 0) + int(m_pick2 >= 0);
9526 } else if (m_mode == Mode::Select || m_mode == Mode::Constrain) {
9527 picks = int(m_selection.size());
9528 } else if (m_mode == Mode::Dimension) {
9529 step = m_dim_has0 ? 1 : 0; // the Dimension tool keeps its first pick, not m_points
9530 } else {
9531 step = int(m_points.size());
9532 }
9533 if (int(m_mode) == m_step_mode_last && step == m_step_last && picks == m_step_picks_last)
9534 return;
9536 on_step_changed(m_mode, step, picks);
9537}
std::function< void(Mode mode, int step, int picks)> on_step_changed
Definition DesignSketchTool.hpp:539
int m_step_picks_last
Definition DesignSketchTool.hpp:1169
bool is_transform_mode() const
Definition DesignSketchTool.hpp:126
int m_step_last
Definition DesignSketchTool.hpp:1168
@ Dimension
Definition DesignSketchTool.hpp:91
bool is_edit_op_mode() const
Definition DesignSketchTool.hpp:124

References Constrain, Dimension, emit_step_hint(), is_edit_op_mode(), is_transform_mode(), m_active, m_constrain_entities, m_dim_has0, m_mirror_targets, m_mode, m_op_a, m_op_b, m_pick0, m_pick1, m_pick2, m_points, m_selection, m_step_last, m_step_mode_last, m_step_picks_last, m_tf_targets, Mirror, on_step_changed, op_ready(), and Select.

Referenced by abort_gesture(), emit_step_hint(), end_chain(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ emit_xform()

void Slic3r::GUI::DesignSketchTool::emit_xform ( )
private
8666{
8669}
std::function< void(int feat, Vec2d offset, double scale_x, double scale_y)> on_imported_transform
Definition DesignSketchTool.hpp:508

References emit_xform(), m_xform_feat, m_xform_offset, m_xform_sx, m_xform_sy, and on_imported_transform.

Referenced by drag_xform_handle(), and emit_xform().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ end_chain()

bool Slic3r::GUI::DesignSketchTool::end_chain ( )
387{
388 if (m_mode != Mode::Polyline && m_mode != Mode::BSpline) return false;
389 std::vector<Vec2d> pts;
390 for (const Vec2d& q : m_points)
391 if (pts.empty() || (q - pts.back()).norm() > m_chain_dup_tol) pts.push_back(q);
392 const int base = int(m_entities.size());
393 if (pts.size() >= 2) {
395 else append_entities(make_bspline(pts));
396 infer_auto_constraints(base); // end poles auto-Coincident -> loops close
397 }
398 m_points.clear();
400 return true;
401}
double m_chain_dup_tol
Definition DesignSketchTool.hpp:1160
void push_open_chain(const std::vector< Vec2d > &pts)
Definition DesignSketchTool.cpp:2927
std::vector< SketchEntity > make_bspline(const std::vector< Vec2d > &ctrl) const
Definition DesignSketchTool.cpp:3284
void append_entities(const std::vector< SketchEntity > &ents)
Definition DesignSketchTool.cpp:2955

References append_entities(), BSpline, emit_step_hint(), infer_auto_constraints(), m_chain_dup_tol, m_entities, m_mode, m_points, make_bspline(), Polyline, and push_open_chain().

Referenced by confirm_pending(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ end_feature()

void Slic3r::GUI::DesignSketchTool::end_feature ( const Vec2d & c0 = Vec2d(0, 0),
const Vec2d & c1 = Vec2d(0, 0),
double param = 0.0,
int sides = 0 )
private
972{
973 if (m_open_feature < 0 || m_open_feature >= int(m_features.size())) return;
975 f.end = int(m_entities.size());
976 f.c0 = c0;
977 f.c1 = c1;
978 f.param = param;
979 f.sides = sides;
980 // Drop a degenerate feature (gesture appended nothing).
981 if (f.end <= f.begin) m_features.pop_back();
982 m_open_feature = -1;
983}

References Slic3r::f(), m_entities, m_features, and m_open_feature.

Referenced by on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ entities()

◆ entity_polyline()

std::vector< Vec2d > Slic3r::GUI::DesignSketchTool::entity_polyline ( const SketchEntity & e,
bool & closed )
staticprivate
3297{
3298 closed = false;
3299 switch (e.type) {
3301 return { e.p0, e.p1 };
3303 closed = true;
3304 return circle_polygon(e.center, e.radius);
3306 const int n = kArcFacets;
3307 std::vector<Vec2d> pts; pts.reserve(n + 1);
3308 for (int i = 0; i <= n; ++i) {
3309 const double a = e.start_angle + (e.end_angle - e.start_angle) * double(i) / double(n);
3310 pts.push_back(Vec2d(e.center.x() + e.radius * std::cos(a),
3311 e.center.y() + e.radius * std::sin(a)));
3312 }
3313 return pts;
3314 }
3316 closed = true;
3317 return ellipse_polyline(e.center, e.radius, e.rminor, e.rotation, 0.0, 2.0 * M_PI);
3319 return ellipse_polyline(e.center, e.radius, e.rminor, e.rotation, e.start_angle, e.end_angle);
3321 return bspline_polyline(e.ctrl);
3323 return { e.p0 };
3324 }
3325 return {};
3326}
static std::vector< Vec2d > circle_polygon(const Vec2d &c, double r, int n=48)
Definition DesignSketchTool.cpp:2806
static constexpr int kArcFacets
Definition DesignSketchTool.cpp:70
static std::vector< Vec2d > ellipse_polyline(const Vec2d &c, double a, double b, double phi, double t0, double t1, int n=48)
Definition DesignSketchTool.cpp:2825
static std::vector< Vec2d > bspline_polyline(const std::vector< Vec2d > &ctrl, int samples=0)
Definition DesignSketchTool.cpp:2868

References Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::BSpline, Slic3r::GUI::bspline_polyline(), Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::GUI::circle_polygon(), Slic3r::SketchEntity::ctrl, Slic3r::SketchEntity::Ellipse, Slic3r::GUI::ellipse_polyline(), Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::end_angle, entity_polyline(), Slic3r::GUI::kArcFacets, Slic3r::SketchEntity::Line, M_PI, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::Point, Slic3r::SketchEntity::radius, Slic3r::SketchEntity::rminor, Slic3r::SketchEntity::rotation, Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by compute_trim_preview(), draw_entities_preview(), entity_polyline(), op_pick(), recompute_op_ghost(), region_loops(), render(), and sketch_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ erase_constraints()

int Slic3r::GUI::DesignSketchTool::erase_constraints ( const std::function< bool(int, const SketchEntityConstraintDef &)> & drop)
private
1770{
1771 std::vector<int> remap(m_constraints.size(), -1);
1772 std::vector<SketchEntityConstraintDef> kept;
1773 kept.reserve(m_constraints.size());
1774 for (int i = 0; i < int(m_constraints.size()); ++i) {
1775 if (drop(i, m_constraints[i])) continue; // remove
1776 remap[i] = int(kept.size());
1777 kept.push_back(m_constraints[i]);
1778 }
1779 if (kept.size() == m_constraints.size()) return 0; // nothing dropped
1780 const int dropped = int(m_constraints.size() - kept.size());
1781 m_constraints.swap(kept);
1782 for (DimAnnot& a : m_dimensions) // repair the cached indices
1783 if (a.con >= 0) a.con = (a.con < int(remap.size())) ? remap[a.con] : -1;
1784 return dropped;
1785}

References erase_constraints(), m_constraints, and m_dimensions.

Referenced by confirm_op(), confirm_transform(), drop_constraints_referencing(), drop_orientation_constraints(), erase_constraints(), remove_constraint(), and upsert_dimension_constraint().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ faces_box()

BoundingBoxf3 Slic3r::GUI::DesignSketchTool::faces_box ( std::vector< std::pair< int, int > > faces) const
3752{
3753 // From the pick mesh: it is in world coordinates already, moved bodies and all.
3754 BoundingBoxf3 box;
3755 if (faces.empty() || m_solid_mesh == nullptr || m_solid_tri_face == nullptr || m_solid_tri_body == nullptr)
3756 return box;
3757 std::sort(faces.begin(), faces.end());
3758 const indexed_triangle_set& its = m_solid_mesh->its;
3759 const size_t n = std::min({ its.indices.size(), m_solid_tri_face->size(), m_solid_tri_body->size() });
3760 for (size_t t = 0; t < n; ++t)
3761 if (std::binary_search(faces.begin(), faces.end(), std::make_pair((*m_solid_tri_body)[t], (*m_solid_tri_face)[t])))
3762 for (int i = 0; i < 3; ++i)
3763 box.merge(its.vertices[its.indices[t][i]].cast<double>());
3764 return box;
3765}
const std::vector< int > * m_solid_tri_body
Definition DesignSketchTool.hpp:1281
const std::vector< int > * m_solid_tri_face
Definition DesignSketchTool.hpp:1280
const TriangleMesh * m_solid_mesh
Definition DesignSketchTool.hpp:1279

References faces_box(), m_solid_mesh, m_solid_tri_body, m_solid_tri_face, and Slic3r::BoundingBox3Base< PointType >::merge().

Referenced by faces_box(), and selection_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ feature_of()

int Slic3r::GUI::DesignSketchTool::feature_of ( int ei) const
private
951{
952 for (int i = int(m_features.size()) - 1; i >= 0; --i)
953 if (ei >= m_features[i].begin && ei < m_features[i].end) return i;
954 return -1;
955}

References begin(), and m_features.

Referenced by on_mouse_impl(), render_live_quotes(), and toggle_selection_construction().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fillet_axis_proj()

double Slic3r::GUI::DesignSketchTool::fillet_axis_proj ( GLCanvas3D & canvas,
const wxMouseEvent & evt ) const
private
6130{
6131 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6132 const Vec3d ro = r.a, rd = r.b - r.a;
6133 const Vec3d e = m_fl_dir;
6134 const Vec3d w0 = m_fl_anchor - ro;
6135 const double a = e.dot(e), b = e.dot(rd), c = rd.dot(rd), dd = e.dot(w0), ee = rd.dot(w0);
6136 const double denom = a * c - b * b;
6137 if (std::abs(denom) < 1e-7) return std::nan("");
6138 return (b * ee - c * dd) / denom;
6139}
Vec3d m_fl_dir
Definition DesignSketchTool.hpp:1485
Vec3d m_fl_anchor
Definition DesignSketchTool.hpp:1484

References Slic3r::Linef3::a, Slic3r::Linef3::b, fillet_axis_proj(), m_fl_anchor, m_fl_dir, Slic3r::GUI::GLCanvas3D::mouse_ray(), and Slic3r::GUI::wxMouseEvent.

Referenced by drag_fillet_arrow(), fillet_axis_proj(), and start_fillet_drag().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ filleting()

bool Slic3r::GUI::DesignSketchTool::filleting ( ) const
inline
389{ return m_fl_active; }

References m_fl_active.

◆ finish()

void Slic3r::GUI::DesignSketchTool::finish ( )
2468{
2469 // A value field still open at commit time outlives the session — the editor is a top-level
2470 // frame — and inline_busy stays set, so every later click is swallowed at on_mouse_impl's
2471 // first branch and the viewport reads as dead. Dismiss it first (keep-as-drawn, the same
2472 // contract as the polyline terminators) and drop any queued field with it.
2474 if (op_ready()) confirm_op(); // apply a pending edit-op gizmo before committing
2475 if (tf_ready()) confirm_transform(); // apply a pending transform gizmo before committing
2476 auto cb = on_commit_entities;
2477 std::vector<SketchEntity> ents = m_entities;
2478 std::vector<SketchEntityConstraintDef> cons = m_constraints;
2479 SketchPlane pl = m_plane;
2480 m_active = false;
2481 m_points.clear();
2482 m_entities.clear();
2483 m_constraints.clear();
2484 m_dimensions.clear();
2485 m_point_sel.clear();
2486 m_dim_has0 = false;
2487 m_pending_dim = -1;
2488 m_has_cursor = false;
2489 m_features.clear();
2490 m_open_feature = -1;
2491 if (cb)
2492 cb(ents, cons, pl);
2493}
std::function< void(const std::vector< SketchEntity > &, const std::vector< SketchEntityConstraintDef > &, const SketchPlane &)> on_commit_entities
Definition DesignSketchTool.hpp:715

References close_session_chrome(), confirm_op(), confirm_transform(), finish(), m_active, m_constraints, m_dim_has0, m_dimensions, m_entities, m_features, m_has_cursor, m_open_feature, m_pending_dim, m_plane, m_point_sel, m_points, on_commit_entities, op_ready(), and tf_ready().

Referenced by finish().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ first_selected_type()

bool Slic3r::GUI::DesignSketchTool::first_selected_type ( SketchEntity::Type & out) const
inline
558 {
559 if (m_selection.empty()) return false;
560 const int i = m_selection.front();
561 if (i < 0 || i >= int(m_entities.size())) return false;
562 out = m_entities[i].type;
563 return true;
564 }

References m_entities, and m_selection.

◆ fit_box()

BoundingBoxf3 Slic3r::GUI::DesignSketchTool::fit_box ( const GLVolumeCollection & volumes) const
3810{
3811 BoundingBoxf3 box = selection_box();
3812 // Nothing selected: everything on show. A hidden body's volume is inactive.
3813 if (!box.defined) {
3814 for (const GLVolume* v : volumes.volumes)
3815 if (v->is_active)
3816 box.merge(v->transformed_bounding_box());
3817 for (const DisplaySketch& d : m_display_sketches)
3818 box.merge(sketch_box(d.entities, d.plane));
3819 if (m_active)
3820 box.merge(sketch_box(m_entities, m_plane));
3821 }
3822 pad_box(box);
3823 return box;
3824}
std::vector< DisplaySketch > m_display_sketches
Definition DesignSketchTool.hpp:1271
BoundingBoxf3 selection_box() const
Definition DesignSketchTool.cpp:3778
static void pad_box(BoundingBoxf3 &box)
Definition DesignSketchTool.cpp:3826
static BoundingBoxf3 sketch_box(const std::vector< SketchEntity > &entities, const SketchPlane &plane)
Definition DesignSketchTool.cpp:3767
Definition DesignSketchTool.hpp:201

References Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::defined, fit_box(), m_active, m_display_sketches, m_entities, m_plane, Slic3r::BoundingBox3Base< PointType >::merge(), pad_box(), selection_box(), sketch_box(), Slic3r::GLVolume::transformed_bounding_box(), and Slic3r::GLVolumeCollection::volumes.

Referenced by fit_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ gesture_pending()

bool Slic3r::GUI::DesignSketchTool::gesture_pending ( ) const
inline
115{ return !m_points.empty() || has_pending_picks(); }

References has_pending_picks(), and m_points.

Referenced by abort_gesture().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ grab_move_arrow()

void Slic3r::GUI::DesignSketchTool::grab_move_arrow ( int axis,
const Linef3 & ray )
5951{
5952 m_mv_drag = axis;
5953 m_mv_grab_along = ray_axis_proj(ray, m_mv_base + m_mv_offset, Vec3d::Unit(axis));
5954}

References grab_move_arrow(), m_mv_base, m_mv_drag, m_mv_grab_along, m_mv_offset, and Slic3r::GUI::ray_axis_proj().

Referenced by grab_move_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_solid_click()

bool Slic3r::GUI::DesignSketchTool::handle_solid_click ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
4083{
4084 SolidPick p;
4085 if (!resolve_solid_pick(canvas, evt.GetX(), evt.GetY(), p))
4086 return false; // missed the solid, or no solid data — same two exits as before
4087
4088 // What was selected BEFORE this pick — the escalation below is the only thing that reads
4089 // it, and everything from here on overwrites it.
4090 const SolidSel prev_kind = m_solid_sel;
4091 const int prev_body = m_sel_body, prev_face = m_sel_face, prev_edge = m_sel_edge;
4092 const Vec3d prev_vtx = m_sel_vertex_pt;
4093
4094 // SHIFT/CTRL+CLICK ON AN EDGE BUILDS AN EDGE SET, the same modifiers that extend a sketch
4095 // selection. Only edges of the one body already picked: a dress-up acts on one body, and a
4096 // set spanning two could not be applied. An edge already in the set leaves it; the last one
4097 // leaving clears the selection. No escalation to the whole body here — a modified click is
4098 // always about the set.
4099 const bool extend = evt.ShiftDown() || evt.ControlDown() || evt.CmdDown();
4100 if (extend && p.kind == SolidSel::Edge && prev_kind == SolidSel::Edge && p.body == prev_body) {
4101 auto more = std::find(m_sel_edges_more.begin(), m_sel_edges_more.end(), p.edge);
4102 if (p.edge == prev_edge) {
4103 if (m_sel_edges_more.empty()) {
4105 } else { // the previous pick becomes the current one
4107 m_sel_edge_pts = std::move(m_sel_edges_more_pts.back());
4108 m_sel_edges_more.pop_back();
4109 m_sel_edges_more_pts.pop_back();
4110 }
4111 } else if (more != m_sel_edges_more.end()) {
4112 const size_t k = size_t(more - m_sel_edges_more.begin());
4113 m_sel_edges_more.erase(more);
4114 m_sel_edges_more_pts.erase(m_sel_edges_more_pts.begin() + k);
4115 } else {
4116 m_sel_edges_more.push_back(prev_edge);
4117 m_sel_edges_more_pts.push_back(std::move(m_sel_edge_pts));
4118 m_sel_edge = p.edge;
4119 m_sel_edge_pts = std::move(p.edge_pts);
4120 m_sel_face = p.face;
4121 }
4122 dp_pick_trace("edge set -> %zu edge(s), current %d", selected_edges().size(), m_sel_edge);
4125 return true;
4126 }
4127 m_sel_edges_more.clear();
4128 m_sel_edges_more_pts.clear();
4129
4130 m_sel_body = p.body;
4131 m_sel_shape = (*m_solid_bodies)[p.body].shape; // resolve_solid_pick checked p.body
4132 m_sel_face = p.face;
4133 m_sel_edge = p.edge;
4134 m_sel_edge_pts = std::move(p.edge_pts);
4135 m_sel_vertex_pt = p.vertex_pt;
4136 m_solid_sel = p.kind;
4137
4138 // CLICK AGAIN ON THE SAME THING -> THE WHOLE BODY (gem). Pointing at a face and
4139 // pointing at its body are different intents, and until now only the rubber band could
4140 // express the second one — so the status line said "face 0 selected" while the user
4141 // believed they had taken the body, and every body verb had to opt into the face kinds to
4142 // stay reachable. One more click on the SAME sub-element escalates.
4143 //
4144 // This is not the pick cycle that was removed (bc2b741ce9). That one was silent and three
4145 // deep, so no click had a predictable meaning. Here the escalation is announced by the
4146 // status line BEFORE you make the click, and a further click just takes the face under the
4147 // cursor again — the ordinary meaning of clicking a face, which needs no teaching.
4148 //
4149 // Double-click is safe: wx sends Down/Up/DClick/Up, and only the first Up carries a
4150 // pending press, so a fast double-click zooms to fit and picks ONCE. Escalation needs two
4151 // separate clicks, the same "click, pause, click" distinction a file manager uses.
4152 //
4153 // "The same thing" is compared AT THE LEVEL THAT WAS PICKED, and nothing else. Requiring
4154 // every field to match looked stricter and was simply wrong: an edge pick leaves m_sel_face
4155 // set to whichever face the ray happened to hit, and a shared edge is reached through a
4156 // different face depending on which side of the body you are looking from. So picking an
4157 // edge, orbiting, and clicking that same edge from the other side left m_sel_edge equal and
4158 // m_sel_face different, and the escalation the status line had just promised did not happen.
4159 // The edge id here is already the STABLE GLOBAL one (edge_index_of, a few lines up) — it
4160 // identifies the edge on its own and does not need the face to disambiguate it.
4161 const bool same_pick = m_solid_sel == prev_kind && m_sel_body == prev_body
4162 && (m_solid_sel == SolidSel::Vertex ? (m_sel_vertex_pt - prev_vtx).norm() < 1e-9
4163 : m_solid_sel == SolidSel::Edge ? m_sel_edge == prev_edge
4164 : m_solid_sel == SolidSel::Face ? m_sel_face == prev_face
4165 : true);
4166 if (same_pick && m_escalate_repick) {
4167 select_body(m_sel_body); // clears face/edge/vertex, tints the whole body
4168 dp_pick_trace("re-pick -> escalated to whole body %d", m_sel_body);
4169 }
4170 dp_pick_trace("pick -> sel=%d body=%d face=%d edge=%d",
4174 return true;
4175}
bool m_escalate_repick
Definition DesignSketchTool.hpp:1339
std::function< void(int level, int body, int face, int edge)> on_solid_selection_changed
Definition DesignSketchTool.hpp:291
void select_body(int body)
Definition DesignSketchTool.cpp:3653
SolidSel
Definition DesignSketchTool.hpp:229
@ Face
Definition DesignSketchTool.hpp:229
@ Vertex
Definition DesignSketchTool.hpp:229
@ Edge
Definition DesignSketchTool.hpp:229
bool resolve_solid_pick(GLCanvas3D &canvas, int mx, int my, SolidPick &out) const
Definition DesignSketchTool.cpp:3950
std::vector< int > selected_edges() const
Definition DesignSketchTool.cpp:3645
void clear_solid_selection()
Definition DesignSketchTool.cpp:3631
Vec3d m_sel_vertex_pt
Definition DesignSketchTool.hpp:1310
static void dp_pick_trace(const char *fmt,...)
Definition DesignSketchTool.cpp:3886

References Slic3r::GUI::DesignSketchTool::SolidPick::body, clear_solid_selection(), Slic3r::GUI::dp_pick_trace(), Edge, Slic3r::GUI::DesignSketchTool::SolidPick::edge, Slic3r::GUI::DesignSketchTool::SolidPick::edge_pts, Face, Slic3r::GUI::DesignSketchTool::SolidPick::face, handle_solid_click(), Slic3r::GUI::DesignSketchTool::SolidPick::kind, m_escalate_repick, m_sel_body, m_sel_edge, m_sel_edge_pts, m_sel_edges_more, m_sel_edges_more_pts, m_sel_face, m_sel_shape, m_sel_vertex_pt, m_solid_sel, on_solid_selection_changed, resolve_solid_pick(), select_body(), selected_edges(), Vertex, Slic3r::GUI::DesignSketchTool::SolidPick::vertex_pt, and Slic3r::GUI::wxMouseEvent.

Referenced by handle_solid_click(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ has_coincident()

bool Slic3r::GUI::DesignSketchTool::has_coincident ( int ea,
SketchPointRole ra,
int eb,
SketchPointRole rb ) const
private
2642{
2643 for (const auto& c : m_constraints) {
2644 if (c.type != SketchConstraintType::Coincident) continue;
2645 if ((c.ea == ea && c.ra == ra && c.eb == eb && c.rb == rb) ||
2646 (c.ea == eb && c.ra == rb && c.eb == ea && c.rb == ra))
2647 return true;
2648 }
2649 return false;
2650}

References Slic3r::Coincident, has_coincident(), and m_constraints.

Referenced by has_coincident(), heal_coincidences(), and infer_auto_constraints().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ has_display()

bool Slic3r::GUI::DesignSketchTool::has_display ( ) const
inline
209 { return m_active || !m_display_sketches.empty()
210 || (m_solid_bodies != nullptr && !m_solid_bodies->empty())
211 || !m_datum_planes.empty()
bool m_show_planes
Definition DesignSketchTool.hpp:1365
bool m_show_axes
Definition DesignSketchTool.hpp:1366
std::vector< SketchPlane > m_datum_planes
Definition DesignSketchTool.hpp:1367

References m_active, m_ct_active, m_datum_planes, m_dbp_active, m_display_sketches, m_dr_active, m_dz_active, m_ex_active, m_fl_active, m_hl_active, m_hx_active, m_mv_active, m_rb_active, m_sh_active, m_show_axes, m_show_planes, m_solid_bodies, and m_th_active.

Referenced by render().

Here is the caller graph for this function:

◆ has_entities()

bool Slic3r::GUI::DesignSketchTool::has_entities ( ) const
inline
182{ return !m_entities.empty(); }

References m_entities.

◆ has_pending_picks()

bool Slic3r::GUI::DesignSketchTool::has_pending_picks ( ) const
inline
112 {
113 return m_dim_has0 || m_op_a >= 0 || !m_tf_targets.empty() || m_pick0 >= 0 || m_sel_a >= 0;
114 }

References m_dim_has0, m_op_a, m_pick0, m_sel_a, and m_tf_targets.

Referenced by abort_gesture(), and gesture_pending().

Here is the caller graph for this function:

◆ has_solid_selection()

bool Slic3r::GUI::DesignSketchTool::has_solid_selection ( ) const
inline
248{ return m_solid_sel != SolidSel::None; }

References m_solid_sel, and None.

◆ heal_coincidences()

int Slic3r::GUI::DesignSketchTool::heal_coincidences ( double tol,
bool ignore_construction )
10618{
10619 if (tol <= 0.0) tol = 1e-3;
10620
10621 const int n = int(m_entities.size());
10622 int welded = 0;
10623 std::vector<SketchEntityConstraintDef> cands;
10624 for (int i = 0; i < n; ++i) {
10625 if (ignore_construction && m_entities[i].construction) continue;
10626 SketchPointRole ir[2]; const int ni = sketch_endpoint_roles(m_entities[i], ir);
10627 for (int a = 0; a < ni; ++a) {
10628 Vec2d pa; if (!point_at(i, ir[a], pa)) continue;
10629 for (int j = i + 1; j < n; ++j) {
10630 if (ignore_construction && m_entities[j].construction) continue;
10631 SketchPointRole jr[2]; const int nj = sketch_endpoint_roles(m_entities[j], jr);
10632 for (int b = 0; b < nj; ++b) {
10633 Vec2d pb; if (!point_at(j, jr[b], pb)) continue;
10634 const double d = (pa - pb).norm();
10635 if (d > tol) continue;
10636 if (has_coincident(i, ir[a], j, jr[b])) continue;
10637 // WELD FIRST, then constrain. Handing the solver two points a tolerance
10638 // apart and asking it to make them equal lets it move the rest of the sketch
10639 // to get there; snapping them together first means the constraint it is
10640 // asked to satisfy is already true, so nothing else shifts.
10641 if (d > 0.0) { set_point(j, jr[b], pa); pb = pa; }
10642 SketchEntityConstraintDef c;
10644 c.ea = i; c.ra = ir[a]; c.eb = j; c.rb = jr[b];
10645 cands.push_back(c);
10646 ++welded;
10647 }
10648 }
10649 }
10650 }
10651 if (!cands.empty()) {
10652 try_add_constraints(cands);
10653 resolve_live();
10654 }
10655 return welded;
10656}
bool has_coincident(int ea, SketchPointRole ra, int eb, SketchPointRole rb) const
Definition DesignSketchTool.cpp:2641
void set_point(int ei, SketchPointRole role, const Vec2d &v)
Definition DesignSketchTool.cpp:1159
static int sketch_endpoint_roles(const SketchEntity &e, SketchPointRole out[2])
Definition DesignSketchTool.cpp:2704

References Slic3r::Coincident, Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, has_coincident(), heal_coincidences(), m_entities, point_at(), Slic3r::SketchEntityConstraintDef::ra, Slic3r::SketchEntityConstraintDef::rb, resolve_live(), set_point(), Slic3r::GUI::sketch_endpoint_roles(), try_add_constraints(), and Slic3r::SketchEntityConstraintDef::type.

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_heal(), and heal_coincidences().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ helix_point()

Vec3d Slic3r::GUI::DesignSketchTool::helix_point ( double t) const
private
5128{
5129 const Vec3d O = m_hx_plane.origin;
5130 const Vec3d n = m_hx_plane.normal.normalized();
5131 const Vec3d u = m_hx_plane.x_axis.normalized();
5132 const Vec3d v = m_hx_plane.y_axis.normalized();
5133 const double a = (m_hx_left ? -1.0 : 1.0) * 2.0 * M_PI * t;
5134 const double z = m_hx_pitch * t; // height risen at this parameter
5135 double rt = m_hx_radius + z * std::tan(m_hx_taper * M_PI / 180.0);
5136 // The kernel REFUSES a taper that drives the radius negative before the full height; the
5137 // preview shows it collapsing instead, so the user can see which value did it.
5138 if (rt < 0.0) rt = 0.0;
5139 return O + u * (rt * std::cos(a)) + v * (rt * std::sin(a)) + n * z;
5140}
bool m_hx_left
Definition DesignSketchTool.hpp:1423
double m_hx_taper
Definition DesignSketchTool.hpp:1422

References helix_point(), m_hx_left, m_hx_pitch, m_hx_plane, m_hx_radius, m_hx_taper, and M_PI.

Referenced by helix_point(), hit_test_helix_handle(), and render_helix_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_display_sketch()

void Slic3r::GUI::DesignSketchTool::hit_display_sketch ( const DisplaySketch & d,
const Vec2d & p,
double tol,
int & edge_feat,
int & edge_reg,
int & edge_ent,
double & edge_d,
int & face_feat,
int & face_reg ) const
private
3379{
3380 const std::vector<RegionLoop> loops = region_loops(d.entities);
3381 // What did the sketch decompose into, and what is under the click? This is the trace that
3382 // settled txp8 — it prints the loop table with each loop's hole count, so
3383 // "containment is wrong" and "the click landed elsewhere" stop being indistinguishable.
3384 // Guarded rather than merely silent: hit_display_sketch runs on every pick, and the message
3385 // costs a string build and a heap allocation per loop even when nothing consumes it.
3386 if (dp_pick_trace_on()) {
3387 std::string h;
3388 for (size_t r = 0; r < loops.size(); ++r) {
3389 h += " loop" + std::to_string(r) + "(ents=" + std::to_string(loops[r].ents.size())
3390 + ",poly=" + std::to_string(loops[r].poly.size())
3391 + ",holes=" + std::to_string(loops[r].holes.size()) + ")";
3392 }
3393 dp_pick_trace("sketch feat=%d entities=%zu loops=%zu:%s", d.feature, d.entities.size(),
3394 loops.size(), h.c_str());
3395 }
3396 std::vector<int> ent_region(d.entities.size(), -1);
3397 for (int r = 0; r < int(loops.size()); ++r)
3398 for (int ei : loops[r].ents)
3399 if (ei >= 0 && ei < int(ent_region.size())) ent_region[ei] = r;
3400
3401 for (int ei = 0; ei < int(d.entities.size()); ++ei) {
3402 if (d.entities[ei].construction) continue; // as region_loops filters it
3403 const double ed = entity_pick_dist(p, d.entities[ei]);
3404 if (ed <= tol * 3.0 && ed < edge_d) {
3405 edge_d = ed; edge_feat = d.feature; edge_reg = ent_region[ei]; edge_ent = ei;
3406 }
3407 }
3408 // Pick the region the point is REALLY in: inside its boundary and not inside any of its
3409 // holes. Clicking the middle of a plate-with-hole must select the plate; clicking inside
3410 // the hole must select the disc, not the plate. Previously the first containing polygon
3411 // won, so a click inside the circle selected the rectangle.
3412 for (int r = 0; r < int(loops.size()); ++r) {
3413 if (face_feat >= 0) break;
3414 if (!point_in_poly(p, loops[r].poly)) continue;
3415 bool in_hole = false;
3416 for (int h : loops[r].holes)
3417 if (h >= 0 && h < int(loops.size()) && point_in_poly(p, loops[h].poly)) { in_hole = true; break; }
3418 if (!in_hole) { face_feat = d.feature; face_reg = r; }
3419 }
3420 // edge_ent is printed because it is now DELIVERED (3648) — a tool can ask for the
3421 // line you pointed at, not just its loop, and "which entity did that click resolve to" is
3422 // otherwise unanswerable from outside.
3423 dp_pick_trace("region hit -> feat=%d reg=%d (edge_feat=%d edge_reg=%d edge_ent=%d)",
3424 face_feat, face_reg, edge_feat, edge_reg, edge_ent);
3425}
static bool dp_pick_trace_on()
Definition DesignSketchTool.cpp:3880
static bool point_in_poly(const Vec2d &q, const std::vector< Vec2d > &poly)
Definition DesignSketchTool.cpp:10288

References Slic3r::GUI::dp_pick_trace(), Slic3r::GUI::dp_pick_trace_on(), Slic3r::GUI::DesignSketchTool::DisplaySketch::entities, Slic3r::GUI::entity_pick_dist(), Slic3r::GUI::DesignSketchTool::DisplaySketch::feature, hit_display_sketch(), Slic3r::holes(), Slic3r::GUI::point_in_poly(), and region_loops().

Referenced by hit_display_sketch(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test()

int Slic3r::GUI::DesignSketchTool::hit_test ( const Vec2d & p,
double tol ) const
private
10705{
10706 double best = tol;
10707 int bi = -1;
10708 for (size_t i = 0; i < m_entities.size(); ++i) {
10709 const double d = entity_pick_dist(p, m_entities[i]);
10710 if (d < best) { best = d; bi = int(i); }
10711 }
10712 return bi;
10713}

References Slic3r::GUI::entity_pick_dist(), hit_test(), and m_entities.

Referenced by hit_test(), on_mouse_impl(), and select_at_screen().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_base_pick()

int Slic3r::GUI::DesignSketchTool::hit_test_base_pick ( GLCanvas3D & canvas,
const wxMouseEvent & evt ) const
private
5744{
5745 if (!m_dbp_active) return -1;
5746 const double H = dbp_half_extent();
5747 const std::vector<SketchPlane> squares = dbp_squares(H);
5748 const Camera& cam = wxGetApp().plater()->get_camera();
5749 // As world_to_screen_px, but refusing a point behind the eye, which would come back mirrored.
5750 const Eigen::Matrix4d to_clip = cam.get_projection_matrix().matrix() * cam.get_view_matrix().matrix();
5751 const std::array<int, 4>& vp = cam.get_viewport();
5752 auto to_screen = [&](const Vec3d& x, Vec2d& out) {
5753 const Eigen::Vector4d clip = to_clip * x.homogeneous();
5754 if (clip.w() <= 1e-9)
5755 return false;
5756 const Vec3d ndc = clip.head<3>() / clip.w();
5757 out = Vec2d(vp[0] + (ndc.x() * 0.5 + 0.5) * vp[2], vp[1] + (1.0 - (ndc.y() * 0.5 + 0.5)) * vp[3]);
5758 return true;
5759 };
5760 const Vec2d mouse(evt.GetX(), evt.GetY());
5761 int lbest = -1;
5762 double lbest_d = std::numeric_limits<double>::max();
5763 for (size_t i = 0; i < squares.size() && i < m_dbp_labels.size(); ++i) {
5764 if (m_dbp_labels[i].empty()) continue;
5765 Vec2d centre;
5766 if (is_base_plane(i < m_dbp_base.size() ? m_dbp_base[i] : -1)) {
5767 // The name lies in its square, so its box is hit as projected, turning with the plane.
5768 const std::array<Vec3d, 4> box = reference_label_box(squares[i], H, m_dbp_labels[i]);
5769 std::array<Vec2d, 4> q;
5770 bool seen = true;
5771 for (size_t c = 0; c < 4 && seen; ++c) seen = to_screen(box[c], q[c]);
5772 if (!seen) continue;
5773 double area = 0.;
5774 bool left = true, right = true; // the cursor on one side of every edge: inside
5775 for (size_t c = 0; c < 4; ++c) {
5776 const Vec2d& a = q[c];
5777 const Vec2d& b = q[(c + 1) % 4];
5778 const double s = (b.x() - a.x()) * (mouse.y() - a.y()) - (b.y() - a.y()) * (mouse.x() - a.x());
5779 left = left && s >= 0.;
5780 right = right && s <= 0.;
5781 area += a.x() * b.y() - b.x() * a.y();
5782 }
5783 if (std::abs(area) < 8. || !(left || right))
5784 continue; // edge-on, or outside
5785 centre = 0.25 * (q[0] + q[1] + q[2] + q[3]);
5786 } else {
5787 // A datum's name is a screen chip. Generous rather than tight: missing the text and
5788 // silently selecting a different plane is the failure this guards against.
5789 if (!to_screen(squares[i].to_world(datum_label_anchor(H)), centre)) continue;
5790 const double hw = (9.0 + 5.0 * double(m_dbp_labels[i].size())) * double(m_render_scale);
5791 const double hh = 11.0 * double(m_render_scale);
5792 if (std::abs(mouse.x() - centre.x()) > hw || std::abs(mouse.y() - centre.y()) > hh) continue;
5793 }
5794 const double d = (mouse - centre).squaredNorm(); // the nearest name if several hold the cursor
5795 if (d < lbest_d) { lbest_d = d; lbest = int(i); }
5796 }
5797 if (lbest >= 0) return lbest;
5798
5799 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
5800 return pick_reference_square(squares, H, r.a, r.b - r.a);
5801}
double dbp_half_extent() const
Definition DesignSketchTool.cpp:5573
std::vector< SketchPlane > dbp_squares(double half) const
Definition DesignSketchTool.cpp:5584
Vec2d datum_label_anchor(double half)
Definition DesignSketchTool.cpp:5484
std::array< Vec3d, 4 > reference_label_box(const SketchPlane &square, double half, const std::string &text)
Definition DesignSketchTool.cpp:5518
static bool is_base_plane(const SketchPlane &p, const Vec3d &modeling_origin)
Definition DesignPanel.cpp:372
int pick_reference_square(const std::vector< SketchPlane > &squares, double half, const Vec3d &from, const Vec3d &dir)
Definition DesignSketchTool.cpp:5529
double area(const ExPolygon &poly)
Definition ExPolygon.hpp:511
bool empty(const BoundingBoxBase< PointType, PointsType > &bb)
Definition BoundingBox.hpp:273
@ right
Definition MarchingSquares.hpp:190
@ left
Definition MarchingSquares.hpp:188

References Slic3r::Linef3::a, Slic3r::area(), Slic3r::Linef3::b, dbp_half_extent(), dbp_squares(), Slic3r::empty(), Slic3r::GUI::Camera::get_projection_matrix(), Slic3r::GUI::Camera::get_view_matrix(), Slic3r::GUI::Camera::get_viewport(), hit_test_base_pick(), Slic3r::GUI::is_base_plane(), m_dbp_active, m_dbp_base, m_dbp_labels, m_render_scale, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::pick_reference_square(), Slic3r::GUI::reference_label_box(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_base_pick(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_cut_arrow()

bool Slic3r::GUI::DesignSketchTool::hit_test_cut_arrow ( GLCanvas3D & canvas,
const wxMouseEvent & evt ) const
private
6909{
6910 if (!m_ct_active) return false;
6911 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6912 const Vec3d ro = r.a, rd = r.b - r.a;
6913 const Camera& cam = wxGetApp().plater()->get_camera();
6914 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6915 const double L_sign = (std::abs(m_ct_offset) < 40.0 * upp)
6916 ? std::copysign(40.0 * upp, (m_ct_offset == 0.0 ? 1.0 : m_ct_offset))
6917 : m_ct_offset;
6918 return ray_segment_dist3(ro, rd, m_ct_base, m_ct_base + m_ct_n * L_sign) <= 12.0 * upp;
6919}
static double ray_segment_dist3(const Vec3d &ro, const Vec3d &rd, const Vec3d &a, const Vec3d &b)
Definition DesignSketchTool.cpp:10323

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), hit_test_cut_arrow(), m_ct_active, m_ct_base, m_ct_n, m_ct_offset, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::ray_segment_dist3(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_cut_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_datum_handle()

bool Slic3r::GUI::DesignSketchTool::hit_test_datum_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int & which ) const
private
5044{
5045 if (!m_dz_active) return false;
5046 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
5047 const Vec3d ro = r.a, rd = r.b - r.a;
5048 const Camera& cam = wxGetApp().plater()->get_camera();
5049 const double tol = 9.0 / std::max(cam.get_zoom(), 1e-6); // ~9 px in world units
5050 const double hu = m_dz_usize * 0.5, hv = m_dz_vsize * 0.5;
5051 const Vec2d hpos[4] = { Vec2d(hu, 0), Vec2d(-hu, 0), Vec2d(0, hv), Vec2d(0, -hv) };
5052 double best = tol; which = -1;
5053 for (int i = 0; i < 4; ++i) {
5054 const Vec3d pt = m_dz_plane.to_world(hpos[i]);
5055 const Vec3d w = pt - ro;
5056 const double t = w.dot(rd) / std::max(rd.dot(rd), 1e-12);
5057 const double d = (w - rd * t).norm();
5058 if (d < best) { best = d; which = i; }
5059 }
5060 if (m_dz_offset_on) { // offset arrow tip = handle 4
5062 const Vec3d w = pt - ro;
5063 const double t = w.dot(rd) / std::max(rd.dot(rd), 1e-12);
5064 const double d = (w - rd * t).norm();
5065 if (d < best) { best = d; which = 4; }
5066 }
5067 return which >= 0;
5068}
bool m_dz_offset_on
Definition DesignSketchTool.hpp:1410

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), hit_test_datum_handle(), m_dz_active, m_dz_anchor, m_dz_normal, m_dz_offset, m_dz_offset_on, m_dz_plane, m_dz_usize, m_dz_vsize, Slic3r::GUI::GLCanvas3D::mouse_ray(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_datum_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_dimension()

int Slic3r::GUI::DesignSketchTool::hit_test_dimension ( const Vec2d & p,
double tol ) const
private
1379{
1380 double best = tol;
1381 int bi = -1;
1382 for (size_t i = 0; i < m_dimensions.size(); ++i) {
1383 const double d = (m_dimensions[i].label_pos - p).norm();
1384 if (d < best) { best = d; bi = int(i); }
1385 }
1386 return bi;
1387}

References m_dimensions.

Referenced by on_mouse_impl().

Here is the caller graph for this function:

◆ hit_test_draft_handle()

bool Slic3r::GUI::DesignSketchTool::hit_test_draft_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt ) const
private
6782{
6783 if (!m_dr_active) return false;
6784 const Linef3 ray = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6785 const Vec3d ro = ray.a, rd = ray.b - ray.a;
6786 const Camera& cam = wxGetApp().plater()->get_camera();
6787 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6788 const Vec3d yax = dr_yaxis(m_dr_axis, m_dr_ref);
6789 const double a = m_dr_angle * M_PI / 180.0;
6790 const double tol = 16.0 * upp;
6791 auto ray_pt = [&](const Vec3d& p) {
6792 const double t = (p - ro).dot(rd) / std::max(rd.dot(rd), 1e-12);
6793 return (p - (ro + t * rd)).norm();
6794 };
6795 const Vec3d tip = m_dr_center + m_dr_radius * (std::cos(a) * m_dr_ref + std::sin(a) * yax);
6796 const Vec3d ref = m_dr_center + m_dr_radius * m_dr_ref; // angle-0 spoke end
6797 const int N = 48;
6798 for (int i = 0; i <= N; ++i) {
6799 const double f = double(i) / double(N);
6800 const double th = a * f;
6801 const Vec3d arc = m_dr_center + m_dr_radius * (std::cos(th) * m_dr_ref + std::sin(th) * yax);
6802 if (ray_pt(arc) <= tol) return true;
6803 if (ray_pt(m_dr_center + f * (tip - m_dr_center)) <= tol) return true;
6804 if (ray_pt(m_dr_center + f * (ref - m_dr_center)) <= tol) return true;
6805 }
6806 return false;
6807}
double m_dr_radius
Definition DesignSketchTool.hpp:1585

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::dot(), Slic3r::GUI::dr_yaxis(), Slic3r::f(), Slic3r::GUI::Camera::get_zoom(), hit_test_draft_handle(), m_dr_active, m_dr_angle, m_dr_axis, m_dr_center, m_dr_radius, m_dr_ref, M_PI, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::N, and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_draft_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_extrude_arrow()

bool Slic3r::GUI::DesignSketchTool::hit_test_extrude_arrow ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int & which ) const
private
4884{
4885 if (!m_ex_active) return false;
4886 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
4887 const Vec3d ro = r.a, rd = r.b - r.a;
4888 const Camera& cam = wxGetApp().plater()->get_camera();
4889 const double tol = 7.0 / std::max(cam.get_zoom(), 1e-6); // ~7 px in world units
4890 const Vec3d ndir = (m_ex_flip ? -1.0 : 1.0) * m_ex_plane.normal.normalized();
4891 const Vec3d base = m_ex_plane.to_world(m_ex_centroid);
4892 double dA = 1e30, dB = 1e30;
4893 if (m_ex_depth > 1e-6) dA = ray_segment_dist3(ro, rd, base, base + ndir * m_ex_depth);
4894 if (m_ex_two_sided && m_ex_depth2 > 1e-6)
4895 dB = ray_segment_dist3(ro, rd, base, base - ndir * m_ex_depth2);
4896 if (dA <= tol && dA <= dB) { which = 0; return true; }
4897 if (dB <= tol) { which = 1; return true; }
4898 return false;
4899}
bool m_ex_two_sided
Definition DesignSketchTool.hpp:1390

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), hit_test_extrude_arrow(), m_ex_active, m_ex_centroid, m_ex_depth, m_ex_depth2, m_ex_flip, m_ex_plane, m_ex_two_sided, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::ray_segment_dist3(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_extrude_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_fillet_arrow()

bool Slic3r::GUI::DesignSketchTool::hit_test_fillet_arrow ( GLCanvas3D & canvas,
const wxMouseEvent & evt ) const
private
6117{
6118 if (!m_fl_active) return false;
6119 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6120 const Vec3d ro = r.a, rd = r.b - r.a;
6121 const Camera& cam = wxGetApp().plater()->get_camera();
6122 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6123 const double L = std::max(m_fl_radius, 40.0 * upp);
6124 return ray_segment_dist3(ro, rd, m_fl_anchor, m_fl_anchor + m_fl_dir * L) <= 12.0 * upp;
6125}

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), hit_test_fillet_arrow(), L, m_fl_active, m_fl_anchor, m_fl_dir, m_fl_radius, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::ray_segment_dist3(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_fillet_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_handle()

bool Slic3r::GUI::DesignSketchTool::hit_test_handle ( const Vec2d & p,
double tol,
Handle & out ) const
private
1046{
1047 bool found = false;
1048 double best = tol;
1049 for (const Handle& h : build_handles()) {
1050 const double d = (h.pos - p).norm();
1051 if (d <= best) { best = d; out = h; out.hovered = true; found = true; }
1052 }
1053 return found;
1054}
std::vector< Handle > build_handles() const
Definition DesignSketchTool.cpp:996

References build_handles(), and Slic3r::GUI::DesignSketchTool::Handle::hovered.

Referenced by on_mouse_impl(), and update_hover().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_helix_handle()

bool Slic3r::GUI::DesignSketchTool::hit_test_helix_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int & which ) const
private
5230{
5231 if (!m_hx_active) return false;
5232 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
5233 const Vec3d ro = r.a, rd = r.b - r.a;
5234 const Camera& cam = wxGetApp().plater()->get_camera();
5235 const double tol = 9.0 / std::max(cam.get_zoom(), 1e-6); // ~9 px in world units
5236 const Vec3d O = m_hx_plane.origin;
5237 const Vec3d n = m_hx_plane.normal.normalized();
5238 const double turns = m_hx_pitch > 1e-9 ? m_hx_height / m_hx_pitch : 0.0;
5239 const Vec3d hpts[3] = { helix_point(0.0), O + n * m_hx_height,
5240 helix_point(m_hx_height < m_hx_pitch ? turns : 1.0) };
5241 double best = tol; which = -1;
5242 for (int i = 0; i < 3; ++i) {
5243 const Vec3d w = hpts[i] - ro;
5244 const double t = w.dot(rd) / std::max(rd.dot(rd), 1e-12);
5245 const double d = (w - rd * t).norm();
5246 if (d < best) { best = d; which = i; }
5247 }
5248 return which >= 0;
5249}
Vec3d helix_point(double t) const
Definition DesignSketchTool.cpp:5127

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), helix_point(), hit_test_helix_handle(), m_hx_active, m_hx_height, m_hx_pitch, m_hx_plane, Slic3r::GUI::GLCanvas3D::mouse_ray(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_helix_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_hole_handle()

int Slic3r::GUI::DesignSketchTool::hit_test_hole_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt ) const
private
6304{
6305 if (!m_hl_active) return -1;
6306 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6307 const Vec3d ro = r.a, rd = r.b - r.a;
6308 const Camera& cam = wxGetApp().plater()->get_camera();
6309 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6310
6311 const Vec3d centre = m_hl_plane.to_world(Vec2d(m_hl_x, m_hl_y));
6312 const Vec3d nrm = m_hl_plane.normal.normalized();
6313 const Vec3d ddir = m_hl_plane.x_axis.normalized();
6314 const double rad = std::max(m_hl_diameter * 0.5, 40.0 * upp);
6315 const double depL = std::max(m_hl_depth, 40.0 * upp);
6316 const double tol = 12.0 * upp;
6317
6318 // Centre wins at the shared base: the move cube straddles the centre, so a grab within the cube
6319 // half-size is a reposition. The arrows are only grabbable along the shaft extending outward,
6320 // which also keeps an edge-on arrow (e.g. depth in top view) from stealing the reposition grab.
6321 if (ray_segment_dist3(ro, rd, centre, centre) <= 9.0 * upp) return 0; // cube half-size
6322
6323 int best = -1; double bestd = tol;
6324 const double dD = ray_segment_dist3(ro, rd, centre, centre + ddir * rad);
6325 if (dD < bestd) { bestd = dD; best = 1; }
6326 if (!m_hl_through) {
6327 const double dZ = ray_segment_dist3(ro, rd, centre, centre + nrm * depL);
6328 if (dZ < bestd) { bestd = dZ; best = 2; }
6329 }
6330 return best;
6331}
bool m_hl_through
Definition DesignSketchTool.hpp:1508

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), hit_test_hole_handle(), m_hl_active, m_hl_depth, m_hl_diameter, m_hl_plane, m_hl_through, m_hl_x, m_hl_y, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::ray_segment_dist3(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_hole_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_move_arc()

bool Slic3r::GUI::DesignSketchTool::hit_test_move_arc ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int & axis ) const
private
5981{
5982 if (!m_mv_active) return false;
5983 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
5984 const Vec3d ro = r.a, rd = r.b - r.a;
5985 const Camera& cam = wxGetApp().plater()->get_camera();
5986 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
5987 const double R = 0.83 * move_gizmo_arm(cam); // rings just inside the arrow tips
5988 const Vec3d anchor = m_mv_base + m_mv_offset;
5989 int best = -1; double bestd = 7.0 * upp;
5990 const int N = 48;
5991 for (int a = 0; a < 3; ++a) {
5992 Vec3d e, u, v; ring_basis(a, e, u, v);
5993 Vec3d prev = anchor + R * u;
5994 for (int i = 1; i <= N; ++i) {
5995 const double t = 2.0 * M_PI * double(i) / double(N);
5996 const Vec3d cur = anchor + R * (std::cos(t) * u + std::sin(t) * v);
5997 const double d = ray_segment_dist3(ro, rd, prev, cur);
5998 if (d <= bestd) { bestd = d; best = a; }
5999 prev = cur;
6000 }
6001 }
6002 if (best < 0) return false;
6003 axis = best; return true;
6004}
double move_gizmo_arm(const Camera &cam) const
Definition DesignSketchTool.cpp:5826

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), hit_test_move_arc(), m_mv_active, m_mv_base, m_mv_offset, M_PI, Slic3r::GUI::GLCanvas3D::mouse_ray(), move_gizmo_arm(), Slic3r::GUI::N, Slic3r::GUI::ray_segment_dist3(), ring_basis(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_move_arc(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_move_arrow()

bool Slic3r::GUI::DesignSketchTool::hit_test_move_arrow ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int & axis ) const
private
5930{
5931 if (!m_mv_active) return false;
5932 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
5933 const Vec3d ro = r.a, rd = r.b - r.a;
5934 const Camera& cam = wxGetApp().plater()->get_camera();
5935 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
5936 const double L = move_gizmo_arm(cam); // must match render_move_gizmo
5937 const Vec3d anchor = m_mv_base + m_mv_offset;
5938 const Vec3d axes[3] = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() };
5939 int best = -1; double bestd = 7.0 * upp; // ~7 px tolerance
5940 for (int a = 0; a < 3; ++a) {
5941 const double d = ray_segment_dist3(ro, rd, anchor, anchor + axes[a] * L);
5942 if (d <= bestd) { bestd = d; best = a; }
5943 }
5944 if (best < 0) return false;
5945 axis = best; return true;
5946}

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), hit_test_move_arrow(), L, m_mv_active, m_mv_base, m_mv_offset, Slic3r::GUI::GLCanvas3D::mouse_ray(), move_gizmo_arm(), Slic3r::GUI::ray_segment_dist3(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_move_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_op_arrow()

bool Slic3r::GUI::DesignSketchTool::hit_test_op_arrow ( const Vec2d & p,
double tol ) const
private
8855{
8856 if (!op_ready() || m_mode == Mode::Mirror) return false;
8857 const Vec2d tip = m_op_anchor + m_op_dir * m_op_value;
8858 return point_segment_dist(p, m_op_anchor, tip) <= tol * 1.5;
8859}
static double point_segment_dist(const Vec2d &p, const Vec2d &a, const Vec2d &b)
Definition DesignSketchTool.cpp:10276

References hit_test_op_arrow(), m_mode, m_op_anchor, m_op_dir, m_op_value, Mirror, op_ready(), and Slic3r::GUI::point_segment_dist().

Referenced by hit_test_op_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_pattern_handle()

bool Slic3r::GUI::DesignSketchTool::hit_test_pattern_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt ) const
private
7199{
7200 if (!m_pt_active) return false;
7201 const Linef3 ray = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
7202 const Vec3d ro = ray.a, rd = ray.b - ray.a;
7203 const Camera& cam = wxGetApp().plater()->get_camera();
7204 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
7205 auto ray_pt = [&](const Vec3d& p) {
7206 const double t = (p - ro).dot(rd) / std::max(rd.dot(rd), 1e-12);
7207 return (p - (ro + t * rd)).norm();
7208 };
7209 if (!m_pt_circular) {
7210 const double tol = 8.0 * upp;
7211 const double L = pt_linear_len(m_pt_spacing, m_pt_count);
7212 return ray_segment_dist3(ro, rd, m_pt_base, m_pt_base + m_pt_dirw * L) <= tol;
7213 }
7214 const double tol = 16.0 * upp;
7215 const Vec3d yax = m_pt_normal.cross(m_pt_cref).normalized();
7216 const double a = m_pt_angle * M_PI / 180.0;
7217 const Vec3d tip = m_pt_ccenter + m_pt_radius * (std::cos(a) * m_pt_cref + std::sin(a) * yax);
7218 const Vec3d ref = m_pt_ccenter + m_pt_radius * m_pt_cref;
7219 const int N = 48;
7220 for (int i = 0; i <= N; ++i) {
7221 const double f = double(i) / double(N);
7222 const Vec3d arc = m_pt_ccenter + m_pt_radius * (std::cos(a * f) * m_pt_cref + std::sin(a * f) * yax);
7223 if (ray_pt(arc) <= tol) return true;
7224 if (ray_pt(m_pt_ccenter + f * (tip - m_pt_ccenter)) <= tol) return true;
7225 if (ray_pt(m_pt_ccenter + f * (ref - m_pt_ccenter)) <= tol) return true;
7226 }
7227 return false;
7228}
double m_pt_radius
Definition DesignSketchTool.hpp:1624
static double pt_linear_len(double spacing, int count)
Definition DesignSketchTool.cpp:7118

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::dot(), Slic3r::f(), Slic3r::GUI::Camera::get_zoom(), hit_test_pattern_handle(), L, M_PI, m_pt_active, m_pt_angle, m_pt_base, m_pt_ccenter, m_pt_circular, m_pt_count, m_pt_cref, m_pt_dirw, m_pt_normal, m_pt_radius, m_pt_spacing, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::N, Slic3r::GUI::pt_linear_len(), Slic3r::GUI::ray_segment_dist3(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_pattern_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_point()

bool Slic3r::GUI::DesignSketchTool::hit_test_point ( const Vec2d & p,
double tol,
int & ei,
SketchPointRole & role ) const
private
1203{
1204 double best = tol;
1205 bool found = false;
1206 auto consider = [&](int i, SketchPointRole r, const Vec2d& q) {
1207 const double d = (q - p).norm();
1208 if (d < best) { best = d; ei = i; role = r; found = true; }
1209 };
1210 for (size_t i = 0; i < m_entities.size(); ++i) {
1211 const SketchEntity& e = m_entities[i];
1212 switch (e.type) {
1214 consider(int(i), SketchPointRole::P0, e.p0);
1215 consider(int(i), SketchPointRole::P1, e.p1);
1216 break;
1219 consider(int(i), SketchPointRole::P0, e.p0);
1220 consider(int(i), SketchPointRole::P1, e.p1);
1221 consider(int(i), SketchPointRole::Center, e.center);
1222 break;
1225 consider(int(i), SketchPointRole::Center, e.center);
1226 break;
1228 consider(int(i), SketchPointRole::P0, e.p0);
1229 consider(int(i), SketchPointRole::P1, e.p1);
1230 break;
1232 consider(int(i), SketchPointRole::P0, e.p0);
1233 break;
1234 }
1235 }
1236 return found;
1237}

References Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::BSpline, Slic3r::Center, Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::SketchEntity::Ellipse, Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::Line, m_entities, Slic3r::P0, Slic3r::SketchEntity::p0, Slic3r::P1, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::Point, and Slic3r::SketchEntity::type.

Referenced by on_mouse_impl(), and select_at_screen().

Here is the caller graph for this function:

◆ hit_test_revolve_handle()

bool Slic3r::GUI::DesignSketchTool::hit_test_revolve_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt ) const
private
7025{
7026 if (!m_rv_active) return false;
7027 const Linef3 ray = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
7028 const Vec3d ro = ray.a, rd = ray.b - ray.a;
7029 const Camera& cam = wxGetApp().plater()->get_camera();
7030 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
7031 const Vec3d yax = rv_yaxis(m_rv_axis, m_rv_ref, m_rv_flip);
7032 const double a = m_rv_angle * M_PI / 180.0;
7033 const double tol = 16.0 * upp;
7034 // Grab anywhere on the whole gizmo (Onshape-style): the arc curve OR either radial spoke.
7035 // Take the nearest ray-to-point distance over a dense sampling.
7036 auto ray_pt = [&](const Vec3d& p) {
7037 const double t = (p - ro).dot(rd) / std::max(rd.dot(rd), 1e-12);
7038 return (p - (ro + t * rd)).norm();
7039 };
7040 const Vec3d tip = m_rv_center + m_rv_radius * (std::cos(a) * m_rv_ref + std::sin(a) * yax);
7041 const Vec3d ref = m_rv_center + m_rv_radius * m_rv_ref; // angle-0 spoke end
7042 const int N = 48;
7043 for (int i = 0; i <= N; ++i) {
7044 const double f = double(i) / double(N);
7045 const double th = a * f;
7046 const Vec3d arc = m_rv_center + m_rv_radius * (std::cos(th) * m_rv_ref + std::sin(th) * yax);
7047 if (ray_pt(arc) <= tol) return true; // on the arc curve
7048 if (ray_pt(m_rv_center + f * (tip - m_rv_center)) <= tol) return true; // on the swept spoke
7049 if (ray_pt(m_rv_center + f * (ref - m_rv_center)) <= tol) return true; // on the ref spoke
7050 }
7051 return false;
7052}
double m_rv_radius
Definition DesignSketchTool.hpp:1569

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::dot(), Slic3r::f(), Slic3r::GUI::Camera::get_zoom(), hit_test_revolve_handle(), M_PI, m_rv_active, m_rv_angle, m_rv_axis, m_rv_center, m_rv_flip, m_rv_radius, m_rv_ref, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::N, Slic3r::GUI::rv_yaxis(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_revolve_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_rib_handle()

bool Slic3r::GUI::DesignSketchTool::hit_test_rib_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int & which ) const
private
5372{
5373 if (!m_rb_active) return false;
5374 Vec2d d, perp, mid; double half;
5375 if (!rib_frame(m_rb_p0, m_rb_p1, m_rb_thickness, d, perp, mid, half)) return false;
5376 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
5377 const Vec3d ro = r.a, rd = r.b - r.a;
5378 const Camera& cam = wxGetApp().plater()->get_camera();
5379 const double tol = 9.0 / std::max(cam.get_zoom(), 1e-6); // ~9 px in world units
5380 const Vec3d hpts[2] = { m_rb_plane.to_world(mid + perp * half),
5381 m_rb_plane.to_world(mid - perp * half) };
5382 double best = tol; which = -1;
5383 for (int i = 0; i < 2; ++i) {
5384 const Vec3d w = hpts[i] - ro;
5385 const double t = w.dot(rd) / std::max(rd.dot(rd), 1e-12);
5386 const double dd = (w - rd * t).norm();
5387 if (dd < best) { best = dd; which = i; }
5388 }
5389 return which >= 0;
5390}

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), hit_test_rib_handle(), m_rb_active, m_rb_p0, m_rb_p1, m_rb_plane, m_rb_thickness, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::perp(), Slic3r::GUI::rib_frame(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_rib_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_shell_arrow()

bool Slic3r::GUI::DesignSketchTool::hit_test_shell_arrow ( GLCanvas3D & canvas,
const wxMouseEvent & evt ) const
private
6653{
6654 if (!m_sh_active) return false;
6655 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6656 const Vec3d ro = r.a, rd = r.b - r.a;
6657 const Camera& cam = wxGetApp().plater()->get_camera();
6658 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6659 const double L = std::max(m_sh_thickness, 40.0 * upp);
6660 return ray_segment_dist3(ro, rd, m_sh_anchor, m_sh_anchor + m_sh_dir * L) <= 12.0 * upp;
6661}

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), hit_test_shell_arrow(), L, m_sh_active, m_sh_anchor, m_sh_dir, m_sh_thickness, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::ray_segment_dist3(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_shell_arrow(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_tf_handle()

bool Slic3r::GUI::DesignSketchTool::hit_test_tf_handle ( const Vec2d & p,
double tol ) const
private
9252{
9253 if (!tf_ready()) return false;
9254 return (tf_handle_pos() - p).norm() <= tol * 2.5;
9255}
Vec2d tf_handle_pos() const
Definition DesignSketchTool.cpp:9239

References hit_test_tf_handle(), tf_handle_pos(), and tf_ready().

Referenced by hit_test_tf_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_thread_handle()

int Slic3r::GUI::DesignSketchTool::hit_test_thread_handle ( GLCanvas3D & canvas,
const wxMouseEvent & evt ) const
private
6517{
6518 if (!m_th_active) return -1;
6519 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6520 const Vec3d ro = r.a, rd = r.b - r.a;
6521 const Camera& cam = wxGetApp().plater()->get_camera();
6522 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6523
6524 const Vec3d centre = m_th_plane.to_world(Vec2d(m_th_x, m_th_y));
6525 const Vec3d nrm = m_th_plane.normal.normalized();
6526 const Vec3d ddir = m_th_plane.x_axis.normalized();
6527 const double rad = std::max(m_th_radius, 40.0 * upp);
6528 const double hL = std::max(m_th_height, 40.0 * upp);
6529 const double tol = 12.0 * upp;
6530
6531 if (ray_segment_dist3(ro, rd, centre, centre) <= tol) return 0; // centre wins at the base
6532 int best = -1; double bestd = tol;
6533 const double dR = ray_segment_dist3(ro, rd, centre, centre + ddir * rad);
6534 if (dR < bestd) { bestd = dR; best = 1; }
6535 const double dH = ray_segment_dist3(ro, rd, centre, centre + nrm * hL);
6536 if (dH < bestd) { bestd = dH; best = 2; }
6537 return best;
6538}

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::Camera::get_zoom(), hit_test_thread_handle(), m_th_active, m_th_height, m_th_plane, m_th_radius, m_th_x, m_th_y, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::ray_segment_dist3(), and Slic3r::GUI::wxMouseEvent.

Referenced by hit_test_thread_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hit_test_xform_handle()

int Slic3r::GUI::DesignSketchTool::hit_test_xform_handle ( const Vec2d & p,
double tol ) const
private
8621{
8622 Vec2d c[4]; xform_world_corners(c);
8623 int best = -1; double bd = tol;
8624 for (int i = 0; i < 4; ++i) { const double d = (c[i] - p).norm(); if (d < bd) { bd = d; best = i; } }
8625 if (best >= 0) return best;
8626 if ((0.5 * (c[0] + c[2]) - p).norm() <= tol) return 4; // centre move-handle
8627 return -1;
8628}
static const wxColour bd
Definition AxisCtrlButton.cpp:25
void xform_world_corners(Vec2d out[4]) const
Definition DesignSketchTool.cpp:8610

References bd, hit_test_xform_handle(), and xform_world_corners().

Referenced by hit_test_xform_handle(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ hole_axis_proj()

double Slic3r::GUI::DesignSketchTool::hole_axis_proj ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
const Vec3d & anchor,
const Vec3d & dir ) const
private
6335{
6336 return ray_axis_proj(canvas.mouse_ray(Point(evt.GetX(), evt.GetY())), anchor, dir);
6337}

References hole_axis_proj(), Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::ray_axis_proj(), and Slic3r::GUI::wxMouseEvent.

Referenced by drag_cut_arrow(), drag_hole_handle(), drag_shell_arrow(), drag_thread_handle(), hole_axis_proj(), start_cut_drag(), start_hole_drag(), start_shell_drag(), and start_thread_drag().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ holing()

bool Slic3r::GUI::DesignSketchTool::holing ( ) const
inline
404{ return m_hl_active; }

References m_hl_active.

◆ infer_at()

InferenceSnap Slic3r::GUI::DesignSketchTool::infer_at ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
const Vec2d & raw ) const
private
2602{
2603 if (evt.ShiftDown()) { InferenceSnap s; s.point = raw; return s; } // Shift suppresses
2604 const double tol = screen_tol(canvas, evt, raw);
2605 return infer_point_snap(m_entities, raw, tol);
2606}
double screen_tol(GLCanvas3D &canvas, const wxMouseEvent &evt, const Vec2d &at, double px=kPickPx) const
Definition DesignSketchTool.cpp:2591
InferenceSnap infer_point_snap(const std::vector< SketchEntity > &entities, const Vec2d &query, double tol, bool include_origin)
Definition SketchInference.cpp:39

References infer_at(), Slic3r::infer_point_snap(), m_entities, Slic3r::InferenceSnap::point, screen_tol(), and Slic3r::GUI::wxMouseEvent.

Referenced by infer_at(), and snap_vertex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ infer_auto_constraints()

void Slic3r::GUI::DesignSketchTool::infer_auto_constraints ( int base,
double ang_tol_rad = 3.0 * M_PI / 180.0,
double weld_tol = 1e-3 )
private
2719{
2720 const int n = int(m_entities.size());
2721 if (base < 0 || base >= n) return;
2722
2723
2724 // 1) Coincident between a new endpoint and any (co-located) endpoint of another
2725 // entity. snap_vertex already drove the coordinates together; this records it
2726 // so a re-solve keeps the loop closed.
2727 std::vector<SketchEntityConstraintDef> coincs;
2728 for (int i = base; i < n; ++i) {
2729 SketchPointRole ir[2]; const int ni = sketch_endpoint_roles(m_entities[i], ir);
2730 for (int a = 0; a < ni; ++a) {
2731 Vec2d pa; if (!point_at(i, ir[a], pa)) continue;
2732 for (int j = 0; j < n; ++j) {
2733 if (j == i) continue;
2734 SketchPointRole jr[2]; const int nj = sketch_endpoint_roles(m_entities[j], jr);
2735 for (int b = 0; b < nj; ++b) {
2736 if (j >= base && j < i) continue; // avoid duplicate (i,j)/(j,i)
2737 Vec2d pb; if (!point_at(j, jr[b], pb)) continue;
2738 if ((pa - pb).squaredNorm() > weld_tol * weld_tol) continue;
2739 if (has_coincident(i, ir[a], j, jr[b])) continue;
2740 SketchEntityConstraintDef c;
2742 c.ea = i; c.ra = ir[a]; c.eb = j; c.rb = jr[b];
2743 coincs.push_back(c);
2744 }
2745 }
2746 }
2747 }
2748 try_add_constraints(coincs); // co-located points: consistent by construction
2749
2750 // 2) Horizontal / Vertical on axis-aligned new line segments. Tried as ONE batch first and
2751 // only then one at a time, which is the same outcome — a single conflict never drops the
2752 // others — for one solve instead of n. That matters now that large sketches actually
2753 // solve: a bulk add of 1200 axis-aligned segments used to be fast only because every
2754 // solve failed instantly on the unknown limit, and once they started succeeding the
2755 // per-constraint loop turned into 1200 solves and blew the MCP main-thread budget.
2756 std::vector<SketchEntityConstraintDef> axes;
2757 for (int i = base; i < n; ++i) {
2758 if (m_entities[i].type != SketchEntity::Type::Line) continue;
2759 auto ax = infer_axis_constraint(m_entities[i].p0, m_entities[i].p1, ang_tol_rad);
2760 if (!ax) continue;
2761 SketchEntityConstraintDef c;
2762 c.type = *ax;
2763 c.ea = i; c.ra = SketchPointRole::P0;
2764 c.eb = i; c.rb = SketchPointRole::P1;
2765 axes.push_back(c);
2766 }
2767 if (!try_add_constraints(axes))
2768 for (const auto& c : axes) try_add_constraints({ c });
2769
2770 // 3) Relational constraints on the new entities (parallel/perpendicular on connected
2771 // lines, equal radius, tangent). Same batch-then-one-at-a-time fallback as above:
2772 // try_add_constraints rolls a conflicting batch back, so a single rejected relation
2773 // never costs the others. Every rule only pins a relation that is ALREADY true, so
2774 // nothing the user drew is moved by this.
2775 // A SCRIPTED ADD IS NOT A DRAWN GESTURE — the rule this function already states at its
2776 // bulk call site, which passes zero tolerances for exactly that reason (8xg1).
2777 // Relational inference must obey it too, and for a second reason beyond tolerance:
2778 // EqualRadius couples entities that are geometrically far apart, so on a real drawing it
2779 // merges independent connected components into one huge system and defeats the
2780 // component partitioning that makes large sketches solvable at all (yww4).
2781 // Measured 2026-08-31 on the corpus rung: geometry stayed correct (32/32 sheets clean)
2782 // but seven of the largest sheets hit main-thread timeout — MPD681 among them, the very
2783 // sheet named in the comment at the bulk call site. Exact-equality would not save it
2784 // either: patterned holes in real drawings ARE exactly equal.
2785 // So: relations only for batches the size of a human gesture. A polyline segment is 1, a
2786 // rectangle 4, a polygon a dozen; a scripted or imported add is hundreds.
2787 constexpr int kRelInferMaxBatch = 16;
2788 std::vector<SketchEntityConstraintDef> rels;
2789 if (n - base <= kRelInferMaxBatch) {
2790 const double rel_len_tol = ang_tol_rad > 0.0 ? 0.01 : 0.0; // exact-only when the caller asked for exact
2791 for (int i = base; i < n; ++i) {
2792 auto r = infer_relations(m_entities, i, ang_tol_rad, rel_len_tol);
2793 rels.insert(rels.end(), r.begin(), r.end());
2794 }
2795 }
2796 // NO one-at-a-time fallback here, unlike the two batches above. Relations are a
2797 // convenience: nothing is incorrect without them. The fallback costs one SOLVE PER
2798 // CONSTRAINT, which is what the warning on the axes batch is about, and paying it for
2799 // optional constraints is how a bulk add pins the app at 100% CPU with the MCP socket
2800 // unresponsive (measured 2026-08-31). If the batch conflicts, drop the batch.
2801 if (!rels.empty()) try_add_constraints(rels);
2802
2803 resolve_live();
2804}
std::vector< SketchEntityConstraintDef > infer_relations(const std::vector< SketchEntity > &entities, int new_ei, double ang_tol_rad, double len_tol_frac)
Definition SketchInference.cpp:157
std::optional< SketchConstraintType > infer_axis_constraint(const Vec2d &anchor, const Vec2d &tip, double ang_tol_rad)
Definition SketchInference.cpp:135

References Slic3r::Coincident, Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, has_coincident(), infer_auto_constraints(), Slic3r::infer_axis_constraint(), Slic3r::infer_relations(), Slic3r::SketchEntity::Line, m_entities, Slic3r::P0, Slic3r::P1, point_at(), Slic3r::SketchEntityConstraintDef::ra, Slic3r::SketchEntityConstraintDef::rb, resolve_live(), Slic3r::GUI::sketch_endpoint_roles(), try_add_constraints(), and Slic3r::SketchEntityConstraintDef::type.

Referenced by add_entities_scripted(), end_chain(), infer_auto_constraints(), keep_segment_as_drawn(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ inline_busy()

bool Slic3r::GUI::DesignSketchTool::inline_busy ( ) const
inline
148{ return m_awaiting_length; } // true while a value field is open

References m_awaiting_length.

◆ is_active()

bool Slic3r::GUI::DesignSketchTool::is_active ( ) const
inline
181{ return m_active; }

References m_active.

Referenced by select_at_screen().

Here is the caller graph for this function:

◆ is_constraining()

bool Slic3r::GUI::DesignSketchTool::is_constraining ( ) const
inline
488{ return m_active && m_mode == Mode::Constrain; }

References Constrain, m_active, and m_mode.

◆ is_constraining_entities()

bool Slic3r::GUI::DesignSketchTool::is_constraining_entities ( ) const
inline

◆ is_creation_autoedit_mode()

bool Slic3r::GUI::DesignSketchTool::is_creation_autoedit_mode ( ) const
inline
132 {
133 switch (m_mode) {
134 case Mode::Line:
140 return true;
141 default: return false;
142 }
143 }

References ArcSlot, CenterArc, CenterCircle, CenterRect, CornerRect, Ellipse, EllipseArc, Line, m_mode, ObliqueRect, Polygon, RoundedRect, Slot, TangentArc, ThreePointArc, ThreePointCircle, and TwoPointCircle.

Referenced by render().

Here is the caller graph for this function:

◆ is_current_shape()

bool Slic3r::GUI::DesignSketchTool::is_current_shape ( int body,
const TopoDS_Shape & sampled ) const
private
3530{
3531 const TopoDS_Shape* shape = body_shape(body);
3532 return shape != nullptr && sampled.IsSame(*shape);
3533}
const TopoDS_Shape * body_shape(int body) const
Definition DesignSketchTool.cpp:3518

References body_shape(), and is_current_shape().

Referenced by cached_face_highlight(), is_current_shape(), make_face_highlight(), refresh_body_edges(), render_face_outline(), and selected_faces().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_edit_op_mode()

bool Slic3r::GUI::DesignSketchTool::is_edit_op_mode ( ) const
inline
124 { return m_mode == Mode::Fillet || m_mode == Mode::Chamfer ||

References Chamfer, Fillet, m_mode, Mirror, and Offset.

Referenced by emit_step_hint(), on_mouse_impl(), render(), and render_live_quotes().

Here is the caller graph for this function:

◆ is_transform_mode()

bool Slic3r::GUI::DesignSketchTool::is_transform_mode ( ) const
inline
126 { return m_mode == Mode::Move || m_mode == Mode::Rotate ||

References Array, m_mode, Move, PolarArray, Rotate, and Scale.

Referenced by emit_step_hint(), on_mouse_impl(), render(), and render_live_quotes().

Here is the caller graph for this function:

◆ keep_segment_as_drawn()

void Slic3r::GUI::DesignSketchTool::keep_segment_as_drawn ( )
2456{
2457 if (m_points.size() == 2) {
2458 const int base = int(m_entities.size());
2459 push_line(m_points[0], m_points[1]); // accrues into the session's entities
2460 infer_auto_constraints(base); // auto Coincident at snapped ends + H/V
2461 }
2462 m_points.clear();
2463 m_has_cursor = false;
2464 m_awaiting_length = false;
2465}
void push_line(const Vec2d &a, const Vec2d &b)
Definition DesignSketchTool.cpp:2884

References infer_auto_constraints(), keep_segment_as_drawn(), m_awaiting_length, m_entities, m_has_cursor, m_points, and push_line().

Referenced by apply_segment_length(), keep_segment_as_drawn(), and on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ live_sketch_has_work()

bool Slic3r::GUI::DesignSketchTool::live_sketch_has_work ( ) const
inline
151{ return !m_entities.empty(); }

References m_entities.

Referenced by request_exit().

Here is the caller graph for this function:

◆ loop_report()

DesignSketchTool::LoopReport Slic3r::GUI::DesignSketchTool::loop_report ( ) const
10493{
10494 LoopReport out;
10495
10496 // Closed regions and their voids come straight from the code the viewport already uses to
10497 // decide what can be extruded, so the report cannot drift from what the tool will build.
10498 const auto regs = region_loops(m_entities);
10499 out.loops.reserve(regs.size());
10500 for (const auto& r : regs) {
10501 LoopInfo li;
10502 li.ents = r.ents;
10503 li.holes = r.holes;
10504 li.closed = true;
10505 li.defect = r.defect;
10506 li.defect_at = r.defect_at;
10507 // Analytic where the loop IS one closed curve; shoelace only where it is a chain.
10508 // region_loops hands back the render polyline, and a circle's is a 64-gon whose area is
10509 // 0.3% short — a number reported as "area" must not be the faceting error.
10510 if (r.ents.size() == 1 && r.ents[0] >= 0 && r.ents[0] < int(m_entities.size()) &&
10511 (m_entities[r.ents[0]].type == SketchEntity::Type::Circle ||
10512 m_entities[r.ents[0]].type == SketchEntity::Type::Ellipse)) {
10513 const SketchEntity& c = m_entities[r.ents[0]];
10514 li.area = (c.type == SketchEntity::Type::Circle)
10515 ? M_PI * c.radius * c.radius
10516 : M_PI * c.radius * c.rminor;
10517 } else {
10518 // EXACT area by Green's theorem over the chain, entity by entity, with no faceting
10519 // anywhere. The obvious alternative — shoelace over the render polyline — is short by
10520 // the slivers between each arc and its chords: 2.02 mm2 on a 3706.86 mm2 stadium,
10521 // 0.054%, invisible on screen and simply wrong in a number reported as "the area".
10522 // Correcting the shoelace afterwards does NOT work: a mirrored arc stores a negated
10523 // sweep, so two corrections that should add cancel instead. Integrating each entity
10524 // in TRAVERSAL order sidesteps the sign question entirely.
10525 // line A->B : x0*y1 - x1*y0
10526 // arc a0->a1: Cx*r*(sin a1 - sin a0) - Cy*r*(cos a1 - cos a0) + r^2*(a1 - a0)
10527 // Both are the integrand of the contour integral, so area2 accumulates 2*area and is
10528 // halved once at the end. (Doubling the arc term instead reads 5913.72 on the stadium
10529 // — exactly one arc's contribution too much, which is how the slip was caught.)
10530 auto ent_ends = [&](int ei, Vec2d& a, Vec2d& b) {
10531 a = m_entities[ei].p0; b = m_entities[ei].p1;
10532 };
10533 const double eps = 1e-6;
10534 double area2 = 0.0;
10535 bool exact = true;
10536 Vec2d cur(0, 0);
10537 for (size_t k = 0; k < r.ents.size(); ++k) {
10538 const int ei = r.ents[k];
10539 if (ei < 0 || ei >= int(m_entities.size())) { exact = false; break; }
10540 const SketchEntity& e = m_entities[ei];
10541 if (e.type != SketchEntity::Type::Line && e.type != SketchEntity::Type::Arc) {
10542 exact = false; break; // spline / ellipse arc: fall back below
10543 }
10544 Vec2d A, B; ent_ends(ei, A, B);
10545 bool rev = false;
10546 if (k == 0) {
10547 // Orient the first entity by whichever of its ends the SECOND one touches:
10548 // that shared point is where this entity must finish.
10549 if (r.ents.size() > 1) {
10550 Vec2d C, D; ent_ends(r.ents[1], C, D);
10551 if ((A - C).norm() < eps || (A - D).norm() < eps) rev = true;
10552 }
10553 } else {
10554 if ((B - cur).norm() < eps) rev = true;
10555 else if ((A - cur).norm() >= eps) { exact = false; break; }
10556 }
10557 const Vec2d P = rev ? B : A;
10558 const Vec2d Q = rev ? A : B;
10559 if (e.type == SketchEntity::Type::Line) {
10560 area2 += P.x() * Q.y() - Q.x() * P.y();
10561 } else {
10562 const double a0 = rev ? e.end_angle : e.start_angle;
10563 const double a1 = rev ? e.start_angle : e.end_angle;
10564 area2 += e.center.x() * e.radius * (std::sin(a1) - std::sin(a0))
10565 - e.center.y() * e.radius * (std::cos(a1) - std::cos(a0))
10566 + e.radius * e.radius * (a1 - a0);
10567 }
10568 cur = Q;
10569 }
10570 if (exact) {
10571 li.area = 0.5 * area2;
10572 } else {
10573 // Splines and elliptical arcs have no closed form here; the render polyline is
10574 // the honest best estimate, and it is flagged as such by being the fallback.
10575 double a = 0.0;
10576 for (size_t i = 0; i + 1 < r.poly.size(); ++i)
10577 a += r.poly[i].x() * r.poly[i + 1].y() - r.poly[i + 1].x() * r.poly[i].y();
10578 if (r.poly.size() > 2)
10579 a += r.poly.back().x() * r.poly.front().y() - r.poly.front().x() * r.poly.back().y();
10580 li.area = 0.5 * a;
10581 }
10582 }
10583 out.loops.push_back(std::move(li));
10584 }
10585
10586 // Open ends: an endpoint of an open curve that no other open curve's endpoint meets. This is
10587 // the actionable half of the report — it says WHERE the profile fails to close, in plane
10588 // coordinates, instead of only that it does.
10589 struct End { Vec2d p; };
10590 std::vector<End> ends;
10591 for (const SketchEntity& e : m_entities) {
10592 if (e.construction) continue;
10593 if (e.type == SketchEntity::Type::Line || e.type == SketchEntity::Type::Arc ||
10595 ends.push_back({ e.p0 });
10596 ends.push_back({ e.p1 });
10597 }
10598 }
10599 const double eps = sketch_join_tol();
10600 for (size_t i = 0; i < ends.size(); ++i) {
10601 int met = 0;
10602 for (size_t j = 0; j < ends.size(); ++j) {
10603 if (i == j) continue;
10604 if ((ends[i].p - ends[j].p).norm() < eps) ++met;
10605 }
10606 if (met == 0) {
10607 // Report each free end once; two ends of the same gap are two different points.
10608 bool dup = false;
10609 for (const Vec2d& q : out.open_ends)
10610 if ((q - ends[i].p).norm() < eps) { dup = true; break; }
10611 if (!dup) out.open_ends.push_back(ends[i].p);
10612 }
10613 }
10614 return out;
10615}
std::vector< int > ents
Definition DesignSketchTool.hpp:601
Definition DesignSketchTool.hpp:608
Definition DesignSketchTool.hpp:600

References Slic3r::SketchEntity::Arc, Slic3r::GUI::DesignSketchTool::LoopInfo::area, Slic3r::SketchEntity::BSpline, Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::GUI::DesignSketchTool::LoopInfo::closed, Slic3r::GUI::DesignSketchTool::LoopInfo::defect, Slic3r::GUI::DesignSketchTool::LoopInfo::defect_at, Slic3r::SketchEntity::Ellipse, Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::end_angle, Slic3r::GUI::DesignSketchTool::LoopInfo::ents, Slic3r::GUI::DesignSketchTool::LoopInfo::holes, Slic3r::SketchEntity::Line, loop_report(), Slic3r::GUI::DesignSketchTool::LoopReport::loops, m_entities, M_PI, Slic3r::GUI::DesignSketchTool::LoopReport::open_ends, Slic3r::P, Slic3r::SketchEntity::radius, region_loops(), Slic3r::SketchEntity::rminor, Slic3r::sketch_join_tol(), Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by loop_report(), and Slic3r::GUI::anonymous_namespace{McpControl.cpp}::sketch_report().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_arc_slot()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_arc_slot ( const Vec2d & center,
const Vec2d & start,
const Vec2d & end_dir,
double half_width ) const
private
3119{
3120 std::vector<SketchEntity> out;
3121 const double Rc = (start - center).norm();
3122 const double w = half_width;
3123 if (Rc < 1e-6 || w < 1e-6 || w >= Rc) return out;
3124 const Vec2d dirS = (start - center) / Rc;
3125 Vec2d de = end_dir - center;
3126 if (de.squaredNorm() < 1e-12) return out;
3127 const Vec2d dirE = de.normalized();
3128 const double aS = std::atan2(dirS.y(), dirS.x());
3129 const double aE = std::atan2(dirE.y(), dirE.x());
3130 const double sweep = wrap_2pi(aE - aS); // CCW start -> end
3131 const double aMid = aS + sweep * 0.5;
3132 const Vec2d uMid(std::cos(aMid), std::sin(aMid));
3133 const Vec2d Sc = center + Rc * dirS; // centerline start point (cap centre)
3134 const Vec2d Ec = center + Rc * dirE; // centerline end point (cap centre)
3135 const Vec2d S_out = center + (Rc + w) * dirS, S_in = center + (Rc - w) * dirS;
3136 const Vec2d E_out = center + (Rc + w) * dirE, E_in = center + (Rc - w) * dirE;
3137 const Vec2d tE(-dirE.y(), dirE.x()); // CCW travel-forward tangent at E
3138 const Vec2d tS(-dirS.y(), dirS.x()); // CCW travel-forward tangent at S
3139 out.push_back(make_arc_through(center, Rc + w, S_out, E_out, center + (Rc + w) * uMid, m_construction)); // outer
3140 out.push_back(make_arc_through(Ec, w, E_out, E_in, Ec + w * tE, m_construction)); // cap @E (forward)
3141 out.push_back(make_arc_through(center, Rc - w, E_in, S_in, center + (Rc - w) * uMid, m_construction)); // inner
3142 out.push_back(make_arc_through(Sc, w, S_in, S_out, Sc - w * tS, m_construction)); // cap @S (backward)
3143 return out;
3144}
static double wrap_2pi(double a)
Definition DesignSketchTool.cpp:2961
static SketchEntity make_arc_through(const Vec2d &center, double radius, const Vec2d &start, const Vec2d &end, const Vec2d &through, bool construction)
Definition DesignSketchTool.cpp:2988

References Slic3r::center(), m_construction, make_arc_slot(), Slic3r::GUI::make_arc_through(), and Slic3r::wrap_2pi().

Referenced by make_arc_slot(), on_mouse_impl(), render(), and set_arc_slot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_bspline()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_bspline ( const std::vector< Vec2d > & ctrl) const
private
3285{
3286 if (ctrl.size() < 2) return {};
3287 SketchEntity e;
3289 e.ctrl = ctrl;
3290 e.p0 = ctrl.front();
3291 e.p1 = ctrl.back();
3292 e.construction = m_construction;
3293 return { e };
3294}

References Slic3r::SketchEntity::BSpline, Slic3r::SketchEntity::construction, Slic3r::SketchEntity::ctrl, m_construction, make_bspline(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, and Slic3r::SketchEntity::type.

Referenced by end_chain(), and make_bspline().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_center_arc()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_center_arc ( const Vec2d & center,
const Vec2d & start,
const Vec2d & end_dir ) const
private
3077{
3078 const double radius = (start - center).norm();
3079 if (radius < 1e-9)
3080 return {};
3081 const double a_start = std::atan2(start.y() - center.y(), start.x() - center.x());
3082 const double a_end = std::atan2(end_dir.y() - center.y(), end_dir.x() - center.x());
3083 const double de = wrap_2pi(a_end - a_start); // CCW sweep start -> end (0,2Ï€)
3084 const Vec2d end = center + radius * Vec2d(std::cos(a_end), std::sin(a_end));
3085 const double a_mid = a_start + de * 0.5; // bisector brackets the sweep
3086 const Vec2d through = center + radius * Vec2d(std::cos(a_mid), std::sin(a_mid));
3087 return { make_arc_through(center, radius, start, end, through, m_construction) };
3088}

References Slic3r::center(), m_construction, Slic3r::GUI::make_arc_through(), make_center_arc(), and Slic3r::wrap_2pi().

Referenced by make_center_arc(), on_mouse_impl(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_ellipse()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_ellipse ( const Vec2d & center,
const Vec2d & major_end,
const Vec2d & minor_pt ) const
private
3249{
3250 double a, b, phi;
3251 ellipse_axes(center, major_end, minor_pt, a, b, phi);
3252 if (b < 1e-6) return {};
3253 SketchEntity e;
3255 e.center = center; e.p0 = center;
3256 e.radius = a; e.rminor = b; e.rotation = phi;
3257 e.start_angle = 0.0; e.end_angle = 2.0 * M_PI;
3258 e.construction = m_construction;
3259 return { e };
3260}
static void ellipse_axes(const Vec2d &center, const Vec2d &major_end, const Vec2d &minor_pt, double &a, double &b, double &phi)
Definition DesignSketchTool.cpp:3227

References Slic3r::center(), Slic3r::SketchEntity::center, Slic3r::SketchEntity::construction, Slic3r::SketchEntity::Ellipse, Slic3r::GUI::ellipse_axes(), Slic3r::SketchEntity::end_angle, m_construction, M_PI, make_ellipse(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::radius, Slic3r::SketchEntity::rminor, Slic3r::SketchEntity::rotation, Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by make_ellipse(), on_mouse_impl(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_ellipse_arc()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_ellipse_arc ( const Vec2d & center,
const Vec2d & major_end,
const Vec2d & minor_pt,
const Vec2d & start_pt,
const Vec2d & end_pt ) const
private
3265{
3266 double a, b, phi;
3267 ellipse_axes(center, major_end, minor_pt, a, b, phi);
3268 if (b < 1e-6) return {};
3269 double t0 = ellipse_param_of(center, a, b, phi, start_pt);
3270 double t1 = ellipse_param_of(center, a, b, phi, end_pt);
3271 // CCW sweep from t0 to t1.
3272 while (t1 <= t0) t1 += 2.0 * M_PI;
3273 SketchEntity e;
3275 e.center = center;
3276 e.radius = a; e.rminor = b; e.rotation = phi;
3277 e.start_angle = t0; e.end_angle = t1;
3278 e.p0 = ellipse_point(center, a, b, phi, t0);
3279 e.p1 = ellipse_point(center, a, b, phi, t1);
3280 e.construction = m_construction;
3281 return { e };
3282}

References Slic3r::center(), Slic3r::SketchEntity::center, Slic3r::SketchEntity::construction, Slic3r::GUI::ellipse_axes(), Slic3r::GUI::ellipse_param_of(), Slic3r::GUI::ellipse_point(), Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::end_angle, m_construction, M_PI, make_ellipse_arc(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::radius, Slic3r::SketchEntity::rminor, Slic3r::SketchEntity::rotation, Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by make_ellipse_arc(), on_mouse_impl(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_face_highlight()

DesignSketchTool::FaceHighlight Slic3r::GUI::DesignSketchTool::make_face_highlight ( int body,
std::vector< int > faces ) const
private
3691{
3692 FaceHighlight h;
3693 h.body = body;
3694 std::sort(faces.begin(), faces.end());
3695 faces.erase(std::unique(faces.begin(), faces.end()), faces.end());
3696 h.faces = std::move(faces);
3697 const TopoDS_Shape* shape = body_shape(body);
3698 if (shape == nullptr)
3699 return h;
3700 h.shape = *shape;
3701 if (h.faces.empty())
3702 return h;
3703 // Sampled at the body edges' tolerance; a whole body reuses its body edges.
3704 const std::vector<TopoDS_Face> all = GeometryEngine::faces_of(*shape);
3705 const bool cached = body < int(m_body_edges_shape.size())
3706 && is_current_shape(body, m_body_edges_shape[body]);
3707 if (cached && h.faces.size() == all.size() && h.faces.front() == 0 && h.faces.back() == int(all.size()) - 1) {
3708 h.edges = m_body_edges[body];
3709 return h;
3710 }
3711 TopoDS_Compound picked;
3712 BRep_Builder builder;
3713 builder.MakeCompound(picked);
3714 for (int f : h.faces)
3715 if (f >= 0 && f < int(all.size()))
3716 builder.Add(picked, all[f]);
3717 try {
3718 h.edges = GeometryEngine::display_edges(picked, cached ? m_body_edges_tol[body] : display_edge_tol(*shape));
3719 } catch (const Standard_Failure&) {
3720 h.edges.clear(); // an edge that cannot be sampled costs the outline, never the fill
3721 }
3722 return h;
3723}
int body
Definition DesignSketchTool.hpp:1348
std::vector< std::vector< std::vector< Vec3d > > > m_body_edges
Definition DesignSketchTool.hpp:1289
std::vector< TopoDS_Shape > m_body_edges_shape
Definition DesignSketchTool.hpp:1290
std::vector< double > m_body_edges_tol
Definition DesignSketchTool.hpp:1291
Definition DesignSketchTool.hpp:1347
static std::vector< TopoDS_Face > faces_of(const TopoDS_Shape &shape)
Definition GeometryEngine.cpp:546
static std::vector< std::vector< Vec3d > > display_edges(const TopoDS_Shape &shape, double chord_tol)
Definition GeometryEngine.cpp:598
static double display_edge_tol(const TopoDS_Shape &shape)
Definition DesignSketchTool.cpp:3473
@ all
Definition MarchingSquares.hpp:194

References Slic3r::GUI::DesignSketchTool::FaceHighlight::body, body_shape(), Slic3r::GUI::display_edge_tol(), Slic3r::GeometryEngine::display_edges(), Slic3r::GUI::DesignSketchTool::FaceHighlight::edges, Slic3r::f(), Slic3r::GUI::DesignSketchTool::FaceHighlight::faces, Slic3r::GeometryEngine::faces_of(), is_current_shape(), m_body_edges, m_body_edges_shape, m_body_edges_tol, make_face_highlight(), and Slic3r::GUI::DesignSketchTool::FaceHighlight::shape.

Referenced by cached_face_highlight(), and make_face_highlight().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_polygon()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_polygon ( const Vec2d & center,
const Vec2d & vertex,
int sides ) const
private
3196{
3197 std::vector<SketchEntity> out;
3198 if (sides < 3) sides = 3;
3199 const Vec2d rv = vertex - center;
3200 const double d = rv.norm();
3201 if (d < 1e-6) return out;
3202 // Inscribed: cursor is a vertex (circumradius = d). Circumscribed: cursor is an
3203 // edge midpoint (apothem = d) → circumradius R = d / cos(pi/n), rotated by half
3204 // a step so an edge midpoint points at the cursor.
3205 double R = d, a0 = std::atan2(rv.y(), rv.x());
3207 R = d / std::cos(M_PI / double(sides));
3208 a0 = std::atan2(rv.y(), rv.x()) - M_PI / double(sides);
3209 }
3210 std::vector<Vec2d> verts; verts.reserve(sides);
3211 for (int i = 0; i < sides; ++i) {
3212 const double a = a0 + 2.0 * M_PI * double(i) / double(sides);
3213 verts.push_back(Vec2d(center.x() + R * std::cos(a), center.y() + R * std::sin(a)));
3214 }
3215 for (int i = 0; i < sides; ++i) {
3216 SketchEntity e; e.type = SketchEntity::Type::Line;
3217 e.p0 = verts[i]; e.p1 = verts[(i + 1) % sides];
3218 e.construction = m_construction;
3219 out.push_back(e);
3220 }
3221 return out;
3222}
bool m_polygon_circumscribed
Definition DesignSketchTool.hpp:1079

References Slic3r::center(), Slic3r::SketchEntity::construction, Slic3r::SketchEntity::Line, m_construction, M_PI, m_polygon_circumscribed, make_polygon(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, and Slic3r::SketchEntity::type.

Referenced by make_polygon(), on_mouse_impl(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_rounded_rect()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_rounded_rect ( const Vec2d & a,
const Vec2d & b,
const Vec2d & radius_pt ) const
private
3175{
3176 std::vector<SketchEntity> out;
3177 const double xmin = std::min(a.x(), b.x()), xmax = std::max(a.x(), b.x());
3178 const double ymin = std::min(a.y(), b.y()), ymax = std::max(a.y(), b.y());
3179 const double bw = xmax - xmin, bh = ymax - ymin;
3180 if (bw < 1e-6 || bh < 1e-6) return out;
3181 const Vec2d cs[4] = { {xmin,ymin}, {xmax,ymin}, {xmax,ymax}, {xmin,ymax} };
3182 double r = 1e18;
3183 for (const Vec2d& c : cs) r = std::min(r, (radius_pt - c).norm());
3184 r = std::min(r, std::min(bw, bh) * 0.5);
3185 if (r < 1e-6) { // degenerate -> plain rectangle
3186 auto line = [&](const Vec2d& p0, const Vec2d& p1) {
3187 SketchEntity e; e.type = SketchEntity::Type::Line; e.p0 = p0; e.p1 = p1;
3188 e.construction = m_construction; return e; };
3189 for (int i = 0; i < 4; ++i) out.push_back(line(cs[i], cs[(i + 1) % 4]));
3190 return out;
3191 }
3192 return rounded_rect_entities(xmin, ymin, xmax, ymax, r);
3193}
std::vector< SketchEntity > rounded_rect_entities(double xmin, double ymin, double xmax, double ymax, double r) const
Definition DesignSketchTool.cpp:3153

References Slic3r::SketchEntity::construction, Slic3r::SketchEntity::Line, m_construction, make_rounded_rect(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, rounded_rect_entities(), and Slic3r::SketchEntity::type.

Referenced by make_rounded_rect(), on_mouse_impl(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_slot()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_slot ( const Vec2d & c0,
const Vec2d & c1,
double half_width ) const
private
3091{
3092 std::vector<SketchEntity> out;
3093 Vec2d u = c1 - c0;
3094 if (u.squaredNorm() < 1e-12 || half_width < 1e-6)
3095 return out;
3096 u.normalize();
3097 const Vec2d nrm(-u.y(), u.x());
3098 const double w = half_width;
3099 // Names avoid termios macros (B0 is a baud-rate #define pulled in transitively).
3100 const Vec2d top0 = c0 + nrm * w, top1 = c1 + nrm * w; // upper side (c0 -> c1)
3101 const Vec2d bot1 = c1 - nrm * w, bot0 = c0 - nrm * w; // lower side (c1 -> c0)
3102
3103 auto line = [&](const Vec2d& p0, const Vec2d& p1) {
3104 SketchEntity e; e.type = SketchEntity::Type::Line; e.p0 = p0; e.p1 = p1;
3105 e.construction = m_construction; return e;
3106 };
3107 out.push_back(line(top0, top1)); // top
3108 out.push_back(make_arc_through(c1, w, top1, bot1, c1 + u * w, m_construction)); // cap @c1 (+u)
3109 out.push_back(line(bot1, bot0)); // bottom
3110 out.push_back(make_arc_through(c0, w, bot0, top0, c0 - u * w, m_construction)); // cap @c0 (-u)
3111 return out;
3112}

References Slic3r::SketchEntity::construction, Slic3r::SketchEntity::Line, m_construction, Slic3r::GUI::make_arc_through(), make_slot(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, and Slic3r::SketchEntity::type.

Referenced by drag_slot_handle(), make_slot(), on_mouse_impl(), render(), set_slot(), and set_slot_angle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_tangent_arc()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_tangent_arc ( const Vec2d & start,
const Vec2d & end ) const
private
3032{
3033 // Tangent direction at `start` = exit direction of the previous entity.
3034 Vec2d t(1, 0);
3035 bool have_t = false;
3036 if (!m_entities.empty()) {
3037 const SketchEntity& prev = m_entities.back();
3038 if (prev.type == SketchEntity::Type::Line) {
3039 t = prev.p1 - prev.p0; have_t = (t.squaredNorm() > 1e-12);
3040 } else if (prev.type == SketchEntity::Type::Arc) {
3041 // Tangent at the arc end p1 is perpendicular to its radius, in the
3042 // sweep direction.
3043 const Vec2d r = prev.p1 - prev.center;
3044 const double sweep = prev.end_angle - prev.start_angle;
3045 t = (sweep >= 0.0) ? Vec2d(-r.y(), r.x()) : Vec2d(r.y(), -r.x());
3046 have_t = (r.squaredNorm() > 1e-12);
3047 }
3048 }
3049 const Vec2d se = end - start;
3050 if (!have_t || se.squaredNorm() < 1e-12) {
3051 // No tangent reference or zero length: fall back to a straight line.
3052 SketchEntity e; e.type = SketchEntity::Type::Line; e.p0 = start; e.p1 = end;
3053 e.construction = m_construction;
3054 return { e };
3055 }
3056 t.normalize();
3057 const Vec2d n(-t.y(), t.x()); // unit normal to the tangent
3058 const double denom = 2.0 * n.dot(se);
3059 if (std::abs(denom) < 1e-9) { // end lies along the tangent: line
3060 SketchEntity e; e.type = SketchEntity::Type::Line; e.p0 = start; e.p1 = end;
3061 e.construction = m_construction;
3062 return { e };
3063 }
3064 const double R = se.squaredNorm() / denom; // signed radius along n
3065 const Vec2d center = start + n * R;
3066 const double radius = std::abs(R);
3067 // Mid of the tangent arc: project the chord midpoint outward onto the circle.
3068 const Vec2d chord_mid = (start + end) * 0.5;
3069 Vec2d to_mid = chord_mid - center;
3070 if (to_mid.squaredNorm() < 1e-12) to_mid = n;
3071 to_mid.normalize();
3072 const Vec2d through = center + to_mid * radius;
3073 return { make_arc_through(center, radius, start, end, through, m_construction) };
3074}

References Slic3r::SketchEntity::Arc, Slic3r::center(), Slic3r::SketchEntity::center, Slic3r::SketchEntity::construction, Slic3r::SketchEntity::end_angle, Slic3r::SketchEntity::Line, m_construction, m_entities, Slic3r::GUI::make_arc_through(), make_tangent_arc(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by make_tangent_arc(), on_mouse_impl(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_three_point_arc()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_three_point_arc ( const Vec2d & start,
const Vec2d & end,
const Vec2d & on_arc ) const
private
3024{
3025 Vec2d center; double radius;
3026 if (!circumcircle(start, end, on_arc, center, radius))
3027 return {};
3028 return { make_arc_through(center, radius, start, end, on_arc, m_construction) };
3029}
static bool circumcircle(const Vec2d &a, const Vec2d &b, const Vec2d &c, Vec2d &center, double &radius)
Definition DesignSketchTool.cpp:2969

References Slic3r::center(), Slic3r::GUI::circumcircle(), m_construction, Slic3r::GUI::make_arc_through(), and make_three_point_arc().

Referenced by make_three_point_arc(), on_mouse_impl(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ make_three_point_circle()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::make_three_point_circle ( const Vec2d & a,
const Vec2d & b,
const Vec2d & c ) const
private
3010{
3011 Vec2d center; double radius;
3012 if (!circumcircle(a, b, c, center, radius))
3013 return {};
3014 SketchEntity e;
3016 e.center = center;
3017 e.p0 = center;
3018 e.radius = radius;
3019 e.construction = m_construction;
3020 return { e };
3021}

References Slic3r::center(), Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::GUI::circumcircle(), Slic3r::SketchEntity::construction, m_construction, make_three_point_circle(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::radius, and Slic3r::SketchEntity::type.

Referenced by make_three_point_circle(), on_mouse_impl(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ measure_dim()

double Slic3r::GUI::DesignSketchTool::measure_dim ( const DimAnnot & a) const
private
1240{
1241 Vec2d pa, pb;
1242 switch (a.kind) {
1243 case DimType::Length:
1244 return (a.ea >= 0 && a.ea < int(m_entities.size()))
1245 ? (m_entities[a.ea].p1 - m_entities[a.ea].p0).norm() : 0.0;
1246 case DimType::Diameter:
1247 return (a.ea >= 0 && a.ea < int(m_entities.size())) ? 2.0 * m_entities[a.ea].radius : 0.0;
1248 case DimType::Radius:
1249 return (a.ea >= 0 && a.ea < int(m_entities.size())) ? m_entities[a.ea].radius : 0.0;
1250 case DimType::Angle: {
1251 // Single line: angle to the +X axis, normalised to [0,360). (Line-to-line angle
1252 // dimensions use the legacy dialog path.)
1253 if (a.ea < 0 || a.ea >= int(m_entities.size())) return 0.0;
1254 const SketchEntity& e = m_entities[a.ea];
1255 if (e.type != SketchEntity::Type::Line) return 0.0;
1256 const Vec2d d = e.p1 - e.p0;
1257 if (d.squaredNorm() < 1e-18) return 0.0;
1258 double deg = std::atan2(d.y(), d.x()) * 180.0 / M_PI;
1259 if (deg < 0.0) deg += 360.0;
1260 return deg;
1261 }
1262 case DimType::Distance:
1263 return (point_at(a.ea, a.ra, pa) && point_at(a.eb, a.rb, pb)) ? (pb - pa).norm() : 0.0;
1265 if (!point_at(a.ea, a.ra, pa) || a.eb < 0 || a.eb >= int(m_entities.size())) return 0.0;
1266 const SketchEntity& L = m_entities[a.eb];
1267 const Vec2d d = L.p1 - L.p0;
1268 const double n = d.norm();
1269 if (n < 1e-9) return 0.0;
1270 const Vec2d nrm(-d.y() / n, d.x() / n);
1271 return std::abs((pa - L.p0).dot(nrm));
1272 }
1273 default: return 0.0;
1274 }
1275}

References Angle, Diameter, Distance, DistanceToLine, Slic3r::GUI::DesignSketchTool::DimAnnot::ea, Slic3r::GUI::DesignSketchTool::DimAnnot::eb, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, L, Length, Slic3r::SketchEntity::Line, m_entities, M_PI, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, point_at(), Slic3r::GUI::DesignSketchTool::DimAnnot::ra, Radius, Slic3r::GUI::DesignSketchTool::DimAnnot::rb, and Slic3r::SketchEntity::type.

Referenced by open_angle_editor(), open_primary_autoedit(), place_dimension(), and render_live_quotes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mode()

Mode Slic3r::GUI::DesignSketchTool::mode ( ) const
inline
107{ return m_mode; }

References m_mode.

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_describe(), begin(), confirm_transform(), and set_tool().

Here is the caller graph for this function:

◆ move_body_index()

int Slic3r::GUI::DesignSketchTool::move_body_index ( ) const
inline
285{ return m_mv_body; }

References m_mv_body.

◆ move_gizmo_arm()

double Slic3r::GUI::DesignSketchTool::move_gizmo_arm ( const Camera & cam) const
private
5827{
5828 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
5829 const double screen_min = 70.0 * upp; // never smaller than the old fixed size
5830 return std::max(screen_min, m_mv_radius * 1.25); // 25% clear of the body surface
5831}
double m_mv_radius
Definition DesignSketchTool.hpp:1467

References Slic3r::GUI::Camera::get_zoom(), m_mv_radius, and move_gizmo_arm().

Referenced by hit_test_move_arc(), hit_test_move_arrow(), move_gizmo_arm(), and render_move_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ notify()

void Slic3r::GUI::DesignSketchTool::notify ( const std::string & msg,
bool error = true )
inline
702{ if (on_notice) on_notice(msg, error); }
std::function< void(const std::string &msg, bool error)> on_notice
Definition DesignSketchTool.hpp:701

References on_notice.

Referenced by announce_loop_defects(), apply_dimension(), confirm_op(), confirm_transform(), on_mouse_impl(), op_pick(), resolve_live_drag(), set_dimension_value(), and show_refusal().

Here is the caller graph for this function:

◆ on_mouse()

bool Slic3r::GUI::DesignSketchTool::on_mouse ( wxMouseEvent & evt,
GLCanvas3D & canvas )
10774{
10775 if (evt.RightDown()) {
10776 m_right_press = evt;
10777 return false;
10778 }
10779 return on_mouse_impl(evt, canvas);
10780}
bool on_mouse_impl(wxMouseEvent &evt, GLCanvas3D &canvas)
Definition DesignSketchTool.cpp:10788

References m_right_press, on_mouse(), on_mouse_impl(), and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ on_mouse_impl()

bool Slic3r::GUI::DesignSketchTool::on_mouse_impl ( wxMouseEvent & evt,
GLCanvas3D & canvas )
private
10789{
10790 // Track the cursor in canvas client px so the in-canvas value editor can open right
10791 // where the user clicked (Onshape places the field at the click, not via a camera
10792 // projection — the design canvas's viewport isn't valid outside its own paint).
10793 m_last_mouse_x = evt.GetX();
10794 m_last_mouse_y = evt.GetY();
10795
10796 // Line draw-then-edit: while the length editor is open right after the second click,
10797 // freeze the canvas so a stray move/click can't push a third point or rubber-band a
10798 // segment under the floating field. The editor's Enter/Esc resolves it
10799 // (apply_segment_length / keep_segment_as_drawn, the latter clears this flag).
10800 if (m_awaiting_length) {
10801 // Polyline terminators must work even with a per-segment field open: right-click or
10802 // double-click accepts the current segment as drawn (close the field) and falls through
10803 // so the Polyline handler ends the chain. Without this the freeze ate every terminator.
10804 if (m_mode == Mode::Polyline && (evt.RightDown() || evt.LeftDClick()) && on_inline_dismiss)
10805 on_inline_dismiss(); // -> set_inline_busy(false), m_awaiting_length=false
10806 // The freeze exists so a stray click can't draw under the floating field — it was
10807 // never meant to trap the camera. Let drags and the wheel through, so a field that
10808 // opens somewhere unexpected can't leave the viewport unusable.
10809 else if (evt.Dragging() || evt.GetWheelRotation() != 0)
10810 return false;
10811 // A click elsewhere accepts the typed value, as Enter would (the field then advances or
10812 // closes). The click itself is still swallowed: it was aimed at leaving the field, not
10813 // at drawing, and a point placed by it would land under a field that just vanished.
10814 else if (evt.LeftDown()) {
10816 return true;
10817 }
10818 else
10819 return true;
10820 }
10821
10822 // No live session, but committed sketches are shown as overlays on the plate: a left
10823 // click on a loop (its edge OR its closed interior) selects that Sketch feature. This
10824 // is the ONLY interaction in display-only mode; everything else (drag/move/wheel/right)
10825 // falls through (return false) so the camera can still orbit the plate.
10826 if (!m_active) {
10827 // Double-click on a committed sketch stroke OPENS IT FOR EDITING; on empty space it
10828 // still fits the view. A sketch line has to be editable from the line, not from a tree
10829 // row — selecting it already lit the feature, but "now go and press Edit in the panel"
10830 // is the side-panel dependency this tab exists to remove. Fit keeps the rest of the
10831 // plate, so nothing is taken away.
10832 if (evt.LeftDClick()) {
10833 int f = -1, r = -1, e = -1, ff = -1, fr = -1; double dbest = 1e30;
10834 const Linef3 dray = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
10835 const Linef3 dray8 = canvas.mouse_ray(Point(evt.GetX() + 8, evt.GetY()));
10836 for (const DisplaySketch& d : m_display_sketches) {
10837 const Vec2d dp = d.plane.project(dray.a, dray.vector());
10838 const Vec2d dp8 = d.plane.project(dray8.a, dray8.vector());
10839 hit_display_sketch(d, dp, std::max(1e-3, (dp8 - dp).norm()), f, r, e, dbest, ff, fr);
10840 }
10841 const int target = (f >= 0) ? f : ff;
10842 if (target >= 0 && on_display_sketch_activated) {
10843 dp_pick_trace("double-click -> edit sketch feature %d (entity %d)", target, e);
10845 return true;
10846 }
10847 canvas.zoom_to_volumes();
10848 return true;
10849 }
10850 // Move-body gizmo (M5): three world-axis arrows on the selected body. Drag an arrow to
10851 // translate live; a stationary click on it opens the inline offset editor; a right click
10852 // opens the offer. Anything else is the camera's: see the end of this block.
10853 if (m_mv_active) {
10854 if (m_mv_drag >= 0 && evt.Dragging() && evt.LeftIsDown()) {
10855 if (m_mv_drag < 3) drag_move_arrow(canvas.mouse_ray(Point(evt.GetX(), evt.GetY())));
10856 else drag_move_arc(canvas, evt, m_mv_drag - 3);
10857 return true;
10858 }
10859 if (evt.LeftUp() && m_mv_drag >= 0) {
10860 const int d = m_mv_drag; m_mv_drag = -1;
10861 const bool moved = std::abs(evt.GetX() - m_mv_press_x) +
10862 std::abs(evt.GetY() - m_mv_press_y) > 3;
10863 if (!moved && d < 3) open_move_editor(d); // stationary click on an arrow = edit offset
10864 return true;
10865 }
10866 // Right-click opens the offer; the move is kept with Enter/✓ and reverted with Esc/✗,
10867 // like every other pending edit. It used to keep the move and close the gizmo — a
10868 // commit on the one button the charter reserves for "what can I do here".
10869 if (evt.RightDown()) return false;
10870 if (evt.LeftDown()) {
10871 int axis = -1;
10872 if (hit_test_move_arrow(canvas, evt, axis)) { // translate arrows win over rings
10873 grab_move_arrow(axis, canvas.mouse_ray(Point(evt.GetX(), evt.GetY())));
10874 m_mv_press_x = evt.GetX(); m_mv_press_y = evt.GetY();
10875 return true;
10876 }
10877 if (hit_test_move_arc(canvas, evt, axis)) {
10878 m_mv_drag = 3 + axis; m_mv_press_x = evt.GetX(); m_mv_press_y = evt.GetY();
10880 double a0; if (arc_mouse_angle(canvas, evt, axis, a0)) m_mv_arc_a0 = a0;
10881 return true;
10882 }
10883 // Off the gizmo a press only steers the camera: no pick, so the selection the
10884 // Move acts on is held until it ends.
10885 return false;
10886 }
10887 if (evt.Moving()) return false; // no hover outline: see set_move_gizmo
10888 }
10889 // Datum-plane resize gizmo (C3): while the Plane card is open the 4 edge handles are
10890 // grabbable — drag changes the u/v extent live. A LeftDown that misses falls through.
10891 if (m_dz_active) {
10892 if (m_dz_drag >= 0 && evt.Dragging() && evt.LeftIsDown()) {
10893 drag_datum_handle(canvas, evt, m_dz_drag);
10894 return true;
10895 }
10896 if (evt.LeftUp() && m_dz_drag >= 0) { m_dz_drag = -1; return true; }
10897 if (evt.LeftDown()) {
10898 int which = -1;
10899 if (hit_test_datum_handle(canvas, evt, which)) {
10900 m_dz_drag = which; m_dz_press_x = evt.GetX(); m_dz_press_y = evt.GetY();
10901 return true;
10902 }
10903 }
10904 }
10905 // Helix gizmo: radius/height/pitch handles on the live curve, while the Helix card is open.
10906 if (m_hx_active) {
10907 if (m_hx_drag >= 0 && evt.Dragging() && evt.LeftIsDown()) {
10908 drag_helix_handle(canvas, evt, m_hx_drag);
10909 return true;
10910 }
10911 if (evt.LeftUp() && m_hx_drag >= 0) { m_hx_drag = -1; return true; }
10912 if (evt.LeftDown()) {
10913 int which = -1;
10914 if (hit_test_helix_handle(canvas, evt, which)) {
10915 m_hx_drag = which; m_hx_press_x = evt.GetX(); m_hx_press_y = evt.GetY();
10916 return true;
10917 }
10918 }
10919 }
10920 // Rib thickness gizmo: two in-plane handles on the slab footprint, while the Rib card is open.
10921 if (m_rb_active) {
10922 if (m_rb_drag >= 0 && evt.Dragging() && evt.LeftIsDown()) {
10923 drag_rib_handle(canvas, evt, m_rb_drag);
10924 return true;
10925 }
10926 if (evt.LeftUp() && m_rb_drag >= 0) { m_rb_drag = -1; return true; }
10927 if (evt.LeftDown()) {
10928 int which = -1;
10929 if (hit_test_rib_handle(canvas, evt, which)) {
10930 m_rb_drag = which;
10931 return true;
10932 }
10933 }
10934 }
10935 // Datum base picker: HOVER highlight only here. The CLICK is handled at the very end of the
10936 // selection fall-through (below), so picking existing geometry (committed sketch loops,
10937 // solid faces/edges) always wins over a base-plane click — the planes never block selection.
10938 if (m_dbp_active && evt.Moving() && !evt.LeftIsDown()) {
10939 const int h = hit_test_base_pick(canvas, evt);
10940 if (h != m_dbp_hover) {
10941 m_dbp_hover = h;
10942 canvas.set_as_dirty();
10943 if (h >= 0) return true; // caller render()s on true -> hover repaints on software GL
10944 }
10945 }
10946 // Visual Extrude gizmo (C5b): while the Extrude card is open the depth arrow is
10947 // grabbable — drag changes the depth live; a click (no drag) on the arrow opens the
10948 // inline depth editor. Intercept before the early no-LeftDown bailout so Dragging/
10949 // LeftUp reach us; a LeftDown that misses the arrow falls through to solid/loop pick.
10950 if (m_ex_active) {
10951 if (m_ex_drag >= 0 && evt.Dragging() && evt.LeftIsDown()) {
10952 drag_extrude_arrow(canvas, evt, m_ex_drag);
10953 return true;
10954 }
10955 if (evt.LeftUp() && m_ex_drag >= 0) {
10956 const int which = m_ex_drag; m_ex_drag = -1;
10957 const bool moved = std::abs(evt.GetX() - m_ex_press_x) +
10958 std::abs(evt.GetY() - m_ex_press_y) > 3;
10959 if (!moved) open_extrude_editor(which); // treat a stationary click as edit
10960 return true;
10961 }
10962 if (evt.LeftDown()) {
10963 int which = -1;
10964 if (hit_test_extrude_arrow(canvas, evt, which)) {
10965 m_ex_drag = which; m_ex_press_x = evt.GetX(); m_ex_press_y = evt.GetY();
10966 return true;
10967 }
10968 }
10969 }
10970 // Revolve angle-arc gizmo: drag the arc tip to sweep the angle; a stationary click on the
10971 // handle opens the inline editor. A LeftDown that misses falls through to normal picking.
10972 if (m_rv_active) {
10973 if (m_rv_drag && evt.Dragging() && evt.LeftIsDown()) {
10974 drag_revolve_arc(canvas, evt);
10975 return true;
10976 }
10977 if (evt.LeftUp() && m_rv_drag) {
10978 m_rv_drag = false;
10979 const bool moved = std::abs(evt.GetX() - m_rv_press_x) +
10980 std::abs(evt.GetY() - m_rv_press_y) > 3;
10981 if (!moved) open_revolve_editor();
10982 return true;
10983 }
10984 if (evt.LeftDown() && hit_test_revolve_handle(canvas, evt)) {
10985 m_rv_drag = true; m_rv_press_x = evt.GetX(); m_rv_press_y = evt.GetY();
10986 return true;
10987 }
10988 }
10989 // Draft angle-arc gizmo: drag the arc tip to sweep the draft angle; a stationary click
10990 // edits it. A LeftDown that misses falls through to normal picking.
10991 if (m_dr_active) {
10992 if (m_dr_drag && evt.Dragging() && evt.LeftIsDown()) {
10993 drag_draft_arc(canvas, evt);
10994 return true;
10995 }
10996 if (evt.LeftUp() && m_dr_drag) {
10997 m_dr_drag = false;
10998 return true;
10999 }
11000 if (evt.LeftDown() && hit_test_draft_handle(canvas, evt)) {
11001 m_dr_drag = true; m_dr_press_x = evt.GetX(); m_dr_press_y = evt.GetY();
11002 return true;
11003 }
11004 }
11005 // Cut gizmo: drag the offset arrow along the cut-plane normal; no positive clamp (offset is signed).
11006 if (m_ct_active) {
11007 if (m_ct_drag && evt.Dragging() && evt.LeftIsDown()) {
11008 drag_cut_arrow(canvas, evt);
11009 return true;
11010 }
11011 if (evt.LeftUp() && m_ct_drag) {
11012 m_ct_drag = false;
11013 return true;
11014 }
11015 if (evt.LeftDown() && hit_test_cut_arrow(canvas, evt)) {
11016 start_cut_drag(canvas, evt);
11017 return true;
11018 }
11019 }
11020 // Pattern gizmo: drag the diamond/arc handle to set the spacing (linear) or angle (circular);
11021 // a stationary click opens the inline editor. A LeftDown that misses falls through to picking.
11022 if (m_pt_active) {
11023 if (m_pt_drag && evt.Dragging() && evt.LeftIsDown()) {
11024 drag_pattern_handle(canvas, evt);
11025 return true;
11026 }
11027 if (evt.LeftUp() && m_pt_drag) {
11028 m_pt_drag = false;
11029 const bool moved = std::abs(evt.GetX() - m_pt_press_x) +
11030 std::abs(evt.GetY() - m_pt_press_y) > 3;
11031 if (!moved) open_pattern_editor();
11032 return true;
11033 }
11034 if (evt.LeftDown() && hit_test_pattern_handle(canvas, evt)) {
11035 m_pt_drag = true; m_pt_press_x = evt.GetX(); m_pt_press_y = evt.GetY();
11036 return true;
11037 }
11038 }
11039 // Fillet/Chamfer radius gizmo: drag the edge-anchored arrow to set the radius live; a
11040 // stationary click opens the inline editor. A LeftDown that misses falls through to pick.
11041 if (m_fl_active) {
11042 if (m_fl_drag && evt.Dragging() && evt.LeftIsDown()) {
11043 drag_fillet_arrow(canvas, evt);
11044 return true;
11045 }
11046 if (evt.LeftUp() && m_fl_drag) {
11047 m_fl_drag = false;
11048 const bool moved = std::abs(evt.GetX() - m_fl_press_x) +
11049 std::abs(evt.GetY() - m_fl_press_y) > 3;
11050 if (!moved) open_fillet_editor(); // stationary click = edit
11051 return true;
11052 }
11053 if (evt.LeftDown() && hit_test_fillet_arrow(canvas, evt)) {
11054 start_fillet_drag(canvas, evt);
11055 return true;
11056 }
11057 }
11058 // Hole gizmo: drag the centre to reposition / the diameter or depth arrow to resize; a
11059 // stationary click on an arrow opens its inline editor. A LeftDown that misses any handle
11060 // falls through to solid/loop picking.
11061 if (m_hl_active) {
11062 if (m_hl_drag >= 0 && evt.Dragging() && evt.LeftIsDown()) {
11063 drag_hole_handle(canvas, evt);
11064 return true;
11065 }
11066 if (evt.LeftUp() && m_hl_drag >= 0) {
11067 const int which = m_hl_drag; m_hl_drag = -1;
11068 const bool moved = std::abs(evt.GetX() - m_hl_press_x) +
11069 std::abs(evt.GetY() - m_hl_press_y) > 3;
11070 if (!moved) open_hole_editor(which); // stationary click = edit
11071 return true;
11072 }
11073 if (evt.LeftDown()) {
11074 const int which = hit_test_hole_handle(canvas, evt);
11075 if (which >= 0) { start_hole_drag(canvas, evt, which); return true; }
11076 }
11077 }
11078 // Thread gizmo: same interaction as the hole gizmo (centre / radius / length handles).
11079 if (m_th_active) {
11080 if (m_th_drag >= 0 && evt.Dragging() && evt.LeftIsDown()) {
11081 drag_thread_handle(canvas, evt);
11082 return true;
11083 }
11084 if (evt.LeftUp() && m_th_drag >= 0) {
11085 const int which = m_th_drag; m_th_drag = -1;
11086 const bool moved = std::abs(evt.GetX() - m_th_press_x) +
11087 std::abs(evt.GetY() - m_th_press_y) > 3;
11088 if (!moved) open_thread_editor(which);
11089 return true;
11090 }
11091 if (evt.LeftDown()) {
11092 const int which = hit_test_thread_handle(canvas, evt);
11093 if (which >= 0) { start_thread_drag(canvas, evt, which); return true; }
11094 }
11095 }
11096 // Shell gizmo: drag the inward thickness arrow; stationary click opens the inline editor.
11097 if (m_sh_active) {
11098 if (m_sh_drag && evt.Dragging() && evt.LeftIsDown()) {
11099 drag_shell_arrow(canvas, evt);
11100 return true;
11101 }
11102 if (evt.LeftUp() && m_sh_drag) {
11103 m_sh_drag = false;
11104 const bool moved = std::abs(evt.GetX() - m_sh_press_x) +
11105 std::abs(evt.GetY() - m_sh_press_y) > 3;
11106 if (!moved) open_shell_editor();
11107 return true;
11108 }
11109 if (evt.LeftDown() && hit_test_shell_arrow(canvas, evt)) {
11110 start_shell_drag(canvas, evt);
11111 return true;
11112 }
11113 }
11114 // Left-drag rubber band -> whole body. Past the click budget the press becomes a sweep:
11115 // the rectangle is anchored at the ORIGINAL press point (not at the frame where the
11116 // threshold was crossed, which would lose the first few pixels) and the events are
11117 // consumed from here on. The camera follows Preferences > Control as in Prepare, so while
11118 // left-drag is given to Rotate or Pan the band takes Shift+left-drag, Prepare's own
11119 // rectangle selection.
11120 // HOVER PRE-HIGHLIGHT (9xw part 3): say what a click would take, before it is
11121 // taken. Plain motion only — no button down, no band running — because during a drag the
11122 // pointer is doing something else and a promise about clicking would be a lie. Returns
11123 // false so the event still reaches the camera; this only asks for a repaint, it does not
11124 // consume the gesture, which is the difference between a hint and a handler.
11125 if (evt.Moving() && !evt.LeftIsDown() && !m_rubber.is_dragging()) {
11126 if (update_solid_hover(canvas, evt)) canvas.set_as_dirty();
11127 return false;
11128 }
11129 const bool left_drag_sweeps =
11130 evt.ShiftDown() || std::atoi(wxGetApp().app_config->get("left_mouse_drag_action").c_str()) == 0;
11131 if (evt.Dragging() && evt.LeftIsDown() && m_pick_pending && (left_drag_sweeps || m_rubber.is_dragging())) {
11132 if (!m_rubber.is_dragging()) {
11133 if (std::max(std::abs(evt.GetX() - m_pick_press_x),
11134 std::abs(evt.GetY() - m_pick_press_y)) <= 8)
11135 return false; // still inside the click budget
11138 }
11139 m_rubber.dragging(Vec2d(evt.GetX(), evt.GetY()));
11140 return true;
11141 }
11142 // Any event with the left button up ends a band — not just LeftUp. A release that lands
11143 // outside the canvas never sends us one, and a band left running would then paint a
11144 // rectangle that follows the cursor with no button held.
11145 if (m_rubber.is_dragging() && !evt.LeftIsDown()) {
11146 m_pick_pending = false;
11147 if (evt.LeftUp()) pick_bodies_in_rectangle(); // a release elsewhere selects nothing
11148 m_rubber.stop_dragging();
11149 return evt.LeftUp();
11150 }
11151 // Click vs drag. Consuming the LeftDown here killed camera orbit/pan the moment a
11152 // solid was on screen: Orca starts a rotate drag on the press, so swallowing it meant
11153 // the canvas never began one. (A SpaceMouse kept working — it never goes through
11154 // wxMouseEvent.) Remember the press, let it fall through so the canvas can orbit, and
11155 // resolve the pick on release only if the pointer stayed put.
11156 if (evt.LeftDown()) {
11157 m_pick_press_x = evt.GetX();
11158 m_pick_press_y = evt.GetY();
11159 m_pick_pending = true;
11160 dp_pick_trace("down x=%d y=%d", evt.GetX(), evt.GetY());
11161 return false;
11162 }
11163 if (!(evt.LeftUp() && m_pick_pending)) {
11164 if (evt.LeftUp()) dp_pick_trace("up with no pending press (press was eaten upstream)");
11165 return false;
11166 }
11167 m_pick_pending = false;
11168 dp_pick_trace("up x=%d y=%d drift=%d", evt.GetX(), evt.GetY(),
11169 std::max(std::abs(evt.GetX() - m_pick_press_x),
11170 std::abs(evt.GetY() - m_pick_press_y)));
11171 // Threshold per axis, at GTK's own drag threshold. A hand-held mouse drifts several
11172 // pixels during an ordinary click — a tight budget silently swallowed real clicks and
11173 // looked exactly like "selection does not work". Synthetic clicks never drift, which
11174 // is why the headless rig could not show this.
11175 if (std::max(std::abs(evt.GetX() - m_pick_press_x),
11176 std::abs(evt.GetY() - m_pick_press_y)) > 8) {
11177 dp_pick_trace("rejected as drag");
11178 return false; // it was a drag: the canvas already orbited, don't also select
11179 }
11180 // Committed-sketch loop pick is computed FIRST. A click that lands on a loop's
11181 // STROKE (edge) selects that loop even when it lies on a solid face — so a sketch
11182 // drawn ON a face can be selected and extruded/cut (Onshape engraving workflow).
11183 // Open-face area (no loop stroke under the cursor) falls through to the solid
11184 // whole/face/edge cycle; an interior hit with no solid behind it is the last resort.
11185 Point pos(evt.GetX(), evt.GetY());
11186 const Linef3 ray = canvas.mouse_ray(pos);
11187 const Linef3 ray8 = canvas.mouse_ray(Point(evt.GetX() + 8, evt.GetY()));
11188 int edge_feat = -1, edge_reg = -1, edge_ent = -1; double edge_d = 1e30; // nearest stroke
11189 int face_feat = -1, face_reg = -1; // interior (fallback)
11190 dp_pick_trace("display sketches available: %zu", m_display_sketches.size());
11191 for (const DisplaySketch& d : m_display_sketches) {
11192 const Vec2d p = d.plane.project(ray.a, ray.vector());
11193 const Vec2d p8 = d.plane.project(ray8.a, ray8.vector());
11194 const double tol = std::max(1e-3, (p8 - p).norm());
11195 hit_display_sketch(d, p, tol, edge_feat, edge_reg, edge_ent, edge_d, face_feat, face_reg);
11196 }
11197 // A precise hit on a loop outline wins over the solid face beneath it.
11198 if (edge_feat >= 0) {
11199 m_display_pick = edge_feat; m_display_pick_region = edge_reg;
11200 if (on_display_sketch_selected) on_display_sketch_selected(edge_feat, edge_reg, edge_ent);
11201 return true;
11202 }
11203 // No loop stroke under the cursor: the solid is the foreground (whole/face/edge cycle).
11204 if (handle_solid_click(canvas, evt)) return true;
11205 // Interior of a committed loop with no solid behind it.
11206 if (face_feat >= 0) {
11207 m_display_pick = face_feat; m_display_pick_region = face_reg;
11208 if (on_display_sketch_selected) on_display_sketch_selected(face_feat, face_reg, -1);
11209 return true;
11210 }
11211 m_display_pick = -1; m_display_pick_region = -1; // clicked bare plate -> drop highlight
11212 // ...and the SOLID selection goes with it (od0). A click that hits nothing has to
11213 // mean what a rubber band that sweeps nothing already means — pick_bodies_in_rectangle
11214 // clears on an empty sweep, and the two gestures cannot disagree about the same outcome.
11215 // Until now the face survived a click on bare plate, so "click away, then click the face
11216 // again" arrived here as the SECOND click on the same face and escalated to the whole
11217 // body, when the click away was the user letting go of it.
11218 //
11219 // The cost is real and is the intended trade: Thicken / Shell / Draft hold their input
11220 // face in the panel's m_sel_solid_face, so a stray click on empty canvas with one of
11221 // those cards open gives that face back. Their handlers already write the "(pick a solid
11222 // face)" placeholder and rebuild the ghost at level 0, so the card SAYS it lost the pick
11223 // rather than confirming against a face the viewport has stopped highlighting.
11224 //
11225 // Guarded on there being something to clear: this runs on every click that misses, and
11226 // the callback re-renders the open card's preview.
11227 if (m_solid_sel != SolidSel::None) {
11229 dp_pick_trace("clicked empty space -> selection cleared");
11232 }
11233 // Last resort: a click that hit no geometry but landed on a reference/base plane picks it.
11234 if (m_dbp_active) {
11235 const int h = hit_test_base_pick(canvas, evt);
11236 if (h >= 0 && h < int(m_dbp_base.size())) {
11238 return true;
11239 }
11240 }
11242 return false; // let the stock canvas orbit / deselect
11243 }
11244
11245 // In-canvas edit-op tools (Fillet/Chamfer/Offset/Mirror): pick entities, then a
11246 // draggable arrow + editable value label (Mirror: a two-phase pick) drives a live
11247 // ghost. Enter or ✓ applies, Esc or right-click discards (charter 4.2).
11248 // Standalone Trim / Extend scissors: click a segment to cut it back to (Trim) or out to
11249 // (Extend) its nearest intersection with the other live entities. One cut per click; the
11250 // tool stays active for more cuts; right-click exits. Drag falls through so the camera can
11251 // still orbit. Operates directly on the live sketch — no Constrain mode.
11252 if (m_mode == Mode::Trim || m_mode == Mode::Extend) {
11253 if (evt.Moving()) { screen_to_plane(canvas, evt, m_cursor); m_has_cursor = true; return true; }
11254 if (evt.LeftDown()) {
11255 Vec2d p; screen_to_plane(canvas, evt, p);
11256 const Linef3 r2 = canvas.mouse_ray(Point(evt.GetX() + 8, evt.GetY()));
11257 const double tol = std::max(1e-3, (m_plane.project(r2.a, r2.vector()) - p).norm());
11258 if (apply_live_trim(p, screen_tol(canvas, evt, p, kToolPickPx), m_mode == Mode::Extend)) {
11259 resolve_live();
11260 } else {
11261 // nde #15: don't fail silently. The pick found nothing to cut/extend — either
11262 // the click missed every live segment, or the picked segment has no crossing /
11263 // target among the OTHER live entities (committed sketches aren't trimmed).
11265 ? _u8L("Extend: click a line or an arc that can reach another entity")
11266 : _u8L("Trim: click a segment where it crosses another entity"));
11267 }
11268 return true;
11269 }
11270 if (evt.RightDown()) return false; // nothing pending to abandon: the offer opens
11271 return false; // let move/drag orbit the camera
11272 }
11273
11274 if (is_edit_op_mode()) {
11275 if (evt.Moving()) {
11276 screen_to_plane(canvas, evt, m_cursor);
11277 m_has_cursor = true;
11278 return true;
11279 }
11280 if (m_op_dragging_arrow && evt.Dragging() && evt.LeftIsDown()) {
11281 Vec2d p; screen_to_plane(canvas, evt, p);
11282 drag_op_arrow(p);
11283 return true;
11284 }
11285 if (evt.LeftUp()) {
11286 if (m_op_dragging_arrow) { m_op_dragging_arrow = false; return true; }
11287 return false;
11288 }
11289 if (evt.LeftDown()) {
11290 Vec2d p; screen_to_plane(canvas, evt, p);
11291 const Linef3 r2 = canvas.mouse_ray(Point(evt.GetX() + 8, evt.GetY()));
11292 const double tol = std::max(1e-3, (m_plane.project(r2.a, r2.vector()) - p).norm());
11293 // 1) live gizmo: click the value label to type, or grab the arrow to drag.
11294 if (op_ready() && m_mode != Mode::Mirror) {
11295 const double ltol = std::max(tol, screen_tol(canvas, evt, p, kLabelPx));
11296 if ((m_op_label - p).norm() <= ltol) { open_op_editor(); return true; }
11297 if (hit_test_op_arrow(p, tol)) { m_op_dragging_arrow = true; return true; }
11298 }
11299 // 2) entity pick (close enough to an entity edge).
11300 double best = 1e30; int bi = -1;
11301 for (size_t i = 0; i < m_entities.size(); ++i) {
11302 const double d = entity_pick_dist(p, m_entities[i]);
11303 if (d < best) { best = d; bi = int(i); }
11304 }
11305 if (bi >= 0 && best <= screen_tol(canvas, evt, p, kToolPickPx)) { op_pick(bi); return true; }
11306 // 3) Empty space never commits (charter 4.2 withdrew that invisible gesture). A ready
11307 // op stays pending and says how to finish it; half-made picks are a selection, and
11308 // empty space clears a selection.
11309 if (op_ready()) notify(_u8L("Press Enter or ✓ to apply, Esc to discard"), false);
11310 else if (m_op_a >= 0) { reset_op(); m_selection.clear(); if (on_selection_changed) on_selection_changed(0); }
11311 return true;
11312 }
11313 if (evt.RightDown()) {
11314 // The draw tools' rule (right_abandon): drop what is pending, else hand the click
11315 // back so the offer opens. Leaving the tool is Esc's job, not right-click's.
11316 if (m_op_a < 0 && m_mirror_targets.empty()) return false;
11317 reset_op();
11318 m_selection.clear();
11320 return true;
11321 }
11322 return false;
11323 }
11324
11325 // In-canvas transform tools (Move/Rotate/Scale/Array/PolarArray): pick subject
11326 // entities, then a single draggable handle + editable value label(s) drive a live
11327 // ghost. Enter or ✓ applies, Esc or right-click discards the pending transform.
11328 if (is_transform_mode()) {
11329 if (evt.Moving()) {
11330 screen_to_plane(canvas, evt, m_cursor);
11331 m_has_cursor = true;
11332 return true;
11333 }
11334 if (m_tf_dragging && evt.Dragging() && evt.LeftIsDown()) {
11335 Vec2d p; screen_to_plane(canvas, evt, p);
11336 drag_tf_handle(p);
11337 return true;
11338 }
11339 if (evt.LeftUp()) {
11340 if (m_tf_dragging) { m_tf_dragging = false; return true; }
11341 return false;
11342 }
11343 if (evt.LeftDown()) {
11344 Vec2d p; screen_to_plane(canvas, evt, p);
11345 const Linef3 r2 = canvas.mouse_ray(Point(evt.GetX() + 8, evt.GetY()));
11346 const double tol = std::max(1e-3, (m_plane.project(r2.a, r2.vector()) - p).norm());
11347 // 1) live gizmo: click a value label to type, or grab the handle to drag.
11348 if (tf_ready()) {
11349 const double ltol = std::max(tol, screen_tol(canvas, evt, p, kLabelPx));
11350 if ((m_tf_label_a - p).norm() <= ltol) { open_tf_editor_a(); return true; }
11351 if ((m_tf_label_b - p).norm() <= ltol) { open_tf_editor_count(); return true; }
11352 if (hit_test_tf_handle(p, tol)) { m_tf_dragging = true; return true; }
11353 }
11354 // 2) entity pick (close enough to an entity edge).
11355 double best = 1e30; int bi = -1;
11356 for (size_t i = 0; i < m_entities.size(); ++i) {
11357 const double d = entity_pick_dist(p, m_entities[i]);
11358 if (d < best) { best = d; bi = int(i); }
11359 }
11360 if (bi >= 0 && best <= screen_tol(canvas, evt, p, kToolPickPx)) { tf_pick(bi); return true; }
11361 // 3) Empty space never commits (charter 4.2): the pending transform waits for Enter/✓.
11362 if (tf_ready()) notify(_u8L("Press Enter or ✓ to apply, Esc to discard"), false);
11363 return true;
11364 }
11365 if (evt.RightDown()) {
11366 if (m_tf_targets.empty()) return false; // nothing to abandon: the offer opens
11367 reset_tf();
11368 m_selection.clear();
11370 return true;
11371 }
11372 return false;
11373 }
11374
11375 // Imported-art bbox transform: drag a corner to scale, the centre to move. Right-click
11376 // ends the session. Values stream live to the host via on_imported_transform.
11377 if (m_mode == Mode::TransformArt) {
11378 if (evt.Moving()) {
11379 screen_to_plane(canvas, evt, m_cursor);
11380 m_has_cursor = true;
11381 return true;
11382 }
11383 if (evt.LeftDown()) {
11384 Vec2d p; screen_to_plane(canvas, evt, p);
11385 const double tol = screen_tol(canvas, evt, p, kPickPx);
11386 const int h = hit_test_xform_handle(p, tol);
11387 if (h >= 0) {
11388 m_xform_handle = h;
11389 if (h == 4) m_xform_anchor = p; // centre move: track the delta
11390 else { Vec2d c[4]; xform_world_corners(c); m_xform_anchor = c[(h + 2) % 4]; }
11391 }
11392 return true; // swallow (no camera orbit while placing)
11393 }
11394 if (m_xform_handle >= 0 && evt.Dragging() && evt.LeftIsDown()) {
11395 Vec2d p; screen_to_plane(canvas, evt, p);
11397 return true;
11398 }
11399 if (evt.LeftUp()) { m_xform_handle = -1; return true; }
11400 // Right-click opens the offer like everywhere else; the placement is kept with Enter/✓
11401 // and discarded with Esc/✗ (the panel's Insert card), never by a mouse button.
11402 if (evt.RightDown()) return false;
11403 return false;
11404 }
11405
11406 // Constrain mode: pick a segment on click; let move/drag fall through so the
11407 // camera can still orbit while inspecting the sketch.
11408 if (m_mode == Mode::Constrain) {
11410 // Pick any entity (line/circle/arc/point): rolling two-slot selection.
11411 if (evt.LeftDown()) {
11412 Vec2d p;
11413 screen_to_plane(canvas, evt, p);
11414 double best = 1e30;
11415 int bi = -1;
11416 for (size_t i = 0; i < m_entities.size(); ++i) {
11417 const double d = entity_pick_dist(p, m_entities[i]);
11418 if (d < best) { best = d; bi = int(i); }
11419 }
11420 // Same reach as every other tool that picks an entity to act on. With no limit,
11421 // a click anywhere on screen picked whatever was nearest; empty space now clears.
11422 if (bi >= 0 && best > screen_tol(canvas, evt, p, kToolPickPx)) {
11423 bi = -1;
11424 m_pick0 = m_pick1 = m_pick2 = -1;
11425 }
11426 if (bi >= 0) {
11427 // Rolling three-slot selection: slots 0/1 feed all 2-entity
11428 // constraints; slot 2 is the Symmetric axis (only filled once
11429 // 0 and 1 are set). A click past slot 2 restarts the cycle.
11430 if (m_pick0 < 0) { m_pick0 = bi; m_pick0_pt = p; }
11431 else if (m_pick1 < 0 && bi != m_pick0) m_pick1 = bi;
11432 else if (m_pick1 >= 0 && m_pick2 < 0 && bi != m_pick0 && bi != m_pick1) m_pick2 = bi;
11433 else { m_pick0 = bi; m_pick1 = m_pick2 = -1; m_pick0_pt = p; }
11434 }
11435 return true;
11436 }
11437 // The picks are this mode's selection, and right-click on a selection opens the
11438 // offer for it — the constraint verbs. It used to cancel(), wiping the whole session
11439 // behind the panel's back. Esc drops the picks.
11440 return false;
11441 }
11442 if (evt.LeftDown()) {
11443 if (m_points.size() < 2)
11444 return false;
11445 Vec2d p;
11446 screen_to_plane(canvas, evt, p);
11447 const size_t n = m_points.size();
11448 double best = 1e30;
11449 int bi = -1;
11450 for (size_t i = 0; i < n; ++i) {
11451 const double d = point_segment_dist(p, m_points[i], m_points[(i + 1) % n]);
11452 if (d < best) { best = d; bi = int(i); }
11453 }
11454 if (bi >= 0) {
11455 m_sel_a = bi;
11456 m_sel_b = int((bi + 1) % n);
11457 }
11458 return true;
11459 }
11460 return false; // right-click included: the offer opens on the picked segment
11461 }
11462
11463 // Selection mode: click to pick an entity, Shift/Ctrl to extend, double-click
11464 // to grab the whole connected loop. Drag falls through so the camera can orbit.
11465 if (m_mode == Mode::Select) {
11466 if (update_hover(canvas, evt)) return true; // repaint when the hovered handle changes
11467 const bool extend = evt.ShiftDown() || evt.ControlDown();
11468
11469 // A constraint badge is a click target: clicking it DELETES that constraint. Existing or
11470 // not is the whole of a constraint's state, so this click is the toggle. Checked before
11471 // entity picking because badges sit clear of the geometry (offset along +Y), so a hit
11472 // here is unambiguous; plain click only, so Shift/Ctrl multi-select is never eaten.
11473 if (evt.LeftDown() && !extend) {
11474 Vec2d gp;
11475 if (screen_to_plane(canvas, evt, gp) && remove_constraint_near(gp)) {
11477 on_selection_changed(int(m_selection.size() + m_point_sel.size()));
11478 return true;
11479 }
11480 }
11481
11482 // Live point drag: once an endpoint/centre was grabbed on LeftDown, dragging
11483 // moves it (re-solving constraints live) until the button is released. When
11484 // nothing is grabbed, drag falls through so the camera can still orbit.
11485 if (m_dragging_point && evt.Dragging() && evt.LeftIsDown()) {
11486 Vec2d p;
11487 screen_to_plane(canvas, evt, p);
11488 if (m_drag_poly_fi >= 0)
11490 else if (m_drag_rect_fi >= 0)
11491 drag_rect_corner(m_drag_rect_fi, p); // resize axis-aligned box
11492 else if (m_drag_slot_fi >= 0)
11493 drag_slot_handle(m_drag_slot_fi, p); // move a slot end
11494 else if (m_drag_ei >= 0 && m_drag_ei < int(m_entities.size()) &&
11496 drag_arc_handle(m_drag_ei, m_drag_role, p); // center/radius/angle grips
11497 else if (m_drag_ei >= 0 && m_drag_ei < int(m_entities.size()) &&
11499 drag_ellipsearc_handle(m_drag_ei, m_drag_role, p); // center/sweep endpoints
11500 else {
11503 }
11504 return true;
11505 }
11506 // Derived-handle drag (A4): the circle RadiusHandle (and later slot/rect/etc.)
11507 // isn't an entity point, so it rides set_handle, which applies the role-specific
11508 // geometry edit + re-solve.
11509 if (m_dragging_handle && evt.Dragging() && evt.LeftIsDown()) {
11510 Vec2d p;
11511 screen_to_plane(canvas, evt, p);
11513 return true;
11514 }
11515 if (evt.LeftUp()) {
11516 if (m_dragging_point) {
11517 Vec2d p;
11518 screen_to_plane(canvas, evt, p);
11519 if (m_drag_poly_fi >= 0)
11521 else if (m_drag_rect_fi >= 0)
11523 else if (m_drag_slot_fi >= 0)
11525 else if (m_drag_ei >= 0 && m_drag_ei < int(m_entities.size()) &&
11528 else if (m_drag_ei >= 0 && m_drag_ei < int(m_entities.size()) &&
11531 else {
11534 }
11535 m_dragging_point = false;
11536 m_drag_ei = -1;
11537 m_drag_poly_fi = -1;
11538 m_drag_rect_fi = -1;
11539 m_drag_slot_fi = -1;
11540 return true;
11541 }
11542 if (m_dragging_handle) {
11543 Vec2d p;
11544 screen_to_plane(canvas, evt, p);
11546 m_dragging_handle = false;
11547 return true;
11548 }
11549 return false;
11550 }
11551
11552 if (evt.LeftDown() || evt.LeftDClick()) {
11553 m_dragging_point = false; // a fresh press disarms any stale grab
11554 m_dragging_handle = false;
11555 m_drag_poly_fi = -1;
11556 m_drag_rect_fi = -1;
11557 m_drag_slot_fi = -1;
11558 Vec2d p;
11559 screen_to_plane(canvas, evt, p);
11560 if (evt.LeftDClick()) { // double-click a quote label -> edit it
11561 // Labels have ONE budget, single- or double-click, and it is in pixels: the old
11562 // 2 mm floor made a label's target grow without bound as the view zoomed in.
11563 const int di = hit_test_dimension(p, screen_tol(canvas, evt, p, kLabelPx));
11564 if (di >= 0) { edit_dimension(di); return true; }
11565 }
11566 // Zoom-aware tolerance: project a point 8 px away and measure in plane units.
11567 const Linef3 r2 = canvas.mouse_ray(Point(evt.GetX() + 8, evt.GetY()));
11568 const Vec2d p2 = m_plane.project(r2.a, r2.vector());
11569 const double tol = std::max(1e-3, (p2 - p).norm());
11570
11571 // Single-click a dimension quote label -> edit its value in place. A placed
11572 // driving quote reopens its editor; a live (non-driving) characteristic quote
11573 // is first promoted to a driving dimension (place_dimension), then its editor
11574 // opens — so typing a value sets the precise dimension. Generous label
11575 // tolerance (~24 px) since text labels are wider than a point grip.
11576 if (evt.LeftDown()) {
11577 const double ltol = std::max(tol, screen_tol(canvas, evt, p, kLabelPx));
11578 const int di = hit_test_dimension(p, ltol);
11579 if (di >= 0) { open_value_editor(di); return true; }
11580 for (const DimAnnot& q : m_live_quotes) {
11581 if ((q.label_pos - p).norm() <= ltol) {
11582 if (q.kind == DimType::Angle)
11583 open_angle_editor(q.ea); // geometric rotate to a typed angle
11584 else
11585 place_dimension(q); // promote -> driving dim + open editor
11586 return true;
11587 }
11588 }
11589 if (m_live_poly_fi >= 0) {
11590 if ((m_live_poly_side_label - p).norm() <= ltol) {
11591 open_polygon_side_editor(m_live_poly_fi); // geometric uniform scale
11592 return true;
11593 }
11594 if ((m_live_poly_angle_label - p).norm() <= ltol) {
11595 open_polygon_angle_editor(m_live_poly_fi); // geometric rotate
11596 return true;
11597 }
11598 }
11599 if (m_live_arc_ei >= 0 && (m_live_arc_angle_label - p).norm() <= ltol) {
11600 open_arc_angle_editor(m_live_arc_ei); // geometric sweep change
11601 return true;
11602 }
11603 if (m_live_ellipse_ei >= 0) {
11604 if ((m_live_ellipse_major_label - p).norm() <= ltol) {
11605 open_ellipse_axis_editor(m_live_ellipse_ei, true); // semi-major
11606 return true;
11607 }
11608 if ((m_live_ellipse_minor_label - p).norm() <= ltol) {
11609 open_ellipse_axis_editor(m_live_ellipse_ei, false); // semi-minor
11610 return true;
11611 }
11612 }
11613 if (m_live_rrect_fi >= 0) {
11614 if ((m_live_rrect_w_label - p).norm() <= ltol) { open_rounded_rect_editor(m_live_rrect_fi, 0); return true; }
11615 if ((m_live_rrect_h_label - p).norm() <= ltol) { open_rounded_rect_editor(m_live_rrect_fi, 1); return true; }
11616 if ((m_live_rrect_r_label - p).norm() <= ltol) { open_rounded_rect_editor(m_live_rrect_fi, 2); return true; }
11617 }
11618 if (m_live_aslot_fi >= 0) {
11619 if ((m_live_aslot_r_label - p).norm() <= ltol) { open_arc_slot_editor(m_live_aslot_fi, true); return true; }
11620 if ((m_live_aslot_w_label - p).norm() <= ltol) { open_arc_slot_editor(m_live_aslot_fi, false); return true; }
11621 }
11622 if (m_live_slot_fi >= 0) {
11623 if ((m_live_slot_len_label - p).norm() <= ltol) { open_slot_editor(m_live_slot_fi, 0); return true; }
11624 if ((m_live_slot_w_label - p).norm() <= ltol) { open_slot_editor(m_live_slot_fi, 1); return true; }
11625 if ((m_live_slot_angle_label - p).norm() <= ltol) { open_slot_editor(m_live_slot_fi, 2); return true; }
11626 }
11627 }
11628
11629 // A derived handle (the circle RadiusHandle — not an entity point, so
11630 // hit_test_point can't grab it) arms a handle drag that resizes on motion.
11631 // Checked before the point/entity hit-tests so the radius grip wins near
11632 // the circle edge.
11633 if (evt.LeftDown()) {
11634 Handle hh;
11635 if (hit_test_handle(p, tol, hh) &&
11636 (hh.role == HandleRole::RadiusHandle || hh.role == HandleRole::MajorAxis ||
11637 hh.role == HandleRole::MinorAxis || hh.role == HandleRole::BSplineCtrl)) {
11638 m_dragging_handle = true;
11639 m_drag_handle = hh;
11640 m_selection.clear();
11641 m_point_sel.clear();
11642 m_selection.push_back(hh.ei); // highlight the circle being resized
11644 on_selection_changed(int(m_selection.size()));
11645 return true;
11646 }
11647 }
11648
11649 // A nearby endpoint/centre selects that POINT (a line = a segment + 2
11650 // points); a click on the bare segment selects the whole entity.
11651 if (evt.LeftDown()) {
11652 int pe; SketchPointRole pr;
11653 if (hit_test_point(p, tol, pe, pr)) {
11654 const auto key = std::make_pair(pe, pr);
11655 auto it = std::find(m_point_sel.begin(), m_point_sel.end(), key);
11656 if (extend) {
11657 if (it == m_point_sel.end()) m_point_sel.push_back(key);
11658 else m_point_sel.erase(it);
11659 } else {
11660 m_selection.clear();
11661 m_point_sel.clear();
11662 m_point_sel.push_back(key);
11663 }
11664 // Arm the drag so the grabbed point follows the cursor.
11665 m_dragging_point = true;
11666 m_drag_ei = pe;
11667 m_drag_role = pr;
11668 // If the grabbed point is a polygon vertex, the drag must keep the
11669 // polygon REGULAR — it adjusts the circumradius + orientation (the
11670 // vertex follows the cursor) instead of moving one point freely.
11671 const int pf = feature_of(pe);
11672 m_drag_poly_fi = (pf >= 0 && m_features[pf].kind == FeatureKind::Polygon) ? pf : -1;
11673 m_drag_rect_fi = -1; m_drag_slot_fi = -1;
11674 if (pf >= 0 && m_drag_poly_fi < 0) {
11675 const Feature& ft = m_features[pf];
11676 if (ft.kind == FeatureKind::CornerRect || ft.kind == FeatureKind::CenterRect) {
11677 // Only axis-aligned boxes resize by corner (oblique rects fall
11678 // back to free point move). Capture the fixed opposite corner.
11679 const SketchEntity& e0 = m_entities[ft.begin];
11680 const Vec2d d0 = e0.p1 - e0.p0;
11681 const bool aa = std::abs(d0.x()) < 1e-6 || std::abs(d0.y()) < 1e-6;
11682 Vec2d gp;
11683 if (aa && point_at(pe, pr, gp)) {
11684 Vec2d opp;
11685 opp.x() = (std::abs(gp.x() - ft.c0.x()) < std::abs(gp.x() - ft.c1.x())) ? ft.c1.x() : ft.c0.x();
11686 opp.y() = (std::abs(gp.y() - ft.c0.y()) < std::abs(gp.y() - ft.c1.y())) ? ft.c1.y() : ft.c0.y();
11688 }
11689 } else if (ft.kind == FeatureKind::Slot &&
11691 (pe == ft.begin + 1 || pe == ft.begin + 3)) {
11692 m_drag_slot_fi = pf; // cap@c1 = begin+1, cap@c0 = begin+3
11693 m_drag_slot_c1 = (pe == ft.begin + 1);
11694 }
11695 }
11697 on_selection_changed(int(m_selection.size() + m_point_sel.size()));
11698 return true;
11699 }
11700 }
11701
11702 const int hit = hit_test(p, tol);
11703
11704 if (evt.LeftDClick() && hit >= 0) {
11705 if (!extend) m_selection.clear();
11706 for (int idx : connected_loop(hit))
11707 if (std::find(m_selection.begin(), m_selection.end(), idx) == m_selection.end())
11708 m_selection.push_back(idx);
11709 } else if (hit >= 0) {
11710 auto it = std::find(m_selection.begin(), m_selection.end(), hit);
11711 if (extend) {
11712 if (it == m_selection.end()) m_selection.push_back(hit);
11713 else m_selection.erase(it); // toggle off
11714 } else {
11715 m_selection.clear();
11716 m_point_sel.clear();
11717 m_selection.push_back(hit);
11718 }
11719 } else if (!extend) {
11720 // Inside a closed loop (not on an edge/point) → select it as a face
11721 // and hand off to the panel, which commits the sketch and extrudes.
11722 if (evt.LeftDown() && on_face_selected) {
11723 const int reg = region_at(p);
11724 if (reg >= 0) {
11725 m_selection.clear();
11726 m_point_sel.clear();
11727 on_face_selected(reg);
11728 return true;
11729 }
11730 }
11731 m_selection.clear(); // clicked empty space
11732 m_point_sel.clear();
11733 }
11735 on_selection_changed(int(m_selection.size() + m_point_sel.size()));
11736 return true;
11737 }
11738 if (evt.RightDown()) {
11739 // Hand the click back (return false) so the offer opens: take_right_click returns
11740 // this value as "the tool USED this right-click", and a plain right-click in Select
11741 // mode is not a gesture terminator.
11742 //
11743 // But do NOT drop the selection on the way out. The offer menu describes WHAT IS
11744 // SELECTED, so clearing first guaranteed it could only ever describe nothing: select
11745 // a line, right-click, and the sketch verbs — Trim, Extend, Fillet, Chamfer, Offset,
11746 // Mirror, the arrays, Constrain — were all greyed, because by the time the menu was
11747 // built the line was no longer selected. Reported from the machine as "selected a
11748 // line, right-click exit from selection: only create and reference are usable".
11749 // Deselecting still has a gesture: left-click on empty space, a few lines above.
11750 return false;
11751 }
11752 return false; // let drag orbit the camera
11753 }
11754
11755 // Dimension mode: click entities directly. 2 points -> Distance, a line -> Length,
11756 // a circle -> Diameter, an arc -> Radius, a point then a line -> DistanceToLine.
11757 // Each resolved pick places a driving quote and pops the value card.
11758 if (m_mode == Mode::Dimension) {
11759 if (update_hover(canvas, evt)) return true; // repaint when the hovered handle changes
11760 if (evt.LeftDClick()) { // double-click a quote label -> edit it
11761 Vec2d p;
11762 screen_to_plane(canvas, evt, p);
11763 const int di = hit_test_dimension(p, screen_tol(canvas, evt, p, kLabelPx));
11764 if (di >= 0) edit_dimension(di);
11765 m_dim_has0 = false;
11766 return true;
11767 }
11768 if (evt.LeftDown()) {
11769 Vec2d p;
11770 screen_to_plane(canvas, evt, p);
11771 const Linef3 r2 = canvas.mouse_ray(Point(evt.GetX() + 8, evt.GetY()));
11772 const Vec2d p2 = m_plane.project(r2.a, r2.vector());
11773 const double tol = std::max(1e-3, (p2 - p).norm());
11774 int pe; SketchPointRole pr;
11775 const bool got_pt = hit_test_point(p, tol, pe, pr);
11776 const int he = hit_test(p, tol);
11777 if (!m_dim_has0) {
11778 if (got_pt) { // first point picked: await a second
11779 m_dim_e0 = pe; m_dim_r0 = pr; m_dim_has0 = true;
11780 } else if (he >= 0) { // whole-entity dimension
11781 DimAnnot a; a.ea = he;
11782 const SketchEntity::Type t = m_entities[he].type;
11783 if (t == SketchEntity::Type::Line) { a.kind = DimType::Length; place_dimension(a); }
11784 else if (t == SketchEntity::Type::Circle) { a.kind = DimType::Diameter; place_dimension(a); }
11785 else if (t == SketchEntity::Type::Arc) { a.kind = DimType::Radius; place_dimension(a); }
11786 else
11787 notify(_u8L("No dimension for that entity yet — click a line, a circle, an arc, or two points"));
11788 }
11789 } else {
11790 if (got_pt && !(pe == m_dim_e0 && pr == m_dim_r0)) {
11792 a.ea = m_dim_e0; a.ra = m_dim_r0; a.eb = pe; a.rb = pr;
11793 place_dimension(a);
11794 } else if (he >= 0 && m_entities[he].type == SketchEntity::Type::Line) {
11796 a.ea = m_dim_e0; a.ra = m_dim_r0; a.eb = he;
11797 place_dimension(a);
11798 } else if (he >= 0) {
11799 notify(_u8L("Click a second point, or a line to measure the distance to"), false);
11800 }
11801 m_dim_has0 = false; // reset after the second pick
11802 }
11803 return true;
11804 }
11805 if (evt.RightDown()) { // abandon the first pick, if any (right_abandon's rule)
11806 if (!m_dim_has0) return false; // nothing down: the offer opens
11807 m_dim_has0 = false;
11808 return true;
11809 }
11810 return false; // let drag orbit the camera
11811 }
11812
11813 if (evt.Moving()) {
11814 m_snap_off = evt.ShiftDown();
11815 screen_to_plane(canvas, evt, m_cursor);
11816 m_has_cursor = true;
11817 m_cursor_locked = false;
11818 bool vsnap = false;
11819 // Preview exactly what the next click will do: a snap marker over a click that then
11820 // lands on the raw point promised a coincidence that never happened.
11821 if (click_snaps()) m_cursor = snap_vertex(canvas, evt, m_cursor, vsnap); // preview-snap
11822 else m_cursor_snap = InferenceSnap{};
11823 // The chain's own start is not an entity yet, so snap_vertex cannot see it. Offer it
11824 // here: the cursor lands exactly on it, so the rubber band below IS the closing segment.
11825 if (snap_chain_start(canvas, evt, m_cursor)) vsnap = true;
11826 const bool line_like = (m_mode == Mode::Polyline || m_mode == Mode::Line);
11827 if (line_like && !m_points.empty() && !vsnap)
11829 if (on_cursor_metrics && line_like && !m_points.empty() && !m_awaiting_length) {
11830 const Vec2d d = m_cursor - m_points.back();
11831 on_cursor_metrics(d.norm(), std::atan2(d.y(), d.x()) * 180.0 / M_PI, m_cursor_locked);
11832 }
11833 return true;
11834 }
11835
11836 switch (m_mode) {
11837
11838 case Mode::Polyline: {
11839 if (evt.LeftDown()) {
11840 Vec2d p;
11841 screen_to_plane(canvas, evt, p);
11842 m_snap_off = evt.ShiftDown();
11843 bool vsnap = false;
11844 p = snap_vertex(canvas, evt, p, vsnap); // snap onto an existing endpoint
11845 if (snap_chain_start(canvas, evt, p)) { // clicked the previewed close target
11846 const int base = int(m_entities.size());
11847 push_closed_lines(m_points); // close the loop
11848 infer_auto_constraints(base); // loop self-closes via auto Coincident + H/V
11849 m_points.clear();
11850 return true;
11851 }
11852 if (!m_points.empty() && !vsnap) {
11853 bool lk = false;
11854 p = snap_dir(m_points.back(), p, lk); // lock new segment to inference angle
11855 }
11856 m_chain_dup_tol = screen_tol(canvas, evt, p, 3.0);
11857 m_points.push_back(p);
11858 arm_polyline_segment_edit(); // refine this segment's Length+Angle, then continue
11859 return true;
11860 }
11861 if (evt.LeftDClick()) {
11862 if (m_points.size() >= 2) end_chain(); // end as an open chain
11863 return true;
11864 }
11865 if (evt.RightDown() && m_points.empty())
11866 return false; // no chain to end — ghcz, let the offer open
11867 if (evt.RightDown()) {
11868 // END the chain — do NOT close it. This used to call push_closed_lines() for three
11869 // or more points, i.e. it drew a final segment from the last point back to the
11870 // first that the user never asked for, and did it silently. No mainstream sketcher
11871 // does that: FreeCAD, Fusion and Onshape all end an open chain on right-click and
11872 // require the close to be EXPLICIT. Ours has that gesture — click the chain's first
11873 // point, which snap_chain_start() previews and snaps onto in the LeftDown branch
11874 // above, so the closing segment is on screen BEFORE it is committed. A closed loop
11875 // is this tab's goal and it stays a four-action triangle either way; what changes
11876 // is that the closing edge is now something the user saw and chose, not one the
11877 // app appended on their behalf.
11878 end_chain();
11879 return true;
11880 }
11881 break;
11882 }
11883
11884 case Mode::Line: {
11885 if (evt.LeftDown()) {
11886 Vec2d p;
11887 screen_to_plane(canvas, evt, p);
11888 m_snap_off = evt.ShiftDown();
11889 bool vsnap = false;
11890 p = snap_vertex(canvas, evt, p, vsnap); // snap onto an existing endpoint
11891 if (m_points.empty()) { // first click = anchor
11892 m_points.push_back(p);
11893 return true;
11894 }
11895 bool lk = false;
11896 if (!vsnap) p = snap_dir(m_points.back(), p, lk); // vertex snap wins over angle
11897 m_points.push_back(p); // second click completes the segment
11898 // Draw-then-edit: just commit the segment. The generic detect/service path
11899 // (is_creation_autoedit_mode now includes Line) auto-selects it and opens its
11900 // Length THEN Angle fields in sequence, each over its label — same UX as every
11901 // other 2D tool. Enter advances (Length drives a Distance constraint, Angle rotates
11902 // about P0); Esc keeps it as drawn.
11904 return true;
11905 }
11906 if (evt.RightDown()) return right_abandon();
11907 break;
11908 }
11909
11910 case Mode::CornerRect: {
11911 if (evt.LeftDown()) {
11912 Vec2d p;
11913 screen_to_plane(canvas, evt, p);
11914 { bool vsnap = false; if (click_snaps()) p = snap_vertex(canvas, evt, p, vsnap); }
11915 if (m_points.empty()) {
11916 m_points.push_back(p);
11917 } else {
11918 const Vec2d A = m_points[0];
11919 const Vec2d B = p;
11920 const int base = int(m_entities.size());
11922 push_closed_lines({ A, Vec2d(B.x(), A.y()), B, Vec2d(A.x(), B.y()) });
11923 infer_auto_constraints(base); // corners Coincident + sides H/V
11924 end_feature(A, B); // group: Width/Height live quotes
11925 m_points.clear();
11926 }
11927 return true;
11928 }
11929 if (evt.RightDown()) return right_abandon();
11930 break;
11931 }
11932
11933 case Mode::CenterRect: {
11934 if (evt.LeftDown()) {
11935 Vec2d p;
11936 screen_to_plane(canvas, evt, p);
11937 { bool vsnap = false; if (click_snaps()) p = snap_vertex(canvas, evt, p, vsnap); }
11938 if (m_points.empty()) {
11939 m_points.push_back(p);
11940 } else {
11941 const Vec2d C = m_points[0];
11942 const double hx = std::abs(p.x() - C.x());
11943 const double hy = std::abs(p.y() - C.y());
11944 const int base = int(m_entities.size());
11947 Vec2d(C.x() - hx, C.y() - hy), Vec2d(C.x() + hx, C.y() - hy),
11948 Vec2d(C.x() + hx, C.y() + hy), Vec2d(C.x() - hx, C.y() + hy) });
11950 end_feature(Vec2d(C.x() - hx, C.y() - hy), Vec2d(C.x() + hx, C.y() + hy));
11951 m_points.clear();
11952 }
11953 return true;
11954 }
11955 if (evt.RightDown()) return right_abandon();
11956 break;
11957 }
11958
11959 case Mode::ObliqueRect: {
11960 if (evt.LeftDown()) {
11961 Vec2d p; screen_to_plane(canvas, evt, p);
11962 bool vsnap = false;
11963 if (m_points.size() < 2) // corners snap; 3rd click is the width
11964 p = snap_vertex(canvas, evt, p, vsnap);
11965 m_points.push_back(p);
11966 if (m_points.size() == 3) {
11967 const Vec2d A = m_points[0], B = m_points[1];
11968 Vec2d u = B - A;
11969 if (u.squaredNorm() > 1e-12) {
11970 u.normalize();
11971 const Vec2d n(-u.y(), u.x());
11972 const double w = n.dot(m_points[2] - A); // signed perpendicular width
11973 const int base = int(m_entities.size());
11975 push_closed_lines({ A, B, B + n * w, A + n * w });
11976 infer_auto_constraints(base); // corners Coincident + the AB pair parallel
11977 end_feature(A, B + n * w); // group: Width/Height live quotes
11978 }
11979 m_points.clear();
11980 }
11981 return true;
11982 }
11983 if (evt.RightDown()) return right_abandon();
11984 break;
11985 }
11986
11987 case Mode::RoundedRect: {
11988 if (evt.LeftDown()) {
11989 Vec2d p; screen_to_plane(canvas, evt, p);
11990 bool vsnap = false;
11991 if (m_points.size() < 2) // the two corners snap; 3rd sets radius
11992 p = snap_vertex(canvas, evt, p, vsnap);
11993 m_points.push_back(p);
11994 if (m_points.size() == 3) {
11995 const int base = int(m_entities.size());
11999 // Group with the actual clamped fillet radius so the W/H/R live quotes
12000 // and rebuild edits can recover the box. (Skip grouping if degenerate.)
12001 const Vec2d a = m_points[0], b = m_points[1];
12002 const double xmin=std::min(a.x(),b.x()), xmax=std::max(a.x(),b.x());
12003 const double ymin=std::min(a.y(),b.y()), ymax=std::max(a.y(),b.y());
12004 const double bw=xmax-xmin, bh=ymax-ymin;
12005 const Vec2d cs[4]={{xmin,ymin},{xmax,ymin},{xmax,ymax},{xmin,ymax}};
12006 double r=1e18; for(const Vec2d&c:cs) r=std::min(r,(m_points[2]-c).norm());
12007 r=std::min(r, std::min(bw,bh)*0.5);
12008 end_feature(Vec2d(xmin,ymin), Vec2d(xmax,ymax), r);
12009 m_points.clear();
12010 }
12011 return true;
12012 }
12013 if (evt.RightDown()) return right_abandon();
12014 break;
12015 }
12016
12017 case Mode::CenterCircle: {
12018 if (evt.LeftDown()) {
12019 Vec2d p;
12020 screen_to_plane(canvas, evt, p);
12021 { bool vsnap = false; if (click_snaps()) p = snap_vertex(canvas, evt, p, vsnap); }
12022 if (m_points.empty()) {
12023 m_points.push_back(p);
12024 } else {
12025 const Vec2d C = m_points[0];
12026 push_circle(C, (p - C).norm());
12027 m_points.clear();
12028 }
12029 return true;
12030 }
12031 if (evt.RightDown()) return right_abandon();
12032 break;
12033 }
12034
12035 case Mode::TwoPointCircle: {
12036 if (evt.LeftDown()) {
12037 Vec2d p; screen_to_plane(canvas, evt, p);
12038 bool vsnap = false;
12039 p = snap_vertex(canvas, evt, p, vsnap); // diameter ends snap onto geometry
12040 m_points.push_back(p);
12041 if (m_points.size() == 2) {
12042 const Vec2d C = (m_points[0] + m_points[1]) * 0.5;
12043 push_circle(C, (m_points[1] - m_points[0]).norm() * 0.5);
12044 m_points.clear();
12045 }
12046 return true;
12047 }
12048 if (evt.RightDown()) return right_abandon();
12049 break;
12050 }
12051
12053 if (evt.LeftDown()) {
12054 Vec2d p; screen_to_plane(canvas, evt, p);
12055 { bool vsnap = false; if (click_snaps()) p = snap_vertex(canvas, evt, p, vsnap); }
12056 m_points.push_back(p);
12057 if (m_points.size() == 3) {
12059 m_points.clear();
12060 }
12061 return true;
12062 }
12063 if (evt.RightDown()) return right_abandon();
12064 break;
12065 }
12066
12067 case Mode::ThreePointArc: {
12068 if (evt.LeftDown()) {
12069 Vec2d p; screen_to_plane(canvas, evt, p);
12070 bool vsnap = false;
12071 if (m_points.size() < 2) // snap the start/end onto endpoints
12072 p = snap_vertex(canvas, evt, p, vsnap); // (the 3rd click is the through-point)
12073 m_points.push_back(p);
12074 if (m_points.size() == 3) {
12075 // clicks: start, end, point-on-arc
12076 const int base = int(m_entities.size());
12078 infer_auto_constraints(base); // arc ends Coincident onto snapped vertices
12079 m_points.clear();
12080 }
12081 return true;
12082 }
12083 if (evt.RightDown()) return right_abandon();
12084 break;
12085 }
12086
12087 case Mode::TangentArc: {
12088 if (evt.LeftDown()) {
12089 Vec2d p; screen_to_plane(canvas, evt, p);
12090 bool vsnap = false;
12091 p = snap_vertex(canvas, evt, p, vsnap); // snap both ends onto endpoints
12092 m_points.push_back(p);
12093 if (m_points.size() == 2) {
12094 const int base = int(m_entities.size());
12096 infer_auto_constraints(base); // tangent-arc ends Coincident onto vertices
12097 m_points.clear();
12098 }
12099 return true;
12100 }
12101 if (evt.RightDown()) return right_abandon();
12102 break;
12103 }
12104
12105 case Mode::CenterArc: {
12106 if (evt.LeftDown()) {
12107 Vec2d p; screen_to_plane(canvas, evt, p);
12108 bool vsnap = false;
12109 // The start (2nd click) snaps onto endpoints; center & end-dir are free.
12110 if (m_points.size() == 1)
12111 p = snap_vertex(canvas, evt, p, vsnap);
12112 m_points.push_back(p);
12113 if (m_points.size() == 3) {
12114 const int base = int(m_entities.size());
12116 infer_auto_constraints(base); // arc start Coincident onto a snapped vertex
12117 m_points.clear();
12118 }
12119 return true;
12120 }
12121 if (evt.RightDown()) return right_abandon();
12122 break;
12123 }
12124
12125 case Mode::Slot: {
12126 if (evt.LeftDown()) {
12127 Vec2d p; screen_to_plane(canvas, evt, p);
12128 { bool vsnap = false; if (click_snaps()) p = snap_vertex(canvas, evt, p, vsnap); }
12129 if (m_points.size() < 2) {
12130 m_points.push_back(p);
12131 } else {
12132 // third click sets the half-width (distance to the centerline)
12133 Vec2d u = m_points[1] - m_points[0];
12134 if (u.squaredNorm() > 1e-12) {
12135 u.normalize();
12136 const Vec2d n(-u.y(), u.x());
12137 const double w = std::abs(n.dot(p - m_points[0]));
12138 const int base = int(m_entities.size());
12142 end_feature(m_points[0], m_points[1], w); // centres + half-width
12143 }
12144 m_points.clear();
12145 }
12146 return true;
12147 }
12148 if (evt.RightDown()) return right_abandon();
12149 break;
12150 }
12151
12152 case Mode::ArcSlot: {
12153 if (evt.LeftDown()) {
12154 Vec2d p; screen_to_plane(canvas, evt, p);
12155 bool vsnap = false;
12156 if (m_points.size() == 1) // start snaps; center & end-dir are free
12157 p = snap_vertex(canvas, evt, p, vsnap);
12158 m_points.push_back(p);
12159 if (m_points.size() == 4) {
12160 // clicks: center, start, end-dir, width
12161 const double Rc = (m_points[1] - m_points[0]).norm();
12162 const double w = std::abs((m_points[3] - m_points[0]).norm() - Rc);
12163 const int base = int(m_entities.size());
12167 // c0 = centre, c1 = centreline start point; param = half-width. The end
12168 // direction is recovered from the cap@E arc centre when rebuilding.
12169 end_feature(m_points[0], m_points[1], w);
12170 m_points.clear();
12171 }
12172 return true;
12173 }
12174 if (evt.RightDown()) return right_abandon();
12175 break;
12176 }
12177
12178 case Mode::Polygon: {
12179 if (evt.LeftDown()) {
12180 Vec2d p; screen_to_plane(canvas, evt, p);
12181 { bool vsnap = false; if (click_snaps()) p = snap_vertex(canvas, evt, p, vsnap); }
12182 if (m_points.empty()) {
12183 m_points.push_back(p);
12184 } else {
12185 const int base = int(m_entities.size());
12189 end_feature(m_points[0], p, (p - m_points[0]).norm(), m_polygon_sides);
12190 m_points.clear();
12191 }
12192 return true;
12193 }
12194 if (evt.RightDown()) return right_abandon();
12195 break;
12196 }
12197
12198 case Mode::Ellipse: {
12199 if (evt.LeftDown()) {
12200 Vec2d p; screen_to_plane(canvas, evt, p);
12201 bool vsnap = false;
12202 if (m_points.empty()) p = snap_vertex(canvas, evt, p, vsnap); // center can snap
12203 m_points.push_back(p);
12204 if (m_points.size() == 3) { // center, major-end, minor
12205 const int base = int(m_entities.size());
12208 m_points.clear();
12209 }
12210 return true;
12211 }
12212 if (evt.RightDown()) return right_abandon();
12213 break;
12214 }
12215
12216 case Mode::EllipseArc: {
12217 if (evt.LeftDown()) {
12218 Vec2d p; screen_to_plane(canvas, evt, p);
12219 bool vsnap = false;
12220 if (m_points.empty()) p = snap_vertex(canvas, evt, p, vsnap); // center can snap
12221 m_points.push_back(p);
12222 if (m_points.size() == 5) { // center, major, minor, start, end
12223 const int base = int(m_entities.size());
12225 m_points[3], m_points[4]));
12227 m_points.clear();
12228 }
12229 return true;
12230 }
12231 if (evt.RightDown()) return right_abandon();
12232 break;
12233 }
12234
12235 case Mode::BSpline: {
12236 // Variable-length: left-click adds a control pole (each can snap onto existing
12237 // geometry); double-click or right-click finishes as an open spline.
12238 if (evt.LeftDown()) {
12239 Vec2d p; screen_to_plane(canvas, evt, p);
12240 m_snap_off = evt.ShiftDown();
12241 bool vsnap = false;
12242 p = snap_vertex(canvas, evt, p, vsnap); // poles can land on endpoints
12243 m_chain_dup_tol = screen_tol(canvas, evt, p, 3.0);
12244 m_points.push_back(p);
12245 return true;
12246 }
12247 if (evt.RightDown() && m_points.empty())
12248 return false; // no poles down — ghcz, let the offer open
12249 if (evt.LeftDClick() || evt.RightDown()) {
12250 end_chain();
12251 return true;
12252 }
12253 break;
12254 }
12255
12256 case Mode::Point: {
12257 if (evt.LeftDown()) {
12258 Vec2d p;
12259 screen_to_plane(canvas, evt, p);
12260 { bool vsnap = false; if (click_snaps()) p = snap_vertex(canvas, evt, p, vsnap); }
12261 push_point(p);
12262 return true;
12263 }
12264 if (evt.RightDown()) return false; // no anchor to abandon: the offer belongs here
12265 break;
12266 }
12267
12268 case Mode::Constrain:
12269 break;
12270 }
12271
12272 if (evt.Dragging())
12273 return false;
12274
12275 return false;
12276}
int m_hx_press_x
Definition DesignSketchTool.hpp:1425
void drag_move_arrow(const Linef3 &ray)
Definition DesignSketchTool.cpp:5957
bool m_op_dragging_arrow
Definition DesignSketchTool.hpp:1177
InferenceSnap m_cursor_snap
Definition DesignSketchTool.hpp:1083
void drag_extrude_arrow(GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
Definition DesignSketchTool.cpp:4903
void open_hole_editor(int which)
Definition DesignSketchTool.cpp:6379
void drag_move_arc(GLCanvas3D &canvas, const wxMouseEvent &evt, int axis)
Definition DesignSketchTool.cpp:6022
int region_at(const Vec2d &p) const
Definition DesignSketchTool.cpp:7413
void open_thread_editor(int which)
Definition DesignSketchTool.cpp:6578
std::vector< SketchEntity > make_polygon(const Vec2d &center, const Vec2d &vertex, int sides) const
Definition DesignSketchTool.cpp:3195
int m_drag_slot_fi
Definition DesignSketchTool.hpp:1115
std::function< void(int base)> on_datum_base_picked
Definition DesignSketchTool.hpp:372
std::function< void(int feature, int region, int entity)> on_display_sketch_selected
Definition DesignSketchTool.hpp:300
int m_dr_press_y
Definition DesignSketchTool.hpp:1588
bool handle_solid_click(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:4082
int m_th_press_x
Definition DesignSketchTool.hpp:1536
void edit_dimension(int di)
Definition DesignSketchTool.cpp:1390
int m_sh_press_y
Definition DesignSketchTool.hpp:1554
void drag_pattern_handle(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:7230
void drag_draft_arc(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:6809
void open_tf_editor_a()
Definition DesignSketchTool.cpp:9280
void push_point(const Vec2d &p)
Definition DesignSketchTool.cpp:2945
void pick_bodies_in_rectangle()
Definition DesignSketchTool.cpp:3909
void arm_polyline_segment_edit()
Definition DesignSketchTool.cpp:1543
bool hit_test_extrude_arrow(GLCanvas3D &canvas, const wxMouseEvent &evt, int &which) const
Definition DesignSketchTool.cpp:4883
Vec2d m_live_ellipse_minor_label
Definition DesignSketchTool.hpp:1134
void drag_helix_handle(GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
Definition DesignSketchTool.cpp:5253
void start_cut_drag(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:6921
int hit_test_thread_handle(GLCanvas3D &canvas, const wxMouseEvent &evt) const
Definition DesignSketchTool.cpp:6516
bool m_snap_off
Definition DesignSketchTool.hpp:1082
void hit_display_sketch(const DisplaySketch &d, const Vec2d &p, double tol, int &edge_feat, int &edge_reg, int &edge_ent, double &edge_d, int &face_feat, int &face_reg) const
Definition DesignSketchTool.cpp:3376
int m_dr_press_x
Definition DesignSketchTool.hpp:1588
void drag_op_arrow(const Vec2d &target)
Definition DesignSketchTool.cpp:8861
int m_live_arc_ei
Definition DesignSketchTool.hpp:1132
bool hit_test_move_arrow(GLCanvas3D &canvas, const wxMouseEvent &evt, int &axis) const
Definition DesignSketchTool.cpp:5929
void drag_rect_corner(int fi, const Vec2d &cursor)
Definition DesignSketchTool.cpp:2342
static constexpr double kLabelPx
Definition DesignSketchTool.hpp:757
bool hit_test_revolve_handle(GLCanvas3D &canvas, const wxMouseEvent &evt) const
Definition DesignSketchTool.cpp:7024
void drag_shell_arrow(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:6673
Handle m_drag_handle
Definition DesignSketchTool.hpp:1123
bool remove_constraint_near(const Vec2d &p)
Definition DesignSketchTool.cpp:2671
void open_polygon_angle_editor(int fi)
Definition DesignSketchTool.cpp:1740
void push_circle(const Vec2d &center, double radius)
Definition DesignSketchTool.cpp:2933
DimType kind
Definition DesignSketchTool.hpp:795
int m_mv_press_y
Definition DesignSketchTool.hpp:1468
std::function< void()> on_inline_commit
Definition DesignSketchTool.hpp:691
void tf_pick(int ei)
Definition DesignSketchTool.cpp:9167
Vec2d m_live_slot_w_label
Definition DesignSketchTool.hpp:1147
bool m_cursor_locked
Definition DesignSketchTool.hpp:1084
Vec2d m_live_slot_angle_label
Definition DesignSketchTool.hpp:1148
int m_fl_press_y
Definition DesignSketchTool.hpp:1488
int m_hl_press_x
Definition DesignSketchTool.hpp:1514
Vec2d m_live_rrect_w_label
Definition DesignSketchTool.hpp:1139
Vec2d m_tf_label_b
Definition DesignSketchTool.hpp:1219
int m_drag_rect_fi
Definition DesignSketchTool.hpp:1113
Vec2d snap_vertex(GLCanvas3D &canvas, const wxMouseEvent &evt, const Vec2d &raw, bool &snapped) const
Definition DesignSketchTool.cpp:2630
int m_dz_press_y
Definition DesignSketchTool.hpp:1406
void drag_fillet_arrow(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:6153
int m_live_ellipse_ei
Definition DesignSketchTool.hpp:1136
int m_live_slot_fi
Definition DesignSketchTool.hpp:1149
void open_slot_editor(int fi, int which)
Definition DesignSketchTool.cpp:2277
std::vector< SketchEntity > make_ellipse(const Vec2d &center, const Vec2d &major_end, const Vec2d &minor_pt) const
Definition DesignSketchTool.cpp:3247
int m_pt_press_x
Definition DesignSketchTool.hpp:1629
Vec2d m_live_rrect_r_label
Definition DesignSketchTool.hpp:1141
bool apply_live_trim(const Vec2d &p, double tol, bool extend)
Definition DesignSketchTool.cpp:1810
void start_thread_drag(GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
Definition DesignSketchTool.cpp:6540
int m_th_press_y
Definition DesignSketchTool.hpp:1536
bool screen_to_plane(GLCanvas3D &canvas, const wxMouseEvent &evt, Vec2d &out) const
Definition DesignSketchTool.cpp:2531
void drag_xform_handle(const Vec2d &target)
Definition DesignSketchTool.cpp:8630
bool click_snaps() const
Definition DesignSketchTool.cpp:2611
bool m_pick_pending
Definition DesignSketchTool.hpp:207
int m_polygon_sides
Definition DesignSketchTool.hpp:1078
Vec2d m_live_poly_side_label
Definition DesignSketchTool.hpp:1128
void open_tf_editor_count()
Definition DesignSketchTool.cpp:9308
void start_fillet_drag(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:6143
void open_arc_angle_editor(int ei)
Definition DesignSketchTool.cpp:1997
Vec2d m_tf_label_a
Definition DesignSketchTool.hpp:1218
Vec2d m_live_slot_len_label
Definition DesignSketchTool.hpp:1146
std::vector< int > connected_loop(int seed) const
Definition DesignSketchTool.cpp:10715
void start_hole_drag(GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
Definition DesignSketchTool.cpp:6339
std::function< void(int feature)> on_display_sketch_activated
Definition DesignSketchTool.hpp:303
void open_angle_editor(int ei)
Definition DesignSketchTool.cpp:1446
bool right_abandon()
Definition DesignSketchTool.cpp:10759
void set_handle(const Handle &h, const Vec2d &target)
Definition DesignSketchTool.cpp:1082
int m_live_poly_fi
Definition DesignSketchTool.hpp:1130
int hit_test_base_pick(GLCanvas3D &canvas, const wxMouseEvent &evt) const
Definition DesignSketchTool.cpp:5743
int hit_test_hole_handle(GLCanvas3D &canvas, const wxMouseEvent &evt) const
Definition DesignSketchTool.cpp:6303
int hit_test_dimension(const Vec2d &p, double tol) const
Definition DesignSketchTool.cpp:1378
void open_polygon_side_editor(int fi)
Definition DesignSketchTool.cpp:1727
void drag_slot_handle(int fi, const Vec2d &cursor)
Definition DesignSketchTool.cpp:2361
int m_drag_ei
Definition DesignSketchTool.hpp:1110
void start_shell_drag(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:6663
std::vector< SketchEntity > make_rounded_rect(const Vec2d &a, const Vec2d &b, const Vec2d &radius_pt) const
Definition DesignSketchTool.cpp:3174
Vec2d m_live_poly_angle_label
Definition DesignSketchTool.hpp:1129
int m_pt_press_y
Definition DesignSketchTool.hpp:1629
bool hit_test_op_arrow(const Vec2d &p, double tol) const
Definition DesignSketchTool.cpp:8854
Vec2d m_live_aslot_w_label
Definition DesignSketchTool.hpp:1144
int hit_test(const Vec2d &p, double tol) const
Definition DesignSketchTool.cpp:10704
int feature_of(int ei) const
Definition DesignSketchTool.cpp:950
std::vector< SketchEntity > make_ellipse_arc(const Vec2d &center, const Vec2d &major_end, const Vec2d &minor_pt, const Vec2d &start_pt, const Vec2d &end_pt) const
Definition DesignSketchTool.cpp:3262
void resolve_live_drag(int dragged_ei, SketchPointRole dragged_role)
Definition DesignSketchTool.cpp:873
bool hit_test_draft_handle(GLCanvas3D &canvas, const wxMouseEvent &evt) const
Definition DesignSketchTool.cpp:6781
void begin_feature(FeatureKind kind)
Definition DesignSketchTool.cpp:959
int m_live_rrect_fi
Definition DesignSketchTool.hpp:1142
void open_shell_editor()
Definition DesignSketchTool.cpp:6681
bool m_dragging_handle
Definition DesignSketchTool.hpp:1122
bool hit_test_pattern_handle(GLCanvas3D &canvas, const wxMouseEvent &evt) const
Definition DesignSketchTool.cpp:7198
void drag_hole_handle(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:6359
int m_sh_press_x
Definition DesignSketchTool.hpp:1554
void open_extrude_editor(int which)
Definition DesignSketchTool.cpp:4919
int m_pick_press_y
Definition DesignSketchTool.hpp:206
void open_pattern_editor()
Definition DesignSketchTool.cpp:7258
std::vector< SketchEntity > make_arc_slot(const Vec2d &center, const Vec2d &start, const Vec2d &end_dir, double half_width) const
Definition DesignSketchTool.cpp:3117
bool update_solid_hover(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:4179
int m_rv_press_y
Definition DesignSketchTool.hpp:1573
int hit_test_xform_handle(const Vec2d &p, double tol) const
Definition DesignSketchTool.cpp:8620
bool hit_test_shell_arrow(GLCanvas3D &canvas, const wxMouseEvent &evt) const
Definition DesignSketchTool.cpp:6652
std::vector< SketchEntity > make_center_arc(const Vec2d &center, const Vec2d &start, const Vec2d &end_dir) const
Definition DesignSketchTool.cpp:3076
int m_dz_press_x
Definition DesignSketchTool.hpp:1406
void drag_arc_handle(int ei, SketchPointRole role, const Vec2d &target)
Definition DesignSketchTool.cpp:2030
void open_arc_slot_editor(int fi, bool radius)
Definition DesignSketchTool.cpp:2228
void open_op_editor()
Definition DesignSketchTool.cpp:8869
void open_rounded_rect_editor(int fi, int which)
Definition DesignSketchTool.cpp:2182
int m_ex_press_y
Definition DesignSketchTool.hpp:1393
bool hit_test_helix_handle(GLCanvas3D &canvas, const wxMouseEvent &evt, int &which) const
Definition DesignSketchTool.cpp:5229
int ea
Definition DesignSketchTool.hpp:796
Vec2d m_live_rrect_h_label
Definition DesignSketchTool.hpp:1140
Vec2d m_live_arc_angle_label
Definition DesignSketchTool.hpp:1131
int m_last_mouse_x
Definition DesignSketchTool.hpp:1107
void drag_ellipsearc_handle(int ei, SketchPointRole role, const Vec2d &target)
Definition DesignSketchTool.cpp:2060
void open_fillet_editor()
Definition DesignSketchTool.cpp:6161
SketchPointRole m_drag_role
Definition DesignSketchTool.hpp:1117
Vec2d snap_dir(const Vec2d &anchor, const Vec2d &raw, bool &locked) const
Definition DesignSketchTool.cpp:2560
std::vector< SketchEntity > make_three_point_circle(const Vec2d &a, const Vec2d &b, const Vec2d &c) const
Definition DesignSketchTool.cpp:3009
GLSelectionRectangle m_rubber
Definition DesignSketchTool.hpp:1330
bool hit_test_rib_handle(GLCanvas3D &canvas, const wxMouseEvent &evt, int &which) const
Definition DesignSketchTool.cpp:5371
@ RoundedRect
Definition DesignSketchTool.hpp:826
@ Polygon
Definition DesignSketchTool.hpp:826
@ ArcSlot
Definition DesignSketchTool.hpp:826
@ Slot
Definition DesignSketchTool.hpp:826
@ CornerRect
Definition DesignSketchTool.hpp:825
@ CenterRect
Definition DesignSketchTool.hpp:825
void op_pick(int ei)
Definition DesignSketchTool.cpp:8789
bool hit_test_fillet_arrow(GLCanvas3D &canvas, const wxMouseEvent &evt) const
Definition DesignSketchTool.cpp:6116
bool hit_test_tf_handle(const Vec2d &p, double tol) const
Definition DesignSketchTool.cpp:9251
void drag_revolve_arc(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:7055
void drag_thread_handle(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:6559
void drag_cut_arrow(GLCanvas3D &canvas, const wxMouseEvent &evt)
Definition DesignSketchTool.cpp:6929
bool hit_test_datum_handle(GLCanvas3D &canvas, const wxMouseEvent &evt, int &which) const
Definition DesignSketchTool.cpp:5043
int m_live_aslot_fi
Definition DesignSketchTool.hpp:1145
bool hit_test_cut_arrow(GLCanvas3D &canvas, const wxMouseEvent &evt) const
Definition DesignSketchTool.cpp:6908
int m_hx_press_y
Definition DesignSketchTool.hpp:1425
void drag_datum_handle(GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
Definition DesignSketchTool.cpp:5072
bool m_dragging_point
Definition DesignSketchTool.hpp:1109
int m_mv_press_x
Definition DesignSketchTool.hpp:1468
@ Trim
Definition DesignSketchTool.hpp:98
@ Extend
Definition DesignSketchTool.hpp:98
int m_rv_press_x
Definition DesignSketchTool.hpp:1573
static constexpr double kToolPickPx
Definition DesignSketchTool.hpp:755
void drag_tf_handle(const Vec2d &target)
Definition DesignSketchTool.cpp:9257
void drag_polygon_vertex(int fi, int ei, SketchPointRole role, const Vec2d &target)
Definition DesignSketchTool.cpp:1943
std::vector< SketchEntity > make_tangent_arc(const Vec2d &start, const Vec2d &end) const
Definition DesignSketchTool.cpp:3031
int m_ex_press_x
Definition DesignSketchTool.hpp:1393
Vec2d m_op_label
Definition DesignSketchTool.hpp:1175
Vec2d m_live_ellipse_major_label
Definition DesignSketchTool.hpp:1133
bool m_tf_dragging
Definition DesignSketchTool.hpp:1217
int m_drag_poly_fi
Definition DesignSketchTool.hpp:1111
void grab_move_arrow(int axis, const Linef3 &ray)
Definition DesignSketchTool.cpp:5950
int m_last_mouse_y
Definition DesignSketchTool.hpp:1108
std::function< void(double length, double angle_deg, bool locked)> on_cursor_metrics
Definition DesignSketchTool.hpp:532
int m_pick_press_x
Definition DesignSketchTool.hpp:205
bool hit_test_point(const Vec2d &p, double tol, int &ei, SketchPointRole &role) const
Definition DesignSketchTool.cpp:1202
int m_hl_press_y
Definition DesignSketchTool.hpp:1514
bool hit_test_handle(const Vec2d &p, double tol, Handle &out) const
Definition DesignSketchTool.cpp:1045
int place_dimension(DimAnnot a)
Definition DesignSketchTool.cpp:1367
std::function< void()> on_empty_pick
Definition DesignSketchTool.hpp:294
bool snap_chain_start(GLCanvas3D &canvas, const wxMouseEvent &evt, Vec2d &p) const
Definition DesignSketchTool.cpp:2548
void open_ellipse_axis_editor(int ei, bool major)
Definition DesignSketchTool.cpp:2083
int m_fl_press_x
Definition DesignSketchTool.hpp:1488
void open_revolve_editor()
Definition DesignSketchTool.cpp:7073
Vec2d m_pick0_pt
Definition DesignSketchTool.hpp:1250
bool hit_test_move_arc(GLCanvas3D &canvas, const wxMouseEvent &evt, int &axis) const
Definition DesignSketchTool.cpp:5980
void drag_rib_handle(GLCanvas3D &canvas, const wxMouseEvent &evt, int which)
Definition DesignSketchTool.cpp:5395
void open_move_editor(int axis)
Definition DesignSketchTool.cpp:5967
static constexpr double kPickPx
Definition DesignSketchTool.hpp:754
std::function< void(int)> on_face_selected
Definition DesignSketchTool.hpp:720
Vec2d m_live_aslot_r_label
Definition DesignSketchTool.hpp:1143
std::vector< SketchEntity > make_three_point_arc(const Vec2d &start, const Vec2d &end, const Vec2d &on_arc) const
Definition DesignSketchTool.cpp:3023
bool update_hover(GLCanvas3D &canvas, wxMouseEvent &evt)
Definition DesignSketchTool.cpp:1059
void end_feature(const Vec2d &c0=Vec2d(0, 0), const Vec2d &c1=Vec2d(0, 0), double param=0.0, int sides=0)
Definition DesignSketchTool.cpp:971
@ Select
Definition GLSelectionRectangle.hpp:20

References _u8L, Slic3r::Linef3::a, Angle, append_entities(), apply_live_trim(), Slic3r::SketchEntity::Arc, arc_mouse_angle(), ArcSlot, arm_polyline_segment_edit(), Slic3r::GUI::DesignSketchTool::Feature::begin, begin_feature(), BSpline, BSplineCtrl, Slic3r::GUI::DesignSketchTool::Feature::c0, Slic3r::GUI::DesignSketchTool::Feature::c1, Slic3r::Center, CenterArc, CenterCircle, CenterRect, Slic3r::SketchEntity::Circle, clear_solid_selection(), click_snaps(), connected_loop(), Constrain, CornerRect, Diameter, Dimension, Distance, DistanceToLine, Slic3r::GUI::dp_pick_trace(), drag_arc_handle(), drag_cut_arrow(), drag_datum_handle(), drag_draft_arc(), drag_ellipsearc_handle(), drag_extrude_arrow(), drag_fillet_arrow(), drag_helix_handle(), drag_hole_handle(), drag_move_arc(), drag_move_arrow(), drag_op_arrow(), drag_pattern_handle(), drag_polygon_vertex(), drag_rect_corner(), drag_revolve_arc(), drag_rib_handle(), drag_shell_arrow(), drag_slot_handle(), drag_tf_handle(), drag_thread_handle(), drag_xform_handle(), Slic3r::GUI::DesignSketchTool::DimAnnot::ea, Slic3r::GUI::DesignSketchTool::DimAnnot::eb, edit_dimension(), Slic3r::GUI::DesignSketchTool::Handle::ei, Ellipse, EllipseArc, Slic3r::SketchEntity::EllipseArc, end_chain(), end_feature(), Slic3r::GUI::entity_pick_dist(), Extend, Slic3r::f(), feature_of(), grab_move_arrow(), handle_solid_click(), hit_display_sketch(), hit_test(), hit_test_base_pick(), hit_test_cut_arrow(), hit_test_datum_handle(), hit_test_dimension(), hit_test_draft_handle(), hit_test_extrude_arrow(), hit_test_fillet_arrow(), hit_test_handle(), hit_test_helix_handle(), hit_test_hole_handle(), hit_test_move_arc(), hit_test_move_arrow(), hit_test_op_arrow(), hit_test_pattern_handle(), hit_test_point(), hit_test_revolve_handle(), hit_test_rib_handle(), hit_test_shell_arrow(), hit_test_tf_handle(), hit_test_thread_handle(), hit_test_xform_handle(), infer_auto_constraints(), is_edit_op_mode(), is_transform_mode(), keep_segment_as_drawn(), Slic3r::GUI::DesignSketchTool::DimAnnot::kind, Slic3r::GUI::DesignSketchTool::Feature::kind, kLabelPx, kPickPx, kToolPickPx, Length, Line, Slic3r::SketchEntity::Line, m_active, m_awaiting_length, m_chain_dup_tol, m_constrain_entities, m_ct_active, m_ct_drag, m_cursor, m_cursor_locked, m_cursor_snap, m_dbp_active, m_dbp_base, m_dbp_hover, m_dim_e0, m_dim_has0, m_dim_r0, m_display_pick, m_display_pick_region, m_display_sketches, m_dr_active, m_dr_drag, m_dr_press_x, m_dr_press_y, m_drag_ei, m_drag_handle, m_drag_poly_fi, m_drag_rect_anchor, m_drag_rect_fi, m_drag_role, m_drag_slot_c1, m_drag_slot_fi, m_dragging_handle, m_dragging_point, m_dz_active, m_dz_drag, m_dz_press_x, m_dz_press_y, m_entities, m_ex_active, m_ex_drag, m_ex_press_x, m_ex_press_y, m_features, m_fl_active, m_fl_drag, m_fl_press_x, m_fl_press_y, m_has_cursor, m_hl_active, m_hl_drag, m_hl_press_x, m_hl_press_y, m_hx_active, m_hx_drag, m_hx_press_x, m_hx_press_y, m_last_mouse_x, m_last_mouse_y, m_live_arc_angle_label, m_live_arc_ei, m_live_aslot_fi, m_live_aslot_r_label, m_live_aslot_w_label, m_live_ellipse_ei, m_live_ellipse_major_label, m_live_ellipse_minor_label, m_live_poly_angle_label, m_live_poly_fi, m_live_poly_side_label, m_live_quotes, m_live_rrect_fi, m_live_rrect_h_label, m_live_rrect_r_label, m_live_rrect_w_label, m_live_slot_angle_label, m_live_slot_fi, m_live_slot_len_label, m_live_slot_w_label, m_mirror_targets, m_mode, m_mv_active, m_mv_arc_a0, m_mv_drag, m_mv_press_x, m_mv_press_y, m_mv_rot, m_mv_rot_start, m_op_a, m_op_dragging_arrow, m_op_label, M_PI, m_pick0, m_pick0_pt, m_pick1, m_pick2, m_pick_pending, m_pick_press_x, m_pick_press_y, m_plane, m_point_sel, m_points, m_polygon_sides, m_pt_active, m_pt_drag, m_pt_press_x, m_pt_press_y, m_rb_active, m_rb_drag, m_rubber, m_rv_active, m_rv_drag, m_rv_press_x, m_rv_press_y, m_sel_a, m_sel_b, m_sel_body, m_sel_edge, m_sel_face, m_selection, m_sh_active, m_sh_drag, m_sh_press_x, m_sh_press_y, m_snap_off, m_solid_sel, m_tf_dragging, m_tf_label_a, m_tf_label_b, m_tf_targets, m_th_active, m_th_drag, m_th_press_x, m_th_press_y, m_xform_anchor, m_xform_handle, MajorAxis, make_arc_slot(), make_center_arc(), make_ellipse(), make_ellipse_arc(), make_polygon(), make_rounded_rect(), make_slot(), make_tangent_arc(), make_three_point_arc(), make_three_point_circle(), MinorAxis, Mirror, Slic3r::GUI::GLCanvas3D::mouse_ray(), None, notify(), ObliqueRect, on_cursor_metrics, on_datum_base_picked, on_display_sketch_activated, on_display_sketch_selected, on_empty_pick, on_face_selected, on_inline_commit, on_inline_dismiss, on_mouse_impl(), on_selection_changed, on_solid_selection_changed, op_pick(), op_ready(), open_angle_editor(), open_arc_angle_editor(), open_arc_slot_editor(), open_ellipse_axis_editor(), open_extrude_editor(), open_fillet_editor(), open_hole_editor(), open_move_editor(), open_op_editor(), open_pattern_editor(), open_polygon_angle_editor(), open_polygon_side_editor(), open_revolve_editor(), open_rounded_rect_editor(), open_shell_editor(), open_slot_editor(), open_tf_editor_a(), open_tf_editor_count(), open_thread_editor(), open_value_editor(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, pick_bodies_in_rectangle(), place_dimension(), Point, point_at(), Slic3r::GUI::point_segment_dist(), Polygon, Polyline, push_circle(), push_closed_lines(), push_point(), Slic3r::GUI::DesignSketchTool::DimAnnot::ra, Radius, RadiusHandle, Slic3r::GUI::DesignSketchTool::DimAnnot::rb, region_at(), remove_constraint_near(), reset_op(), reset_tf(), resolve_live(), resolve_live_drag(), right_abandon(), Slic3r::GUI::DesignSketchTool::Handle::role, RoundedRect, screen_to_plane(), screen_tol(), Select, Slic3r::GUI::GLSelectionRectangle::Select, Slic3r::GUI::GLCanvas3D::set_as_dirty(), set_handle(), set_point(), Slot, snap_chain_start(), snap_dir(), snap_vertex(), start_cut_drag(), start_fillet_drag(), start_hole_drag(), start_shell_drag(), start_thread_drag(), TangentArc, tf_pick(), tf_ready(), ThreePointArc, ThreePointCircle, TransformArt, Trim, TwoPointCircle, update_hover(), update_solid_hover(), Slic3r::Linef3::vector(), Slic3r::GUI::wxMouseEvent, xform_world_corners(), and Slic3r::GUI::GLCanvas3D::zoom_to_volumes().

Referenced by on_mouse(), on_mouse_impl(), and take_right_click().

Here is the caller graph for this function:

◆ op_chain_entities()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::op_chain_entities ( ) const
private
8563{
8564 std::vector<SketchEntity> out;
8565 for (int i : m_op_chain)
8566 if (i >= 0 && i < int(m_entities.size())) out.push_back(m_entities[i]);
8567 return out;
8568}

References m_entities, m_op_chain, and op_chain_entities().

Referenced by confirm_op(), op_chain_entities(), and recompute_op_ghost().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ op_corner()

bool Slic3r::GUI::DesignSketchTool::op_corner ( int a,
int b,
Vec2d & C,
Vec2d & bis,
double & theta ) const
private
8707{
8708 if (a < 0 || b < 0 || a >= int(m_entities.size()) || b >= int(m_entities.size())) return false;
8709 const SketchEntity& ea = m_entities[a];
8710 const SketchEntity& eb = m_entities[b];
8711 if (ea.type != SketchEntity::Type::Line || eb.type != SketchEntity::Type::Line) return false;
8712 const Vec2d da = ea.p1 - ea.p0, db = eb.p1 - eb.p0;
8713 const double denom = da.x() * db.y() - da.y() * db.x();
8714 if (std::abs(denom) < 1e-12) return false; // parallel
8715 const Vec2d diff = eb.p0 - ea.p0;
8716 const double s = (diff.x() * db.y() - diff.y() * db.x()) / denom;
8717 C = ea.p0 + s * da;
8718 Vec2d ua = ((ea.p0 - C).norm() <= (ea.p1 - C).norm()) ? (ea.p1 - C) : (ea.p0 - C);
8719 Vec2d ub = ((eb.p0 - C).norm() <= (eb.p1 - C).norm()) ? (eb.p1 - C) : (eb.p0 - C);
8720 if (ua.norm() < 1e-12 || ub.norm() < 1e-12) return false;
8721 ua.normalize(); ub.normalize();
8722 theta = std::acos(std::max(-1.0, std::min(1.0, ua.dot(ub))));
8723 bis = ua + ub;
8724 if (bis.norm() < 1e-12) return false; // 180° corner
8725 bis.normalize();
8726 return true;
8727}
Slic3r::Polygons diff(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:731

References Slic3r::diff(), Slic3r::SketchEntity::Line, m_entities, op_corner(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, and Slic3r::SketchEntity::type.

Referenced by op_corner(), op_pick(), and recompute_op_ghost().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ op_pick()

void Slic3r::GUI::DesignSketchTool::op_pick ( int ei)
private
8790{
8791 if (ei < 0 || ei >= int(m_entities.size())) return;
8792 const SketchEntity::Type t = m_entities[ei].type;
8793 switch (m_mode) {
8794 case Mode::Fillet:
8795 case Mode::Chamfer:
8796 if (t != SketchEntity::Type::Line) return; // corner ops need two lines
8797 if (m_op_a < 0) m_op_a = ei;
8798 else if (ei != m_op_a) {
8799 Vec2d cC, cBis; double cTh = 0.0;
8800 if (!op_corner(m_op_a, ei, cC, cBis, cTh)) { // parallel or straight: no corner
8801 notify(_u8L("Those two lines do not meet at a corner — pick two lines that do"));
8802 return;
8803 }
8804 m_op_b = ei;
8805 const double la = (m_entities[m_op_a].p1 - m_entities[m_op_a].p0).norm();
8806 const double lb = (m_entities[m_op_b].p1 - m_entities[m_op_b].p0).norm();
8807 m_op_value = std::max(0.001, 0.2 * std::min(la, lb)); // a sensible starting size
8809 }
8810 break;
8811 case Mode::Offset: {
8812 m_op_a = ei;
8813 // The whole outline the entity belongs to, not the one segment under the pointer: a
8814 // glyph or an imported outline is hundreds of short lines, and offsetting one of them
8815 // gave a ghost a few hundredths of a millimetre long — no visible preview, and a typed
8816 // distance that moved one invisible segment. Same construction state only.
8817 m_op_chain.clear();
8818 for (int ci : connected_loop(ei))
8819 if (m_entities[ci].construction == m_entities[ei].construction) m_op_chain.push_back(ci);
8820 if (m_op_chain.empty()) m_op_chain.push_back(ei);
8821 // A starting distance that is visible: a twentieth of the outline's size.
8822 Vec2d lo(1e30, 1e30), hi(-1e30, -1e30);
8823 for (int ci : m_op_chain) {
8824 bool closed = false;
8825 for (const Vec2d& q : entity_polyline(m_entities[ci], closed)) { lo = lo.cwiseMin(q); hi = hi.cwiseMax(q); }
8826 }
8827 const double sz = (hi.x() >= lo.x()) ? std::max(hi.x() - lo.x(), hi.y() - lo.y()) : 1.0;
8828 m_op_value = std::max(0.001, 0.05 * sz);
8830 break;
8831 }
8832 case Mode::Mirror:
8833 if (m_op_a < 0) {
8834 if (t != SketchEntity::Type::Line) return; // axis must be a line
8835 m_op_a = ei;
8836 } else if (ei != m_op_a) {
8837 auto it = std::find(m_mirror_targets.begin(), m_mirror_targets.end(), ei);
8838 if (it == m_mirror_targets.end()) m_mirror_targets.push_back(ei);
8839 else m_mirror_targets.erase(it);
8841 }
8842 break;
8843 default: break;
8844 }
8845 // Mirror the picks into m_selection so the existing highlight shows them.
8846 m_selection.clear();
8847 if (m_op_a >= 0) m_selection.push_back(m_op_a);
8848 if (m_op_b >= 0) m_selection.push_back(m_op_b);
8849 for (int ti : m_mirror_targets) m_selection.push_back(ti);
8850 for (int ci : m_op_chain) if (ci != m_op_a) m_selection.push_back(ci);
8852}
bool op_corner(int a, int b, Vec2d &C, Vec2d &bis, double &theta) const
Definition DesignSketchTool.cpp:8706

References _u8L, Chamfer, connected_loop(), entity_polyline(), Fillet, Slic3r::SketchEntity::Line, m_entities, m_mirror_targets, m_mode, m_op_a, m_op_b, m_op_chain, m_op_value, m_selection, Mirror, notify(), Offset, on_selection_changed, op_corner(), op_pick(), and recompute_op_ghost().

Referenced by on_mouse_impl(), and op_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ op_ready()

bool Slic3r::GUI::DesignSketchTool::op_ready ( ) const
private
8693{
8694 switch (m_mode) {
8695 case Mode::Fillet:
8696 case Mode::Chamfer: return m_op_a >= 0 && m_op_b >= 0;
8697 case Mode::Offset: return m_op_a >= 0;
8698 case Mode::Mirror: return m_op_a >= 0 && !m_mirror_targets.empty();
8699 default: return false;
8700 }
8701}

References Chamfer, Fillet, m_mirror_targets, m_mode, m_op_a, m_op_b, Mirror, Offset, and op_ready().

Referenced by confirm_op(), confirm_pending(), emit_step_hint(), finish(), hit_test_op_arrow(), on_mouse_impl(), op_ready(), open_op_editor(), render_op_gizmo(), and set_tool().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_angle_editor()

void Slic3r::GUI::DesignSketchTool::open_angle_editor ( int ei)
private
1447{
1448 if (ei < 0 || ei >= int(m_entities.size())) return;
1449 if (m_entities[ei].type != SketchEntity::Type::Line) return;
1450 if (!on_inline_edit) return;
1451 DimAnnot a; a.kind = DimType::Angle; a.ea = ei;
1452 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
1453 on_inline_edit(px, measure_dim(a), _u8L("Angle (°)"),
1454 [this, ei](double deg) { set_line_angle(ei, deg); },
1455 []() {});
1456}
double measure_dim(const DimAnnot &a) const
Definition DesignSketchTool.cpp:1239
void set_line_angle(int ei, double deg)
Definition DesignSketchTool.cpp:1486
int64_t px(const Point &pt)
Definition ClipperUtils.cpp:207

References _u8L, Angle, Slic3r::GUI::DesignSketchTool::DimAnnot::ea, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, Slic3r::SketchEntity::Line, m_entities, m_last_mouse_x, m_last_mouse_y, measure_dim(), on_inline_edit, and set_line_angle().

Referenced by on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_arc_angle_editor()

void Slic3r::GUI::DesignSketchTool::open_arc_angle_editor ( int ei)
private
1998{
1999 if (ei < 0 || ei >= int(m_entities.size()) || !on_inline_edit) return;
2000 const SketchEntity& e = m_entities[ei];
2001 if (e.type != SketchEntity::Type::Arc) return;
2002 double swdeg = std::abs(e.end_angle - e.start_angle) * 180.0 / M_PI;
2003 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
2004 on_inline_edit(px, swdeg, _u8L("Angle (°)"),
2005 [this, ei](double v) { set_arc_sweep(ei, v); },
2006 []() {});
2007}
void set_arc_sweep(int ei, double deg)
Definition DesignSketchTool.cpp:2013

References _u8L, Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::end_angle, m_entities, m_last_mouse_x, m_last_mouse_y, M_PI, on_inline_edit, open_arc_angle_editor(), set_arc_sweep(), Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by on_mouse_impl(), and open_arc_angle_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_arc_slot_editor()

void Slic3r::GUI::DesignSketchTool::open_arc_slot_editor ( int fi,
bool radius )
private
2229{
2230 if (fi < 0 || fi >= int(m_features.size()) || !on_inline_edit) return;
2231 const Feature& f = m_features[fi];
2232 const double Rc = (f.c1 - f.c0).norm();
2233 const double v = radius ? Rc : (2.0 * f.param); // width quote shows the FULL width
2234 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
2235 on_inline_edit(px, v, radius ? _u8L("Radius") : _u8L("Width"),
2236 [this, fi, radius](double nv) {
2237 const Feature& g = m_features[fi];
2238 const double gRc = (g.c1 - g.c0).norm();
2239 if (radius) set_arc_slot(fi, nv, g.param);
2240 else set_arc_slot(fi, gRc, nv * 0.5); // full width -> half
2241 },
2242 []() {});
2243}
void set_arc_slot(int fi, double Rc, double w)
Definition DesignSketchTool.cpp:2248

References _u8L, Slic3r::GUI::DesignSketchTool::Feature::c0, Slic3r::GUI::DesignSketchTool::Feature::c1, Slic3r::f(), m_features, m_last_mouse_x, m_last_mouse_y, on_inline_edit, open_arc_slot_editor(), Slic3r::GUI::DesignSketchTool::Feature::param, and set_arc_slot().

Referenced by on_mouse_impl(), and open_arc_slot_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_ellipse_axis_editor()

void Slic3r::GUI::DesignSketchTool::open_ellipse_axis_editor ( int ei,
bool major )
private
2084{
2085 if (ei < 0 || ei >= int(m_entities.size()) || !on_inline_edit) return;
2086 const SketchEntity& e = m_entities[ei];
2087 if (e.type != SketchEntity::Type::Ellipse && e.type != SketchEntity::Type::EllipseArc) return;
2088 const double v = major ? e.radius : e.rminor;
2089 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
2090 on_inline_edit(px, v, major ? _u8L("Semi-major axis") : _u8L("Semi-minor axis"),
2091 [this, ei, major](double nv) { set_ellipse_axis(ei, major, nv); },
2092 []() {});
2093}
void set_ellipse_axis(int ei, bool major, double v)
Definition DesignSketchTool.cpp:2096

References _u8L, Slic3r::SketchEntity::Ellipse, Slic3r::SketchEntity::EllipseArc, m_entities, m_last_mouse_x, m_last_mouse_y, on_inline_edit, open_ellipse_axis_editor(), Slic3r::SketchEntity::radius, Slic3r::SketchEntity::rminor, set_ellipse_axis(), and Slic3r::SketchEntity::type.

Referenced by on_mouse_impl(), and open_ellipse_axis_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_extrude_editor()

void Slic3r::GUI::DesignSketchTool::open_extrude_editor ( int which)
private
4920{
4921 if (!on_inline_edit) return;
4922 const double cur = (which == 1) ? m_ex_depth2 : m_ex_depth;
4923 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
4924 on_inline_edit(px, cur, "",
4925 [this, which](double v) {
4926 const double d = std::max(0.01, v);
4927 if (which == 1) m_ex_depth2 = d; else m_ex_depth = d;
4929 },
4930 []() {});
4931}

References m_ex_depth, m_ex_depth2, m_last_mouse_x, m_last_mouse_y, on_extrude_depth_changed, on_inline_edit, and open_extrude_editor().

Referenced by on_mouse_impl(), and open_extrude_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_fillet_editor()

void Slic3r::GUI::DesignSketchTool::open_fillet_editor ( )
private
6162{
6163 if (!on_inline_edit) return;
6164 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
6166 [this](double v) {
6167 m_fl_radius = std::max(0.01, v);
6169 },
6170 []() {});
6171}

References m_fl_radius, m_last_mouse_x, m_last_mouse_y, on_fillet_radius_changed, on_inline_edit, and open_fillet_editor().

Referenced by on_mouse_impl(), and open_fillet_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_hole_editor()

void Slic3r::GUI::DesignSketchTool::open_hole_editor ( int which)
private
6380{
6381 if (!on_inline_edit) return;
6382 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
6383 if (which == 1) {
6385 [this](double v) {
6386 m_hl_diameter = std::max(0.01, v);
6388 },
6389 []() {});
6390 } else if (which == 2) {
6391 on_inline_edit(px, m_hl_depth, "",
6392 [this](double v) {
6393 m_hl_depth = std::max(0.01, v);
6395 },
6396 []() {});
6397 } else if (which == 3) { // #2 Part B: edit the distance from the u-side
6398 const double ru = m_hl_has_bounds ? m_hl_umin : 0.0;
6399 on_inline_edit(px, m_hl_x - ru, "",
6400 [this, ru](double v) {
6401 m_hl_x = ru + v;
6403 },
6404 []() {});
6405 } else if (which == 4) { // edit the distance from the v-side
6406 const double rv = m_hl_has_bounds ? m_hl_vmin : 0.0;
6407 on_inline_edit(px, m_hl_y - rv, "",
6408 [this, rv](double v) {
6409 m_hl_y = rv + v;
6411 },
6412 []() {});
6413 }
6414 // which == 0 (centre): no scalar to edit inline — it's a drag-only reposition handle.
6415}
bool m_hl_has_bounds
Definition DesignSketchTool.hpp:1511
double m_hl_umin
Definition DesignSketchTool.hpp:1512
double m_hl_vmin
Definition DesignSketchTool.hpp:1512

References m_hl_depth, m_hl_diameter, m_hl_has_bounds, m_hl_umin, m_hl_vmin, m_hl_x, m_hl_y, m_last_mouse_x, m_last_mouse_y, on_hole_changed, on_inline_edit, and open_hole_editor().

Referenced by on_mouse_impl(), and open_hole_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_move_editor()

void Slic3r::GUI::DesignSketchTool::open_move_editor ( int axis)
private
5968{
5969 if (!on_inline_edit) return;
5970 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
5971 on_inline_edit(px, m_mv_offset[axis], "",
5972 [this, axis](double v) {
5973 m_mv_offset[axis] = v;
5975 },
5976 []() {});
5977}

References compose_move_xform(), m_last_mouse_x, m_last_mouse_y, m_mv_body, m_mv_offset, on_body_move_changed, on_inline_edit, and open_move_editor().

Referenced by on_mouse_impl(), and open_move_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_next_autoedit_dim()

void Slic3r::GUI::DesignSketchTool::open_next_autoedit_dim ( )
private
1505{
1506 if (!on_inline_edit || !m_active) { m_autoedit_dim_idx = -1; return; }
1508 m_autoedit_dim_idx = -1;
1509 return;
1510 }
1512 // Anchor the field OVER this dimension's label (project its plane-coords centre to the
1513 // viewport), not at the last cursor spot — otherwise each field pops up in an unrelated
1514 // screen position. Fall back to the cursor if the label projects off-screen.
1515 // Anchor the field OVER this dimension's label (project its plane-coords centre to the
1516 // viewport). A label can project OFF-screen (near-degenerate perspective divide when the
1517 // sketch plane is viewed at a grazing angle), in which case we fall back to the cursor —
1518 // but staggered by step index, so a shape's successive fields (rrect W/H/R) don't all
1519 // stack on the exact same pixel and hide each other.
1520 const Camera& cam = wxGetApp().plater()->get_camera();
1521 const wxPoint lp = world_to_screen_px(cam, m_plane.to_world(step.label));
1522 const std::array<int, 4>& vp = cam.get_viewport();
1524 if (lp.x >= vp[0] && lp.y >= vp[1] && lp.x <= vp[0] + vp[2] && lp.y <= vp[1] + vp[3])
1525 px = lp;
1526 on_inline_edit(px, step.value, step.title,
1527 [this, step](double v) { // commit: apply this dimension, then next
1528 if (step.apply) step.apply(v);
1529 // A refused value brought the same field back (show_refusal): stay on this step.
1530 if (inline_editor != nullptr && inline_editor->is_open()) return;
1531 ++m_autoedit_dim_idx;
1532 wxGetApp().CallAfter([this] { open_next_autoedit_dim(); });
1533 },
1534 [this]() { m_autoedit_dim_idx = -1; }); // cancel: keep as drawn, stop the chain
1535}
Definition DesignSketchTool.hpp:1090

References Slic3r::GUI::Camera::get_viewport(), m_active, m_autoedit_dim_idx, m_autoedit_dims, m_last_mouse_x, m_last_mouse_y, m_plane, on_inline_edit, and Slic3r::GUI::world_to_screen_px().

Referenced by arm_polyline_segment_edit(), and open_primary_autoedit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_op_editor()

void Slic3r::GUI::DesignSketchTool::open_op_editor ( )
private
8870{
8871 if (!on_inline_edit || !op_ready() || m_mode == Mode::Mirror) return;
8872 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
8873 // Offset is signed the same way the arrow drag is (the sign picks the side), so the field
8874 // shows and accepts the sign instead of silently keeping the old one. Fillet/Chamfer sizes
8875 // are positive: a non-positive one is refused, not clamped to a hairline.
8876 on_inline_edit(px, m_op_value, m_mode == Mode::Offset ? _u8L("Distance") : m_mode == Mode::Fillet ? _u8L("Radius") : _u8L("Size"),
8877 [this](double v) {
8878 if (m_mode != Mode::Offset && v <= 0.0) {
8879 show_refusal(_u8L("The size must be greater than zero"));
8880 return;
8881 }
8882 m_op_value = v;
8883 // Entering a radius IS the commit. Leaving it as a preview meant the most obvious
8884 // route of all — click the radius, type it, press Return — ended with the value set,
8885 // the ghost drawn, and no geometry written; the only paths that ever applied it were
8886 // finishing the whole sketch or clicking empty space, neither of which is signposted.
8887 if (op_ready()) confirm_op();
8888 else recompute_op_ghost();
8889 },
8890 []() {});
8891}

References _u8L, confirm_op(), Fillet, m_last_mouse_x, m_last_mouse_y, m_mode, m_op_value, Mirror, Offset, on_inline_edit, op_ready(), open_op_editor(), recompute_op_ghost(), and show_refusal().

Referenced by on_mouse_impl(), and open_op_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_pattern_editor()

void Slic3r::GUI::DesignSketchTool::open_pattern_editor ( )
private
7259{
7260 if (!on_inline_edit) return;
7261 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
7262 const double cur = m_pt_circular ? m_pt_angle : m_pt_spacing;
7263 on_inline_edit(px, cur, "",
7264 [this](double v) {
7265 if (m_pt_circular) m_pt_angle = std::min(360.0, std::max(1.0, v));
7266 else m_pt_spacing = std::max(0.1, v);
7268 },
7269 []() {});
7270}

References m_last_mouse_x, m_last_mouse_y, m_pt_angle, m_pt_circular, m_pt_spacing, on_inline_edit, on_pattern_changed, and open_pattern_editor().

Referenced by on_mouse_impl(), and open_pattern_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_polygon_angle_editor()

void Slic3r::GUI::DesignSketchTool::open_polygon_angle_editor ( int fi)
private
1741{
1742 if (fi < 0 || fi >= int(m_features.size()) || !on_inline_edit) return;
1743 const Feature& f = m_features[fi];
1744 if (f.begin < 0 || f.begin >= int(m_entities.size())) return;
1745 const Vec2d sp = m_entities[f.begin].p0 - f.c0; // centre -> vertex0 spoke
1746 double deg = std::atan2(sp.y(), sp.x()) * 180.0 / M_PI;
1747 if (deg < 0.0) deg += 360.0;
1748 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
1749 on_inline_edit(px, deg, _u8L("Angle (°)"),
1750 [this, fi](double v) { set_polygon_angle(fi, v); },
1751 []() {});
1752}
void set_polygon_angle(int fi, double deg)
Definition DesignSketchTool.cpp:1913

References _u8L, Slic3r::f(), m_entities, m_features, m_last_mouse_x, m_last_mouse_y, M_PI, on_inline_edit, open_polygon_angle_editor(), and set_polygon_angle().

Referenced by on_mouse_impl(), and open_polygon_angle_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_polygon_side_editor()

void Slic3r::GUI::DesignSketchTool::open_polygon_side_editor ( int fi)
private
1728{
1729 if (fi < 0 || fi >= int(m_features.size()) || !on_inline_edit) return;
1730 const Feature& f = m_features[fi];
1731 if (f.begin < 0 || f.begin >= int(m_entities.size())) return;
1732 const double side = (m_entities[f.begin].p1 - m_entities[f.begin].p0).norm();
1733 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
1734 // TRN Design sketch: length of one side of a regular polygon (inline value editor title)
1735 on_inline_edit(px, side, _u8L("Side"),
1736 [this, fi](double v) { set_polygon_side(fi, v); },
1737 []() {});
1738}
void set_polygon_side(int fi, double side)
Definition DesignSketchTool.cpp:1756

References _u8L, Slic3r::f(), m_entities, m_features, m_last_mouse_x, m_last_mouse_y, on_inline_edit, open_polygon_side_editor(), and set_polygon_side().

Referenced by on_mouse_impl(), and open_polygon_side_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_primary_autoedit()

void Slic3r::GUI::DesignSketchTool::open_primary_autoedit ( )
private
1600{
1601 if (!on_inline_edit) { trace_autoedit("skip: no on_inline_edit host", 0); return; }
1602 if (m_awaiting_length) { trace_autoedit("skip: a field is already open", 0); return; }
1603 if (!m_active) { trace_autoedit("skip: session ended before the deferred tick", 0); return; }
1604
1605 // Build ONE ordered list of edit steps covering EVERY characteristic dimension of the
1606 // freshly-drawn shape — scalar quotes (constraint-based) AND geometric editors — so every
1607 // 2D tool behaves like the rectangle: a linear sequence of value fields, each over its own
1608 // label, Enter advances to the next, Esc keeps the shape as drawn. (Line keeps its own
1609 // dedicated length field; Polyline/BSpline/Point have no two-click dimension set.)
1610 m_autoedit_dims.clear();
1611
1612 // (1) Scalar quotes: rect Width+Height, slot Distance+Radius, circle/arc Radius, line
1613 // Length. The lone Angle quote (only a single Line emits one) becomes a GEOMETRIC
1614 // orientation step (set_line_angle, like the polygon angle) — so the Line tool gets
1615 // Length THEN Angle, same as the rectangle gets W then H.
1616 for (const DimAnnot& q : m_live_quotes) {
1617 if (q.kind == DimType::Angle) {
1618 const int ei = q.ea;
1619 m_autoedit_dims.push_back({ q.label_pos, measure_dim(q),
1620 [this, ei](double v) { set_line_angle(ei, v); }, { ei }, _u8L("Angle (°)") });
1621 continue;
1622 }
1623 DimAnnot a = q;
1624 a.value = measure_dim(a);
1625 m_autoedit_dims.push_back({ a.label_pos, a.value,
1626 [this, a](double v) mutable {
1627 const bool positive = a.kind == DimType::Length || a.kind == DimType::Radius || a.kind == DimType::Diameter;
1628 if (!std::isfinite(v) || (positive && v <= 0.0) || (!positive && v < 0.0)) {
1629 show_refusal(positive ? _u8L("The value must be greater than zero")
1630 : _u8L("The value must not be negative (zero means coincident)"));
1631 return;
1632 }
1633 a.value = v;
1636 resolve_live();
1637 }, { a.ea, a.eb }, dimtype_title(a.kind) });
1638 }
1639
1640 // (2) Geometric editors (mutate geometry directly, no constraint). Each reads the CURRENT
1641 // feature/entity state inside apply(), so sequential edits compose correctly.
1642 // Entities to highlight = the feature's whole [begin,end) span, so editing any of its
1643 // characteristic dims lights up the shape it drives.
1644 auto span = [this](int fi) {
1645 std::vector<int> v;
1646 if (fi >= 0 && fi < int(m_features.size()))
1647 for (int k = m_features[fi].begin; k < m_features[fi].end; ++k) v.push_back(k);
1648 return v;
1649 };
1650 if (m_live_poly_fi >= 0) {
1652 const int fi = m_live_poly_fi;
1653 if (f.begin >= 0 && f.begin < int(m_entities.size())) {
1654 const double side = (m_entities[f.begin].p1 - m_entities[f.begin].p0).norm();
1655 const Vec2d sp = m_entities[f.begin].p0 - f.c0;
1656 double deg = std::atan2(sp.y(), sp.x()) * 180.0 / M_PI; if (deg < 0.0) deg += 360.0;
1657 m_autoedit_dims.push_back({ m_live_poly_side_label, side, [this, fi](double v){ set_polygon_side(fi, v); }, span(fi), _u8L("Side") });
1658 m_autoedit_dims.push_back({ m_live_poly_angle_label, deg, [this, fi](double v){ set_polygon_angle(fi, v); }, span(fi), _u8L("Angle (°)") });
1659 }
1660 }
1661 if (m_live_rrect_fi >= 0) {
1663 const int fi = m_live_rrect_fi;
1664 const double w = std::abs(f.c1.x() - f.c0.x()), h = std::abs(f.c1.y() - f.c0.y()), r = f.param;
1665 auto rr_w = [this, fi](double v){ const Feature& g = m_features[fi]; set_rounded_rect(fi, v, std::abs(g.c1.y()-g.c0.y()), g.param); };
1666 auto rr_h = [this, fi](double v){ const Feature& g = m_features[fi]; set_rounded_rect(fi, std::abs(g.c1.x()-g.c0.x()), v, g.param); };
1667 auto rr_r = [this, fi](double v){ const Feature& g = m_features[fi]; set_rounded_rect(fi, std::abs(g.c1.x()-g.c0.x()), std::abs(g.c1.y()-g.c0.y()), v); };
1668 m_autoedit_dims.push_back({ m_live_rrect_w_label, w, rr_w, span(fi), _u8L("Width") });
1669 m_autoedit_dims.push_back({ m_live_rrect_h_label, h, rr_h, span(fi), _u8L("Height") });
1670 m_autoedit_dims.push_back({ m_live_rrect_r_label, r, rr_r, span(fi), _u8L("Radius") });
1671 }
1672 if (m_live_aslot_fi >= 0) {
1674 const int fi = m_live_aslot_fi;
1675 const double Rc = (f.c1 - f.c0).norm(), fw = 2.0 * f.param;
1676 m_autoedit_dims.push_back({ m_live_aslot_r_label, Rc, [this, fi](double v){ const Feature& g = m_features[fi]; set_arc_slot(fi, v, g.param); }, span(fi), _u8L("Radius") });
1677 m_autoedit_dims.push_back({ m_live_aslot_w_label, fw, [this, fi](double v){ const Feature& g = m_features[fi]; set_arc_slot(fi, (g.c1-g.c0).norm(), v * 0.5); }, span(fi), _u8L("Width") });
1678 }
1679 if (m_live_slot_fi >= 0) {
1681 const int fi = m_live_slot_fi;
1682 // Slot dims, in order: (1) inter-centre distance, (2) full width (as the arc slot), (3) angle.
1683 const Vec2d d = f.c1 - f.c0;
1684 const double Lc = d.norm();
1685 double deg = std::atan2(d.y(), d.x()) * 180.0 / M_PI; if (deg < 0.0) deg += 360.0;
1686 m_autoedit_dims.push_back({ m_live_slot_len_label, Lc, [this, fi](double v){ const Feature& g = m_features[fi]; set_slot(fi, v, g.param); }, span(fi), _u8L("Length") });
1687 m_autoedit_dims.push_back({ m_live_slot_w_label, 2.0 * f.param, [this, fi](double v){ const Feature& g = m_features[fi]; set_slot(fi, (g.c1-g.c0).norm(), v * 0.5); }, span(fi), _u8L("Width") });
1688 m_autoedit_dims.push_back({ m_live_slot_angle_label, deg, [this, fi](double v){ set_slot_angle(fi, v); }, span(fi), _u8L("Angle (°)") });
1689 }
1690 if (m_live_arc_ei >= 0) { // arc Radius is already a scalar step above; add its sweep angle
1691 const int ei = m_live_arc_ei;
1692 const SketchEntity& e = m_entities[ei];
1693 const double swdeg = std::abs(e.end_angle - e.start_angle) * 180.0 / M_PI;
1694 m_autoedit_dims.push_back({ m_live_arc_angle_label, swdeg, [this, ei](double v){ set_arc_sweep(ei, v); }, { ei }, _u8L("Angle (°)") });
1695 }
1696 if (m_live_ellipse_ei >= 0) {
1697 const int ei = m_live_ellipse_ei;
1698 const SketchEntity& e = m_entities[ei];
1699 m_autoedit_dims.push_back({ m_live_ellipse_major_label, e.radius, [this, ei](double v){ set_ellipse_axis(ei, true, v); }, { ei }, _u8L("Semi-major axis") });
1700 m_autoedit_dims.push_back({ m_live_ellipse_minor_label, e.rminor, [this, ei](double v){ set_ellipse_axis(ei, false, v); }, { ei }, _u8L("Semi-minor axis") });
1701 if (e.type == SketchEntity::Type::EllipseArc) { // + included sweep
1702 const double swdeg = std::abs(e.end_angle - e.start_angle) * 180.0 / M_PI;
1704 [this, ei](double v){ set_ellipsearc_sweep(ei, v); }, { ei }, _u8L("Angle (°)") });
1705 }
1706 }
1707 if (m_live_obrect_fi >= 0) { // oblique rect: W,H already added as scalars; + orientation
1708 const int fi = m_live_obrect_fi;
1709 const Feature& f = m_features[fi];
1710 const SketchEntity& e0 = m_entities[f.begin];
1711 double adeg = std::atan2(e0.p1.y() - e0.p0.y(), e0.p1.x() - e0.p0.x()) * 180.0 / M_PI;
1712 if (adeg < 0.0) adeg += 360.0;
1714 [this, fi](double v){ set_rect_angle(fi, v); }, span(fi), _u8L("Angle (°)") });
1715 }
1716
1717 trace_autoedit(m_autoedit_dims.empty() ? "built NO steps (no live quote matched)" : "opening",
1718 m_autoedit_dims.size());
1719 if (!m_autoedit_dims.empty()) {
1722 }
1723}
void set_ellipsearc_sweep(int ei, double deg)
Definition DesignSketchTool.cpp:2117
Vec2d m_live_ellipsearc_sweep_label
Definition DesignSketchTool.hpp:1135
int upsert_dimension(const DimAnnot &a)
Definition DesignSketchTool.cpp:1325
double value
Definition DesignSketchTool.hpp:798
void set_slot_angle(int fi, double deg)
Definition DesignSketchTool.cpp:2319
int upsert_dimension_constraint(const SketchEntityConstraintDef &c)
Definition DesignSketchTool.cpp:1308
Vec2d m_live_obrect_angle_label
Definition DesignSketchTool.hpp:1137
SketchEntityConstraintDef constraint_for(const DimAnnot &a) const
Definition DesignSketchTool.cpp:1340
int m_live_obrect_fi
Definition DesignSketchTool.hpp:1138
void set_slot(int fi, double length, double w)
Definition DesignSketchTool.cpp:2298
std::string dimtype_title(DimType k) const
Definition DesignSketchTool.cpp:1573
void set_rounded_rect(int fi, double w, double h, double r)
Definition DesignSketchTool.cpp:2206
void set_rect_angle(int fi, double deg)
Definition DesignSketchTool.cpp:2134
static void trace_autoedit(const char *why, size_t n)
Definition DesignSketchTool.cpp:1592

References _u8L, Angle, begin(), Slic3r::GUI::DesignSketchTool::Feature::c0, Slic3r::GUI::DesignSketchTool::Feature::c1, Slic3r::GUI::DesignSketchTool::DimAnnot::con, constraint_for(), Diameter, dimtype_title(), Slic3r::GUI::DesignSketchTool::DimAnnot::ea, Slic3r::GUI::DesignSketchTool::DimAnnot::eb, Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::end_angle, Slic3r::f(), Slic3r::GUI::DesignSketchTool::DimAnnot::kind, Slic3r::GUI::DesignSketchTool::DimAnnot::label_pos, Length, m_active, m_autoedit_dim_idx, m_autoedit_dims, m_awaiting_length, m_entities, m_features, m_live_arc_angle_label, m_live_arc_ei, m_live_aslot_fi, m_live_aslot_r_label, m_live_aslot_w_label, m_live_ellipse_ei, m_live_ellipse_major_label, m_live_ellipse_minor_label, m_live_ellipsearc_sweep_label, m_live_obrect_angle_label, m_live_obrect_fi, m_live_poly_angle_label, m_live_poly_fi, m_live_poly_side_label, m_live_quotes, m_live_rrect_fi, m_live_rrect_h_label, m_live_rrect_r_label, m_live_rrect_w_label, m_live_slot_angle_label, m_live_slot_fi, m_live_slot_len_label, m_live_slot_w_label, M_PI, measure_dim(), on_inline_edit, open_next_autoedit_dim(), open_primary_autoedit(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::GUI::DesignSketchTool::Feature::param, Radius, Slic3r::SketchEntity::radius, resolve_live(), Slic3r::SketchEntity::rminor, set_arc_slot(), set_arc_sweep(), set_ellipse_axis(), set_ellipsearc_sweep(), set_line_angle(), set_polygon_angle(), set_polygon_side(), set_rect_angle(), set_rounded_rect(), set_slot(), set_slot_angle(), show_refusal(), Slic3r::SketchEntity::start_angle, Slic3r::GUI::trace_autoedit(), Slic3r::SketchEntity::type, upsert_dimension(), upsert_dimension_constraint(), and Slic3r::GUI::DesignSketchTool::DimAnnot::value.

Referenced by open_primary_autoedit(), and render().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_revolve_editor()

void Slic3r::GUI::DesignSketchTool::open_revolve_editor ( )
private
7074{
7075 if (!on_inline_edit) return;
7076 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
7077 on_inline_edit(px, m_rv_angle, "",
7078 [this](double v) {
7079 m_rv_angle = std::min(360.0, std::max(1.0, v));
7081 },
7082 []() {});
7083}

References m_last_mouse_x, m_last_mouse_y, m_rv_angle, on_inline_edit, on_revolve_angle_changed, and open_revolve_editor().

Referenced by on_mouse_impl(), and open_revolve_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_rounded_rect_editor()

void Slic3r::GUI::DesignSketchTool::open_rounded_rect_editor ( int fi,
int which )
private
2183{
2184 if (fi < 0 || fi >= int(m_features.size()) || !on_inline_edit) return;
2185 const Feature& f = m_features[fi];
2186 const double w = std::abs(f.c1.x() - f.c0.x());
2187 const double h = std::abs(f.c1.y() - f.c0.y());
2188 const double r = f.param;
2189 const double v = (which == 0) ? w : (which == 1) ? h : r;
2190 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
2191 on_inline_edit(px, v, which == 0 ? _u8L("Width") : which == 1 ? _u8L("Height") : _u8L("Radius"),
2192 [this, fi, which](double nv) {
2193 const Feature& g = m_features[fi];
2194 double gw = std::abs(g.c1.x() - g.c0.x());
2195 double gh = std::abs(g.c1.y() - g.c0.y());
2196 double gr = g.param;
2197 if (which == 0) gw = nv; else if (which == 1) gh = nv; else gr = nv;
2198 set_rounded_rect(fi, gw, gh, gr);
2199 },
2200 []() {});
2201}

References _u8L, Slic3r::GUI::DesignSketchTool::Feature::c0, Slic3r::GUI::DesignSketchTool::Feature::c1, Slic3r::f(), m_features, m_last_mouse_x, m_last_mouse_y, on_inline_edit, open_rounded_rect_editor(), Slic3r::GUI::DesignSketchTool::Feature::param, and set_rounded_rect().

Referenced by on_mouse_impl(), and open_rounded_rect_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_selection_dimension_editor()

bool Slic3r::GUI::DesignSketchTool::open_selection_dimension_editor ( )
1467{
1468 if (!on_inline_edit || !selection_valid()) return false;
1469 const DimType k = dimension_kind();
1470 if (k == DimType::None) return false;
1471 const std::string title = dimtype_title(k);
1472 // Anchor over the geometry it belongs to, not the panel: the value belongs to the element.
1473 DimAnnot a; a.kind = k;
1474 a.ea = m_selection.empty() ? -1 : m_selection[0];
1475 if (m_selection.size() > 1) a.eb = m_selection[1];
1476 const Vec2d at = dim_anchor(a);
1477 const Camera& cam = wxGetApp().plater()->get_camera();
1478 wxPoint px = world_to_screen_px(cam, m_plane.to_world(at));
1479 if (px.x < 0 || px.y < 0) px = wxPoint(m_last_mouse_x, m_last_mouse_y);
1480 on_inline_edit(px, dimension_current(), title,
1481 [this](double v) { apply_dimension(v); },
1482 []() {});
1483 return true;
1484}
void apply_dimension(double v)
Definition DesignSketchTool.cpp:746
double dimension_current() const
Definition DesignSketchTool.cpp:667
Vec2d dim_anchor(const DimAnnot &a) const
Definition DesignSketchTool.cpp:1399

References apply_dimension(), dim_anchor(), dimension_current(), dimension_kind(), dimtype_title(), Slic3r::GUI::DesignSketchTool::DimAnnot::ea, Slic3r::GUI::DesignSketchTool::DimAnnot::eb, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, m_last_mouse_x, m_last_mouse_y, m_plane, m_selection, None, on_inline_edit, selection_valid(), and Slic3r::GUI::world_to_screen_px().

Here is the call graph for this function:

◆ open_shell_editor()

void Slic3r::GUI::DesignSketchTool::open_shell_editor ( )
private
6682{
6683 if (!on_inline_edit) return;
6684 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
6686 [this](double v) {
6687 m_sh_thickness = std::max(0.01, v);
6689 },
6690 []() {});
6691}

References m_last_mouse_x, m_last_mouse_y, m_sh_thickness, on_inline_edit, on_shell_thickness_changed, and open_shell_editor().

Referenced by on_mouse_impl(), and open_shell_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_slot_editor()

void Slic3r::GUI::DesignSketchTool::open_slot_editor ( int fi,
int which )
private
2278{
2279 if (fi < 0 || fi >= int(m_features.size()) || !on_inline_edit) return;
2280 const Feature& f = m_features[fi];
2281 const Vec2d d = f.c1 - f.c0;
2282 double deg = std::atan2(d.y(), d.x()) * 180.0 / M_PI; if (deg < 0.0) deg += 360.0;
2283 const double v = (which == 0) ? d.norm() : (which == 1) ? 2.0 * f.param : deg;
2284 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
2285 on_inline_edit(px, v, which == 0 ? _u8L("Length") : which == 1 ? _u8L("Width") : _u8L("Angle (°)"),
2286 [this, fi, which](double nv) {
2287 const Feature& g = m_features[fi];
2288 if (which == 0) set_slot(fi, nv, g.param);
2289 else if (which == 1) set_slot(fi, (g.c1 - g.c0).norm(), nv * 0.5); // full width -> half
2290 else set_slot_angle(fi, nv);
2291 },
2292 []() {});
2293}

References _u8L, Slic3r::GUI::DesignSketchTool::Feature::c0, Slic3r::GUI::DesignSketchTool::Feature::c1, Slic3r::f(), m_features, m_last_mouse_x, m_last_mouse_y, M_PI, on_inline_edit, open_slot_editor(), Slic3r::GUI::DesignSketchTool::Feature::param, set_slot(), and set_slot_angle().

Referenced by on_mouse_impl(), and open_slot_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_tf_editor_a()

void Slic3r::GUI::DesignSketchTool::open_tf_editor_a ( )
private
9281{
9282 if (!on_inline_edit || !tf_ready()) return;
9283 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
9284 double cur;
9285 if (m_mode == Mode::Rotate || m_mode == Mode::PolarArray) cur = m_tf_angle * 180.0 / M_PI;
9286 else if (m_mode == Mode::Scale) cur = m_tf_scale;
9287 else cur = m_tf_delta.norm();
9288 Vec2d dir = m_tf_delta; if (dir.norm() > 1e-9) dir.normalize(); else dir = Vec2d(1, 0);
9289 const char* title = (m_mode == Mode::Rotate || m_mode == Mode::PolarArray) ? L("Angle (°)")
9290 : (m_mode == Mode::Scale) ? L("Scale factor") : L("Distance");
9291 on_inline_edit(px, cur, _u8L(title),
9292 [this, dir](double v) {
9293 switch (m_mode) {
9294 case Mode::Move: case Mode::Array: m_tf_delta = dir * v; break; // signed: flips the direction
9295 case Mode::Rotate: case Mode::PolarArray: m_tf_angle = v * M_PI / 180.0; break; // signed: CCW positive
9296 case Mode::Scale:
9297 if (v <= 0.0) { show_refusal(_u8L("The scale factor must be greater than zero")); return; }
9298 m_tf_scale = v;
9299 break;
9300 default: break;
9301 }
9302 // Enter IS the commit, the same rule the edit-op field follows.
9304 },
9305 []() {});
9306}

References _u8L, Array, confirm_transform(), L, m_last_mouse_x, m_last_mouse_y, m_mode, M_PI, m_tf_angle, m_tf_delta, m_tf_scale, Move, on_inline_edit, open_tf_editor_a(), PolarArray, Rotate, Scale, show_refusal(), and tf_ready().

Referenced by on_mouse_impl(), and open_tf_editor_a().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_tf_editor_count()

void Slic3r::GUI::DesignSketchTool::open_tf_editor_count ( )
private
9309{
9310 if (!on_inline_edit || !tf_ready()) return;
9311 if (m_mode != Mode::Array && m_mode != Mode::PolarArray) return;
9312 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
9313 on_inline_edit(px, double(std::max(2, m_tf_count)), _u8L("Copies"),
9314 [this](double v) {
9315 if (v < 2.0 || std::abs(v - std::round(v)) > 1e-9) {
9316 show_refusal(_u8L("The number of copies must be a whole number, 2 or more"));
9317 return;
9318 }
9319 m_tf_count = int(std::round(v));
9321 },
9322 []() {});
9323}

References _u8L, Array, confirm_transform(), m_last_mouse_x, m_last_mouse_y, m_mode, m_tf_count, on_inline_edit, open_tf_editor_count(), PolarArray, show_refusal(), and tf_ready().

Referenced by on_mouse_impl(), and open_tf_editor_count().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_thread_editor()

void Slic3r::GUI::DesignSketchTool::open_thread_editor ( int which)
private
6579{
6580 if (!on_inline_edit) return;
6581 const wxPoint px(m_last_mouse_x, m_last_mouse_y);
6582 if (which == 1) {
6584 [this](double v) {
6585 m_th_radius = std::max(0.01, v);
6587 },
6588 []() {});
6589 } else if (which == 2) {
6591 [this](double v) {
6592 m_th_height = std::max(0.01, v);
6594 },
6595 []() {});
6596 }
6597}

References m_last_mouse_x, m_last_mouse_y, m_th_height, m_th_radius, m_th_x, m_th_y, on_inline_edit, on_thread_changed, and open_thread_editor().

Referenced by on_mouse_impl(), and open_thread_editor().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_value_editor()

void Slic3r::GUI::DesignSketchTool::open_value_editor ( int di)
private
1419{
1420 if (di < 0 || di >= int(m_dimensions.size())) return;
1421 m_pending_dim = di;
1422 if (!on_inline_edit) {
1424 return;
1425 }
1426 const DimAnnot& a = m_dimensions[di];
1427 // Anchor the field OVER the dimension (project its label/anchor to the viewport), same as
1428 // the draw-then-edit tools and Constrain mode; fall back to the click point if it projects
1429 // off-screen.
1431 const Camera& cam = wxGetApp().plater()->get_camera();
1432 const wxPoint lp = world_to_screen_px(cam, m_plane.to_world(dim_anchor(a)));
1433 const std::array<int, 4>& vp = cam.get_viewport();
1434 if (lp.x >= vp[0] && lp.y >= vp[1] && lp.x <= vp[0] + vp[2] && lp.y <= vp[1] + vp[3])
1435 px = lp;
1436 on_inline_edit(px, a.value, dimtype_title(a.kind),
1437 [this](double v) { set_dimension_value(v); },
1438 [this]() { cancel_dimension_value(); });
1439}
std::function< void(double current)> on_dimension_pick_complete
Definition DesignSketchTool.hpp:674

References dim_anchor(), dimtype_title(), Slic3r::GUI::Camera::get_viewport(), Slic3r::GUI::DesignSketchTool::DimAnnot::kind, m_dimensions, m_last_mouse_x, m_last_mouse_y, m_pending_dim, m_plane, on_dimension_pick_complete, on_inline_edit, Slic3r::GUI::DesignSketchTool::DimAnnot::value, and Slic3r::GUI::world_to_screen_px().

Referenced by edit_dimension(), on_mouse_impl(), and place_dimension().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pad_box()

void Slic3r::GUI::DesignSketchTool::pad_box ( BoundingBoxf3 & box)
static
3827{
3828 // A vertex has no size, nor has a sketch along its normal, and the camera cannot frame an
3829 // extent it does not see. Every axis gets at least a small neighbourhood.
3830 if (!box.defined)
3831 return;
3832 constexpr double min_extent = 10.; // mm
3833 const Vec3d grow = (Vec3d::Constant(min_extent) - box.size()).cwiseMax(0.) * 0.5;
3834 box.min -= grow;
3835 box.max += grow;
3836}

References Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::defined, Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::max, Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::min, pad_box(), and Slic3r::BoundingBox3Base< PointType >::size().

Referenced by fit_box(), pad_box(), and Slic3r::GUI::DesignCanvas::zoom_to_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ patterning()

bool Slic3r::GUI::DesignSketchTool::patterning ( ) const
inline
482{ return m_pt_active; }

References m_pt_active.

◆ pending_dimension_type()

DesignSketchTool::DimType Slic3r::GUI::DesignSketchTool::pending_dimension_type ( ) const
2378{
2379 return (m_pending_dim >= 0 && m_pending_dim < int(m_dimensions.size()))
2381}

References m_dimensions, m_pending_dim, None, and pending_dimension_type().

Referenced by pending_dimension_type().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pending_points()

int Slic3r::GUI::DesignSketchTool::pending_points ( ) const
inline
108{ return int(m_points.size()); }

References m_points.

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_describe().

Here is the caller graph for this function:

◆ pick0_point()

bool Slic3r::GUI::DesignSketchTool::pick0_point ( Vec2d & out) const
inline
514{ out = m_pick0_pt; return m_pick0 >= 0; }

References m_pick0, and m_pick0_pt.

◆ pick2()

int Slic3r::GUI::DesignSketchTool::pick2 ( ) const
inline
512{ return m_pick2; }

References m_pick2.

◆ pick_bodies_in_rectangle()

void Slic3r::GUI::DesignSketchTool::pick_bodies_in_rectangle ( )
private
3910{
3911 if (m_solid_mesh == nullptr || m_solid_tri_body == nullptr || m_solid_bodies == nullptr)
3912 return;
3913 const indexed_triangle_set& its = m_solid_mesh->its;
3914 std::vector<Vec3d> pts;
3915 std::vector<int> owner;
3916 pts.reserve(its.indices.size() * 4);
3917 owner.reserve(its.indices.size() * 4);
3918 for (size_t i = 0; i < its.indices.size(); ++i) {
3919 const int b = (i < m_solid_tri_body->size()) ? (*m_solid_tri_body)[i] : -1;
3920 if (!body_pickable(b)) continue; // hidden bodies aren't swept either
3921 const auto& idx = its.indices[i];
3922 Vec3d c = Vec3d::Zero();
3923 for (int k = 0; k < 3; ++k) {
3924 const Vec3d p = its.vertices[idx(k)].cast<double>();
3925 pts.push_back(p); owner.push_back(b); c += p;
3926 }
3927 pts.push_back(c / 3.0); owner.push_back(b);
3928 }
3929
3930 std::vector<int> hits(m_solid_bodies->size(), 0);
3931 if (!pts.empty())
3932 for (unsigned int i : m_rubber.contains(pts))
3933 if (i < owner.size() && owner[i] >= 0 && owner[i] < int(hits.size()))
3934 ++hits[owner[i]];
3935
3936 int best = -1, best_n = 0;
3937 for (int b = 0; b < int(hits.size()); ++b)
3938 if (hits[b] > best_n) { best_n = hits[b]; best = b; }
3939
3940 if (best < 0) clear_solid_selection(); // swept empty space -> drop the selection
3941 else select_body(best);
3942 dp_pick_trace("rubber band -> body=%d (%d samples)", best, best_n);
3945 if (best < 0 && on_empty_pick) on_empty_pick();
3946}
bool body_pickable(int b) const
Definition DesignSketchTool.cpp:3615

References body_pickable(), clear_solid_selection(), Slic3r::GUI::dp_pick_trace(), m_rubber, m_sel_body, m_sel_edge, m_sel_face, m_solid_bodies, m_solid_mesh, m_solid_sel, m_solid_tri_body, on_empty_pick, on_solid_selection_changed, pick_bodies_in_rectangle(), and select_body().

Referenced by on_mouse_impl(), and pick_bodies_in_rectangle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ picked_faces()

std::vector< std::pair< int, int > > Slic3r::GUI::DesignSketchTool::picked_faces ( ) const
private
3726{
3727 std::vector<std::pair<int, int>> out;
3728 const TopoDS_Shape* shape = body_shape(m_sel_body);
3729 if (shape == nullptr)
3730 return out;
3731 if (m_solid_sel == SolidSel::Face && m_sel_face >= 0)
3732 out.emplace_back(m_sel_body, m_sel_face);
3733 else if (m_solid_sel == SolidSel::Whole)
3734 for (int f = 0, n = GeometryEngine::face_count(*shape); f < n; ++f)
3735 out.emplace_back(m_sel_body, f);
3736 return out;
3737}
@ Whole
Definition DesignSketchTool.hpp:229
static int face_count(const TopoDS_Shape &shape)
Definition GeometryEngine.cpp:526

References body_shape(), Slic3r::f(), Face, Slic3r::GeometryEngine::face_count(), m_sel_body, m_sel_face, m_solid_sel, picked_faces(), and Whole.

Referenced by picked_faces(), render_solid_highlight(), and selected_faces().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ place_dimension()

int Slic3r::GUI::DesignSketchTool::place_dimension ( DimAnnot a)
private
1368{
1369 a.value = measure_dim(a);
1371 const int di = upsert_dimension(a);
1372 resolve_live();
1374 return m_pending_dim;
1375}

References Slic3r::GUI::DesignSketchTool::DimAnnot::con, constraint_for(), m_pending_dim, measure_dim(), open_value_editor(), resolve_live(), upsert_dimension(), upsert_dimension_constraint(), and Slic3r::GUI::DesignSketchTool::DimAnnot::value.

Referenced by on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ plane()

const SketchPlane & Slic3r::GUI::DesignSketchTool::plane ( ) const
inline
579{ return m_plane; }

References m_plane.

Referenced by begin(), begin_constrain(), begin_constrain_entities(), begin_edit(), begin_imported_transform(), set_cut_gizmo(), set_datum_gizmo(), set_extrude_gizmo(), set_helix_gizmo(), set_hole_gizmo(), set_pattern_gizmo(), set_revolve_gizmo(), set_rib_gizmo(), set_thread_gizmo(), and sketch_box().

Here is the caller graph for this function:

◆ point_at()

bool Slic3r::GUI::DesignSketchTool::point_at ( int ei,
SketchPointRole role,
Vec2d & out ) const
private
1145{
1146 if (ei < 0 || ei >= int(m_entities.size())) return false;
1147 const SketchEntity& e = m_entities[ei];
1148 switch (role) {
1149 case SketchPointRole::P0: out = e.p0; return true;
1150 case SketchPointRole::P1: out = e.p1; return true;
1151 case SketchPointRole::Center: out = e.center; return true;
1152 }
1153 return false;
1154}

References Slic3r::Center, Slic3r::SketchEntity::center, m_entities, Slic3r::P0, Slic3r::SketchEntity::p0, Slic3r::P1, and Slic3r::SketchEntity::p1.

Referenced by dim_anchor(), drag_polygon_vertex(), draw_dim_quote(), heal_coincidences(), infer_auto_constraints(), measure_dim(), and on_mouse_impl().

Here is the caller graph for this function:

◆ push_circle()

void Slic3r::GUI::DesignSketchTool::push_circle ( const Vec2d & center,
double radius )
private
2934{
2935 if (radius < 1e-3) return;
2936 SketchEntity e;
2938 e.center = center;
2939 e.p0 = center;
2940 e.radius = radius;
2941 e.construction = m_construction;
2942 m_entities.push_back(e);
2943}

References Slic3r::center(), Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::SketchEntity::construction, m_construction, m_entities, Slic3r::SketchEntity::p0, push_circle(), Slic3r::SketchEntity::radius, and Slic3r::SketchEntity::type.

Referenced by on_mouse_impl(), and push_circle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ push_closed_lines()

void Slic3r::GUI::DesignSketchTool::push_closed_lines ( const std::vector< Vec2d > & corners)
private
2920{
2921 const size_t n = corners.size();
2922 if (n < 2) return;
2923 for (size_t i = 0; i < n; ++i)
2924 push_line(corners[i], corners[(i + 1) % n]);
2925}

References push_closed_lines(), and push_line().

Referenced by add_imported_regions(), on_mouse_impl(), and push_closed_lines().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ push_line()

void Slic3r::GUI::DesignSketchTool::push_line ( const Vec2d & a,
const Vec2d & b )
private
2885{
2886 if ((b - a).squaredNorm() < 1e-9)
2887 return;
2888 SketchEntity e;
2889 e.type = SketchEntity::Type::Line;
2890 e.p0 = a;
2891 e.p1 = b;
2892 e.construction = m_construction;
2893 m_entities.push_back(e);
2894}

References Slic3r::SketchEntity::construction, Slic3r::SketchEntity::Line, m_construction, m_entities, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, push_line(), and Slic3r::SketchEntity::type.

Referenced by keep_segment_as_drawn(), push_closed_lines(), push_line(), and push_open_chain().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ push_open_chain()

void Slic3r::GUI::DesignSketchTool::push_open_chain ( const std::vector< Vec2d > & pts)
private
2928{
2929 for (size_t i = 0; i + 1 < pts.size(); ++i)
2930 push_line(pts[i], pts[i + 1]);
2931}

References push_line(), and push_open_chain().

Referenced by end_chain(), and push_open_chain().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ push_point()

void Slic3r::GUI::DesignSketchTool::push_point ( const Vec2d & p)
private
2946{
2947 SketchEntity e;
2949 e.p0 = p;
2950 e.center = p;
2951 e.construction = m_construction;
2952 m_entities.push_back(e);
2953}

References Slic3r::SketchEntity::center, Slic3r::SketchEntity::construction, m_construction, m_entities, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::Point, push_point(), and Slic3r::SketchEntity::type.

Referenced by on_mouse_impl(), and push_point().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ rebuild_features_from_entities()

void Slic3r::GUI::DesignSketchTool::rebuild_features_from_entities ( )
private
155{
156 m_features.clear();
157 m_open_feature = -1;
158 const int n = int(m_entities.size());
159 using T = SketchEntity::Type;
160 auto start = [&](int i) { return m_entities[i].p0; };
161 auto end = [&](int i) { const SketchEntity& e = m_entities[i];
162 return (e.type == T::Line || e.type == T::Arc) ? e.p1 : e.p0; };
163 auto is_near = [](const Vec2d& a, const Vec2d& b) {
164 return (a - b).norm() <= 0.05 + 1e-3 * std::max(a.norm(), b.norm()); };
165
166 int i = 0;
167 while (i < n) {
168 int j = i; bool closed = false; // greedily extend a consecutive chain
169 while (j + 1 < n && is_near(end(j), start(j + 1))) {
170 ++j;
171 if ((j - i) >= 2 && is_near(end(j), start(i))) { closed = true; break; }
172 }
173 const int cnt = j - i + 1;
174 if (!closed || cnt < 3) { ++i; continue; }
175
176 int arcs = 0; bool all_line = true;
177 for (int k = i; k <= j; ++k) {
178 if (m_entities[k].type == T::Arc) ++arcs;
179 if (m_entities[k].type != T::Line) all_line = false;
180 }
181 Vec2d c(0, 0); for (int k = i; k <= j; ++k) c += start(k); c /= double(cnt);
182 Feature f; f.begin = i; f.end = j + 1; f.c0 = c;
183
184 if (cnt == 4 && arcs == 2 &&
185 m_entities[i].type == T::Line && m_entities[i + 1].type == T::Arc &&
186 m_entities[i + 2].type == T::Line && m_entities[i + 3].type == T::Arc) {
187 f.kind = FeatureKind::Slot; // make_slot: top, cap@c1, bottom, cap@c0
188 f.c0 = m_entities[i + 3].center;
189 f.c1 = m_entities[i + 1].center;
190 f.param = m_entities[i + 1].radius;
191 m_features.push_back(f);
192 } else if (cnt == 4 && arcs == 4 &&
193 is_near(m_entities[i].center, m_entities[i + 2].center) &&
194 std::abs(m_entities[i + 1].radius - m_entities[i + 3].radius) <=
195 0.02 * std::max(m_entities[i + 1].radius, 1e-6) &&
196 m_entities[i].radius > m_entities[i + 2].radius) {
197 // make_arc_slot: [0]outer(Rc+w), [1]cap@E(w), [2]inner(Rc-w), [3]cap@S(w).
198 // c0=main centre, c1=centreline start (cap@S centre = Sc), param=half-width.
199 f.kind = FeatureKind::ArcSlot;
200 f.c0 = m_entities[i].center;
201 f.c1 = m_entities[i + 3].center;
202 f.param = m_entities[i + 3].radius;
203 m_features.push_back(f);
204 } else if (cnt == 8 && arcs == 4 &&
205 m_entities[i].type == T::Line && m_entities[i + 1].type == T::Arc &&
206 m_entities[i + 2].type == T::Line && m_entities[i + 3].type == T::Arc &&
207 m_entities[i + 4].type == T::Line && m_entities[i + 5].type == T::Arc &&
208 m_entities[i + 6].type == T::Line && m_entities[i + 7].type == T::Arc) {
209 // rounded_rect_entities: 4 corner arcs (equal radius r) at the inset corners.
210 // Recover the axis-aligned bounds from the arc centres ± r.
211 const double r = m_entities[i + 1].radius;
212 bool equal_r = true;
213 for (int k : {3, 5, 7})
214 if (std::abs(m_entities[i + k].radius - r) > 0.02 * std::max(r, 1e-6))
215 equal_r = false;
216 if (equal_r && r > 1e-6) {
217 double cxmin = 1e18, cxmax = -1e18, cymin = 1e18, cymax = -1e18;
218 for (int k : {1, 3, 5, 7}) {
219 const Vec2d& o = m_entities[i + k].center;
220 cxmin = std::min(cxmin, o.x()); cxmax = std::max(cxmax, o.x());
221 cymin = std::min(cymin, o.y()); cymax = std::max(cymax, o.y());
222 }
224 f.c0 = Vec2d(cxmin - r, cymin - r); // (xmin,ymin)
225 f.c1 = Vec2d(cxmax + r, cymax + r); // (xmax,ymax)
226 f.param = r;
227 m_features.push_back(f);
228 }
229 } else if (all_line) {
230 std::vector<double> sidelen(cnt);
231 for (int k = 0; k < cnt; ++k) sidelen[k] = (m_entities[i + k].p1 - m_entities[i + k].p0).norm();
232 const double lmin = *std::min_element(sidelen.begin(), sidelen.end());
233 const double lmax = *std::max_element(sidelen.begin(), sidelen.end());
234 const bool equal_sides = lmin > 1e-6 && (lmax - lmin) / lmax < 0.02;
235 bool all_right = true;
236 for (int k = 0; k < cnt && all_right; ++k) {
237 Vec2d u = m_entities[i + k].p1 - m_entities[i + k].p0;
238 Vec2d v = m_entities[i + (k + 1) % cnt].p1 - m_entities[i + (k + 1) % cnt].p0;
239 if (u.norm() < 1e-9 || v.norm() < 1e-9) { all_right = false; break; }
240 if (std::abs(u.normalized().dot(v.normalized())) > 0.06) all_right = false; // ~3.4°
241 }
242 if (cnt == 4 && all_right) {
243 f.kind = FeatureKind::CornerRect; f.c0 = start(i); f.c1 = start(i + 2);
244 m_features.push_back(f);
245 } else if (equal_sides) {
246 f.kind = FeatureKind::Polygon; f.c0 = c; f.c1 = start(i);
247 f.sides = cnt; f.param = (start(i) - c).norm();
248 m_features.push_back(f);
249 }
250 }
251 i = j + 1;
252 }
253}

References ArcSlot, Slic3r::center(), CornerRect, Slic3r::f(), m_entities, m_features, m_open_feature, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Polygon, RoundedRect, Slot, and Slic3r::SketchEntity::type.

Referenced by begin_edit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ recompute_op_ghost()

void Slic3r::GUI::DesignSketchTool::recompute_op_ghost ( )
private
8730{
8731 m_op_ghost.clear();
8732 if (m_mode == Mode::Fillet || m_mode == Mode::Chamfer) {
8733 if (m_op_a < 0 || m_op_b < 0) return;
8734 Vec2d C, bis; double theta;
8735 if (op_corner(m_op_a, m_op_b, C, bis, theta)) { m_op_anchor = C; m_op_dir = bis; }
8736 SketchEntity a_out, b_out, extra;
8737 const bool ok = (m_mode == Mode::Fillet)
8740 if (ok) m_op_ghost = { a_out, b_out, extra };
8741 } else if (m_mode == Mode::Offset) {
8742 if (m_op_a < 0) return;
8743 const SketchEntity& e = m_entities[m_op_a];
8744 if (e.type == SketchEntity::Type::Line) {
8745 m_op_anchor = 0.5 * (e.p0 + e.p1);
8746 Vec2d u = e.p1 - e.p0; if (u.norm() > 1e-12) u.normalize();
8747 m_op_dir = Vec2d(-u.y(), u.x()); // left normal = +distance side
8748 } else if (e.type == SketchEntity::Type::Circle || e.type == SketchEntity::Type::Arc) {
8749 // The same "+distance = left of travel" rule the engine uses: inward for a circle
8750 // and a CCW arc, outward for a CW arc. The arrow pointed outward for all of them, so
8751 // dragging it out shrank a CCW arc.
8752 const bool ccw = e.type == SketchEntity::Type::Circle || e.end_angle >= e.start_angle;
8753 m_op_anchor = e.center + Vec2d(e.radius, 0.0);
8754 m_op_dir = Vec2d(ccw ? -1.0 : 1.0, 0.0);
8755 }
8757 // In a chain the engine walks the entities in its own traversal order, so the picked
8758 // one may be travelled backwards and "+distance = left" lands on the other side of it.
8759 // Read the side off the ghost instead: the arrow points from the picked entity to its
8760 // offset copy, flipped for a negative distance, so dragging it always follows the ghost.
8761 if (m_op_chain.size() > 1 && std::abs(m_op_value) > 1e-12 && !m_op_ghost.empty()) {
8762 double best = 1e30; Vec2d closest = m_op_anchor; // not "near": a macro in windows.h
8763 for (const SketchEntity& g : m_op_ghost) {
8764 bool closed = false;
8765 const std::vector<Vec2d> pl = entity_polyline(g, closed);
8766 for (size_t k = 0; k + 1 < pl.size(); ++k) {
8767 const Vec2d a = pl[k], d = pl[k + 1] - pl[k];
8768 const double l2 = d.squaredNorm();
8769 const double t = l2 > 1e-24 ? std::clamp((m_op_anchor - a).dot(d) / l2, 0.0, 1.0) : 0.0;
8770 const Vec2d q = a + t * d;
8771 if ((q - m_op_anchor).norm() < best) { best = (q - m_op_anchor).norm(); closest = q; }
8772 }
8773 }
8774 const Vec2d v = closest - m_op_anchor;
8775 if (v.norm() > 1e-12) m_op_dir = (m_op_value > 0 ? 1.0 : -1.0) * v.normalized();
8776 }
8777 } else if (m_mode == Mode::Mirror) {
8778 if (m_op_a < 0 || m_mirror_targets.empty()) return;
8779 const SketchEntity& axis = m_entities[m_op_a];
8780 std::vector<SketchEntity> src;
8781 for (int ti : m_mirror_targets)
8782 if (ti >= 0 && ti < int(m_entities.size())) src.push_back(m_entities[ti]);
8783 m_op_ghost = SketchEngine::mirror_entities(src, axis.p0, axis.p1);
8784 }
8785}
std::vector< SketchEntity > m_op_ghost
Definition DesignSketchTool.hpp:1176
static bool chamfer_lines(const SketchEntity &a, const SketchEntity &b, double d, SketchEntity &a_out, SketchEntity &b_out, SketchEntity &seg_out)
Definition SketchEngine.cpp:1661
Foot closest(const Contour &c, const Vec2d &p, double stop=-1.0, const std::vector< Vec2d > *source_normals=nullptr, double normal_cosine=0.0)
Definition SeamContour.cpp:36
T l2(const boost::geometry::model::d2::point_xy< T > &v)
Definition ExtrusionSimulator.cpp:177

References Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::center, Chamfer, Slic3r::SketchEngine::chamfer_lines(), Slic3r::SketchEntity::Circle, Slic3r::dot(), Slic3r::SketchEntity::end_angle, entity_polyline(), Fillet, Slic3r::SketchEngine::fillet_lines(), Slic3r::l2(), Slic3r::SketchEntity::Line, m_entities, m_mirror_targets, m_mode, m_op_a, m_op_anchor, m_op_b, m_op_chain, m_op_dir, m_op_ghost, m_op_value, Mirror, Slic3r::SketchEngine::mirror_entities(), Offset, Slic3r::SketchEngine::offset_entities(), op_chain_entities(), op_corner(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::radius, recompute_op_ghost(), Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by drag_op_arrow(), op_pick(), open_op_editor(), and recompute_op_ghost().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ recompute_tf_ghost()

void Slic3r::GUI::DesignSketchTool::recompute_tf_ghost ( )
private
9208{
9209 m_tf_ghost.clear();
9210 if (m_tf_targets.empty()) return;
9211 std::vector<SketchEntity> src;
9212 for (int ti : m_tf_targets)
9213 if (ti >= 0 && ti < int(m_entities.size())) src.push_back(m_entities[ti]);
9214 if (src.empty()) return;
9215 const int count = std::max(2, m_tf_count);
9216 switch (m_mode) {
9217 case Mode::Move:
9219 break;
9220 case Mode::Rotate:
9222 break;
9223 case Mode::Scale:
9225 break;
9226 case Mode::Array:
9228 break;
9229 case Mode::PolarArray:
9231 break;
9232 default: break;
9233 }
9234}
std::vector< SketchEntity > m_tf_ghost
Definition DesignSketchTool.hpp:1215

References Array, Slic3r::SketchEngine::array_entities(), count, m_entities, m_mode, m_tf_angle, m_tf_count, m_tf_delta, m_tf_ghost, m_tf_pivot, m_tf_scale, m_tf_targets, Move, PolarArray, recompute_tf_ghost(), Rotate, Scale, and Slic3r::SketchEngine::transform_entities().

Referenced by drag_tf_handle(), recompute_tf_ghost(), and tf_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ record_dimension_constraint()

void Slic3r::GUI::DesignSketchTool::record_dimension_constraint ( double v)
private
820{
821 const DimType k = dimension_kind();
822 auto role = [&](int i) {
825 };
826 SketchEntityConstraintDef c;
827 switch (k) {
828 case DimType::Length:
830 c.ea = m_selection[0]; c.ra = SketchPointRole::P0;
831 c.eb = m_selection[0]; c.rb = SketchPointRole::P1;
832 c.value = v; upsert_dimension_constraint(c); break;
834 c.type = SketchConstraintType::Diameter; c.ea = m_selection[0]; c.value = v;
836 case DimType::Radius:
837 c.type = SketchConstraintType::Radius; c.ea = m_selection[0]; c.value = v;
839 case DimType::Angle:
841 c.ea = m_selection[0]; c.eb = m_selection[1]; c.value = v;
843 case DimType::Distance: {
844 const int ia = m_selection[0], ib = m_selection[1];
845 if (v < 1e-9) c.type = SketchConstraintType::Coincident;
846 else { c.type = SketchConstraintType::Distance; c.value = v; }
847 c.ea = ia; c.ra = role(ia); c.eb = ib; c.rb = role(ib);
849 }
851 // Point-on-line driving constraint: hold the point-like entity at unsigned
852 // perpendicular distance v from the line (v == 0 -> on the axis).
853 const bool aLine = (m_entities[m_selection[0]].type == SketchEntity::Type::Line);
854 const int ip = m_selection[aLine ? 1 : 0]; // point-like (Point/Circle/Arc)
855 const int il = m_selection[aLine ? 0 : 1]; // line
857 c.ea = ip; c.ra = role(ip); c.eb = il; c.value = v;
859 }
860 default: break; // None: no driving constraint recorded
861 }
862}

References Angle, Slic3r::Angle, Slic3r::Center, Slic3r::Coincident, Diameter, Slic3r::Diameter, dimension_kind(), Distance, Slic3r::Distance, DistanceToLine, Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, Length, Slic3r::SketchEntity::Line, m_entities, m_selection, Slic3r::P0, Slic3r::P1, Slic3r::SketchEntity::Point, Slic3r::PointOnLine, Slic3r::SketchEntityConstraintDef::ra, Radius, Slic3r::Radius, Slic3r::SketchEntityConstraintDef::rb, Slic3r::SketchEntityConstraintDef::type, upsert_dimension_constraint(), and Slic3r::SketchEntityConstraintDef::value.

Referenced by apply_dimension().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ redo_last_entity()

bool Slic3r::GUI::DesignSketchTool::redo_last_entity ( )
480{
481 if (!can_redo_entity()) { m_sketch_redo.clear(); return false; }
482 SketchSnap s = std::move(m_sketch_redo.back());
483 m_sketch_redo.pop_back();
484 m_entities = std::move(s.entities);
485 m_constraints = std::move(s.constraints);
486 m_features = std::move(s.features);
487 m_dimensions = std::move(s.dimensions);
488 m_selection.clear();
489 m_point_sel.clear();
491 resolve_live();
493 return true;
494}
bool can_redo_entity() const
Definition DesignSketchTool.cpp:472
Definition DesignSketchTool.hpp:1153

References can_redo_entity(), Slic3r::GUI::DesignSketchTool::SketchSnap::constraints, Slic3r::GUI::DesignSketchTool::SketchSnap::dimensions, Slic3r::GUI::DesignSketchTool::SketchSnap::entities, Slic3r::GUI::DesignSketchTool::SketchSnap::features, m_constraints, m_dimensions, m_entities, m_features, m_point_sel, m_selection, m_sketch_redo, on_selection_changed, reset_autoedit(), and resolve_live().

Here is the call graph for this function:

◆ refresh_body_edges()

void Slic3r::GUI::DesignSketchTool::refresh_body_edges ( )
3481{
3482 const size_t n = m_solid_bodies != nullptr ? m_solid_bodies->size() : 0;
3483 bool rebuilt = n < m_body_edges_shape.size(); // a body went away
3484 m_body_edges.resize(n);
3485 m_body_edges_shape.resize(n);
3486 m_body_edges_tol.resize(n, 0.0);
3487 for (size_t b = 0; b < n; ++b) {
3488 if (is_current_shape(int(b), m_body_edges_shape[b]))
3489 continue;
3490 rebuilt = rebuilt || !m_body_edges_shape[b].IsNull(); // a body sampled before was rebuilt
3491 const TopoDS_Shape& shape = (*m_solid_bodies)[b].shape;
3492 m_body_edges_shape[b] = shape;
3493 m_body_edges[b].clear();
3494 if (shape.IsNull())
3495 continue;
3497 try {
3499 } catch (const Standard_Failure&) {
3500 m_body_edges[b].clear(); // an unsampleable edge costs its body the lines, nothing else
3501 }
3502 }
3503 // A pick expires once the body it was taken on is rebuilt, which renumbers its faces and
3504 // edges. Judged by that body's shape, not by these lines: a recompute that refreshed no lines
3505 // (adding a datum, say) may come before a pick on the bodies it built, and that pick holds.
3506 // The hover is resolved again on the next mouse move, so any rebuild just drops it.
3509 else if (rebuilt)
3510 m_pre = SolidPick{};
3511 // The face outlines of a rebuilt body let go of its shape, which may be a large import.
3512 const auto stale = [this](const FaceHighlight& h) { return !is_current_shape(h.body, h.shape); };
3513 if (stale(m_sel_hl)) m_sel_hl = FaceHighlight{};
3514 if (stale(m_pre_hl)) m_pre_hl = FaceHighlight{};
3515 m_hl_faces.erase(std::remove_if(m_hl_faces.begin(), m_hl_faces.end(), stale), m_hl_faces.end());
3516}
FaceHighlight m_pre_hl
Definition DesignSketchTool.hpp:1362
std::vector< FaceHighlight > m_hl_faces
Definition DesignSketchTool.hpp:1360
FaceHighlight m_sel_hl
Definition DesignSketchTool.hpp:1361

References clear_solid_selection(), Slic3r::GUI::display_edge_tol(), Slic3r::GeometryEngine::display_edges(), is_current_shape(), m_body_edges, m_body_edges_shape, m_body_edges_tol, m_hl_faces, m_pre, m_pre_hl, m_sel_body, m_sel_hl, m_sel_shape, m_solid_bodies, m_solid_sel, None, and refresh_body_edges().

Referenced by refresh_body_edges(), and set_solid_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ region_at()

int Slic3r::GUI::DesignSketchTool::region_at ( const Vec2d & p) const
private
7414{
7415 // Walk region_loops (which already knows about holes) rather than the raw polygons: the
7416 // returned index must stay meaningful after the sketch is committed, so it has to use the
7417 // SAME numbering selected_loop_entities() and hit_display_sketch consume.
7418 const std::vector<RegionLoop> regions = region_loops(m_entities);
7419 auto inside = [](const Vec2d& q, const std::vector<Vec2d>& poly) {
7420 bool in = false;
7421 for (size_t i = 0, j = poly.size() - 1; i < poly.size(); j = i++) {
7422 const Vec2d& a = poly[i];
7423 const Vec2d& b = poly[j];
7424 if (((a.y() > q.y()) != (b.y() > q.y())) &&
7425 (q.x() < (b.x() - a.x()) * (q.y() - a.y()) / (b.y() - a.y()) + a.x()))
7426 in = !in;
7427 }
7428 return in;
7429 };
7430 // Shoelace area (absolute): the SMALLEST loop containing p is the innermost one, which is
7431 // the region that actually owns the point — a bore inside a plate resolves to the disc, and
7432 // a click on the plate material resolves to the plate even though the disc is also inside it.
7433 auto poly_area = [](const std::vector<Vec2d>& q) {
7434 double a2 = 0.0;
7435 for (size_t i = 0, j = q.size() - 1; i < q.size(); j = i++)
7436 a2 += (q[j].x() + q[i].x()) * (q[j].y() - q[i].y());
7437 return std::abs(a2) * 0.5;
7438 };
7439 int best = -1;
7440 double best_area = 0.0;
7441 for (size_t i = 0; i < regions.size(); ++i) {
7442 if (regions[i].poly.size() < 3) continue;
7443 if (!inside(p, regions[i].poly)) continue;
7444 bool in_hole = false; // p inside one of this region's holes → that hole owns it, not us
7445 for (int h : regions[i].holes) {
7446 if (h < 0 || h >= int(regions.size()) || regions[h].poly.size() < 3) continue;
7447 if (inside(p, regions[h].poly)) { in_hole = true; break; }
7448 }
7449 if (in_hole) continue;
7450 const double a = poly_area(regions[i].poly);
7451 if (best < 0 || a < best_area) { best = int(i); best_area = a; }
7452 }
7453 return best;
7454}
bool inside(const Polygons &polygons, const Point &p)
Definition TreeNode.cpp:160
double poly_area(const Points &pts)
Definition Arrange.cpp:1187

References Slic3r::holes(), m_entities, region_at(), and region_loops().

Referenced by on_mouse_impl(), and region_at().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ region_entity_indices()

std::vector< std::vector< int > > Slic3r::GUI::DesignSketchTool::region_entity_indices ( const std::vector< SketchEntity > & ents) const
3342{
3343 std::vector<std::vector<int>> out;
3344 for (RegionLoop& r : region_loops(ents)) out.push_back(std::move(r.ents));
3345 return out;
3346}

References region_entity_indices(), and region_loops().

Referenced by region_entity_indices().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ region_entity_indices_with_holes()

std::vector< std::vector< int > > Slic3r::GUI::DesignSketchTool::region_entity_indices_with_holes ( const std::vector< SketchEntity > & ents) const
3350{
3351 const std::vector<RegionLoop> loops = region_loops(ents);
3352 std::vector<std::vector<int>> out;
3353 out.reserve(loops.size());
3354 for (const RegionLoop& r : loops) {
3355 std::vector<int> ids = r.ents;
3356 for (int h : r.holes)
3357 if (h >= 0 && h < int(loops.size()))
3358 ids.insert(ids.end(), loops[h].ents.begin(), loops[h].ents.end());
3359 out.push_back(std::move(ids));
3360 }
3361 return out;
3362}

References region_entity_indices_with_holes(), and region_loops().

Referenced by region_entity_indices_with_holes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ region_loops()

std::vector< DesignSketchTool::RegionLoop > Slic3r::GUI::DesignSketchTool::region_loops ( const std::vector< SketchEntity > & ents) const
private
7277{
7278 std::vector<RegionLoop> regions;
7279 const double eps2 = sketch_join_tol() * sketch_join_tol();
7280 auto is_near = [&](const Vec2d& a, const Vec2d& b) { return (a - b).squaredNorm() < eps2; };
7281
7282 // Circles are self-closed regions; lines/arcs are open segments to be chained. Each
7283 // Seg remembers the entity index it came from.
7284 struct Seg { std::vector<Vec2d> pts; int ent{-1}; bool used{false}; };
7285 std::vector<Seg> segs;
7286 for (int i = 0; i < int(ents.size()); ++i) {
7287 const SketchEntity& e = ents[i];
7288 if (e.construction) continue;
7289 bool closed = false;
7290 if (e.type == SketchEntity::Type::Circle || e.type == SketchEntity::Type::Ellipse) {
7291 regions.push_back({ entity_polyline(e, closed), { i } });
7292 } else if (e.type == SketchEntity::Type::Line || e.type == SketchEntity::Type::Arc
7294 || e.type == SketchEntity::Type::BSpline) {
7295 std::vector<Vec2d> p = entity_polyline(e, closed);
7296 if (p.size() >= 2) segs.push_back({ std::move(p), i, false });
7297 }
7298 }
7299
7300 // Walk each unused segment endpoint-to-endpoint until the chain returns to its
7301 // start (a closed loop) or stalls (an open chain, discarded).
7302 for (size_t s = 0; s < segs.size(); ++s) {
7303 if (segs[s].used) continue;
7304 segs[s].used = true;
7305 std::vector<Vec2d> loop = segs[s].pts;
7306 std::vector<int> loop_ents = { segs[s].ent };
7307 const Vec2d start = loop.front();
7308 Vec2d cur = loop.back();
7309 bool extended = true;
7310 while (extended && !is_near(cur, start)) {
7311 extended = false;
7312 for (size_t t = 0; t < segs.size(); ++t) {
7313 if (segs[t].used) continue;
7314 const std::vector<Vec2d>& q = segs[t].pts;
7315 if (is_near(q.front(), cur)) {
7316 for (size_t k = 1; k < q.size(); ++k) loop.push_back(q[k]);
7317 cur = q.back();
7318 } else if (is_near(q.back(), cur)) {
7319 for (int k = int(q.size()) - 2; k >= 0; --k) loop.push_back(q[k]);
7320 cur = q.front();
7321 } else {
7322 continue;
7323 }
7324 segs[t].used = true;
7325 loop_ents.push_back(segs[t].ent);
7326 extended = true;
7327 break;
7328 }
7329 }
7330 if (is_near(cur, start) && loop.size() >= 4) {
7331 loop.pop_back(); // drop the duplicate closing vertex
7332 regions.push_back({ std::move(loop), std::move(loop_ents), {} });
7333 }
7334 }
7335
7336 // NESTING. A loop drawn inside another one is that one's HOLE. Without this a sketch is
7337 // just N disjoint filled polygons, so "the plate with the hole" is not expressible and the
7338 // multi-loop kernel path (88v) is unreachable from the viewport — which is exactly
7339 // what Tommaso hit: a rectangle with a circle inside extruded to a plain box, because only
7340 // the rectangle loop could be picked and only its entities were passed on.
7341 //
7342 // Loops in a well-formed sketch do not cross, so testing ONE point decides containment.
7343 // Each loop is assigned to the SMALLEST loop that contains it, which is what makes a hole
7344 // belong to the region that actually bounds it rather than to every enclosing loop.
7345 //
7346 // The point must be STRICTLY INSIDE the loop, not one of its vertices. A vertex is exactly
7347 // where two loops are most likely to touch in a real drawing — a bore breaking out through
7348 // a boss wall, a slot that ends on an outline — and a ray cast from a point that lies ON the
7349 // polygon being tested answers by rounding, so the same drawing can be read either way.
7350 // Measured on the StudyCadCam corpus: the engine and an independent containment check
7351 // disagreed on 6 of 39 sheets, and every disagreement was a probe point sitting on the other
7352 // loop's boundary. 5hvl.
7353 auto poly_area = [](const std::vector<Vec2d>& q) {
7354 double a2 = 0.0;
7355 for (size_t i = 0, j = q.size() - 1; i < q.size(); j = i++)
7356 a2 += (q[j].x() + q[i].x()) * (q[j].y() - q[i].y());
7357 return std::abs(a2) * 0.5;
7358 };
7359 auto point_in = [](const Vec2d& pt, const std::vector<Vec2d>& q) {
7360 bool in = false;
7361 for (size_t i = 0, j = q.size() - 1; i < q.size(); j = i++) {
7362 const Vec2d& A = q[i]; const Vec2d& B = q[j];
7363 if (((A.y() > pt.y()) != (B.y() > pt.y())) &&
7364 (pt.x() < (B.x() - A.x()) * (pt.y() - A.y()) / (B.y() - A.y()) + A.x()))
7365 in = !in;
7366 }
7367 return in;
7368 };
7369 // A point strictly inside a simple polygon: the lowest vertex of a simple polygon is always
7370 // CONVEX, so stepping from it along the bisector of its two edges goes into the interior.
7371 // The step is a small fraction of the shorter adjacent edge, so it stays inside however
7372 // sharp the corner is.
7373 auto interior_point = [](const std::vector<Vec2d>& q) {
7374 size_t k = 0;
7375 for (size_t i = 1; i < q.size(); ++i)
7376 if (q[i].y() < q[k].y() || (q[i].y() == q[k].y() && q[i].x() < q[k].x())) k = i;
7377 const Vec2d& v = q[k];
7378 Vec2d a = q[(k + q.size() - 1) % q.size()] - v;
7379 Vec2d b = q[(k + 1) % q.size()] - v;
7380 const double la = a.norm(), lb = b.norm();
7381 if (la < 1e-12 || lb < 1e-12) return v; // degenerate: nothing better to say
7382 a /= la; b /= lb;
7383 Vec2d bis = a + b;
7384 if (bis.norm() < 1e-12) return v; // 180 deg spike: same
7385 bis.normalize();
7386 return Vec2d(v + bis * (1e-3 * std::min(la, lb)));
7387 };
7388 std::vector<Vec2d> probe(regions.size());
7389 for (size_t i = 0; i < regions.size(); ++i)
7390 if (regions[i].poly.size() >= 3) probe[i] = interior_point(regions[i].poly);
7391 else if (!regions[i].poly.empty()) probe[i] = regions[i].poly.front();
7392 for (size_t i = 0; i < regions.size(); ++i) {
7393 if (regions[i].poly.empty()) continue;
7394 int best = -1;
7395 double best_area = 0.0;
7396 for (size_t j = 0; j < regions.size(); ++j) {
7397 if (i == j || regions[j].poly.size() < 3) continue;
7398 if (!point_in(probe[i], regions[j].poly)) continue;
7399 const double a2 = poly_area(regions[j].poly);
7400 if (best < 0 || a2 < best_area) { best = int(j); best_area = a2; }
7401 }
7402 if (best >= 0) regions[best].holes.push_back(int(i));
7403 }
7404 // Closed is not the same as bounding one region: the chainer only asks whether the ends
7405 // meet. A loop that crosses itself, or turns straight back along itself, meets at every
7406 // joint and still cannot be built — the kernel refuses a crossing, and a fold back is never
7407 // what was meant. Say so here, where the region is drawn, instead of after an extrude.
7408 for (RegionLoop& r : regions)
7409 r.defect = sketch_loop_defect(ents, r.ents, r.defect_at);
7410 return regions;
7411}
bool interior_point(const TopoDS_Face &face, gp_Pnt &p, gp_Dir &n)
Definition CadDocument.cpp:4279
bool sketch_loop_defect(const std::vector< SketchEntity > &ents, const std::vector< int > &order, Vec2d &at)
Definition SketchEngine.cpp:2242

References Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::BSpline, Slic3r::SketchEntity::Circle, Slic3r::SketchEntity::construction, Slic3r::SketchEntity::Ellipse, Slic3r::SketchEntity::EllipseArc, entity_polyline(), Slic3r::SketchEntity::Line, region_loops(), Slic3r::sketch_join_tol(), Slic3r::sketch_loop_defect(), and Slic3r::SketchEntity::type.

Referenced by announce_loop_defects(), closed_regions(), hit_display_sketch(), loop_report(), region_at(), region_entity_indices(), region_entity_indices_with_holes(), region_loops(), render(), and selected_loop_entities().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_constraint()

bool Slic3r::GUI::DesignSketchTool::remove_constraint ( int idx)
2685{
2686 if (idx < 0 || idx >= int(m_constraints.size())) return false;
2687 const size_t before = m_constraints.size();
2688 erase_constraints([idx](int i, const SketchEntityConstraintDef&) { return i == idx; });
2689 if (m_constraints.size() == before) return false;
2690 // resolve_live(), not a bare solve: it is the path that recomputes the DoF, clears the
2691 // per-entity conflict flags and fires on_solve_state. Solving directly would relax the
2692 // geometry while leaving the DoF readout and any red over-constrained tint stale — the
2693 // readout would still describe the constraint that was just deleted.
2694 resolve_live();
2695 m_glyph_hits.clear(); // stale until the next render rebuilds them
2697 return true;
2698}
std::function< void()> on_constraints_changed
Definition DesignSketchTool.hpp:543

References erase_constraints(), m_constraints, m_glyph_hits, on_constraints_changed, remove_constraint(), and resolve_live().

Referenced by remove_constraint(), and remove_constraint_near().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_constraint_near()

bool Slic3r::GUI::DesignSketchTool::remove_constraint_near ( const Vec2d & p)
2672{
2673 if (m_glyph_hits.empty() || m_glyph_r <= 0.0) return false;
2674 int best = -1;
2675 double best_d = m_glyph_r;
2676 for (const GlyphHit& g : m_glyph_hits) {
2677 const double d = (g.c - p).norm();
2678 if (d < best_d && g.con >= 0 && g.con < int(m_constraints.size())) { best_d = d; best = g.con; }
2679 }
2680 if (best < 0) return false;
2681 return remove_constraint(best);
2682}
bool remove_constraint(int idx)
Definition DesignSketchTool.cpp:2684
Definition DesignSketchTool.hpp:1255

References m_constraints, m_glyph_hits, m_glyph_r, remove_constraint(), and remove_constraint_near().

Referenced by on_mouse_impl(), and remove_constraint_near().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render()

void Slic3r::GUI::DesignSketchTool::render ( GLCanvas3D & canvas)
9540{
9541 m_dim_label_seq = 0;
9542 m_label_rects.clear();
9543 m_render_scale = canvas.get_scale();
9544 // The open value field is anchored OVER the label it edits, and the label draws on top of
9545 // it — the same number twice at the same spot. Record which label that is so draw_text can
9546 // skip exactly it; the shape's other values must stay legible as the chain walks them.
9547 m_autoedit_label_pos = Vec2d(1e18, 1e18);
9548 if (inline_editor != nullptr && m_autoedit_dim_idx >= 0
9549 && m_autoedit_dim_idx < int(m_autoedit_dims.size()))
9551 emit_step_hint(); // before the early returns: an armed tool on an empty sketch still guides
9552 // The value field, BEFORE every early return below. It can be up in Constrain mode on a
9553 // committed feature and on an empty sketch, and a field that is not drawn is a field that is
9554 // not there — there is no window to fall back to any more.
9555 if (inline_editor != nullptr)
9556 inline_editor->render(*wxGetApp().imgui(), m_render_scale);
9557 // ...and on top of the dimension labels, which are all drawn after it and each lift their
9558 // own window to the front (draw_dim_label): without this a label prints across the number
9559 // being typed. A guard, because the labels come from many of the exit paths below.
9560 ScopeGuard field_on_top([this] { if (inline_editor != nullptr) inline_editor->bring_to_front(); });
9561 if (render_overlays)
9563 (void)canvas;
9564 if (!has_display()) {
9565 if (on_readout) on_readout(std::string()); // nothing to show -> hide HUD
9566 return;
9567 }
9568 render_view_helpers(); // origin planes / world axes — drawn whenever their toggle is on
9569 m_rubber.render(canvas); // left-drag rubber band (no-op unless one is being swept). Drawn
9570 // here, ahead of every early return below, so a band over an empty
9571 // plate is still visible.
9572 if (m_active && m_mode != Mode::Constrain && m_entities.empty() && m_points.empty()
9573 && m_display_sketches.empty()) {
9574 if (on_readout) on_readout(std::string());
9575 return;
9576 }
9577
9578
9579 // Draw-then-edit: a creation tool that just committed a new entity/feature (gesture now
9580 // idle) gets its result auto-selected — so render_live_quotes below computes its quotes —
9581 // and the primary value editor armed (opened after those quotes exist, see service block).
9582 if (m_active && is_creation_autoedit_mode() && m_points.empty() &&
9584 const int n = int(m_entities.size());
9585 if (m_autoedit_seen >= 0 && n > m_autoedit_seen && n > 0) {
9586 m_selection.clear();
9587 m_selection.push_back(n - 1); // feature_of(last) groups rect/slot/poly/ellipse
9588 m_autoedit_pending = true;
9589 }
9590 m_autoedit_seen = n;
9591 }
9592
9593 GLShaderProgram* shader = wxGetApp().get_shader("flat");
9594 if (shader == nullptr)
9595 return;
9596
9599 shader->start_using();
9600 const Camera& camera = wxGetApp().plater()->get_camera();
9601 shader->set_uniform("view_model_matrix", camera.get_view_matrix());
9602 shader->set_uniform("projection_matrix", camera.get_projection_matrix());
9603
9605
9606 // Persistent committed sketches (e.g. an un-consumed sketch left visible after its
9607 // extrude is removed): faces translucent, outlines orange. Each uses its own plane.
9608 if (!m_display_sketches.empty()) {
9609 const SketchPlane saved_plane = m_plane;
9610 // CYAN/BLUE MEANS SELECTED — nothing else may wear it. The unselected fill used to be
9611 // (0.30,0.60,1.0), one shade off the selected (0.30,0.80,1.0), so an ordinary region
9612 // read as picked and a picked one added nothing. The outlines already got this right:
9613 // orange for a sketch, cyan for the selection. The fill now follows the same logic, so
9614 // an unselected region is faint amber — the sketch's own colour — and every blue thing
9615 // on screen is something you selected.
9616 const ColorRGBA dface = design_idle_face_color(); // unselected: neutral grey, never the selection colour
9617 const ColorRGBA sface = design_selection_color(0.34f); // selected region
9618 const ColorRGBA dwire(1.0f, 0.55f, 0.1f, 1.0f); // normal orange outline
9619 const ColorRGBA swire = design_selection_color(); // selected outline
9622 for (const DisplaySketch& ds : m_display_sketches) {
9623 m_plane = ds.plane;
9624 const std::vector<RegionLoop> loops = region_loops(ds.entities);
9625 for (int r = 0; r < int(loops.size()); ++r) {
9626 const bool sel = (ds.feature == m_display_pick && r == m_display_pick_region);
9627 const ColorRGBA* hlc = sketch_hl_color(ds.feature);
9628 ColorRGBA fc = sel ? sface : dface;
9629 if (hlc && !sel) { fc = *hlc; fc.a(0.20f); }
9630 std::vector<std::vector<Vec2d>> hp;
9631 for (int h : loops[r].holes)
9632 if (h >= 0 && h < int(loops.size())) hp.push_back(loops[h].poly);
9633 draw_fill_holed(m_fill_model, loops[r].poly, hp, fc);
9634 }
9635 }
9637 for (const DisplaySketch& ds : m_display_sketches) {
9638 m_plane = ds.plane;
9639 // Entities forming the selected loop (highlighted cyan); the rest stay orange.
9640 std::vector<char> sel_ent(ds.entities.size(), 0);
9641 if (ds.feature == m_display_pick && m_display_pick_region >= 0) {
9642 const std::vector<RegionLoop> loops = region_loops(ds.entities);
9643 if (m_display_pick_region < int(loops.size())) {
9644 // The holes light up with their region. The highlight has to show what will
9645 // be EXTRUDED, and a hole is part of that — a plate whose bore stays orange
9646 // while its outline turns cyan would say the circle is not coming along,
9647 // which is precisely the thing that used to be true and is now not.
9648 auto mark = [&](int region) {
9649 if (region < 0 || region >= int(loops.size())) return;
9650 for (int ei : loops[region].ents)
9651 if (ei >= 0 && ei < int(sel_ent.size())) sel_ent[ei] = 1;
9652 };
9654 for (int h : loops[m_display_pick_region].holes) mark(h);
9655 }
9656 }
9657 std::vector<Vec2d> point_markers, sel_point_markers;
9658 for (int i = 0; i < int(ds.entities.size()); ++i) {
9659 const SketchEntity& e = ds.entities[i];
9660 // A Point has no polyline to strip; draw it as a vertex marker so a committed
9661 // point stays visible (it vanished on commit). Selection colouring keeps working:
9662 // sel_ent[] stays index-aligned with ds.entities, untouched for the other types.
9663 if (e.type == SketchEntity::Type::Point) {
9664 (sel_ent[i] ? sel_point_markers : point_markers).push_back(e.p0);
9665 continue;
9666 }
9667 bool closed = false;
9668 std::vector<Vec2d> poly = entity_polyline(e, closed);
9669 const ColorRGBA* hlc = sketch_hl_color(ds.feature);
9670 ColorRGBA wc = sel_ent[i] ? swire : (hlc ? *hlc : dwire);
9671 draw_quad_strip(m_line_model, poly, closed, wc);
9672 }
9673 if (!point_markers.empty()) {
9674 const ColorRGBA* hlc = sketch_hl_color(ds.feature);
9675 draw_vertices(m_vertex_model, point_markers, hlc ? *hlc : dwire);
9676 }
9677 if (!sel_point_markers.empty())
9678 draw_vertices(m_highlight_model, sel_point_markers, swire);
9679 }
9680 m_plane = saved_plane;
9681 }
9682
9683 // Nothing else to draw when no live sketch session is active — except the solid
9684 // selection and the Feature tree's faces (render_solid_highlight).
9685 if (!m_active) {
9689 if (draws_reference_axes()) render_base_pick(); // the canvas drops the bed's triad on the same test
9703 shader->stop_using();
9706 return;
9707 }
9708
9709 // Imported-art transform: only the bbox + handles over the (display-overlay) art.
9710 if (m_mode == Mode::TransformArt) {
9712 shader->stop_using();
9715 return;
9716 }
9717
9718 const ColorRGBA orange(1.0f, 0.55f, 0.1f, 1.0f);
9719 const ColorRGBA yellow(1.0f, 0.85f, 0.2f, 1.0f);
9720 const ColorRGBA grey(0.55f, 0.55f, 0.60f, 1.0f);
9721
9722 if (m_mode == Mode::Constrain) {
9723 // The live session's palette, so a sketch looks the same whether you are drawing it or
9724 // constraining it: picks wear THE selection colour, idle geometry orange (construction
9725 // grey). It used to draw everything in the old near-selection cyan and the picks RED —
9726 // the colour that means "conflicting" everywhere else in the sketch.
9727 const ColorRGBA sel_col = design_selection_color();
9729 std::vector<Vec2d> markers;
9730 for (size_t i = 0; i < m_entities.size(); ++i) {
9731 const SketchEntity& e = m_entities[i];
9732 const bool sel = (int(i) == m_pick0 || int(i) == m_pick1 || int(i) == m_pick2);
9733 // Constraint-manager highlight: the entities a selected constraint
9734 // references glow yellow (picked entities still win as red).
9735 const bool hl = !sel && std::find(m_constraint_hl.begin(), m_constraint_hl.end(),
9736 int(i)) != m_constraint_hl.end();
9737 const ColorRGBA col = sel ? sel_col : hl ? yellow : e.construction ? grey : orange;
9738 if (e.type == SketchEntity::Type::Point) { markers.push_back(e.p0); continue; }
9739 bool closed = false;
9740 std::vector<Vec2d> poly = entity_polyline(e, closed);
9741 draw_quad_strip((sel || hl) ? m_highlight_model : m_line_model, poly, closed, col);
9742 }
9743 if (!markers.empty())
9745 // Constraint badges (C3.4b): iconic glyphs near each constraint's entity.
9746 {
9747 const double upp = 1.0 / std::max(camera.get_zoom(), 1e-6);
9748 std::vector<std::pair<Vec2d, Vec2d>> glyphs;
9750 if (!glyphs.empty()) {
9751 const ColorRGBA badge(0.45f, 0.95f, 0.70f, 1.0f); // CAD teal-green
9752 draw_strokes(m_fill_model, glyphs, std::max(0.9 * upp, 1e-4), badge);
9753 }
9754 }
9755 shader->stop_using();
9758 return;
9759 }
9762 if (m_sel_a >= 0 && m_sel_b >= 0 &&
9763 m_sel_a < int(m_points.size()) && m_sel_b < int(m_points.size())) {
9764 std::vector<Vec2d> seg = { m_points[m_sel_a], m_points[m_sel_b] };
9765 draw_quad_strip(m_highlight_model, seg, false, sel_col);
9766 }
9767 shader->stop_using();
9770 return;
9771 }
9772
9773 // Closed loops fill as translucent faces (the "closed loop = selectable face"
9774 // affordance). Drawn first so the entity outlines paint over the fill.
9775 {
9776 // region_loops(), NOT closed_regions(): the latter returns raw polygons with no notion
9777 // of nesting, so a circle drawn inside a rectangle was filled as its own solid disc on
9778 // top of a solid rectangle. That is why a live sketch still showed a filled blue circle
9779 // however often the COMMITTED renderer below was corrected — these are two separate
9780 // renderers and only one of them had been taught about holes.
9781 const std::vector<RegionLoop> loops = region_loops(m_entities);
9782 if (!loops.empty()) {
9785 // A bore is not a face. Skip loops that are somebody's hole, and cut those holes out
9786 // of the region that owns them, so a plate with a hole LOOKS like one while drawing.
9787 std::vector<char> is_hole(loops.size(), 0);
9788 for (const RegionLoop& L : loops)
9789 for (int h : L.holes)
9790 if (h >= 0 && h < int(is_hole.size())) is_hole[h] = 1;
9791 std::vector<Vec2d> defects;
9792 for (size_t r = 0; r < loops.size(); ++r) {
9793 if (loops[r].defect) defects.push_back(loops[r].defect_at);
9794 if (is_hole[r]) continue;
9795 std::vector<std::vector<Vec2d>> hp;
9796 for (int h : loops[r].holes)
9797 if (h >= 0 && h < int(loops.size())) hp.push_back(loops[h].poly);
9798 // A loop that crosses or folds back is tinted red, not offered as a face.
9799 draw_fill_holed(m_fill_model, loops[r].poly, hp,
9800 loops[r].defect ? ColorRGBA(1.0f, 0.22f, 0.22f, 0.18f) : design_idle_face_color());
9801 }
9803 if (!defects.empty()) // and the place it goes wrong gets a screen-constant red marker
9804 draw_vertices(m_vertex_model, defects, ColorRGBA(1.0f, 0.22f, 0.22f, 1.0f),
9805 5.0 / std::max(camera.get_zoom(), 1e-6));
9806 }
9807 }
9808
9809 // Committed entities of this session. DoF feedback (P3): a fully-constrained
9810 // sketch (dof==0, consistent) paints green; entities touched by a conflicting
9811 // constraint paint red; otherwise the under-constrained default (orange / grey
9812 // construction). Selected entities always override to the shared selection colour.
9813 // NOT white: the Design tab now paints a bed grid, and white-on-grid made a freshly
9814 // drawn (hence auto-selected) line invisible against it. design_selection_color() is
9815 // the same cyan the solid picks already wear, so "selected" reads the same everywhere.
9816 const ColorRGBA white(1.0f, 1.0f, 1.0f, 1.0f); // hover handle only
9817 const ColorRGBA sel_col = design_selection_color();
9818 const ColorRGBA green(0.30f, 0.85f, 0.42f, 1.0f);
9819 const ColorRGBA conflict(1.0f, 0.22f, 0.22f, 1.0f);
9820 const ColorRGBA opref(0.80f, 0.45f, 1.0f, 1.0f); // violet: the edit-op's reference pick
9821 const double upp_dash = 1.0 / std::max(camera.get_zoom(), 1e-6); // world units per pixel
9822 const ColorRGBA editing(1.0f, 0.78f, 0.10f, 1.0f); // amber: entity whose dim is being typed
9823 const bool fully = (m_dof == 0 && m_solve_ok);
9824 // While an auto-edit value field is open, the active step names the entities its dimension
9825 // drives — light them up so it's obvious WHICH feature the number (e.g. a circle's radius)
9826 // changes.
9827 const std::vector<int>* edit_hi =
9829 ? &m_autoedit_dims[m_autoedit_dim_idx].hi : nullptr;
9830 std::vector<Vec2d> point_markers, sel_point_markers;
9831 for (size_t i = 0; i < m_entities.size(); ++i) {
9832 const SketchEntity& e = m_entities[i];
9833 const bool selected =
9834 std::find(m_selection.begin(), m_selection.end(), int(i)) != m_selection.end();
9835 const bool editing_this =
9836 edit_hi && std::find(edit_hi->begin(), edit_hi->end(), int(i)) != edit_hi->end();
9837 const bool bad = i < m_entity_conflict.size() && m_entity_conflict[i];
9838 // The first pick of an edit-op has a DIFFERENT ROLE from the rest of the selection —
9839 // Mirror's is the axis, Fillet/Chamfer's is the first of the two lines — and until now
9840 // every pick painted the same white, so the picture could not answer "what did I select
9841 // as what". Violet, not cyan: cyan means SELECTED here and nothing else may wear it.
9842 // vd6v.
9843 const bool op_ref = is_edit_op_mode() && int(i) == m_op_a;
9844 ColorRGBA col;
9845 if (editing_this) col = editing;
9846 else if (op_ref) col = opref;
9847 else if (selected) col = sel_col;
9848 else if (bad) col = conflict;
9849 else if (e.construction) col = grey;
9850 else col = fully ? green : orange;
9851 if (e.type == SketchEntity::Type::Point) {
9852 (selected ? sel_point_markers : point_markers).push_back(e.p0);
9853 continue;
9854 }
9855 bool closed = false;
9856 std::vector<Vec2d> poly = entity_polyline(e, closed);
9857 GLModel& target = (selected || editing_this || op_ref) ? m_highlight_model : m_line_model;
9858 if (e.construction) {
9859 for (const std::vector<Vec2d>& d : dash_polyline(poly, closed, 9.0 * upp_dash, 6.0 * upp_dash))
9860 draw_quad_strip(target, d, false, col);
9861 } else {
9862 draw_quad_strip(target, poly, closed, col);
9863 }
9864 }
9865 if (!point_markers.empty())
9866 draw_vertices(m_vertex_model, point_markers, yellow);
9867 if (!sel_point_markers.empty())
9868 draw_vertices(m_highlight_model, sel_point_markers, sel_col);
9869
9870 // Constraint badges during a LIVE sketch. They used to render only inside Mode::Constrain
9871 // on a COMMITTED feature, so every constraint applied while drawing — which is the path the
9872 // Constrain buttons take during a session — was invisible and unremovable: you could not
9873 // tell whether Parallel had been applied, nor take it back. Same glyphs, same teal, sourced
9874 // from this session's m_constraints; click one to delete it (remove_constraint_near).
9875 if (!m_constraints.empty()) {
9876 std::vector<std::pair<Vec2d, Vec2d>> glyphs;
9877 build_constraint_glyphs(upp_dash, m_constraints, glyphs);
9878 if (!glyphs.empty())
9879 draw_strokes(m_fill_model, glyphs, std::max(0.9 * upp_dash, 1e-4),
9880 ColorRGBA(0.45f, 0.95f, 0.70f, 1.0f)); // CAD teal-green
9881 }
9882
9883 // Endpoint / centre handles so individual points are visible and pickable in the
9884 // Select and Dimension tools (a line = a segment + 2 points). Selected ones cyan.
9886 if (m_show_handles) {
9887 std::vector<Vec2d> handles, sel_handles;
9888 auto add_h = [&](int ei, SketchPointRole r, const Vec2d& q) {
9889 const bool s = std::find(m_point_sel.begin(), m_point_sel.end(),
9890 std::make_pair(ei, r)) != m_point_sel.end();
9891 (s ? sel_handles : handles).push_back(q);
9892 };
9893 for (size_t i = 0; i < m_entities.size(); ++i) {
9894 const SketchEntity& e = m_entities[i];
9895 switch (e.type) {
9897 add_h(int(i), SketchPointRole::P0, e.p0);
9898 add_h(int(i), SketchPointRole::P1, e.p1);
9899 break;
9902 add_h(int(i), SketchPointRole::P0, e.p0);
9903 add_h(int(i), SketchPointRole::P1, e.p1);
9904 add_h(int(i), SketchPointRole::Center, e.center);
9905 break;
9908 add_h(int(i), SketchPointRole::Center, e.center);
9909 break;
9911 add_h(int(i), SketchPointRole::P0, e.p0);
9912 add_h(int(i), SketchPointRole::P1, e.p1);
9913 break;
9915 break; // its own marker is drawn above
9916 }
9917 }
9918 if (!handles.empty()) draw_vertices(m_vertex_model, handles, ColorRGBA(0.65f, 0.65f, 0.30f, 1.0f));
9919 if (!sel_handles.empty()) draw_vertices(m_highlight_model, sel_handles, sel_col);
9920
9921 // Midpoint of every segment, drawn smaller and cooler than the endpoint handles
9922 // (te8v). Without it the Midpoint snap is invisible: it exists in the
9923 // inference engine but the user has nothing to aim at. Construction lines get one
9924 // too — you constrain to them as readily as to real geometry.
9925 std::vector<Vec2d> mids;
9926 for (const SketchEntity& e : m_entities) {
9927 if (e.type == SketchEntity::Type::Line)
9928 mids.push_back(0.5 * (e.p0 + e.p1));
9929 else if (e.type == SketchEntity::Type::Arc) {
9930 const double am = 0.5 * (e.start_angle + e.end_angle);
9931 mids.push_back(Vec2d(e.center.x() + e.radius * std::cos(am),
9932 e.center.y() + e.radius * std::sin(am)));
9933 }
9934 }
9935 if (!mids.empty())
9936 draw_vertices(m_vertex_model, mids, ColorRGBA(0.85f, 0.85f, 0.88f, 1.0f), 0.9); // neutral: not the selection hue
9937
9938 // Derived feature handles (A3): the circle RadiusHandle is not a SketchPointRole,
9939 // so the per-point pass above doesn't draw it. Render it (cyan) + the hovered
9940 // handle (white, larger) at a screen-constant size so they stay grabbable at any
9941 // zoom. A4 makes these draggable; later phases add slot/rect/polygon handles.
9942 const double upp = 1.0 / std::max(camera.get_zoom(), 1e-6);
9943 std::vector<Vec2d> radius_h;
9944 for (const Handle& h : build_handles())
9945 if (h.role == HandleRole::RadiusHandle || h.role == HandleRole::MajorAxis ||
9946 h.role == HandleRole::MinorAxis || h.role == HandleRole::BSplineCtrl)
9947 radius_h.push_back(h.pos);
9948 if (!radius_h.empty())
9949 draw_vertices(m_vertex_model, radius_h, ColorRGBA(0.95f, 0.95f, 0.95f, 1.0f),
9950 std::max(4.0 * upp, 1e-4));
9953 std::max(5.5 * upp, 1e-4));
9954 }
9955
9956 // Placed dimension quotes (drawn in every mode so they persist while sketching).
9957 // Pass plane-units-per-pixel so labels keep a constant on-screen size.
9958 render_dimensions(1.0 / std::max(camera.get_zoom(), 1e-6));
9959 render_live_quotes(1.0 / std::max(camera.get_zoom(), 1e-6));
9960 // Draw-then-edit: the selection's live quotes now exist. Open the primary value editor on
9961 // the next event-loop tick (NOT here inside the paint) so the floating field grabs focus
9962 // cleanly — the same context the Line path opens from. m_live_quotes persists until the
9963 // next render_live_quotes(), so the deferred open still sees this frame's values.
9964 if (m_autoedit_pending) {
9965 m_autoedit_pending = false;
9966 trace_autoedit("pending -> deferring open", 0);
9967 wxGetApp().CallAfter([this] { open_primary_autoedit(); });
9968 }
9969 if (is_edit_op_mode())
9970 render_op_gizmo(1.0 / std::max(camera.get_zoom(), 1e-6));
9971 if (is_transform_mode())
9972 render_tf_gizmo(1.0 / std::max(camera.get_zoom(), 1e-6));
9973
9974 // In-progress entity preview for the active tool.
9975 const ColorRGBA preview = m_construction ? grey : orange;
9976 switch (m_mode) {
9977
9978 case Mode::Select:
9979 case Mode::Dimension:
9980 break; // selection highlight / placed quotes are drawn above; no rubber-band
9981
9982 case Mode::Polyline: {
9983 std::vector<Vec2d> pts = m_points;
9984 if (m_has_cursor)
9985 pts.push_back(m_cursor);
9986 draw_quad_strip(m_highlight_model, pts, false, preview);
9988 // Teal rubber-band = the new segment is locked to an inference angle.
9989 if (m_cursor_locked && m_has_cursor && !m_points.empty()) {
9990 const ColorRGBA lock(0.10f, 0.85f, 0.80f, 1.0f);
9991 std::vector<Vec2d> seg = { m_points.back(), m_cursor };
9992 draw_quad_strip(m_line_model, seg, false, lock);
9993 }
9994 break;
9995 }
9996
9997 case Mode::Line: {
9998 std::vector<Vec2d> pts = m_points;
9999 if (m_has_cursor && m_points.size() == 1)
10000 pts.push_back(m_cursor);
10001 if (pts.size() >= 2) {
10002 const ColorRGBA col = (m_cursor_locked && m_points.size() == 1)
10003 ? ColorRGBA(0.10f, 0.85f, 0.80f, 1.0f) : preview;
10004 draw_quad_strip(m_highlight_model, pts, false, col);
10005 }
10007 break;
10008 }
10009
10010 case Mode::CornerRect: {
10011 if (m_points.size() == 1 && m_has_cursor) {
10012 const Vec2d A = m_points[0];
10013 const Vec2d B = m_cursor;
10014 std::vector<Vec2d> corners = { A, Vec2d(B.x(), A.y()), B, Vec2d(A.x(), B.y()) };
10015 draw_quad_strip(m_highlight_model, corners, true, preview);
10016 }
10017 break;
10018 }
10019
10020 case Mode::CenterRect: {
10021 if (m_points.size() == 1 && m_has_cursor) {
10022 const Vec2d C = m_points[0];
10023 const Vec2d P = m_cursor;
10024 const double hx = std::abs(P.x() - C.x());
10025 const double hy = std::abs(P.y() - C.y());
10026 std::vector<Vec2d> corners = {
10027 Vec2d(C.x() - hx, C.y() - hy), Vec2d(C.x() + hx, C.y() - hy),
10028 Vec2d(C.x() + hx, C.y() + hy), Vec2d(C.x() - hx, C.y() + hy) };
10029 draw_quad_strip(m_highlight_model, corners, true, preview);
10030 draw_vertices(m_vertex_model, { C }, yellow);
10031 }
10032 break;
10033 }
10034
10035 case Mode::ObliqueRect: {
10037 if (m_points.size() == 2 && m_has_cursor) {
10038 const Vec2d A = m_points[0], B = m_points[1];
10039 Vec2d u = B - A;
10040 if (u.squaredNorm() > 1e-12) {
10041 u.normalize();
10042 const Vec2d n(-u.y(), u.x());
10043 const double w = n.dot(m_cursor - A);
10044 draw_quad_strip(m_highlight_model, { A, B, B + n * w, A + n * w }, true, preview);
10045 }
10046 }
10047 break;
10048 }
10049
10050 case Mode::RoundedRect: {
10052 if (m_points.size() == 1 && m_has_cursor) {
10053 const Vec2d A = m_points[0], B = m_cursor; // box not yet fixed: plain rect
10054 draw_quad_strip(m_highlight_model, { A, Vec2d(B.x(), A.y()), B, Vec2d(A.x(), B.y()) }, true, preview);
10055 } else if (m_points.size() == 2 && m_has_cursor) {
10057 }
10058 break;
10059 }
10060
10061 case Mode::CenterCircle: {
10062 if (m_points.size() == 1 && m_has_cursor) {
10063 const Vec2d C = m_points[0];
10064 const double r = (m_cursor - C).norm();
10065 draw_quad_strip(m_highlight_model, circle_polygon(C, r), true, preview);
10066 draw_vertices(m_vertex_model, { C }, yellow);
10067 }
10068 break;
10069 }
10070
10071 case Mode::TwoPointCircle: {
10073 if (m_points.size() == 1 && m_has_cursor) {
10074 const Vec2d C = (m_points[0] + m_cursor) * 0.5;
10075 const double r = (m_cursor - m_points[0]).norm() * 0.5;
10076 draw_quad_strip(m_highlight_model, circle_polygon(C, r), true, preview);
10077 }
10078 break;
10079 }
10080
10083 if (m_points.size() == 2 && m_has_cursor)
10085 break;
10086 }
10087
10088 case Mode::ThreePointArc: {
10090 if (m_points.size() == 2 && m_has_cursor)
10092 break;
10093 }
10094
10095 case Mode::TangentArc: {
10097 if (m_points.size() == 1 && m_has_cursor)
10099 break;
10100 }
10101
10102 case Mode::CenterArc: {
10104 if (m_points.size() == 1 && m_has_cursor) {
10105 // center placed: show the radius rubber-band as a faint guide circle
10106 SketchEntity g; g.type = SketchEntity::Type::Circle; g.center = m_points[0];
10107 g.p0 = m_points[0]; g.radius = (m_cursor - m_points[0]).norm(); g.construction = true;
10108 draw_entities_preview({ g }, preview);
10109 } else if (m_points.size() == 2 && m_has_cursor) {
10111 }
10112 break;
10113 }
10114
10115 case Mode::Slot: {
10117 if (m_points.size() == 1 && m_has_cursor) {
10119 } else if (m_points.size() == 2 && m_has_cursor) {
10120 Vec2d u = m_points[1] - m_points[0];
10121 if (u.squaredNorm() > 1e-12) {
10122 u.normalize();
10123 const Vec2d n(-u.y(), u.x());
10124 const double w = std::abs(n.dot(m_cursor - m_points[0]));
10125 draw_entities_preview(make_slot(m_points[0], m_points[1], w), preview);
10126 }
10127 }
10128 break;
10129 }
10130
10131 case Mode::ArcSlot: {
10133 if (m_points.size() == 1 && m_has_cursor) {
10134 // center placed: faint guide circle for the centerline radius
10135 SketchEntity g; g.type = SketchEntity::Type::Circle; g.center = m_points[0];
10136 g.p0 = m_points[0]; g.radius = (m_cursor - m_points[0]).norm(); g.construction = true;
10137 draw_entities_preview({ g }, preview);
10138 } else if (m_points.size() == 2 && m_has_cursor) {
10139 draw_entities_preview(make_center_arc(m_points[0], m_points[1], m_cursor), preview); // centerline arc
10140 } else if (m_points.size() == 3 && m_has_cursor) {
10141 const double Rc = (m_points[1] - m_points[0]).norm();
10142 const double w = std::abs((m_cursor - m_points[0]).norm() - Rc);
10144 }
10145 break;
10146 }
10147
10148 case Mode::Polygon: {
10150 if (m_points.size() == 1 && m_has_cursor)
10152 break;
10153 }
10154
10155 case Mode::Ellipse: {
10157 if (m_points.size() == 1 && m_has_cursor) {
10158 SketchEntity g; g.type = SketchEntity::Type::Line;
10159 g.p0 = m_points[0]; g.p1 = m_cursor; g.construction = true; // major-axis rubber band
10160 draw_entities_preview({ g }, preview);
10161 } else if (m_points.size() == 2 && m_has_cursor) {
10163 }
10164 break;
10165 }
10166
10167 case Mode::EllipseArc: {
10169 if (m_points.size() == 1 && m_has_cursor) {
10170 SketchEntity g; g.type = SketchEntity::Type::Line;
10171 g.p0 = m_points[0]; g.p1 = m_cursor; g.construction = true;
10172 draw_entities_preview({ g }, preview);
10173 } else if (m_points.size() == 2 && m_has_cursor) {
10175 } else if (m_points.size() == 3 && m_has_cursor) {
10176 std::vector<SketchEntity> full = make_ellipse(m_points[0], m_points[1], m_points[2]);
10177 for (auto& e : full) e.construction = true; // faint full ellipse
10178 draw_entities_preview(full, preview);
10179 } else if (m_points.size() == 4 && m_has_cursor) {
10181 m_points[3], m_cursor), preview);
10182 }
10183 break;
10184 }
10185
10186 case Mode::BSpline: {
10187 std::vector<Vec2d> poles = m_points;
10188 if (m_has_cursor) poles.push_back(m_cursor);
10189 // Faint control polygon as a placement guide.
10190 if (poles.size() >= 2) {
10191 std::vector<SketchEntity> guide;
10192 for (size_t i = 1; i < poles.size(); ++i) {
10193 SketchEntity g; g.type = SketchEntity::Type::Line;
10194 g.p0 = poles[i - 1]; g.p1 = poles[i]; g.construction = true;
10195 guide.push_back(g);
10196 }
10198 }
10199 // The spline curve itself.
10200 if (poles.size() >= 2)
10201 draw_quad_strip(m_highlight_model, bspline_polyline(poles), false, preview);
10203 break;
10204 }
10205
10206 case Mode::Trim:
10207 case Mode::Extend: {
10208 // Hover preview: paint the exact sub-portion a click would cut (Trim) / add (Extend)
10209 // in red, recomputed from the cursor every frame (never persisted). The pick tolerance
10210 // matches on_mouse: ~8 px projected to plane units, x3 (here via zoom -> units/px).
10211 if (m_has_cursor) {
10212 const double upp = 1.0 / std::max(camera.get_zoom(), 1e-6);
10213 int subj = -1;
10214 std::vector<Vec2d> removed;
10215 const ColorRGBA cut(1.0f, 0.2f, 0.2f, 1.0f);
10216 if (compute_trim_preview(m_cursor, 24.0 * upp, m_mode == Mode::Extend, subj, removed))
10217 draw_quad_strip(m_highlight_model, removed, false, cut);
10218 }
10219 break;
10220 }
10221
10222 case Mode::Point:
10223 case Mode::Constrain:
10224 break;
10225 }
10226
10227 // Inference hint: highlight the snapped target under the cursor (C1.3). Colour
10228 // encodes what the placed point will be Coincident/PointOnObject/Fixed onto.
10229 if (m_has_cursor && m_mode != Mode::Constrain && m_cursor_snap.snapped()) {
10230 ColorRGBA hint(1.0f, 0.55f, 0.1f, 1.0f); // endpoint: orange
10231 switch (m_cursor_snap.kind) {
10232 case InferenceSnap::Kind::Midpoint: hint = ColorRGBA(0.35f, 0.90f, 0.75f, 1.0f); break; // teal
10233 case InferenceSnap::Kind::Center: hint = ColorRGBA(1.0f, 0.85f, 0.2f, 1.0f); break; // yellow (cyan = selected)
10234 case InferenceSnap::Kind::Origin: hint = ColorRGBA(1.0f, 0.30f, 0.85f, 1.0f); break; // magenta
10235 case InferenceSnap::Kind::OnEdge: hint = ColorRGBA(0.45f, 0.70f, 1.0f, 1.0f); break; // blue
10236 default: break;
10237 }
10239 }
10240
10241 shader->stop_using();
10244
10245 if (on_readout) on_readout(build_readout()); // bottom-right viewport HUD
10246}
#define glsafe(cmd)
Definition OpenGLUtils.hpp:25
void render_op_gizmo(double unit_per_px)
Definition DesignSketchTool.cpp:8893
Handle m_hover_handle
Definition DesignSketchTool.hpp:1125
void render_rib_gizmo()
Definition DesignSketchTool.cpp:5312
void render_datum_gizmo()
Definition DesignSketchTool.cpp:4956
void build_constraint_glyphs(double unit_per_px, const std::vector< SketchEntityConstraintDef > &cons, std::vector< std::pair< Vec2d, Vec2d > > &out)
Definition DesignSketchTool.cpp:8446
void render_live_quotes(double unit_per_px)
Definition DesignSketchTool.cpp:8081
void render_tf_gizmo(double unit_per_px)
Definition DesignSketchTool.cpp:9325
void render_dimensions(double unit_per_px)
Definition DesignSketchTool.cpp:8057
void render_fillet_gizmo()
Definition DesignSketchTool.cpp:6081
GLModel m_fill_model
Definition DesignSketchTool.hpp:1270
bool draws_reference_axes() const
Definition DesignSketchTool.hpp:378
void render_shell_gizmo()
Definition DesignSketchTool.cpp:6618
bool m_has_hover_handle
Definition DesignSketchTool.hpp:1124
void render_helix_gizmo()
Definition DesignSketchTool.cpp:5144
void render_hole_gizmo()
Definition DesignSketchTool.cpp:6203
void open_primary_autoedit()
Definition DesignSketchTool.cpp:1599
void render_thread_gizmo()
Definition DesignSketchTool.cpp:6439
void render_revolve_gizmo()
Definition DesignSketchTool.cpp:6963
void render_move_gizmo()
Definition DesignSketchTool.cpp:5865
void render_view_helpers()
Definition DesignSketchTool.cpp:4307
void draw_fill_holed(GLModel &model, const std::vector< Vec2d > &outer, const std::vector< std::vector< Vec2d > > &holes, const ColorRGBA &color)
Definition DesignSketchTool.cpp:7600
bool has_display() const
Definition DesignSketchTool.hpp:209
void render_xform_gizmo()
Definition DesignSketchTool.cpp:8671
bool compute_trim_preview(const Vec2d &p, double tol, bool extend, int &subject_ei, std::vector< Vec2d > &removed_poly) const
Definition DesignSketchTool.cpp:1837
void render_cut_gizmo()
Definition DesignSketchTool.cpp:6850
void draw_entities_preview(const std::vector< SketchEntity > &ents, const ColorRGBA &color)
Definition DesignSketchTool.cpp:8527
void render_datum_planes()
Definition DesignSketchTool.cpp:4365
void render_mate_connectors()
Definition DesignSketchTool.cpp:4460
std::string build_readout() const
Definition DesignSketchTool.cpp:10251
std::function< void()> render_overlays
Definition DesignSketchTool.hpp:196
void render_body_edges()
Definition DesignSketchTool.cpp:3579
class SketchInlineEditor * inline_editor
Definition DesignSketchTool.hpp:194
bool m_show_handles
Definition DesignSketchTool.hpp:1121
bool is_creation_autoedit_mode() const
Definition DesignSketchTool.hpp:132
void render_pattern_gizmo()
Definition DesignSketchTool.cpp:7123
GLModel m_vertex_model
Definition DesignSketchTool.hpp:1259
void render_base_pick()
Definition DesignSketchTool.cpp:5649
void render_draft_gizmo()
Definition DesignSketchTool.cpp:6734
void render_solid_highlight()
Definition DesignSketchTool.cpp:4264
void render_extrude_gizmo()
Definition DesignSketchTool.cpp:4839
const ColorRGBA * sketch_hl_color(int feature) const
Definition DesignSketchTool.cpp:9500
#define glEnable
Definition gl.h:3667
#define GL_DEPTH_TEST
Definition gl.h:574
#define GL_SRC_ALPHA
Definition gl.h:1621
#define GL_CULL_FACE
Definition gl.h:500
#define GL_BLEND
Definition gl.h:275
#define GL_ONE_MINUS_SRC_ALPHA
Definition gl.h:1239
#define glDisable
Definition gl.h:3607
#define glBlendFunc
Definition gl.h:3325
ColorRGBA design_idle_face_color()
Definition DesignSketchTool.hpp:55
ColorRGBA design_selection_color(float alpha=1.0f)
Definition DesignSketchTool.hpp:49
static std::vector< std::vector< Vec2d > > dash_polyline(const std::vector< Vec2d > &pts, bool closed, double dash, double gap)
Definition DesignSketchTool.cpp:7463
static std::string orange
Definition UnsavedChangesDialog.cpp:103
static std::string grey
Definition UnsavedChangesDialog.cpp:102
@ lock
Definition GLGizmoEmboss.cpp:209
@ OnEdge
Definition SketchInference.hpp:20
@ Origin
Definition SketchInference.hpp:20
@ Center
Definition SketchInference.hpp:20
@ Midpoint
Definition SketchInference.hpp:20

References Slic3r::ColorRGBA::a(), Slic3r::SketchEntity::Arc, ArcSlot, BSpline, Slic3r::SketchEntity::BSpline, Slic3r::GUI::bspline_polyline(), BSplineCtrl, build_constraint_glyphs(), build_handles(), build_readout(), Slic3r::InferenceSnap::Center, Slic3r::Center, Slic3r::SketchEntity::center, CenterArc, CenterCircle, CenterRect, Slic3r::SketchEntity::Circle, Slic3r::GUI::circle_polygon(), compute_trim_preview(), Constrain, Slic3r::SketchEntity::construction, CornerRect, Slic3r::GUI::dash_polyline(), Slic3r::GUI::design_idle_face_color(), Slic3r::GUI::design_selection_color(), Dimension, draw_entities_preview(), draw_fill_holed(), draw_quad_strip(), draw_strokes(), draw_vertices(), draws_reference_axes(), Ellipse, Slic3r::SketchEntity::Ellipse, EllipseArc, Slic3r::SketchEntity::EllipseArc, emit_step_hint(), entity_polyline(), Extend, Slic3r::GUI::Camera::get_projection_matrix(), Slic3r::GUI::GLCanvas3D::get_scale(), Slic3r::GUI::Camera::get_view_matrix(), Slic3r::GUI::Camera::get_zoom(), GL_BLEND, GL_CULL_FACE, GL_DEPTH_TEST, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, glBlendFunc, glDisable, glEnable, glsafe, Slic3r::GUI::grey, has_display(), Slic3r::holes(), inline_editor, is_creation_autoedit_mode(), is_edit_op_mode(), is_transform_mode(), L, Line, Slic3r::SketchEntity::Line, m_active, m_autoedit_dim_idx, m_autoedit_dims, m_autoedit_label_pos, m_autoedit_pending, m_autoedit_seen, m_awaiting_length, m_constrain_cons, m_constrain_entities, m_constraint_hl, m_constraints, m_construction, m_ct_active, m_cursor, m_cursor_locked, m_cursor_snap, m_dim_label_seq, m_display_pick, m_display_pick_region, m_display_sketches, m_dof, m_dr_active, m_dz_active, m_entities, m_entity_conflict, m_ex_active, m_fill_model, m_fl_active, m_has_cursor, m_has_hover_handle, m_highlight_model, m_hl_active, m_hover_handle, m_hx_active, m_label_rects, m_line_model, m_mode, m_mv_active, m_op_a, m_open_feature, m_pick0, m_pick1, m_pick2, m_plane, m_point_sel, m_points, m_polygon_sides, m_pt_active, m_rb_active, m_render_scale, m_rubber, m_rv_active, m_sel_a, m_sel_b, m_selection, m_sh_active, m_show_handles, m_solve_ok, m_th_active, m_vertex_model, MajorAxis, make_arc_slot(), make_center_arc(), make_ellipse(), make_ellipse_arc(), make_polygon(), make_rounded_rect(), make_slot(), make_tangent_arc(), make_three_point_arc(), make_three_point_circle(), Slic3r::InferenceSnap::Midpoint, MinorAxis, ObliqueRect, on_readout, Slic3r::InferenceSnap::OnEdge, open_primary_autoedit(), Slic3r::GUI::orange, Slic3r::InferenceSnap::Origin, Slic3r::P, Slic3r::P0, Slic3r::SketchEntity::p0, Slic3r::P1, Slic3r::SketchEntity::p1, Point, Slic3r::SketchEntity::Point, Polygon, Polyline, Slic3r::SketchEntity::radius, RadiusHandle, region_loops(), render(), render_base_pick(), render_body_edges(), render_cut_gizmo(), render_datum_gizmo(), render_datum_planes(), render_dimensions(), render_draft_gizmo(), render_extrude_gizmo(), render_fillet_gizmo(), render_helix_gizmo(), render_hole_gizmo(), render_live_quotes(), render_mate_connectors(), render_move_gizmo(), render_op_gizmo(), render_overlays, render_pattern_gizmo(), render_revolve_gizmo(), render_rib_gizmo(), render_shell_gizmo(), render_solid_highlight(), render_tf_gizmo(), render_thread_gizmo(), render_view_helpers(), render_xform_gizmo(), RoundedRect, Select, Slic3r::GLShaderProgram::set_uniform(), sketch_hl_color(), Slot, Slic3r::GLShaderProgram::start_using(), Slic3r::GLShaderProgram::stop_using(), TangentArc, ThreePointArc, ThreePointCircle, Slic3r::GUI::trace_autoedit(), TransformArt, Trim, TwoPointCircle, and Slic3r::SketchEntity::type.

Referenced by render().

Here is the caller graph for this function:

◆ render_base_pick()

void Slic3r::GUI::DesignSketchTool::render_base_pick ( )
private
5650{
5651 if (!m_dbp_active || m_dbp_planes.empty()) return;
5654 const double H = dbp_half_extent();
5655 const std::vector<SketchPlane> squares = dbp_squares(H);
5656 const int selected = selected_base ? selected_base() : -1;
5657 auto base_of = [this](size_t i) { return i < m_dbp_base.size() ? m_dbp_base[i] : -1; };
5658 enum class Look { Idle, Hover, Selected };
5659 auto look = [&](size_t i) {
5660 return base_of(i) >= 0 && base_of(i) == selected ? Look::Selected : int(i) == m_dbp_hover ? Look::Hover : Look::Idle;
5661 };
5662 // Each base plane in the colour of the axis it is normal to: XY blue, XZ green, YZ red. A datum the
5663 // Plane card offers as a base keeps a slate of its own, clear of the grey hover.
5664 auto hue = [&](size_t i) {
5665 switch (base_of(i)) {
5666 case 0: return ColorRGBA(0.30f, 0.55f, 0.95f, 1.0f);
5667 case 1: return ColorRGBA(0.35f, 0.80f, 0.45f, 1.0f);
5668 case 2: return ColorRGBA(0.92f, 0.42f, 0.42f, 1.0f);
5669 default: return ColorRGBA(0.55f, 0.60f, 0.72f, 1.0f);
5670 }
5671 };
5672 // Where squares overlap on screen, two layers of alpha a blended in either order differ by only
5673 // a^2 of their colour difference, so much fainter fills would hide which one is in front however
5674 // well the pieces are sorted. The selected plane goes near solid in its own colour: a fixed
5675 // selection colour would match one of the three.
5676 auto fill = [&](size_t i) {
5677 ColorRGBA c = look(i) == Look::Hover ? ColorRGBA(0.80f, 0.80f, 0.80f, 1.0f) : hue(i);
5678 c.a(look(i) == Look::Selected ? 0.85f : look(i) == Look::Hover ? 0.45f : 0.50f);
5679 return c;
5680 };
5681 auto ink = [&](size_t i) {
5682 switch (look(i)) {
5683 case Look::Selected: return ColorRGBA(0.20f, 0.25f, 0.35f, 1.0f);
5684 case Look::Hover: return ColorRGBA(0.62f, 0.62f, 0.62f, 1.0f);
5685 default: return hue(i);
5686 }
5687 };
5688 const Camera& cam = wxGetApp().plater()->get_camera();
5691 glsafe(::glEnable(GL_BLEND)); // alpha is ignored without this; destination alpha stays 1
5693
5694 for (size_t i = 0; i < m_dbp_planes.size(); ++i)
5695 if (is_base_plane(base_of(i))) { // the base planes all pass through the modeling origin
5696 render_reference_axes(m_dbp_planes[i].origin, H);
5697 break;
5698 }
5699
5700 const std::vector<PlanePiece> pieces = planes_back_to_front(squares, H, cam.get_position(), cam.get_dir_forward(),
5701 cam.get_type() == Camera::EType::Perspective);
5702 const SketchPlane saved_plane = m_plane;
5703 for (size_t k = 0; k < pieces.size(); ++k) {
5704 const PlanePiece& piece = pieces[k];
5705 const size_t i = size_t(piece.plane);
5706 GLModel::Geometry g;
5707 g.format = { EPT::Triangles, EVL::P3 };
5708 for (const Vec3d& q : piece.corners) g.add_vertex((Vec3f)q.cast<float>());
5709 for (unsigned int c = 1; c + 1 < piece.corners.size(); ++c) g.add_triangle(0, c, c + 1); // convex: a fan
5710 GLModel m;
5711 m.init_from(std::move(g));
5712 m.set_color(fill(i));
5713 m.render();
5714
5715 // A base plane's name goes down with its last piece, so a square in front tints it as it
5716 // tints the fill.
5717 if (!is_base_plane(base_of(i)) || i >= m_dbp_labels.size() || m_dbp_labels[i].empty()
5718 || std::any_of(pieces.begin() + k + 1, pieces.end(), [&](const PlanePiece& p) { return p.plane == piece.plane; }))
5719 continue;
5720 const double th = label_height(H);
5721 Vec2d size;
5722 std::vector<std::pair<Vec2d, Vec2d>> strokes = text_strokes(m_dbp_labels[i], th, size);
5723 const Vec2d c = label_centre(H, size);
5724 for (auto& [a, b] : strokes) {
5725 a += c;
5726 b += c;
5727 }
5728 m_plane = squares[i]; // draw_strokes lifts plane coordinates through m_plane
5729 draw_strokes(m_line_model, strokes, 0.07 * th, ink(i));
5730 }
5731 for (size_t i = 0; i < m_dbp_planes.size() && i < m_dbp_labels.size(); ++i)
5732 if (!is_base_plane(base_of(i)) && !m_dbp_labels[i].empty()) {
5733 m_plane = squares[i]; // draw_text anchors through m_plane too
5734 draw_text(m_line_model, m_dbp_labels[i], datum_label_anchor(H), H * 0.10, ink(i));
5735 }
5736 m_plane = saved_plane;
5738}
void render_reference_axes(const Vec3d &origin, double half)
Definition DesignSketchTool.cpp:5594
std::function< int()> selected_base
Definition DesignSketchTool.hpp:375
#define glBlendFuncSeparate
Definition gl.h:3327
#define GL_ONE
Definition gl.h:1232
Vec2d label_centre(double half, const Vec2d &size)
Definition DesignSketchTool.cpp:5481
double label_height(double half)
Definition DesignSketchTool.cpp:5480
std::vector< std::pair< Vec2d, Vec2d > > text_strokes(const std::string &text, double height, Vec2d &size)
Definition DesignSketchTool.cpp:7856
@ Idle
Definition DesignInteraction.hpp:19
std::vector< PlanePiece > planes_back_to_front(const std::vector< SketchPlane > &planes, double half, const Vec3d &eye, const Vec3d &forward, bool perspective)
Definition DesignSketchTool.cpp:5494
@ Perspective
Definition Camera.hpp:40
EVertexLayout
Definition GLModel.hpp:41
EPrimitiveType
Definition GLModel.hpp:30

References Slic3r::ColorRGBA::a(), Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::GUI::PlanePiece::corners, dbp_half_extent(), dbp_squares(), draw_strokes(), draw_text(), Slic3r::empty(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_position(), Slic3r::GUI::Camera::get_type(), GL_BLEND, GL_CULL_FACE, GL_DEPTH_TEST, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, glBlendFuncSeparate, glDisable, glEnable, glsafe, Slic3r::GUI::Idle, Slic3r::GUI::GLModel::init_from(), Slic3r::GUI::is_base_plane(), m_dbp_active, m_dbp_base, m_dbp_hover, m_dbp_labels, m_dbp_planes, m_line_model, m_plane, Slic3r::GUI::Camera::Perspective, Slic3r::GUI::PlanePiece::plane, Slic3r::GUI::planes_back_to_front(), Slic3r::GUI::GLModel::render(), render_base_pick(), render_reference_axes(), selected_base, and Slic3r::GUI::GLModel::set_color().

Referenced by render(), and render_base_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_body_edges()

void Slic3r::GUI::DesignSketchTool::render_body_edges ( )
private
3580{
3581 if (m_body_edges_hidden || m_solid_bodies == nullptr)
3582 return;
3583 const Camera& cam = wxGetApp().plater()->get_camera();
3584 const Vec3d vd = cam.get_dir_forward();
3585 const double px = 1.0 / std::max(cam.get_zoom(), 1e-6);
3586 const double hw = 1.0 * px; // ~2 px wide: at 1.5 the lines read as hairlines
3587 const Vec3d pull = -vd * (3.0 * px);
3588 // Two passes: the edges of a body faded by body focus are fainter, like the body itself.
3589 for (int pass = 0; pass < 2; ++pass) {
3590 GLModel::Geometry g;
3591 for (int b = 0; b < int(m_body_edges.size()); ++b) {
3592 if (m_solid_visible != nullptr && b < int(m_solid_visible->size()) && !(*m_solid_visible)[b])
3593 continue;
3594 const bool faded = m_pick_only_body >= 0 && m_pick_only_body < int(m_body_edges.size())
3595 && b != m_pick_only_body;
3596 if (faded != (pass == 1))
3597 continue;
3598 append_ribbons(g, b, m_body_edges[b], vd, pull, hw);
3599 }
3600 render_ribbons(m_body_edges_model, std::move(g), ColorRGBA(0.08f, 0.09f, 0.11f, pass == 0 ? 0.85f : 0.25f));
3601 }
3602}
void append_ribbons(GLModel::Geometry &g, int body, const std::vector< std::vector< Vec3d > > &polylines, const Vec3d &vd, const Vec3d &pull, double hw) const
Definition DesignSketchTool.cpp:3538
bool m_body_edges_hidden
Definition DesignSketchTool.hpp:1292
GLModel m_body_edges_model
Definition DesignSketchTool.hpp:1380
wxBitmap faded(const wxBitmap &bmp, double alpha)
Definition UVEditorCanvas.cpp:1761
static void render_ribbons(GLModel &model, GLModel::Geometry &&g, const ColorRGBA &colour)
Definition DesignSketchTool.cpp:3560

References append_ribbons(), Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_zoom(), m_body_edges, m_body_edges_hidden, m_body_edges_model, m_pick_only_body, m_solid_bodies, m_solid_visible, Slic3r::pull, render_body_edges(), and Slic3r::GUI::render_ribbons().

Referenced by render(), and render_body_edges().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_cut_gizmo()

void Slic3r::GUI::DesignSketchTool::render_cut_gizmo ( )
private
6851{
6852 if (!m_ct_active) return;
6853 const Camera& cam = wxGetApp().plater()->get_camera();
6854 const Vec3d right = cam.get_dir_right().normalized();
6855 const Vec3d up = cam.get_dir_up().normalized();
6856 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6857 const double th = std::max(15.0 * upp, 1e-4);
6858 const ColorRGBA teal(0.20f, 0.80f, 0.75f, 1.0f);
6859
6860 // ---- Wire rectangle in the cut plane ----
6861 {
6862 const Vec3d cutpos = m_ct_base + m_ct_offset * m_ct_n;
6863 const SketchPlane saved = m_plane;
6864 SketchPlane rp; rp.origin = cutpos; rp.x_axis = m_ct_u; rp.y_axis = m_ct_v; rp.normal = m_ct_n;
6865 m_plane = rp;
6866 const double h = m_ct_half;
6867 std::vector<std::pair<Vec2d, Vec2d>> segs;
6868 segs.emplace_back(Vec2d(-h, -h), Vec2d( h, -h));
6869 segs.emplace_back(Vec2d( h, -h), Vec2d( h, h));
6870 segs.emplace_back(Vec2d( h, h), Vec2d(-h, h));
6871 segs.emplace_back(Vec2d(-h, h), Vec2d(-h, -h));
6873 draw_strokes(m_ct_rect_model, segs, std::max(0.7 * upp, 1e-4), teal);
6874 m_plane = saved;
6875 }
6876
6877 // ---- Offset arrow (billboarded, clone of render_shell_gizmo) ----
6878 {
6879 const double L_sign = (std::abs(m_ct_offset) < 40.0 * upp)
6880 ? std::copysign(40.0 * upp, (m_ct_offset == 0.0 ? 1.0 : m_ct_offset))
6881 : m_ct_offset;
6882 const Vec3d tipw = m_ct_base + m_ct_n * L_sign;
6883
6884 const SketchPlane saved = m_plane;
6885 SketchPlane bb; bb.origin = m_ct_base; bb.x_axis = right; bb.y_axis = up;
6886 bb.normal = cam.get_dir_forward().normalized();
6887 m_plane = bb;
6888
6889 const Vec2d tip2((tipw - m_ct_base).dot(right), (tipw - m_ct_base).dot(up));
6890 if (tip2.norm() > 1e-6) {
6891 const Vec2d u = tip2.normalized();
6892 const Vec2d nrm(-u.y(), u.x());
6893 std::vector<std::pair<Vec2d, Vec2d>> segs;
6894 segs.emplace_back(Vec2d(0, 0), tip2);
6895 const double as = std::max(tip2.norm() * 0.20, th * 0.9);
6896 const Vec2d back = tip2 - u * as;
6897 segs.emplace_back(tip2, back + nrm * (as * 0.5));
6898 segs.emplace_back(tip2, back - nrm * (as * 0.5));
6900 draw_strokes(m_ct_stroke_model, segs, std::max(0.7 * upp, 1e-4), teal);
6901 DimAnnot da; da.kind = DimType::Distance; da.value = m_ct_offset;
6902 draw_text(m_line_model, dim_text(da), tip2 + u * (th * 1.4), th, teal);
6903 }
6904 m_plane = saved;
6905 }
6906}
double m_ct_half
Definition DesignSketchTool.hpp:1602
Vec3d m_ct_v
Definition DesignSketchTool.hpp:1600
Vec3d m_ct_u
Definition DesignSketchTool.hpp:1599
GLModel m_ct_stroke_model
Definition DesignSketchTool.hpp:1610
GLModel m_ct_rect_model
Definition DesignSketchTool.hpp:1611

References dim_text(), Distance, Slic3r::dot(), draw_strokes(), draw_text(), Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, m_ct_active, m_ct_base, m_ct_half, m_ct_n, m_ct_offset, m_ct_rect_model, m_ct_stroke_model, m_ct_u, m_ct_v, m_line_model, m_plane, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, render_cut_gizmo(), Slic3r::GUI::DesignSketchTool::DimAnnot::value, Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_cut_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_datum_gizmo()

void Slic3r::GUI::DesignSketchTool::render_datum_gizmo ( )
private
4957{
4958 if (!m_dz_active) return;
4961 const Camera& cam = wxGetApp().plater()->get_camera();
4962 const Vec3d right = cam.get_dir_right().normalized();
4963 const Vec3d up = cam.get_dir_up().normalized();
4964 const Vec3d vd = cam.get_dir_forward();
4965 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
4966 const double hs = 6.0 * upp; // handle half-size (~6 px)
4967 const double hw = 1.5 * upp; // outline ribbon half-width
4968 const double hu = m_dz_usize * 0.5, hv = m_dz_vsize * 0.5;
4969 const SketchPlane& p = m_dz_plane;
4970
4971 // Rectangle outline (4 thin camera-facing ribbons).
4972 const Vec3d c[4] = { p.to_world(Vec2d(-hu, -hv)), p.to_world(Vec2d(hu, -hv)),
4973 p.to_world(Vec2d(hu, hv)), p.to_world(Vec2d(-hu, hv)) };
4974 GLModel::Geometry border; border.format = { EPT::Triangles, EVL::P3 };
4975 unsigned int bb = 0;
4976 for (int s = 0; s < 4; ++s) {
4977 const Vec3d a = c[s], b = c[(s + 1) & 3];
4978 Vec3d dir = b - a; if (dir.norm() < 1e-9) continue; dir.normalize();
4979 Vec3d off = dir.cross(vd);
4980 if (off.norm() < 1e-9) off = dir.cross(up);
4981 if (off.norm() < 1e-9) continue;
4982 off.normalize(); off *= hw;
4983 border.add_vertex((Vec3f)(a + off).cast<float>()); border.add_vertex((Vec3f)(b + off).cast<float>());
4984 border.add_vertex((Vec3f)(b - off).cast<float>()); border.add_vertex((Vec3f)(a - off).cast<float>());
4985 border.add_triangle(bb, bb + 1, bb + 2); border.add_triangle(bb, bb + 2, bb + 3); bb += 4;
4986 }
4987
4988 // 4 edge-midpoint handle squares.
4989 const Vec2d hpos[4] = { Vec2d(hu, 0), Vec2d(-hu, 0), Vec2d(0, hv), Vec2d(0, -hv) };
4990 GLModel::Geometry handles; handles.format = { EPT::Triangles, EVL::P3 };
4991 unsigned int hb = 0;
4992 for (int i = 0; i < 4; ++i) {
4993 const Vec3d ctr = p.to_world(hpos[i]);
4994 const Vec3d q0 = ctr - right * hs - up * hs, q1 = ctr + right * hs - up * hs,
4995 q2 = ctr + right * hs + up * hs, q3 = ctr - right * hs + up * hs;
4996 handles.add_vertex((Vec3f)q0.cast<float>()); handles.add_vertex((Vec3f)q1.cast<float>());
4997 handles.add_vertex((Vec3f)q2.cast<float>()); handles.add_vertex((Vec3f)q3.cast<float>());
4998 handles.add_triangle(hb, hb + 1, hb + 2); handles.add_triangle(hb, hb + 2, hb + 3); hb += 4;
4999 }
5000
5002 if (bb > 0) {
5003 GLModel m; m.init_from(std::move(border));
5004 m.set_color(ColorRGBA(1.0f, 0.62f, 0.16f, 0.9f)); // CAD amber
5005 m.render();
5006 }
5007 if (hb > 0) {
5008 GLModel m; m.init_from(std::move(handles));
5009 m.set_color(ColorRGBA(1.0f, 0.72f, 0.28f, 1.0f));
5010 m.render();
5011 }
5012
5013 // Offset arrow: a camera-facing ribbon from the base origin along the base normal to the
5014 // datum origin, with a grabbable square at the tip. Drag the tip to set the offset distance.
5015 if (m_dz_offset_on) {
5016 const Vec3d tip = m_dz_anchor + m_dz_normal * m_dz_offset;
5017 Vec3d off = m_dz_normal.cross(vd);
5018 if (off.norm() < 1e-9) off = m_dz_normal.cross(up);
5019 GLModel::Geometry shaft; shaft.format = { EPT::Triangles, EVL::P3 };
5020 if (off.norm() > 1e-9 && (tip - m_dz_anchor).norm() > 1e-9) {
5021 off.normalize(); off *= hw;
5022 shaft.add_vertex((Vec3f)(m_dz_anchor + off).cast<float>());
5023 shaft.add_vertex((Vec3f)(tip + off).cast<float>());
5024 shaft.add_vertex((Vec3f)(tip - off).cast<float>());
5025 shaft.add_vertex((Vec3f)(m_dz_anchor - off).cast<float>());
5026 shaft.add_triangle(0, 1, 2); shaft.add_triangle(0, 2, 3);
5027 GLModel sm; sm.init_from(std::move(shaft));
5028 sm.set_color(ColorRGBA(0.30f, 0.78f, 1.0f, 0.95f)); // cyan offset axis
5029 sm.render();
5030 }
5031 GLModel::Geometry tipsq; tipsq.format = { EPT::Triangles, EVL::P3 };
5032 const Vec3d t0 = tip - right * hs - up * hs, t1 = tip + right * hs - up * hs,
5033 t2 = tip + right * hs + up * hs, t3 = tip - right * hs + up * hs;
5034 tipsq.add_vertex((Vec3f)t0.cast<float>()); tipsq.add_vertex((Vec3f)t1.cast<float>());
5035 tipsq.add_vertex((Vec3f)t2.cast<float>()); tipsq.add_vertex((Vec3f)t3.cast<float>());
5036 tipsq.add_triangle(0, 1, 2); tipsq.add_triangle(0, 2, 3);
5037 GLModel tm; tm.init_from(std::move(tipsq));
5038 tm.set_color(ColorRGBA(0.45f, 0.86f, 1.0f, 1.0f));
5039 tm.render();
5040 }
5041}

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::cast(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::GLModel::init_from(), m_dz_active, m_dz_anchor, m_dz_normal, m_dz_offset, m_dz_offset_on, m_dz_plane, m_dz_usize, m_dz_vsize, Slic3r::GUI::GLModel::render(), render_datum_gizmo(), Slic3r::GUI::GLModel::set_color(), and Slic3r::SketchPlane::to_world().

Referenced by render(), and render_datum_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_datum_planes()

void Slic3r::GUI::DesignSketchTool::render_datum_planes ( )
private
4366{
4367 if (m_datum_planes.empty()) return;
4370 const double H = 40.0; // default half-extent when no per-plane size is given (mm)
4371 const Camera& cam = wxGetApp().plater()->get_camera();
4372 const Vec3d vd = cam.get_dir_forward();
4373 const double hw = 1.5 / std::max(cam.get_zoom(), 1e-6); // ~1.5 px border ribbon
4374
4375 GLModel::Geometry fill; fill.format = { EPT::Triangles, EVL::P3 };
4376 GLModel::Geometry border; border.format = { EPT::Triangles, EVL::P3 };
4377 unsigned int fb = 0, bb = 0;
4378 for (size_t pi = 0; pi < m_datum_planes.size(); ++pi) {
4379 const SketchPlane& p = m_datum_planes[pi];
4380 // Per-plane u/v half-extent (the GUI Size U/V + drag handles drive these); fall
4381 // back to the square default when no size was supplied.
4382 const double hu = (pi < m_datum_sizes.size() && m_datum_sizes[pi].x() > 1e-6)
4383 ? m_datum_sizes[pi].x() * 0.5 : H;
4384 const double hv = (pi < m_datum_sizes.size() && m_datum_sizes[pi].y() > 1e-6)
4385 ? m_datum_sizes[pi].y() * 0.5 : H;
4386 const Vec3d c[4] = { p.to_world(Vec2d(-hu, -hv)), p.to_world(Vec2d(hu, -hv)),
4387 p.to_world(Vec2d(hu, hv)), p.to_world(Vec2d(-hu, hv)) };
4388 fill.add_vertex((Vec3f)c[0].cast<float>()); fill.add_vertex((Vec3f)c[1].cast<float>());
4389 fill.add_vertex((Vec3f)c[2].cast<float>()); fill.add_triangle(fb, fb + 1, fb + 2); fb += 3;
4390 fill.add_vertex((Vec3f)c[0].cast<float>()); fill.add_vertex((Vec3f)c[2].cast<float>());
4391 fill.add_vertex((Vec3f)c[3].cast<float>()); fill.add_triangle(fb, fb + 1, fb + 2); fb += 3;
4392 for (int s = 0; s < 4; ++s) {
4393 const Vec3d a = c[s], b = c[(s + 1) & 3];
4394 Vec3d dir = b - a; if (dir.norm() < 1e-9) continue; dir.normalize();
4395 Vec3d off = dir.cross(vd);
4396 if (off.norm() < 1e-9) off = dir.cross(cam.get_dir_up());
4397 if (off.norm() < 1e-9) continue;
4398 off.normalize(); off *= hw;
4399 border.add_vertex((Vec3f)(a + off).cast<float>());
4400 border.add_vertex((Vec3f)(b + off).cast<float>());
4401 border.add_vertex((Vec3f)(b - off).cast<float>());
4402 border.add_vertex((Vec3f)(a - off).cast<float>());
4403 border.add_triangle(bb, bb + 1, bb + 2);
4404 border.add_triangle(bb, bb + 2, bb + 3); bb += 4;
4405 }
4406 }
4410 if (fb > 0) {
4411 GLModel fm; fm.init_from(std::move(fill));
4412 fm.set_color(ColorRGBA(0.62f, 0.52f, 0.95f, 0.10f));
4413 fm.render();
4414 }
4415 if (bb > 0) {
4416 GLModel bm; bm.init_from(std::move(border));
4417 bm.set_color(ColorRGBA(0.70f, 0.60f, 1.0f, 0.85f));
4418 bm.render();
4419 }
4421}
std::vector< Vec2d > m_datum_sizes
Definition DesignSketchTool.hpp:1368

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::cast(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_BLEND, GL_DEPTH_TEST, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, glBlendFunc, glDisable, glEnable, glsafe, Slic3r::GUI::GLModel::init_from(), m_datum_planes, m_datum_sizes, Slic3r::GUI::GLModel::render(), render_datum_planes(), Slic3r::GUI::GLModel::set_color(), and Slic3r::SketchPlane::to_world().

Referenced by render(), and render_datum_planes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_dimensions()

void Slic3r::GUI::DesignSketchTool::render_dimensions ( double unit_per_px)
private
8058{
8059 if (m_dimensions.empty()) return;
8060 const ColorRGBA dimcol(0.85f, 0.85f, 0.85f, 1.0f); // neutral leader (Measure parity)
8061 // Label text is a CONSTANT screen size (like real CAD), not scaled to geometry,
8062 // so a long line doesn't get huge text. ~15 px tall in plane units at this zoom.
8063 const double th = std::max(15.0 * unit_per_px, 1e-4);
8064 for (size_t di = 0; di < m_dimensions.size(); ++di) {
8065 Vec2d label;
8066 // A dimension whose driving constraint the solver rejected is drawn in the refusal
8067 // colour: its label is showing a value the geometry does not have, and this is the only
8068 // thing on screen that points at WHICH number is the lie.
8069 const bool bad = std::find(m_bad_dims.begin(), m_bad_dims.end(), int(di)) != m_bad_dims.end();
8070 const ColorRGBA col = bad ? ColorRGBA(0.92f, 0.35f, 0.35f, 1.0f) : dimcol;
8071 if (draw_dim_quote(m_dimensions[di], th, col, label))
8072 m_dimensions[di].label_pos = label;
8073 }
8074}
bool draw_dim_quote(const DimAnnot &a, double th, const ColorRGBA &col, Vec2d &out_label)
Definition DesignSketchTool.cpp:7965
std::vector< int > m_bad_dims
Definition DesignSketchTool.hpp:1238

References draw_dim_quote(), m_bad_dims, m_dimensions, and render_dimensions().

Referenced by render(), and render_dimensions().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_draft_gizmo()

void Slic3r::GUI::DesignSketchTool::render_draft_gizmo ( )
private
6735{
6736 if (!m_dr_active) return;
6737 const Camera& cam = wxGetApp().plater()->get_camera();
6738 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6739 const double th = std::max(15.0 * upp, 1e-4);
6740 const Vec3d yax = dr_yaxis(m_dr_axis, m_dr_ref);
6741
6742 const SketchPlane saved = m_plane;
6743 SketchPlane rp; rp.origin = m_dr_center; rp.x_axis = m_dr_ref; rp.y_axis = yax; rp.normal = m_dr_axis;
6744 m_plane = rp;
6745 const ColorRGBA arcc(0.15f, 0.92f, 1.0f, 1.0f);
6746 const double r = m_dr_radius;
6747 // Draft angle can be negative: sweep counter-clockwise (positive) or clockwise (negative)
6748 const double a = m_dr_angle * M_PI / 180.0;
6749 const int N = std::max(8, int(std::abs(a) / (M_PI / 32.0))); // ~ every 5.6°
6750
6751 std::vector<std::pair<Vec2d, Vec2d>> segs;
6752 Vec2d prev(r, 0.0);
6753 for (int i = 1; i <= N; ++i) {
6754 const double t = a * double(i) / double(N);
6755 const Vec2d cur(r * std::cos(t), r * std::sin(t));
6756 segs.emplace_back(prev, cur);
6757 prev = cur;
6758 }
6759 const Vec2d tip(r * std::cos(a), r * std::sin(a));
6760 segs.emplace_back(Vec2d(0, 0), Vec2d(r, 0)); // spoke at angle 0
6761 segs.emplace_back(Vec2d(0, 0), tip); // spoke at the swept angle (the handle)
6762 const Vec2d tang(-std::sin(a), std::cos(a));
6763 const Vec2d radial = tip.normalized();
6764 const double as = std::max(r * 0.14, th);
6765 segs.emplace_back(tip, tip - tang * as - radial * (as * 0.5));
6766 segs.emplace_back(tip, tip - tang * as + radial * (as * 0.5));
6767 const double hs = std::max(th * 0.8, r * 0.05);
6768 const Vec2d du = radial * hs, dv = Vec2d(-radial.y(), radial.x()) * hs;
6769 segs.emplace_back(tip + du, tip + dv);
6770 segs.emplace_back(tip + dv, tip - du);
6771 segs.emplace_back(tip - du, tip - dv);
6772 segs.emplace_back(tip - dv, tip + du);
6773
6775 draw_strokes(m_dr_stroke_model, segs, std::max(0.8 * upp, 1e-4), arcc);
6776 DimAnnot da; da.kind = DimType::Angle; da.value = m_dr_angle;
6777 draw_text(m_line_model, dim_text(da), tip * 1.14, th, arcc);
6778 m_plane = saved;
6779}
GLModel m_dr_stroke_model
Definition DesignSketchTool.hpp:1592

References Angle, dim_text(), Slic3r::GUI::dr_yaxis(), draw_strokes(), draw_text(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, m_dr_active, m_dr_angle, m_dr_axis, m_dr_center, m_dr_radius, m_dr_ref, m_dr_stroke_model, m_line_model, M_PI, m_plane, Slic3r::GUI::N, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, render_draft_gizmo(), Slic3r::GUI::DesignSketchTool::DimAnnot::value, Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_draft_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_extrude_gizmo()

void Slic3r::GUI::DesignSketchTool::render_extrude_gizmo ( )
private
4840{
4841 if (!m_ex_active) return;
4842 const Camera& cam = wxGetApp().plater()->get_camera();
4843 const Vec3d right = cam.get_dir_right().normalized();
4844 const Vec3d up = cam.get_dir_up().normalized();
4845 const Vec3d fwd = cam.get_dir_forward().normalized();
4846 const Vec3d base = m_ex_plane.to_world(m_ex_centroid);
4847 const Vec3d ndir = (m_ex_flip ? -1.0 : 1.0) * m_ex_plane.normal.normalized();
4848 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
4849 const double th = std::max(15.0 * upp, 1e-4);
4850
4851 // Express everything in the billboard frame (origin=base) so it always faces the camera.
4852 const SketchPlane saved = m_plane;
4853 SketchPlane bb; bb.origin = base; bb.x_axis = right; bb.y_axis = up; bb.normal = fwd;
4854 m_plane = bb;
4855 const ColorRGBA arrowc(1.0f, 0.62f, 0.16f, 1.0f); // CAD amber
4856
4857 auto draw_arrow = [&](double depth, bool flip_side) {
4858 if (depth <= 1e-6) return;
4859 const Vec3d dirw = (flip_side ? -1.0 : 1.0) * ndir; // world arrow direction
4860 const Vec3d tipw = base + dirw * depth;
4861 const Vec2d tip2((tipw - base).dot(right), (tipw - base).dot(up));
4862 if (tip2.norm() < 1e-6) return; // axis ~ parallel to view: no arrow
4863 const Vec2d u = tip2.normalized();
4864 const Vec2d nrm(-u.y(), u.x());
4865 std::vector<std::pair<Vec2d, Vec2d>> segs;
4866 segs.emplace_back(Vec2d(0, 0), tip2);
4867 const double as = std::max(tip2.norm() * 0.18, th * 0.9); // arrowhead size
4868 const Vec2d back = tip2 - u * as;
4869 segs.emplace_back(tip2, back + nrm * (as * 0.5));
4870 segs.emplace_back(tip2, back - nrm * (as * 0.5));
4871 draw_strokes(m_ex_arrow_model, segs, std::max(0.7 * upp, 1e-4), arrowc);
4872 DimAnnot a; a.kind = DimType::Distance; a.value = depth;
4873 draw_text(m_line_model, dim_text(a), tip2 + u * (th * 1.4), th, arrowc);
4874 };
4875
4877 draw_arrow(m_ex_depth, false);
4878 if (m_ex_two_sided) draw_arrow(m_ex_depth2, true);
4879 m_plane = saved;
4880}
GLModel m_ex_arrow_model
Definition DesignSketchTool.hpp:1398

References dim_text(), Distance, Slic3r::dot(), draw_strokes(), draw_text(), Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, m_ex_active, m_ex_arrow_model, m_ex_centroid, m_ex_depth, m_ex_depth2, m_ex_flip, m_ex_plane, m_ex_two_sided, m_line_model, m_plane, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, render_extrude_gizmo(), Slic3r::GUI::DesignSketchTool::DimAnnot::value, Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_extrude_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_face_outline()

void Slic3r::GUI::DesignSketchTool::render_face_outline ( const FaceHighlight & h,
bool quiet )
private
3853{
3854 if (m_body_edges_hidden || !is_current_shape(h.body, h.shape) || !body_pickable(h.body))
3855 return; // hidden, or the body was rebuilt and these face ids are stale
3856
3857 const Camera& cam = wxGetApp().plater()->get_camera();
3858 // View-facing ribbons like the body edges, pulled a pixel further toward the eye so they win
3859 // over the dark body edges along the same curves.
3860 const Vec3d vd = cam.get_dir_forward();
3861 const double px = 1.0 / std::max(cam.get_zoom(), 1e-6);
3862 const Vec3d pull = -vd * (4.0 * px);
3863 auto draw = [&](double hw_px, const ColorRGBA& colour) {
3864 GLModel::Geometry g;
3865 append_ribbons(g, h.body, h.edges, vd, pull, hw_px * px);
3866 render_ribbons(m_solid_edge_model, std::move(g), colour);
3867 };
3868 if (quiet) {
3869 draw(1.0, design_selection_color(0.8f));
3870 } else {
3871 draw(2.25, ColorRGBA(0.05f, 0.06f, 0.08f, 1.0f));
3873 }
3874}
GLModel m_solid_edge_model
Definition DesignSketchTool.hpp:1379
void draw(const IconManager::Icon &icon, const ImVec2 &size, const ImVec4 &tint_col, const ImVec4 &border_col)
Draw imgui image with icon.
Definition IconManager.cpp:373

References append_ribbons(), Slic3r::GUI::DesignSketchTool::FaceHighlight::body, body_pickable(), Slic3r::GUI::design_selection_color(), Slic3r::GUI::draw(), Slic3r::GUI::DesignSketchTool::FaceHighlight::edges, Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_zoom(), is_current_shape(), m_body_edges_hidden, m_solid_edge_model, Slic3r::pull, render_face_outline(), Slic3r::GUI::render_ribbons(), and Slic3r::GUI::DesignSketchTool::FaceHighlight::shape.

Referenced by render_face_outline(), and render_solid_highlight().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_fillet_gizmo()

void Slic3r::GUI::DesignSketchTool::render_fillet_gizmo ( )
private
6082{
6083 if (!m_fl_active) return;
6084 const Camera& cam = wxGetApp().plater()->get_camera();
6085 const Vec3d right = cam.get_dir_right().normalized();
6086 const Vec3d up = cam.get_dir_up().normalized();
6087 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6088 const double th = std::max(15.0 * upp, 1e-4);
6089 const double L = std::max(m_fl_radius, 40.0 * upp); // WYSIWYG, floored to a comfortable handle
6090 const Vec3d tipw = m_fl_anchor + m_fl_dir * L;
6091
6092 const SketchPlane saved = m_plane;
6093 SketchPlane bb; bb.origin = m_fl_anchor; bb.x_axis = right; bb.y_axis = up; bb.normal = cam.get_dir_forward().normalized();
6094 m_plane = bb;
6095 const ColorRGBA arrowc(1.0f, 0.62f, 0.16f, 1.0f); // CAD amber
6096
6097 const Vec2d tip2((tipw - m_fl_anchor).dot(right), (tipw - m_fl_anchor).dot(up));
6098 if (tip2.norm() > 1e-6) {
6099 const Vec2d u = tip2.normalized();
6100 const Vec2d nrm(-u.y(), u.x());
6101 std::vector<std::pair<Vec2d, Vec2d>> segs;
6102 segs.emplace_back(Vec2d(0, 0), tip2);
6103 const double as = std::max(tip2.norm() * 0.20, th * 0.9);
6104 const Vec2d back = tip2 - u * as;
6105 segs.emplace_back(tip2, back + nrm * (as * 0.5));
6106 segs.emplace_back(tip2, back - nrm * (as * 0.5));
6108 draw_strokes(m_fl_arrow_model, segs, std::max(0.7 * upp, 1e-4), arrowc);
6109 DimAnnot da; da.kind = DimType::Radius; da.value = m_fl_radius;
6110 draw_text(m_line_model, dim_text(da), tip2 + u * (th * 1.4), th, arrowc);
6111 }
6112 m_plane = saved;
6113}
GLModel m_fl_arrow_model
Definition DesignSketchTool.hpp:1497

References dim_text(), Slic3r::dot(), draw_strokes(), draw_text(), Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, L, m_fl_active, m_fl_anchor, m_fl_arrow_model, m_fl_dir, m_fl_radius, m_line_model, m_plane, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, Radius, render_fillet_gizmo(), Slic3r::GUI::DesignSketchTool::DimAnnot::value, Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_fillet_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_helix_gizmo()

void Slic3r::GUI::DesignSketchTool::render_helix_gizmo ( )
private
5145{
5146 if (!m_hx_active) return;
5149 const Camera& cam = wxGetApp().plater()->get_camera();
5150 const Vec3d right = cam.get_dir_right().normalized();
5151 const Vec3d up = cam.get_dir_up().normalized();
5152 const Vec3d vd = cam.get_dir_forward();
5153 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
5154 const double hs = 6.0 * upp; // handle half-size (~6 px)
5155 const double hw = 1.5 * upp; // ribbon half-width
5156 const Vec3d O = m_hx_plane.origin;
5157 const Vec3d n = m_hx_plane.normal.normalized();
5158 const double turns = m_hx_pitch > 1e-9 ? m_hx_height / m_hx_pitch : 0.0;
5159
5160 // Curve ribbon: connected thin camera-facing quads over t in [0, turns].
5161 const int segs = std::min(2048, std::max(48, int(turns * 32.0)));
5162 GLModel::Geometry curve; curve.format = { EPT::Triangles, EVL::P3 };
5163 unsigned int cb = 0;
5164 auto add_seg = [&](const Vec3d& a, const Vec3d& b) {
5165 Vec3d dir = b - a; if (dir.norm() < 1e-9) return; dir.normalize();
5166 Vec3d off = dir.cross(vd);
5167 if (off.norm() < 1e-9) off = dir.cross(up);
5168 if (off.norm() < 1e-9) return;
5169 off.normalize(); off *= hw;
5170 curve.add_vertex((Vec3f)(a + off).cast<float>()); curve.add_vertex((Vec3f)(b + off).cast<float>());
5171 curve.add_vertex((Vec3f)(b - off).cast<float>()); curve.add_vertex((Vec3f)(a - off).cast<float>());
5172 curve.add_triangle(cb, cb + 1, cb + 2); curve.add_triangle(cb, cb + 2, cb + 3); cb += 4;
5173 };
5174 for (int i = 0; i < segs; ++i)
5175 add_seg(helix_point(turns * i / segs), helix_point(turns * (i + 1) / segs));
5176
5177 // Axis: a dim line from the plane origin to the top of the helix.
5178 const Vec3d top = O + n * m_hx_height;
5179 GLModel::Geometry axis; axis.format = { EPT::Triangles, EVL::P3 };
5180 {
5181 Vec3d dir = top - O;
5182 if (dir.norm() > 1e-9) {
5183 dir.normalize();
5184 Vec3d off = dir.cross(vd);
5185 if (off.norm() < 1e-9) off = dir.cross(up);
5186 if (off.norm() > 1e-9) {
5187 off.normalize(); off *= hw * 0.6;
5188 axis.add_vertex((Vec3f)(O + off).cast<float>()); axis.add_vertex((Vec3f)(top + off).cast<float>());
5189 axis.add_vertex((Vec3f)(top - off).cast<float>()); axis.add_vertex((Vec3f)(O - off).cast<float>());
5190 axis.add_triangle(0, 1, 2); axis.add_triangle(0, 2, 3);
5191 }
5192 }
5193 }
5194
5195 // Three handles: 0=radius (t=0), 1=height (axis top), 2=pitch (end of first turn, or the
5196 // whole curve if shorter than one turn so the handle never floats off a missing curve).
5197 const Vec3d hpts[3] = { helix_point(0.0), top,
5198 helix_point(m_hx_height < m_hx_pitch ? turns : 1.0) };
5199 const ColorRGBA hcol[3] = { ColorRGBA(1.0f, 0.72f, 0.28f, 1.0f), // radius — amber
5200 ColorRGBA(0.45f, 0.86f, 1.0f, 1.0f), // height — cyan
5201 ColorRGBA(0.30f, 0.80f, 0.34f, 1.0f) }; // pitch — green
5202 const ColorRGBA hot(1.0f, 0.85f, 0.2f, 1.0f);
5203
5205 if (cb > 0) {
5206 GLModel m; m.init_from(std::move(curve));
5207 m.set_color(ColorRGBA(1.0f, 0.62f, 0.16f, 0.9f)); // CAD amber helix curve
5208 m.render();
5209 }
5210 if (!axis.vertices.empty()) {
5211 GLModel m; m.init_from(std::move(axis));
5212 m.set_color(ColorRGBA(0.42f, 0.46f, 0.52f, 0.55f)); // dim grey axis
5213 m.render();
5214 }
5215 for (int i = 0; i < 3; ++i) {
5216 const Vec3d ctr = hpts[i];
5217 const Vec3d q0 = ctr - right * hs - up * hs, q1 = ctr + right * hs - up * hs,
5218 q2 = ctr + right * hs + up * hs, q3 = ctr - right * hs + up * hs;
5219 GLModel::Geometry sq; sq.format = { EPT::Triangles, EVL::P3 };
5220 sq.add_vertex((Vec3f)q0.cast<float>()); sq.add_vertex((Vec3f)q1.cast<float>());
5221 sq.add_vertex((Vec3f)q2.cast<float>()); sq.add_vertex((Vec3f)q3.cast<float>());
5222 sq.add_triangle(0, 1, 2); sq.add_triangle(0, 2, 3);
5223 GLModel m; m.init_from(std::move(sq));
5224 m.set_color(m_hx_drag == i ? hot : hcol[i]);
5225 m.render();
5226 }
5227}

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::cast(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, helix_point(), Slic3r::GUI::GLModel::init_from(), m_hx_active, m_hx_drag, m_hx_height, m_hx_pitch, m_hx_plane, Slic3r::GUI::GLModel::render(), render_helix_gizmo(), Slic3r::GUI::GLModel::set_color(), and Slic3r::GUI::GLModel::Geometry::vertices.

Referenced by render(), and render_helix_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_hole_gizmo()

void Slic3r::GUI::DesignSketchTool::render_hole_gizmo ( )
private
6204{
6205 if (!m_hl_active) return;
6206 const Camera& cam = wxGetApp().plater()->get_camera();
6207 const Vec3d right = cam.get_dir_right().normalized();
6208 const Vec3d up = cam.get_dir_up().normalized();
6209 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6210 const double th = std::max(15.0 * upp, 1e-4);
6211
6212 const Vec3d centre = m_hl_plane.to_world(Vec2d(m_hl_x, m_hl_y));
6213 const Vec3d nrm = m_hl_plane.normal.normalized();
6214 const Vec3d ddir = m_hl_plane.x_axis.normalized(); // diameter arrow runs along plane u
6215 const double r = std::max(0.01, m_hl_diameter * 0.5);
6216
6217 const SketchPlane saved = m_plane;
6218
6219 // (1) Footprint circle drawn ON the plane (lifts plane u/v -> world through to_world).
6220 {
6222 std::vector<std::pair<Vec2d, Vec2d>> segs;
6223 const int N = 48;
6224 for (int i = 0; i < N; ++i) {
6225 const double a0 = (2.0 * M_PI * i) / N, a1 = (2.0 * M_PI * (i + 1)) / N;
6226 segs.emplace_back(Vec2d(m_hl_x + r * std::cos(a0), m_hl_y + r * std::sin(a0)),
6227 Vec2d(m_hl_x + r * std::cos(a1), m_hl_y + r * std::sin(a1)));
6228 }
6230 draw_strokes(m_hl_stroke_model, segs, std::max(0.6 * upp, 1e-4), ColorRGBA(1.0f, 0.62f, 0.16f, 1.0f));
6231 m_plane = saved;
6232 }
6233
6234 // (2) Billboarded handles (centre marker + diameter arrow + depth arrow), screen-facing frame
6235 // at the centre so draw_strokes/draw_text read on top regardless of orientation.
6236 SketchPlane bb; bb.origin = centre; bb.x_axis = right; bb.y_axis = up; bb.normal = cam.get_dir_forward().normalized();
6237 m_plane = bb;
6238 const ColorRGBA amber(1.0f, 0.62f, 0.16f, 1.0f);
6239 const ColorRGBA blue (0.30f, 0.55f, 1.0f, 1.0f);
6240
6241 auto arrow_to = [&](const Vec3d& tipw, const ColorRGBA& col, const DimAnnot& da) {
6242 const Vec2d tip2((tipw - centre).dot(right), (tipw - centre).dot(up));
6243 if (tip2.norm() <= 1e-6) return;
6244 const Vec2d u = tip2.normalized();
6245 const Vec2d nrm2(-u.y(), u.x());
6246 std::vector<std::pair<Vec2d, Vec2d>> segs;
6247 segs.emplace_back(Vec2d(0, 0), tip2);
6248 const double as = std::max(tip2.norm() * 0.20, th * 0.9);
6249 const Vec2d back = tip2 - u * as;
6250 segs.emplace_back(tip2, back + nrm2 * (as * 0.5));
6251 segs.emplace_back(tip2, back - nrm2 * (as * 0.5));
6253 draw_strokes(m_hl_stroke_model, segs, std::max(0.7 * upp, 1e-4), col);
6254 draw_text(m_line_model, dim_text(da), tip2 + u * (th * 1.4), th, col);
6255 };
6256
6257 // Diameter arrow: WYSIWYG radius, floored to a grabbable handle; label shows Ø (full diameter).
6258 {
6259 const double L = std::max(r, 40.0 * upp);
6260 DimAnnot da; da.kind = DimType::Diameter; da.value = m_hl_diameter;
6261 arrow_to(centre + ddir * L, amber, da);
6262 }
6263 // Depth arrow along +normal (blind cut). Through cuts ignore depth, so skip the arrow then.
6264 if (!m_hl_through) {
6265 const double L = std::max(m_hl_depth, 40.0 * upp);
6266 DimAnnot da; da.kind = DimType::Distance; da.value = m_hl_depth;
6267 arrow_to(centre + nrm * L, blue, da);
6268 }
6269
6270 m_plane = saved;
6271
6272 // Move handle: a small 3D CUBE at the hole centre (Orca text/SVG-on-face feel) — grab and drag
6273 // it to slide the hole across the face. Built from the plane axes so it sits flat on the face.
6274 {
6277 const double hs = 9.0 * upp; // cube half-size (~9 px); hit-test uses the same below
6278 const Vec3d U = ddir * hs, V = m_hl_plane.y_axis.normalized() * hs, Nn = nrm * hs;
6279 // Cube centred EXACTLY on the surface point (= the hole). Depth-test ON occludes the inner
6280 // half inside the solid, so the visible half-cube reads as planted at the hole — no depth-off
6281 // float that looked offset from the on-surface footprint. Hit-test targets the same `centre`.
6282 Vec3d c8[8];
6283 for (int i = 0; i < 8; ++i)
6284 c8[i] = centre + ((i & 1) ? U : -U) + ((i & 2) ? V : -V) + ((i & 4) ? Nn : -Nn);
6285 // 6 faces (CCW), each as 2 triangles, lightly shaded so the box reads as a cube.
6286 const int faces[6][4] = { {0,1,3,2},{4,6,7,5},{0,4,5,1},{2,3,7,6},{0,2,6,4},{1,5,7,3} };
6287 const float shade[6] = { 0.78f, 1.0f, 0.86f, 0.92f, 0.70f, 0.96f };
6290 for (int f = 0; f < 6; ++f) {
6291 GLModel::Geometry g; g.format = { EPT::Triangles, EVL::P3 };
6292 for (int k = 0; k < 4; ++k) g.add_vertex((Vec3f)c8[faces[f][k]].cast<float>());
6293 g.add_triangle(0, 1, 2); g.add_triangle(0, 2, 3);
6294 GLModel m; m.init_from(std::move(g));
6295 m.set_color(ColorRGBA(1.0f * shade[f], 0.62f * shade[f], 0.16f * shade[f], 1.0f));
6296 m.render();
6297 }
6298 }
6299}
GLModel m_hl_stroke_model
Definition DesignSketchTool.hpp:1526

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Diameter, dim_text(), Distance, Slic3r::dot(), draw_strokes(), draw_text(), Slic3r::f(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_CULL_FACE, GL_DEPTH_TEST, glDisable, glEnable, glsafe, Slic3r::GUI::GLModel::init_from(), Slic3r::GUI::DesignSketchTool::DimAnnot::kind, L, m_hl_active, m_hl_depth, m_hl_diameter, m_hl_plane, m_hl_stroke_model, m_hl_through, m_hl_x, m_hl_y, m_line_model, M_PI, m_plane, Slic3r::GUI::N, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, Slic3r::GUI::GLModel::render(), render_hole_gizmo(), Slic3r::GUI::GLModel::set_color(), Slic3r::GUI::DesignSketchTool::DimAnnot::value, Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_hole_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_live_quotes()

void Slic3r::GUI::DesignSketchTool::render_live_quotes ( double unit_per_px)
private
8082{
8083 m_live_quotes.clear();
8084 m_live_poly_fi = -1;
8086 m_live_arc_ei = -1;
8087 m_live_arc_angle_label = Vec2d(1e18, 1e18);
8088 m_live_ellipse_ei = -1;
8091 m_live_obrect_fi = -1;
8092 m_live_obrect_angle_label = Vec2d(1e18, 1e18);
8093 m_live_rrect_fi = -1;
8095 m_live_aslot_fi = -1;
8097 m_live_slot_fi = -1;
8099 // Edit-op tools (Fillet/Chamfer/Offset/Mirror) put their picks in m_selection for the
8100 // highlight, but their own arrow/label gizmo is the value affordance — don't also draw
8101 // the picked entity's characteristic quotes (Length/Angle/…) or the view gets cluttered.
8102 if (is_edit_op_mode() || is_transform_mode()) return;
8103 int ei = -1;
8104 if (m_dragging_point && m_drag_ei >= 0) ei = m_drag_ei;
8105 else if (m_dragging_handle) ei = m_drag_handle.ei;
8106 else if (m_selection.size() == 1) ei = m_selection[0];
8107 else if (!m_selection.empty()) {
8108 // A GROUPED FEATURE SELECTS EVERY MEMBER, so "exactly one entity" hid the characteristic
8109 // quotes for precisely the shapes that have nothing else. A rounded rectangle is eight
8110 // entities — four lines and four arcs — so picking it makes m_selection.size() == 8, this
8111 // pass returned here, and its Width / Height / Radius labels were never drawn. With no
8112 // label on screen there is nothing to click, which is the whole of "cannot edit labels in
8113 // rounded rectangles": not a value that refuses to change, a label that does not exist.
8114 //
8115 // A plain rectangle looked fine only by accident: typing into its auto-edit chain creates
8116 // a DRIVEN dimension, and render_dimensions draws that one from the annotation list. The
8117 // rounded rect's W/H/R go through set_rounded_rect, which rebuilds the geometry and leaves
8118 // no annotation behind — so the live label was the only affordance it ever had.
8119 //
8120 // Accept a selection that is entirely ONE feature and let any member speak for it; the
8121 // switch below already keys off feature_of(ei) rather than the entity itself.
8122 const int f0 = feature_of(m_selection.front());
8123 if (f0 >= 0) {
8124 bool same_feature = true;
8125 for (int s : m_selection)
8126 if (feature_of(s) != f0) { same_feature = false; break; }
8127 if (same_feature) ei = m_selection.front();
8128 }
8129 }
8130 if (ei < 0 || ei >= int(m_entities.size())) return;
8131 const SketchEntity& e = m_entities[ei];
8132
8133 std::vector<DimAnnot> protos;
8134 auto add_len = [&](int line_ei, double side) {
8135 if (line_ei < 0 || line_ei >= int(m_entities.size())) return;
8136 if (m_entities[line_ei].type != SketchEntity::Type::Line) return;
8137 DimAnnot a; a.kind = DimType::Length; a.ea = line_ei; a.side = side; protos.push_back(a);
8138 };
8139
8140 // A grouped gesture (rect/slot/polygon decomposes into raw lines/arcs) exposes its
8141 // DERIVED characteristic dims off the Feature span, regardless of which member edge
8142 // was picked. Rect: Width = first edge length, Height = second edge length (the two
8143 // axes of the 4-line loop pushed by push_closed_lines: edge0 horizontal, edge1
8144 // vertical). Quotes offset to opposite sides so they don't overlap.
8145 const int fi = feature_of(ei);
8146 if (fi >= 0) {
8147 const Feature& f = m_features[fi];
8148 switch (f.kind) {
8151 add_len(f.begin + 0, 1.0); // Width
8152 add_len(f.begin + 1, -1.0); // Height
8153 // OBLIQUE rect (drawn off-axis, also a CornerRect feature): expose its orientation
8154 // too. Gated to genuinely-tilted edges so an axis-aligned Corner/Center rect never
8155 // gets an angle quote (and its verified W/H behaviour is untouched).
8156 if (f.begin >= 0 && f.begin < int(m_entities.size())) {
8157 const SketchEntity& e0 = m_entities[f.begin];
8158 Vec2d d0 = e0.p1 - e0.p0;
8159 if (d0.squaredNorm() > 1e-12) {
8160 double deg = std::atan2(d0.y(), d0.x()) * 180.0 / M_PI;
8161 const double off = std::fmod(std::fmod(deg, 90.0) + 90.0, 90.0); // dist to axis
8162 if (off > 2.0 && off < 88.0) {
8163 const ColorRGBA dc(0.30f, 0.88f, 0.66f, 1.0f);
8164 const double th = std::max(15.0 * unit_per_px, 1e-4);
8165 double adeg = deg; if (adeg < 0.0) adeg += 360.0;
8166 const Vec2d mid = 0.5 * (e0.p0 + e0.p1);
8167 Vec2d nrm(-d0.y(), d0.x()); if (nrm.squaredNorm() > 1e-12) nrm.normalize();
8168 m_live_obrect_angle_label = mid + nrm * (th * 1.4);
8169 DimAnnot at; at.kind = DimType::Angle; at.value = adeg;
8171 m_live_obrect_fi = fi;
8172 }
8173 }
8174 }
8175 break;
8176 }
8177 case FeatureKind::Slot: {
8178 // Straight slot edits GEOMETRICALLY (like the arc-slot / rounded-rect), NOT through
8179 // the constraint-based scalar quotes. Its dims are the centreline LENGTH (distance
8180 // between the two cap centres c0,c1) and the WIDTH (2*param). The old
8181 // Distance-between-arc-centres + Radius quotes never registered as editable, so the
8182 // labels did nothing on click (nde #6). Draw both labels clear of the fillable face
8183 // and remember the feature so open_primary_autoedit / click-to-promote drive set_slot.
8184 // Slot dims: (1) inter-centre distance, (2) full width, (3) centreline angle.
8185 const ColorRGBA dc(0.30f, 0.88f, 0.66f, 1.0f);
8186 const double th = std::max(15.0 * unit_per_px, 1e-4);
8187 Vec2d u = f.c1 - f.c0;
8188 const double Lc = u.norm();
8189 if (Lc > 1e-9) {
8190 u /= Lc;
8191 const Vec2d n(-u.y(), u.x());
8192 const double w = f.param;
8193 DimAnnot len; len.kind = DimType::Length; len.value = Lc;
8194 m_live_slot_len_label = 0.5 * (f.c0 + f.c1) + n * (w + th * 2.0);
8196 DimAnnot rd; rd.kind = DimType::Length; rd.value = 2.0 * w; // full width, as the arc slot
8197 m_live_slot_w_label = f.c1 + u * (w + th * 2.0);
8199 double deg = std::atan2(f.c1.y() - f.c0.y(), f.c1.x() - f.c0.x()) * 180.0 / M_PI;
8200 if (deg < 0.0) deg += 360.0;
8201 DimAnnot an; an.kind = DimType::Angle; an.value = deg;
8202 m_live_slot_angle_label = f.c0 - u * (w + th * 2.0);
8204 m_live_slot_fi = fi;
8205 }
8206 break;
8207 }
8208 case FeatureKind::Polygon: {
8209 // A regular polygon is N raw lines (no centre entity). Its natural editable
8210 // dims are the SIDE length and the ORIENTATION — NOT a circumradius (a polygon
8211 // is not a circle). Both edit the whole loop geometrically: side scales it
8212 // uniformly, angle rotates it. Drawn off edge0 with draw_dim_quote (Length +
8213 // Angle); the side quote is offset OUTWARD so its label clears the face.
8214 if (f.begin < int(m_entities.size()) &&
8215 m_entities[f.begin].type == SketchEntity::Type::Line) {
8216 const ColorRGBA dc(0.30f, 0.88f, 0.66f, 1.0f);
8217 const double th = std::max(15.0 * unit_per_px, 1e-4);
8218 const SketchEntity& e0 = m_entities[f.begin];
8219 const Vec2d m0 = 0.5 * (e0.p0 + e0.p1);
8220 Vec2d u0 = e0.p1 - e0.p0;
8221 if (u0.squaredNorm() > 1e-12) u0.normalize();
8222 const Vec2d n0(-u0.y(), u0.x());
8223 const double outsign = ((m0 + n0) - f.c0).norm() >= (m0 - f.c0).norm() ? 1.0 : -1.0;
8224 DimAnnot side; side.kind = DimType::Length; side.ea = f.begin; side.side = outsign;
8225 side.value = measure_dim(side);
8226 Vec2d slbl;
8227 if (draw_dim_quote(side, th, dc, slbl)) m_live_poly_side_label = slbl;
8228
8229 // Orientation = the angle of the centre->vertex0 spoke from +X (the
8230 // intuitive "which way does the polygon point"), NOT the edge direction.
8231 // Drawn as a wedge OUTSIDE the polygon (radius just past the circumradius)
8232 // so its arc/label clear the fillable face.
8233 const Vec2d sp = m_entities[f.begin].p0 - f.c0; // centre -> vertex0
8234 const double R = sp.norm();
8235 if (R > 1e-6) {
8236 double av = std::atan2(sp.y(), sp.x());
8237 double avdeg = av * 180.0 / M_PI; if (avdeg < 0.0) avdeg += 360.0;
8238 const double rr = R + th * 2.5; // wedge just outside the loop
8239 std::vector<std::pair<Vec2d, Vec2d>> asegs;
8240 asegs.emplace_back(f.c0, f.c0 + Vec2d(rr, 0.0)); // +X leg
8241 asegs.emplace_back(f.c0, f.c0 + Vec2d(std::cos(av), std::sin(av)) * rr); // spoke leg
8242 const int N = 20; Vec2d prev = f.c0 + Vec2d(rr, 0.0);
8243 for (int i = 1; i <= N; ++i) {
8244 const double t = av * double(i) / N;
8245 const Vec2d cur = f.c0 + Vec2d(rr * std::cos(t), rr * std::sin(t));
8246 asegs.emplace_back(prev, cur); prev = cur;
8247 }
8248 const double mid = av * 0.5;
8249 const Vec2d albl = f.c0 + Vec2d(std::cos(mid), std::sin(mid)) * (rr + th * 1.2);
8250 DimAnnot at; at.kind = DimType::Angle; at.value = avdeg; // "NN.N°"
8251 draw_strokes(m_highlight_model, asegs, 0.6, dc);
8252 draw_text(m_line_model, dim_text(at), albl, th, dc);
8254 }
8255 m_live_poly_fi = fi;
8256 }
8257 break;
8258 }
8260 // Width + Height (box bounds) + fillet Radius, drawn as clickable quotes that
8261 // rebuild the box geometrically (set_rounded_rect). c0=min corner, c1=max, param=r.
8262 const ColorRGBA dc(0.30f, 0.88f, 0.66f, 1.0f);
8263 const double th = std::max(15.0 * unit_per_px, 1e-4);
8264 const double xmin = std::min(f.c0.x(), f.c1.x()), xmax = std::max(f.c0.x(), f.c1.x());
8265 const double ymin = std::min(f.c0.y(), f.c1.y()), ymax = std::max(f.c0.y(), f.c1.y());
8266 const double w = xmax - xmin, h = ymax - ymin, r = f.param;
8267 const double off = th * 2.0;
8268 std::vector<std::pair<Vec2d, Vec2d>> segs;
8269 // Width quote below the box.
8270 const double yb = ymin - off;
8271 segs.emplace_back(Vec2d(xmin, ymin), Vec2d(xmin, yb));
8272 segs.emplace_back(Vec2d(xmax, ymin), Vec2d(xmax, yb));
8273 segs.emplace_back(Vec2d(xmin, yb), Vec2d(xmax, yb));
8274 // Height quote left of the box.
8275 const double xl = xmin - off;
8276 segs.emplace_back(Vec2d(xmin, ymin), Vec2d(xl, ymin));
8277 segs.emplace_back(Vec2d(xmin, ymax), Vec2d(xl, ymax));
8278 segs.emplace_back(Vec2d(xl, ymin), Vec2d(xl, ymax));
8279 // Fillet-radius leader from the TR arc centre out to the corner.
8280 const Vec2d rc(xmax - r, ymax - r);
8281 segs.emplace_back(rc, rc + Vec2d(r, r).normalized() * r);
8282 draw_strokes(m_highlight_model, segs, 0.6, dc);
8283 DimAnnot wa; wa.kind = DimType::Length; wa.value = w;
8284 DimAnnot ha; ha.kind = DimType::Length; ha.value = h;
8285 DimAnnot ra; ra.kind = DimType::Radius; ra.value = r;
8286 m_live_rrect_w_label = Vec2d((xmin + xmax) * 0.5, yb - th * 0.8);
8287 m_live_rrect_h_label = Vec2d(xl - th * 0.8, (ymin + ymax) * 0.5);
8288 m_live_rrect_r_label = rc + Vec2d(r, r).normalized() * (r + th * 1.2);
8292 m_live_rrect_fi = fi;
8293 break;
8294 }
8295 case FeatureKind::ArcSlot: {
8296 // Centreline Radius + slot Width quotes. centre=f.c0, centreline start=f.c1,
8297 // half-width=f.param; end direction from the cap@E arc centre (begin+1).
8298 if (f.begin + 1 < int(m_entities.size())) {
8299 const ColorRGBA dc(0.30f, 0.88f, 0.66f, 1.0f);
8300 const double th = std::max(15.0 * unit_per_px, 1e-4);
8301 const Vec2d center = f.c0;
8302 const double Rc = (f.c1 - center).norm();
8303 const double w = f.param;
8304 Vec2d dirS = (f.c1 - center);
8305 Vec2d dirE = (m_entities[f.begin + 1].center - center);
8306 if (dirS.squaredNorm() > 1e-12 && dirE.squaredNorm() > 1e-12 && Rc > 1e-6) {
8307 dirS.normalize(); dirE.normalize();
8308 const double aS = std::atan2(dirS.y(), dirS.x());
8309 double sweep = std::atan2(dirE.y(), dirE.x()) - aS;
8310 while (sweep < 0) sweep += 2.0 * M_PI;
8311 const double aMid = aS + sweep * 0.5;
8312 const Vec2d uMid(std::cos(aMid), std::sin(aMid));
8313 // Centreline-radius leader: centre -> centreline midpoint.
8314 std::vector<std::pair<Vec2d, Vec2d>> segs;
8315 segs.emplace_back(center, center + uMid * Rc);
8316 // Width tick across the slot at the start cap (outer<->inner).
8317 segs.emplace_back(center + dirS * (Rc + w), center + dirS * (Rc - w));
8318 draw_strokes(m_highlight_model, segs, 0.6, dc);
8319 DimAnnot ra; ra.kind = DimType::Radius; ra.value = Rc;
8320 DimAnnot wa; wa.kind = DimType::Length; wa.value = 2.0 * w;
8321 m_live_aslot_r_label = center + uMid * (Rc * 0.5) + Vec2d(0, th);
8322 m_live_aslot_w_label = center + dirS * (Rc + w) + dirS * (th * 1.2);
8325 m_live_aslot_fi = fi;
8326 }
8327 }
8328 break;
8329 }
8330 default: break; // other features: later chunks
8331 }
8332 }
8333
8334 if (protos.empty() && m_live_poly_fi < 0 && m_live_rrect_fi < 0 &&
8335 m_live_aslot_fi < 0 && m_live_slot_fi < 0) { // ungrouped single entity
8336 switch (e.type) {
8338 DimAnnot len; len.kind = DimType::Length; len.ea = ei; len.side = 1.0; protos.push_back(len);
8339 DimAnnot ang; ang.kind = DimType::Angle; ang.ea = ei; ang.eb = -1; protos.push_back(ang);
8340 break; // segment length + angle-to-horizontal
8341 }
8343 DimAnnot a; a.kind = DimType::Radius; a.ea = ei; protos.push_back(a); break;
8344 }
8346 // Arc radius is its single defining dimension (sweep angles edit via the end
8347 // handles). radius lives in the same .radius field measure_dim/constraint_for
8348 // read, so the Radius promotion path is identical to Circle.
8349 DimAnnot a; a.kind = DimType::Radius; a.ea = ei; protos.push_back(a); break;
8350 }
8351 default: break; // ellipse/bspline: later
8352 }
8353 }
8354
8355 // Arc sweep-angle wedge: drawn inline (like the polygon orientation) because it is a
8356 // GEOMETRIC edit (SLVS angle constraints are line-to-line). A wedge spans the arc's
8357 // start->end angles just OUTSIDE the radius; its label shows the included angle and is
8358 // clickable to type a new sweep. The radius quote is still emitted via `protos`.
8359 if (m_live_poly_fi < 0 && m_live_rrect_fi < 0 && m_live_aslot_fi < 0 && m_live_slot_fi < 0 &&
8360 e.type == SketchEntity::Type::Arc && e.radius > 1e-6) {
8361 const ColorRGBA dc(0.30f, 0.88f, 0.66f, 1.0f);
8362 const double th = std::max(15.0 * unit_per_px, 1e-4);
8363 const Vec2d c = e.center;
8364 const double a0 = e.start_angle, a1 = e.end_angle;
8365 const double sweep = a1 - a0; // signed (CCW>0); |sweep| shown
8366 double swdeg = std::abs(sweep) * 180.0 / M_PI;
8367 const double rr = e.radius + th * 2.5; // wedge just outside the arc
8368 std::vector<std::pair<Vec2d, Vec2d>> asegs;
8369 asegs.emplace_back(c, c + Vec2d(std::cos(a0), std::sin(a0)) * rr); // start leg
8370 asegs.emplace_back(c, c + Vec2d(std::cos(a1), std::sin(a1)) * rr); // end leg
8371 const int N = 24; Vec2d prev = c + Vec2d(std::cos(a0), std::sin(a0)) * rr;
8372 for (int i = 1; i <= N; ++i) {
8373 const double t = a0 + sweep * double(i) / N;
8374 const Vec2d cur = c + Vec2d(rr * std::cos(t), rr * std::sin(t));
8375 asegs.emplace_back(prev, cur); prev = cur;
8376 }
8377 const double mid = a0 + sweep * 0.5;
8378 const Vec2d albl = c + Vec2d(std::cos(mid), std::sin(mid)) * (rr + th * 1.2);
8379 DimAnnot at; at.kind = DimType::Angle; at.value = swdeg; // "NN.N°"
8380 draw_strokes(m_highlight_model, asegs, 0.6, dc);
8381 draw_text(m_line_model, dim_text(at), albl, th, dc);
8383 m_live_arc_ei = ei;
8384 }
8385
8386 // Ellipse: two clickable axis quotes — semi-major (a) along the major direction and
8387 // semi-minor (b) along the minor. Both edit geometrically (a=e.radius, b=e.rminor);
8388 // phi (orientation) is changed by dragging the major grip, not via a label.
8389 if (m_live_poly_fi < 0 && m_live_rrect_fi < 0 &&
8391 e.radius > 1e-6 && e.rminor > 1e-6) {
8392 const ColorRGBA dc(0.30f, 0.88f, 0.66f, 1.0f);
8393 const double th = std::max(15.0 * unit_per_px, 1e-4);
8394 const Vec2d c = e.center;
8395 const Vec2d um(std::cos(e.rotation), std::sin(e.rotation)); // major dir
8396 const Vec2d un(-um.y(), um.x()); // minor dir
8397 std::vector<std::pair<Vec2d, Vec2d>> segs;
8398 const Vec2d majEnd = c + um * e.radius, minEnd = c + un * e.rminor;
8399 segs.emplace_back(c, majEnd);
8400 segs.emplace_back(c, minEnd);
8401 draw_strokes(m_highlight_model, segs, 0.6, dc);
8402 DimAnnot ma; ma.kind = DimType::Length; ma.value = e.radius; // plain "NN.N"
8403 DimAnnot mi; mi.kind = DimType::Length; mi.value = e.rminor;
8404 const Vec2d majLbl = c + um * (e.radius * 0.5) + un * (th * 1.0);
8405 const Vec2d minLbl = c + un * (e.rminor * 0.5) + um * (th * 1.0);
8406 draw_text(m_line_model, dim_text(ma), majLbl, th, dc);
8407 draw_text(m_line_model, dim_text(mi), minLbl, th, dc);
8410 m_live_ellipse_ei = ei;
8411 // Elliptical arc also has a SWEEP (included parametric angle), drawn outside the arc
8412 // midpoint; the full ellipse skips this (closed).
8413 if (e.type == SketchEntity::Type::EllipseArc) {
8414 const double midp = 0.5 * (e.start_angle + e.end_angle);
8415 const Vec2d mp = ellipse_point(c, e.radius, e.rminor, e.rotation, midp);
8416 Vec2d outw = mp - c; if (outw.squaredNorm() > 1e-12) outw.normalize();
8417 m_live_ellipsearc_sweep_label = mp + outw * (th * 1.5);
8418 DimAnnot sw; sw.kind = DimType::Angle;
8419 sw.value = std::abs(e.end_angle - e.start_angle) * 180.0 / M_PI;
8421 }
8422 }
8423
8424 if (protos.empty()) return;
8425
8426 const ColorRGBA dimcol(0.30f, 0.88f, 0.66f, 1.0f);
8427 const double th = std::max(15.0 * unit_per_px, 1e-4);
8428 for (DimAnnot a : protos) {
8429 bool driven = false; // skip if already a driving dim of this kind
8430 for (const DimAnnot& d : m_dimensions)
8431 if (d.ea == a.ea && d.kind == a.kind) { driven = true; break; }
8432 if (driven) continue;
8433 a.value = measure_dim(a);
8434 Vec2d label;
8435 if (draw_dim_quote(a, th, dimcol, label)) {
8436 a.label_pos = label;
8437 m_live_quotes.push_back(a); // remember for click-to-promote
8438 }
8439 }
8440}

References Angle, Slic3r::SketchEntity::Arc, ArcSlot, Slic3r::center(), Slic3r::SketchEntity::center, CenterRect, Slic3r::SketchEntity::Circle, CornerRect, dim_text(), draw_dim_quote(), draw_strokes(), draw_text(), Slic3r::GUI::DesignSketchTool::DimAnnot::ea, Slic3r::GUI::DesignSketchTool::DimAnnot::eb, Slic3r::SketchEntity::Ellipse, Slic3r::GUI::ellipse_point(), Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::end_angle, Slic3r::f(), feature_of(), is_edit_op_mode(), is_transform_mode(), Slic3r::GUI::DesignSketchTool::DimAnnot::kind, Length, Slic3r::SketchEntity::Line, m_dimensions, m_drag_ei, m_drag_handle, m_dragging_handle, m_dragging_point, m_entities, m_features, m_highlight_model, m_line_model, m_live_arc_angle_label, m_live_arc_ei, m_live_aslot_fi, m_live_aslot_r_label, m_live_aslot_w_label, m_live_ellipse_ei, m_live_ellipse_major_label, m_live_ellipse_minor_label, m_live_ellipsearc_sweep_label, m_live_obrect_angle_label, m_live_obrect_fi, m_live_poly_angle_label, m_live_poly_fi, m_live_poly_side_label, m_live_quotes, m_live_rrect_fi, m_live_rrect_h_label, m_live_rrect_r_label, m_live_rrect_w_label, m_live_slot_angle_label, m_live_slot_fi, m_live_slot_len_label, m_live_slot_w_label, M_PI, m_selection, measure_dim(), Slic3r::GUI::N, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Polygon, Radius, Slic3r::SketchEntity::radius, render_live_quotes(), Slic3r::SketchEntity::rminor, Slic3r::SketchEntity::rotation, RoundedRect, Slic3r::GUI::DesignSketchTool::DimAnnot::side, Slot, Slic3r::SketchEntity::start_angle, Slic3r::SketchEntity::type, and Slic3r::GUI::DesignSketchTool::DimAnnot::value.

Referenced by render(), and render_live_quotes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_mate_connectors()

void Slic3r::GUI::DesignSketchTool::render_mate_connectors ( )
private
4461{
4462 if (m_mate_connectors.empty()) return;
4463 static const bool style_A = [] {
4464 const char* s = ::getenv("ORCA_CAD_GLYPH");
4465 return s && (*s == 'A' || *s == 'a');
4466 }();
4467 // The face treatment, on by default. Read every frame rather than latched in a static, so
4468 // toggling the preference takes effect on the next repaint instead of at the next launch —
4469 // it is a look, and a look you cannot A/B without restarting will not get compared.
4470 // ORCA_CAD_GLYPH=D forces the disc regardless, which is how the rig drives the other branch.
4471 const bool face_style = !style_A
4472 && wxGetApp().app_config->get_bool("design_connector_face_glyph")
4473 && [] { const char* s = ::getenv("ORCA_CAD_GLYPH");
4474 return !(s && (*s == 'D' || *s == 'd')); }();
4475
4476 const Camera& cam = wxGetApp().plater()->get_camera();
4477 const Vec3d right = cam.get_dir_right().normalized();
4478 const Vec3d up = cam.get_dir_up().normalized();
4479 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
4480 const double R = 22.0 * upp; // disc radius, ~22 px
4481 const double lw = std::max(0.9 * upp, 1e-4);
4482
4483 const ColorRGBA gold (0.93f, 0.66f, 0.09f, 1.0f);
4484 const ColorRGBA blue (0.18f, 0.44f, 0.93f, 1.0f);
4485 const ColorRGBA grey (0.42f, 0.46f, 0.52f, 1.0f);
4486 // F5: roll-undefined was a loud red — the strongest colour in the viewport spent on the LEAST
4487 // important connector, which pulled the eye away from the mate being made. It is a "this one
4488 // could not be derived" mark, not an error: muted amber says look-here without shouting.
4489 const ColorRGBA warn (0.72f, 0.55f, 0.22f, 1.0f);
4490
4491 const SketchPlane saved = m_plane;
4492
4493 for (const MateConnectorGlyph& g : m_mate_connectors) {
4494 const Vec3d X = g.x.normalized();
4495 const Vec3d Y = g.y.normalized();
4496 const Vec3d Z = X.cross(Y).normalized();
4497 const ColorRGBA body = (g.role == 2) ? blue : grey;
4498
4499 // ---- disc + quadrant, drawn IN the connector's own plane. This is the part that must not
4500 // be billboarded: a disc that always faces the camera cannot show the frame's orientation,
4501 // which is the only reason it is a disc and not a dot.
4502 // Lifted off the surface by a sub-pixel epsilon. A connector's disc is EXACTLY coplanar with
4503 // the face it sits on, so depth-testing it z-fights: on the rig the disc came out as a broken
4504 // dotted arc that flickered with the camera. Depth off floats it through solids, depth on and
4505 // coplanar tears it — the lift is what buys both. Scaled by upp so it stays sub-pixel at any
4506 // zoom instead of becoming a visible gap when you zoom in.
4507 // A face asserts a definite roll. When the roll could NOT be derived, drawing one would be
4508 // a confident lie about the very thing that is unknown — the same objection that rejected
4509 // billboarding the quadrant — so an underived connector keeps the disc treatment and its
4510 // hatched quadrant, whatever the preference says.
4511 if (face_style && !g.roll_undefined) {
4512 render_mate_face(g.origin, X, Y, Z, R, body);
4513 } else {
4514
4515 SketchPlane cp; cp.origin = g.origin + Z * (0.7 * upp);
4516 cp.x_axis = X; cp.y_axis = Y; cp.normal = Z;
4517 m_plane = cp;
4518 {
4519 std::vector<std::pair<Vec2d, Vec2d>> segs;
4520 const int N = 40;
4521 for (int i = 0; i < N; ++i) {
4522 const double a0 = (2.0 * M_PI * i) / N, a1 = (2.0 * M_PI * (i + 1)) / N;
4523 segs.emplace_back(Vec2d(R * std::cos(a0), R * std::sin(a0)),
4524 Vec2d(R * std::cos(a1), R * std::sin(a1)));
4525 }
4526 // Depth test ON for the disc, deliberately. With it off, a connector on a face pointing
4527 // AWAY from the camera still drew its disc over the solid, so the part looked covered in
4528 // frames that were really on its back — and a disc floating over an edge read as
4529 // detached rather than planted. render_hole_gizmo learned the same thing for its cube.
4531 draw_strokes(m_mc_stroke_model, segs, lw, g.roll_undefined ? warn : body);
4532
4533 // The quadrant: hatched when the roll could not be derived (a full circular face or a
4534 // seam offers no in-plane direction), so the fallback is a mark you cannot miss rather
4535 // than a silent guess.
4536 std::vector<std::pair<Vec2d, Vec2d>> q;
4537 const double qr = R * 0.84;
4538 const int QN = 10;
4539 for (int i = 0; i < QN; ++i) {
4540 const double a0 = (M_PI_2 * i) / QN, a1 = (M_PI_2 * (i + 1)) / QN;
4541 q.emplace_back(Vec2d(qr * std::cos(a0), qr * std::sin(a0)),
4542 Vec2d(qr * std::cos(a1), qr * std::sin(a1)));
4543 }
4544 q.emplace_back(Vec2d(0, 0), Vec2d(qr, 0));
4545 q.emplace_back(Vec2d(0, 0), Vec2d(0, qr));
4546 if (!g.roll_undefined) {
4547 for (int i = 1; i < 5; ++i) { // fan lines read as "filled" at any angle
4548 const double a = (M_PI_2 * i) / 5.0;
4549 q.emplace_back(Vec2d(0, 0), Vec2d(qr * std::cos(a), qr * std::sin(a)));
4550 }
4551 // F4: the quadrant collapses to a blob at grazing angles — exactly when the roll
4552 // is hardest to read. A radial tick along +X, extending PAST the disc rim, is what
4553 // survives that: as the disc flattens to a line the sector loses all area, but a
4554 // radial spoke keeps its length and its direction along the one axis that still
4555 // projects.
4556 //
4557 // The alternative on the issue was billboarding the quadrant. Rejected, and not
4558 // on taste: at true grazing the view direction lies IN the connector's plane, so
4559 // every in-plane direction projects onto the same screen line and the roll is
4560 // geometrically unrecoverable. A billboarded quadrant would not recover it — it
4561 // would face the camera and read as a definite orientation that is not the frame's.
4562 // Better to degrade to a direction you can still trust than to draw a confident
4563 // lie. Judge the tick on the rig at a true grazing view before calling F4 closed.
4564 q.emplace_back(Vec2d(R, 0), Vec2d(R * 1.28, 0));
4565 }
4566 draw_strokes(m_mc_stroke_model, q, lw, g.roll_undefined ? warn : gold);
4567 }
4568 } // end of the disc treatment
4569
4570 // ---- the axes. Billboarded at the origin: a 3D direction is projected onto the screen
4571 // frame, which is the only way an arrow keeps a readable head at any viewing angle.
4572 SketchPlane bb; bb.origin = g.origin; bb.x_axis = right; bb.y_axis = up;
4573 bb.normal = cam.get_dir_forward().normalized();
4574 m_plane = bb;
4575
4576 auto arrow = [&](const Vec3d& dir, double len, const ColorRGBA& col, bool filled_head) {
4577 const Vec3d tipw = g.origin + dir * len;
4578 const Vec2d tip2((tipw - g.origin).dot(right), (tipw - g.origin).dot(up));
4579 std::vector<std::pair<Vec2d, Vec2d>> segs;
4580 // Foreshortening: when the axis points at (or away from) the camera it projects to
4581 // nothing and an arrow degenerates into a dot. Draw a ring instead — "pointing at you"
4582 // — rather than silently vanishing, which is what a naive projection does.
4583 if (tip2.norm() < R * 0.28) {
4584 const int N = 24;
4585 const double rr = R * 0.30;
4586 for (int i = 0; i < N; ++i) {
4587 const double a0 = (2.0 * M_PI * i) / N, a1 = (2.0 * M_PI * (i + 1)) / N;
4588 segs.emplace_back(Vec2d(rr * std::cos(a0), rr * std::sin(a0)),
4589 Vec2d(rr * std::cos(a1), rr * std::sin(a1)));
4590 }
4591 draw_strokes(m_mc_stroke_model, segs, lw, col);
4592 return;
4593 }
4594 const Vec2d u = tip2.normalized();
4595 const Vec2d n(-u.y(), u.x());
4596 const double as = R * 0.42;
4597 const Vec2d back = tip2 - u * as;
4598 segs.emplace_back(Vec2d(0, 0), back);
4599 segs.emplace_back(tip2, back + n * (as * 0.45));
4600 segs.emplace_back(tip2, back - n * (as * 0.45));
4601 if (filled_head) {
4602 // A closed head reads solid; the open one is left as two barbs. At 20-odd pixels
4603 // this is the difference that says "this body travels".
4604 segs.emplace_back(back + n * (as * 0.45), back - n * (as * 0.45));
4605 segs.emplace_back(back + n * (as * 0.22), tip2);
4606 segs.emplace_back(back - n * (as * 0.22), tip2);
4607 } else {
4608 segs.emplace_back(back + n * (as * 0.45), back - n * (as * 0.45));
4609 }
4611 draw_strokes(m_mc_stroke_model, segs, lw, col);
4612 };
4613
4614 if (style_A) {
4615 arrow(X, R * 1.15, ColorRGBA(0.85f, 0.29f, 0.24f, 1.0f), true);
4616 arrow(Y, R * 1.15, ColorRGBA(0.23f, 0.65f, 0.35f, 1.0f), true);
4617 arrow(Z, R * 1.60, blue, true);
4618 } else {
4619 arrow(Z, R * 2.10, body, g.role == 2); // +Z only. Nothing is ever drawn on -Z.
4620 }
4621 }
4622
4623 // ---- the pair line. Dashed, drawn IN WORLD along the segment joining the two origins, so it
4624 // foreshortens with the model and its length is the gap the mate has still to close. Screen-
4625 // constant dashes like everything else here; the dash pitch opens up on a long span so a mate
4626 // across a large assembly cannot emit thousands of segments.
4627 for (const auto& lnk : m_mate_links) {
4628 const Vec3d d = lnk.second - lnk.first;
4629 const double L = d.norm();
4630 if (L < 1e-9) continue;
4631 SketchPlane lp;
4632 lp.origin = lnk.first;
4633 lp.x_axis = d / L;
4634 lp.y_axis = lp.x_axis.cross(cam.get_dir_forward().normalized());
4635 if (lp.y_axis.norm() < 1e-6) lp.y_axis = lp.x_axis.cross(up); // link along the view axis
4636 lp.y_axis.normalize();
4637 lp.normal = lp.x_axis.cross(lp.y_axis);
4638 m_plane = lp;
4639
4640 std::vector<std::pair<Vec2d, Vec2d>> segs;
4641 const double dash = 6.0 * upp;
4642 const double step = std::max(dash + 4.0 * upp, L / 400.0);
4643 for (double t = 0.0; t < L; t += step)
4644 segs.emplace_back(Vec2d(t, 0.0), Vec2d(std::min(t + dash, L), 0.0));
4645 // Depth off: the line's job is to say "these two belong together", and it has to say it
4646 // even when the parts it spans are between the camera and one of the ends.
4649 }
4650
4651 m_plane = saved;
4652}
GLModel m_mc_stroke_model
Definition DesignSketchTool.hpp:1377
void render_mate_face(const Vec3d &origin, const Vec3d &X, const Vec3d &Y, const Vec3d &Z, double R, const ColorRGBA &body)
Definition DesignSketchTool.cpp:4707
Definition DesignSketchTool.hpp:439
@ Y
Definition libslic3r.h:142
@ Z
Definition libslic3r.h:143
@ X
Definition libslic3r.h:141

References draw_strokes(), Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glEnable, glsafe, Slic3r::GUI::grey, L, m_mate_connectors, m_mate_links, m_mc_stroke_model, M_PI, m_plane, Slic3r::GUI::N, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, render_mate_connectors(), render_mate_face(), Slic3r::X, Slic3r::SketchPlane::x_axis, Slic3r::Y, Slic3r::SketchPlane::y_axis, and Slic3r::Z.

Referenced by render(), and render_mate_connectors().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_mate_face()

void Slic3r::GUI::DesignSketchTool::render_mate_face ( const Vec3d & origin,
const Vec3d & X,
const Vec3d & Y,
const Vec3d & Z,
double R,
const ColorRGBA & body )
private
4709{
4710 const Camera& cam = wxGetApp().plater()->get_camera();
4711 const Vec3d right = cam.get_dir_right().normalized();
4712 const Vec3d up = cam.get_dir_up().normalized();
4713 const Vec3d fwd = cam.get_dir_forward().normalized();
4714 const double S = 2.0 * R; // the table spans 1.0, the disc spans 2R
4715
4716 // Light fixed in CAMERA space, so orbiting the model does not swing the shading around and
4717 // turn a stable symbol into a flickering one.
4718 const Vec3d light = (-0.35 * right + 0.55 * up - 0.76 * fwd).normalized();
4719
4720 auto to_world = [&](const Vec3d& p) {
4721 return origin + X * (p.x() * S) + Y * (p.y() * S) + Z * (p.z() * S);
4722 };
4723
4724 struct Facet { std::vector<Vec3d> w; ColorRGBA c; double depth; };
4725 std::vector<Facet> facets;
4726 auto emit = [&](std::vector<Vec3d> pts, const ColorRGBA& base, bool shade) {
4727 if (pts.size() < 3) return;
4728 Facet f; f.w.reserve(pts.size());
4729 for (const Vec3d& p : pts) f.w.push_back(to_world(p));
4730 const Vec3d n0 = (f.w[1] - f.w[0]).cross(f.w[2] - f.w[0]);
4731 Vec3d n = Z;
4732 if (n0.norm() > 1e-12) n = n0.normalized();
4733 if (n.dot(fwd) > 0.0) n = -n; // always take the camera-facing side
4734 double k = 1.0;
4735 if (shade) {
4736 // Ambient floor so a facet turned away still reads as part of the same object rather
4737 // than as a hole punched in it.
4738 k = 0.42 + 0.58 * std::max(0.0, n.dot(light));
4739 }
4740 f.c = ColorRGBA(float(base.r() * k), float(base.g() * k), float(base.b() * k), base.a());
4741 double d = 0.0;
4742 for (const Vec3d& p : f.w) d += p.dot(fwd);
4743 f.depth = d / double(f.w.size());
4744 facets.push_back(std::move(f));
4745 };
4746
4747 const int NO = int(sizeof(kBearOutline) / sizeof(kBearOutline[0]));
4748 const double zp = kBearPlateZ;
4749
4750 // The plate: sides first so the silhouette exists at a grazing view, then the top.
4751 for (int i = 0; i < NO; ++i) {
4752 const Vec2d& a = kBearOutline[i];
4753 const Vec2d& b = kBearOutline[(i + 1) % NO];
4754 emit({ Vec3d(a.x(), a.y(), 0.0), Vec3d(b.x(), b.y(), 0.0),
4755 Vec3d(b.x(), b.y(), zp), Vec3d(a.x(), a.y(), zp) }, body, true);
4756 }
4757 {
4758 std::vector<Vec3d> top;
4759 top.reserve(NO);
4760 for (int i = 0; i < NO; ++i) top.emplace_back(kBearOutline[i].x(), kBearOutline[i].y(), zp);
4761 emit(std::move(top), body, true);
4762 }
4763
4764 // The marks, a hair above the plate so they cannot z-fight it: two eyes then the cheek dot.
4765 const ColorRGBA mark(body.r() * 0.30f, body.g() * 0.30f, body.b() * 0.30f, 1.0f);
4766 const double zm = zp + 0.004;
4767 for (const Vec3d& m : kBearMarks) {
4768 std::vector<Vec3d> disc;
4769 const int N = 12;
4770 for (int i = 0; i < N; ++i) {
4771 const double a = (2.0 * M_PI * i) / N;
4772 disc.emplace_back(m.x() + m.z() * std::cos(a), m.y() + m.z() * std::sin(a), zm);
4773 }
4774 emit(std::move(disc), mark, false);
4775 }
4776 {
4777 std::vector<Vec3d> chin;
4778 for (const Vec2d& p : kBearChin) chin.emplace_back(p.x(), p.y(), zm);
4779 emit(std::move(chin), mark, false);
4780 }
4781
4782 // THE MUZZLE, and the two decisions that make it legible rather than merely present.
4783 //
4784 // It is the one feature standing along +Z, so it says which way the connector points, and it
4785 // is all that survives edge-on where a drawing in the plane has nothing left. Its geometry is
4786 // the part's own ridge: crest 29.0 mm, 6.58 mm drop, 13.1 deg, against the 28.3 / 6.61 / 13.1
4787 // the review measured on the B-rep. Base taken from the mesh, NOT recomputed from
4788 // height*tan(draft) -- that produced a needle, because the real base overhangs the crest at
4789 // both ends and it is the overhang that makes this a wedge rather than a blade.
4790 //
4791 // BUT FIDELITY ALONE FAILS. Scaled honestly the ridge is 11.3 mm on an 83.3 mm face, 13.6 %
4792 // of the width, and at 22-48 px that reads as a scratch -- Tommaso looked at the faithful
4793 // version and could not find the muzzle at all, which is the only test that counts. A glyph
4794 // is a symbol, not a scale model, so it gets two deliberate exaggerations:
4795 //
4796 // COLOUR does the work. In the body tone the muzzle is a grey sliver whichever way it is
4797 // lit; in the accent it is the first thing the eye lands on at every elevation, and at 6
4798 // degrees it is the ONLY structured thing above the flat line. Measured share of lit
4799 // pixels at 90/16/6 deg: body 14.8/11.3/17.5 %, accent 18.3/19.2/23.9 %.
4800 // WIDTH 1.8x on top of that: 23.5/25.2/31.2 %, and it stops reading as a needle.
4801 //
4802 // The accent is the same gold the disc treatment spends on its roll quadrant, which is
4803 // consistent -- it is this tab's "here is the direction that matters" colour. Polarity is
4804 // still carried by the Z arrow's head, so nothing collides.
4805 {
4806 const ColorRGBA gold(0.93f, 0.66f, 0.09f, 1.0f);
4807 const double widen = 1.8;
4808 const Vec3d& A = kBearCrest[0];
4809 const Vec3d& B = kBearCrest[1];
4810 auto base = [&](int i) {
4811 return Vec3d(kBearSnoutBase[i].x() * widen, kBearSnoutBase[i].y(), zp);
4812 };
4813 const Vec3d nl = base(0), nr = base(1), tr = base(2), tl = base(3);
4814 emit({ nl, tl, B, A }, gold, true); // left flank
4815 emit({ nr, A, B, tr }, gold, true); // right flank
4816 emit({ nl, A, nr }, gold, true); // nose cap, sloped by the base overhang
4817 emit({ tr, B, tl }, gold, true); // tail cap
4818 }
4819
4820 // Painter's algorithm: depth testing is off for this overlay, so draw order IS the depth.
4821 std::sort(facets.begin(), facets.end(),
4822 [](const Facet& a, const Facet& b) { return a.depth > b.depth; });
4823
4824 // draw_fill works in m_plane, so project into a screen-aligned frame at the connector origin
4825 // and hand it flat polygons. The relief survives because the PROJECTION is 3D, not the plane.
4826 const SketchPlane saved = m_plane;
4827 SketchPlane bb; bb.origin = origin; bb.x_axis = right; bb.y_axis = up; bb.normal = fwd;
4828 m_plane = bb;
4830 for (const Facet& f : facets) {
4831 std::vector<Vec2d> poly;
4832 poly.reserve(f.w.size());
4833 for (const Vec3d& p : f.w) poly.emplace_back((p - origin).dot(right), (p - origin).dot(up));
4834 draw_fill(m_mc_fill_model, poly, f.c);
4835 }
4836 m_plane = saved;
4837}
GLModel m_mc_fill_model
Definition DesignSketchTool.hpp:1378
static const Vec3d kBearCrest[]
Definition DesignSketchTool.cpp:4702
static const Vec2d kBearOutline[]
Definition DesignSketchTool.cpp:4678
static const Vec2d kBearSnoutBase[]
Definition DesignSketchTool.cpp:4696
static const Vec2d kBearChin[]
Definition DesignSketchTool.cpp:4684
static const double kBearPlateZ
Definition DesignSketchTool.cpp:4695
static const Vec3d kBearMarks[]
Definition DesignSketchTool.cpp:4688

References Slic3r::ColorRGBA::b(), Slic3r::cross(), Slic3r::dot(), draw_fill(), Slic3r::f(), Slic3r::ColorRGBA::g(), Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::kBearChin, Slic3r::GUI::kBearCrest, Slic3r::GUI::kBearMarks, Slic3r::GUI::kBearOutline, Slic3r::GUI::kBearPlateZ, Slic3r::GUI::kBearSnoutBase, m_mc_fill_model, M_PI, m_plane, Slic3r::GUI::N, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, Slic3r::ColorRGBA::r(), render_mate_face(), Slic3r::X, Slic3r::SketchPlane::x_axis, Slic3r::Y, Slic3r::SketchPlane::y_axis, and Slic3r::Z.

Referenced by render_mate_connectors(), and render_mate_face().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_move_gizmo()

void Slic3r::GUI::DesignSketchTool::render_move_gizmo ( )
private
5866{
5867 if (!m_mv_active) return;
5868 const Camera& cam = wxGetApp().plater()->get_camera();
5869 const Vec3d right = cam.get_dir_right().normalized();
5870 const Vec3d up = cam.get_dir_up().normalized();
5871 const Vec3d fwd = cam.get_dir_forward().normalized();
5872 const Vec3d anchor = m_mv_base + m_mv_offset;
5873 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
5874 const double th = std::max(15.0 * upp, 1e-4);
5875 const double L = move_gizmo_arm(cam); // scales with the body (see move_gizmo_arm)
5876
5877 const SketchPlane saved = m_plane;
5878 SketchPlane bb; bb.origin = anchor; bb.x_axis = right; bb.y_axis = up; bb.normal = fwd;
5879 m_plane = bb;
5880
5881 const Vec3d axes[3] = { Vec3d::UnitX(), Vec3d::UnitY(), Vec3d::UnitZ() };
5882 const ColorRGBA cols[3] = { ColorRGBA(0.92f, 0.28f, 0.28f, 1.0f), // X red
5883 ColorRGBA(0.30f, 0.80f, 0.34f, 1.0f), // Y green
5884 ColorRGBA(0.32f, 0.55f, 0.95f, 1.0f) }; // Z blue
5885
5887 for (int a = 0; a < 3; ++a) {
5888 const Vec3d tipw = anchor + axes[a] * L;
5889 const Vec2d tip2((tipw - anchor).dot(right), (tipw - anchor).dot(up));
5890 if (tip2.norm() < 1e-6) continue; // axis ~parallel to view: skip
5891 const Vec2d u = tip2.normalized();
5892 const Vec2d nrm(-u.y(), u.x());
5893 std::vector<std::pair<Vec2d, Vec2d>> segs;
5894 segs.emplace_back(Vec2d(0, 0), tip2);
5895 const double as = std::max(tip2.norm() * 0.20, th * 0.9);
5896 const Vec2d back = tip2 - u * as;
5897 segs.emplace_back(tip2, back + nrm * (as * 0.5));
5898 segs.emplace_back(tip2, back - nrm * (as * 0.5));
5899 draw_strokes(m_mv_arrow_model, segs, std::max(0.7 * upp, 1e-4), cols[a]);
5900 const double off = m_mv_offset[a];
5901 if (std::abs(off) > 1e-4) {
5902 DimAnnot da; da.kind = DimType::Distance; da.value = std::abs(off);
5903 draw_text(m_line_model, dim_text(da), tip2 + u * (th * 1.4), th, cols[a]);
5904 }
5905 }
5906 m_plane = saved;
5907
5908 // Three world-axis rotation rings (X/Y/Z), each a circle in the plane perpendicular to
5909 // its axis through the gizmo anchor — drag a ring to rotate the body about that axis.
5910 const double R = 0.83 * move_gizmo_arm(cam); // rings just inside the arrow tips
5911 for (int a = 0; a < 3; ++a) {
5912 Vec3d e, u, v; ring_basis(a, e, u, v);
5913 SketchPlane rp; rp.origin = anchor; rp.x_axis = u; rp.y_axis = v; rp.normal = e;
5914 m_plane = rp;
5915 std::vector<std::pair<Vec2d, Vec2d>> segs;
5916 const int N = 48;
5917 Vec2d prev(R, 0.0);
5918 for (int i = 1; i <= N; ++i) {
5919 const double t = 2.0 * M_PI * double(i) / double(N);
5920 const Vec2d cur(R * std::cos(t), R * std::sin(t));
5921 segs.emplace_back(prev, cur); prev = cur;
5922 }
5923 draw_strokes(m_mv_arrow_model, segs, std::max(0.55 * upp, 1e-4), cols[a]);
5924 }
5925 m_plane = saved;
5926}
GLModel m_mv_arrow_model
Definition DesignSketchTool.hpp:1480
size_t cols(const T &raster)
Definition MarchingSquares.hpp:173

References dim_text(), Distance, Slic3r::dot(), draw_strokes(), draw_text(), Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, L, m_line_model, m_mv_active, m_mv_arrow_model, m_mv_base, m_mv_offset, M_PI, m_plane, move_gizmo_arm(), Slic3r::GUI::N, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, render_move_gizmo(), ring_basis(), Slic3r::GUI::DesignSketchTool::DimAnnot::value, Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_move_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_op_gizmo()

void Slic3r::GUI::DesignSketchTool::render_op_gizmo ( double unit_per_px)
private
8894{
8895 m_op_label = Vec2d(1e18, 1e18);
8896 if (!op_ready()) return;
8897 const ColorRGBA ghostc(0.30f, 0.88f, 0.66f, 0.55f);
8899 if (m_mode == Mode::Mirror) return; // pick-only, no arrow/label
8900 const ColorRGBA dc(0.30f, 0.88f, 0.66f, 1.0f);
8901 const double th = std::max(15.0 * unit_per_px, 1e-4);
8902 const Vec2d dir = (m_op_value >= 0 ? m_op_dir : -m_op_dir);
8903 const Vec2d tip = m_op_anchor + m_op_dir * m_op_value; // signed length picks the side
8904 std::vector<std::pair<Vec2d, Vec2d>> segs;
8905 segs.emplace_back(m_op_anchor, tip);
8906 const double as = std::max(std::abs(m_op_value) * 0.18, th * 0.8); // arrowhead size
8907 const Vec2d nrm(-dir.y(), dir.x());
8908 const Vec2d back = tip - dir * as;
8909 segs.emplace_back(tip, back + nrm * (as * 0.5));
8910 segs.emplace_back(tip, back - nrm * (as * 0.5));
8911 draw_strokes(m_highlight_model, segs, 0.6, dc);
8912 DimAnnot a;
8914 a.value = std::abs(m_op_value);
8915 m_op_label = tip + dir * (th * 1.2);
8917}

References dim_text(), Distance, draw_entities_preview(), draw_strokes(), draw_text(), Fillet, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, m_highlight_model, m_line_model, m_mode, m_op_anchor, m_op_dir, m_op_ghost, m_op_label, m_op_value, Mirror, op_ready(), Radius, render_op_gizmo(), and Slic3r::GUI::DesignSketchTool::DimAnnot::value.

Referenced by render(), and render_op_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_pattern_gizmo()

void Slic3r::GUI::DesignSketchTool::render_pattern_gizmo ( )
private
7124{
7125 if (!m_pt_active) return;
7126 const Camera& cam = wxGetApp().plater()->get_camera();
7127 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
7128 const double th = std::max(15.0 * upp, 1e-4);
7129 const ColorRGBA col(0.15f, 0.92f, 1.0f, 1.0f); // vivid cyan, matches the gizmo family
7130 const SketchPlane saved = m_plane;
7131 std::vector<std::pair<Vec2d, Vec2d>> segs;
7132
7133 if (!m_pt_circular) {
7134 // The arrow lives in the true world plane (NOT billboarded) so the march reads in 3D.
7135 const Vec3d perp = m_pt_normal.cross(m_pt_dirw).normalized();
7136 SketchPlane fp; fp.origin = m_pt_base; fp.x_axis = m_pt_dirw; fp.y_axis = perp; fp.normal = m_pt_normal;
7137 m_plane = fp;
7138 const int copies = std::max(1, m_pt_count);
7139 const double L = pt_linear_len(m_pt_spacing, copies);
7140 segs.emplace_back(Vec2d(0, 0), Vec2d(L, 0)); // shaft
7141 const double as = std::max(L * 0.12, th); // arrowhead
7142 segs.emplace_back(Vec2d(L, 0), Vec2d(L - as, as * 0.5));
7143 segs.emplace_back(Vec2d(L, 0), Vec2d(L - as, -as * 0.5));
7144 const double tk = std::max(th, L * 0.05); // copy tick half-height
7145 for (int i = 0; i < copies; ++i) {
7146 const double x = m_pt_spacing * i;
7147 segs.emplace_back(Vec2d(x, -tk), Vec2d(x, tk));
7148 }
7149 const Vec2d E(L, 0); // diamond grab-handle
7150 const double hs = std::max(th * 0.8, L * 0.04);
7151 segs.emplace_back(E + Vec2d(hs, 0), E + Vec2d(0, hs));
7152 segs.emplace_back(E + Vec2d(0, hs), E + Vec2d(-hs, 0));
7153 segs.emplace_back(E + Vec2d(-hs, 0), E + Vec2d(0, -hs));
7154 segs.emplace_back(E + Vec2d(0, -hs), E + Vec2d(hs, 0));
7156 draw_strokes(m_pt_stroke_model, segs, std::max(0.8 * upp, 1e-4), col);
7157 DimAnnot da; da.kind = DimType::Distance; da.value = m_pt_spacing;
7158 draw_text(m_line_model, dim_text(da), Vec2d(m_pt_spacing * 0.5, tk * 1.7), th, col);
7159 m_plane = saved;
7160 return;
7161 }
7162
7163 // ---- Circular: clone the Revolve arc about the plane normal through the plane origin ----
7164 const Vec3d yax = m_pt_normal.cross(m_pt_cref).normalized();
7165 SketchPlane rp; rp.origin = m_pt_ccenter; rp.x_axis = m_pt_cref; rp.y_axis = yax; rp.normal = m_pt_normal;
7166 m_plane = rp;
7167 const double r = m_pt_radius;
7168 const double a = m_pt_angle * M_PI / 180.0;
7169 const int N = std::max(8, int(a / (M_PI / 32.0)));
7170 Vec2d prev(r, 0.0);
7171 for (int i = 1; i <= N; ++i) {
7172 const double t = a * double(i) / double(N);
7173 const Vec2d cur(r * std::cos(t), r * std::sin(t));
7174 segs.emplace_back(prev, cur);
7175 prev = cur;
7176 }
7177 const Vec2d tip(r * std::cos(a), r * std::sin(a));
7178 segs.emplace_back(Vec2d(0, 0), Vec2d(r, 0)); // angle-0 spoke
7179 segs.emplace_back(Vec2d(0, 0), tip); // swept spoke (the handle)
7180 const Vec2d tang(-std::sin(a), std::cos(a));
7181 const Vec2d radial = tip.normalized();
7182 const double as = std::max(r * 0.14, th);
7183 segs.emplace_back(tip, tip - tang * as - radial * (as * 0.5));
7184 segs.emplace_back(tip, tip - tang * as + radial * (as * 0.5));
7185 const double hs = std::max(th * 0.8, r * 0.05);
7186 const Vec2d du = radial * hs, dv = Vec2d(-radial.y(), radial.x()) * hs;
7187 segs.emplace_back(tip + du, tip + dv);
7188 segs.emplace_back(tip + dv, tip - du);
7189 segs.emplace_back(tip - du, tip - dv);
7190 segs.emplace_back(tip - dv, tip + du);
7192 draw_strokes(m_pt_stroke_model, segs, std::max(0.8 * upp, 1e-4), col);
7193 DimAnnot da; da.kind = DimType::Angle; da.value = m_pt_angle;
7194 draw_text(m_line_model, dim_text(da), tip * 1.14, th, col);
7195 m_plane = saved;
7196}
GLModel m_pt_stroke_model
Definition DesignSketchTool.hpp:1634
@ E
Definition libslic3r.h:144

References Angle, dim_text(), Distance, draw_strokes(), draw_text(), Slic3r::E, Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, L, m_line_model, M_PI, m_plane, m_pt_active, m_pt_angle, m_pt_base, m_pt_ccenter, m_pt_circular, m_pt_count, m_pt_cref, m_pt_dirw, m_pt_normal, m_pt_radius, m_pt_spacing, m_pt_stroke_model, Slic3r::GUI::N, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, Slic3r::perp(), Slic3r::GUI::pt_linear_len(), render_pattern_gizmo(), Slic3r::GUI::DesignSketchTool::DimAnnot::value, Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_pattern_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_reference_axes()

void Slic3r::GUI::DesignSketchTool::render_reference_axes ( const Vec3d & origin,
double half )
private
5595{
5598 const Camera& cam = wxGetApp().plater()->get_camera();
5599 const Vec3d vd = cam.get_dir_forward();
5600 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6); // world units per screen pixel
5601 const double len = 1.2 * (reference_square_gap(half) + 2.0 * half);
5602 // A dash, then a dot, every kPeriod of the axis.
5603 constexpr double kDash = 0.07, kDotFrom = 0.10, kDotTo = 0.115, kPeriod = 0.145;
5604 const ColorRGBA colours[3] = { ColorRGBA(0.92f, 0.28f, 0.28f, 1.0f), ColorRGBA(0.30f, 0.80f, 0.34f, 1.0f),
5605 ColorRGBA(0.32f, 0.55f, 0.95f, 1.0f) };
5606 for (int k = 0; k < 3; ++k) {
5607 const Vec3d axis = Vec3d::Unit(k) * (len * reference_octant()[k]);
5608 std::vector<std::vector<Vec3d>> strokes;
5609 for (double t = 0.; t < 1.; t += kPeriod) {
5610 strokes.push_back({ origin + axis * t, origin + axis * std::min(t + kDash, 1.) });
5611 if (t + kDotFrom < 1.)
5612 strokes.push_back({ origin + axis * (t + kDotFrom), origin + axis * std::min(t + kDotTo, 1.) });
5613 }
5614 GLModel::Geometry g;
5615 append_ribbons(g, -1, strokes, vd, Vec3d::Zero(), 1.5 * upp); // body -1: already world coordinates
5616 if (g.is_empty())
5617 continue; // seen end-on
5618 GLModel m;
5619 m.init_from(std::move(g));
5620 m.set_color(colours[k]);
5621 m.render();
5622 }
5623
5624 const Vec3d right = cam.get_dir_right(), up = cam.get_dir_up();
5625 auto disc = [&](double radius_px, const ColorRGBA& colour) {
5626 constexpr int kSides = 24;
5627 GLModel::Geometry g;
5628 g.format = { EPT::Triangles, EVL::P3 };
5629 g.add_vertex((Vec3f) origin.cast<float>());
5630 for (int i = 0; i < kSides; ++i) {
5631 const double a = 2. * M_PI * i / kSides;
5632 g.add_vertex((Vec3f) (origin + (right * std::cos(a) + up * std::sin(a)) * (radius_px * upp)).cast<float>());
5633 }
5634 for (int i = 0; i < kSides; ++i)
5635 g.add_triangle(0, 1 + i, 1 + (i + 1) % kSides);
5636 GLModel m;
5637 m.init_from(std::move(g));
5638 m.set_color(colour);
5639 m.render();
5640 };
5641 disc(6.0, ColorRGBA(0.30f, 0.30f, 0.32f, 1.0f)); // a dark ring round
5642 disc(4.5, ColorRGBA(0.92f, 0.92f, 0.92f, 1.0f)); // a light centre
5643}
Vec3d reference_octant()
Definition DesignSketchTool.cpp:5491
double reference_square_gap(double half)
Definition DesignSketchTool.hpp:80

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), append_ribbons(), Slic3r::cast(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), Slic3r::GUI::GLModel::init_from(), Slic3r::GUI::GLModel::Geometry::is_empty(), M_PI, Slic3r::GUI::reference_square_gap(), Slic3r::GUI::GLModel::render(), render_reference_axes(), and Slic3r::GUI::GLModel::set_color().

Referenced by render_base_pick(), and render_reference_axes().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_revolve_gizmo()

void Slic3r::GUI::DesignSketchTool::render_revolve_gizmo ( )
private
6964{
6965 if (!m_rv_active) return;
6966 const Camera& cam = wxGetApp().plater()->get_camera();
6967 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6968 const double th = std::max(15.0 * upp, 1e-4);
6969 const Vec3d yax = rv_yaxis(m_rv_axis, m_rv_ref, m_rv_flip);
6970
6971 // The arc lives in the true revolve plane (NOT billboarded) so the sweep reads in 3D.
6972 const SketchPlane saved = m_plane;
6973 SketchPlane rp; rp.origin = m_rv_center; rp.x_axis = m_rv_ref; rp.y_axis = yax; rp.normal = m_rv_axis;
6974 m_plane = rp;
6975 // Vivid cyan: the revolve ghost is amber, so the arc manipulator must contrast with it
6976 // (it overlaps the solid, unlike the extrude depth-arrow which points away into empty space).
6977 const ColorRGBA arcc(0.15f, 0.92f, 1.0f, 1.0f);
6978 const double r = m_rv_radius;
6979 const double a = m_rv_angle * M_PI / 180.0;
6980 const int N = std::max(8, int(a / (M_PI / 32.0))); // ~ every 5.6°
6981
6982 std::vector<std::pair<Vec2d, Vec2d>> segs;
6983 Vec2d prev(r, 0.0);
6984 for (int i = 1; i <= N; ++i) {
6985 const double t = a * double(i) / double(N);
6986 const Vec2d cur(r * std::cos(t), r * std::sin(t));
6987 segs.emplace_back(prev, cur);
6988 prev = cur;
6989 }
6990 const Vec2d tip(r * std::cos(a), r * std::sin(a));
6991 segs.emplace_back(Vec2d(0, 0), Vec2d(r, 0)); // spoke at angle 0
6992 segs.emplace_back(Vec2d(0, 0), tip); // spoke at the swept angle (the handle)
6993 // Arrowhead at the tip, pointing along the sweep tangent (-sin,cos) rotated by a.
6994 const Vec2d tang(-std::sin(a), std::cos(a));
6995 const Vec2d radial = tip.normalized();
6996 const double as = std::max(r * 0.14, th);
6997 segs.emplace_back(tip, tip - tang * as - radial * (as * 0.5));
6998 segs.emplace_back(tip, tip - tang * as + radial * (as * 0.5));
6999 // A diamond grab-handle at the tip so the draggable target is unmistakable.
7000 const double hs = std::max(th * 0.8, r * 0.05);
7001 const Vec2d du = radial * hs, dv = Vec2d(-radial.y(), radial.x()) * hs;
7002 segs.emplace_back(tip + du, tip + dv);
7003 segs.emplace_back(tip + dv, tip - du);
7004 segs.emplace_back(tip - du, tip - dv);
7005 segs.emplace_back(tip - dv, tip + du);
7006
7008 draw_strokes(m_rv_stroke_model, segs, std::max(0.8 * upp, 1e-4), arcc);
7009 DimAnnot da; da.kind = DimType::Angle; da.value = m_rv_angle;
7010 draw_text(m_line_model, dim_text(da), tip * 1.14, th, arcc);
7011 // The axis itself, dashed, past both ends of the sweep: which line is being revolved about
7012 // is the one thing the card's list cannot show.
7013 SketchPlane ap; ap.origin = m_rv_center; ap.x_axis = m_rv_axis; ap.y_axis = m_rv_ref;
7014 ap.normal = m_rv_axis.cross(m_rv_ref);
7015 m_plane = ap;
7016 std::vector<std::pair<Vec2d, Vec2d>> dashes;
7017 const double L = 1.6 * r, dash = std::max(r * 0.08, th * 0.5);
7018 for (double u = -L; u < L; u += 2.0 * dash)
7019 dashes.emplace_back(Vec2d(u, 0.0), Vec2d(std::min(u + dash, L), 0.0));
7020 draw_strokes(m_rv_stroke_model, dashes, std::max(0.8 * upp, 1e-4), ColorRGBA(1.0f, 0.55f, 0.1f, 1.0f));
7021 m_plane = saved;
7022}
GLModel m_rv_stroke_model
Definition DesignSketchTool.hpp:1578

References Angle, dim_text(), draw_strokes(), draw_text(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, L, m_line_model, M_PI, m_plane, m_rv_active, m_rv_angle, m_rv_axis, m_rv_center, m_rv_flip, m_rv_radius, m_rv_ref, m_rv_stroke_model, Slic3r::GUI::N, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, render_revolve_gizmo(), Slic3r::GUI::rv_yaxis(), Slic3r::GUI::DesignSketchTool::DimAnnot::value, Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_revolve_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_rib_gizmo()

void Slic3r::GUI::DesignSketchTool::render_rib_gizmo ( )
private
5313{
5314 if (!m_rb_active) return;
5315 Vec2d d, perp, mid; double half;
5316 if (!rib_frame(m_rb_p0, m_rb_p1, m_rb_thickness, d, perp, mid, half)) return;
5319 const Camera& cam = wxGetApp().plater()->get_camera();
5320 const Vec3d right = cam.get_dir_right().normalized();
5321 const Vec3d up = cam.get_dir_up().normalized();
5322 const Vec3d vd = cam.get_dir_forward();
5323 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
5324 const double hs = 6.0 * upp; // handle half-size (~6 px)
5325 const double hw = 1.5 * upp; // ribbon half-width
5326
5327 // Slab footprint outline (4 thin camera-facing ribbons).
5328 const Vec3d c[4] = { m_rb_plane.to_world(m_rb_p0 + perp * half),
5329 m_rb_plane.to_world(m_rb_p1 + perp * half),
5330 m_rb_plane.to_world(m_rb_p1 - perp * half),
5331 m_rb_plane.to_world(m_rb_p0 - perp * half) };
5332 GLModel::Geometry border; border.format = { EPT::Triangles, EVL::P3 };
5333 unsigned int bb = 0;
5334 for (int s = 0; s < 4; ++s) {
5335 const Vec3d a = c[s], b = c[(s + 1) & 3];
5336 Vec3d dir = b - a; if (dir.norm() < 1e-9) continue; dir.normalize();
5337 Vec3d off = dir.cross(vd);
5338 if (off.norm() < 1e-9) off = dir.cross(up);
5339 if (off.norm() < 1e-9) continue;
5340 off.normalize(); off *= hw;
5341 border.add_vertex((Vec3f)(a + off).cast<float>()); border.add_vertex((Vec3f)(b + off).cast<float>());
5342 border.add_vertex((Vec3f)(b - off).cast<float>()); border.add_vertex((Vec3f)(a - off).cast<float>());
5343 border.add_triangle(bb, bb + 1, bb + 2); border.add_triangle(bb, bb + 2, bb + 3); bb += 4;
5344 }
5345
5346 // Two handles: 0 = +perp side, 1 = -perp side (both at half-thickness).
5347 const Vec3d hpts[2] = { m_rb_plane.to_world(mid + perp * half),
5348 m_rb_plane.to_world(mid - perp * half) };
5349 const ColorRGBA hot(1.0f, 0.85f, 0.2f, 1.0f);
5350
5352 if (bb > 0) {
5353 GLModel m; m.init_from(std::move(border));
5354 m.set_color(ColorRGBA(1.0f, 0.62f, 0.16f, 0.9f)); // CAD amber slab footprint
5355 m.render();
5356 }
5357 for (int i = 0; i < 2; ++i) {
5358 const Vec3d ctr = hpts[i];
5359 const Vec3d q0 = ctr - right * hs - up * hs, q1 = ctr + right * hs - up * hs,
5360 q2 = ctr + right * hs + up * hs, q3 = ctr - right * hs + up * hs;
5361 GLModel::Geometry sq; sq.format = { EPT::Triangles, EVL::P3 };
5362 sq.add_vertex((Vec3f)q0.cast<float>()); sq.add_vertex((Vec3f)q1.cast<float>());
5363 sq.add_vertex((Vec3f)q2.cast<float>()); sq.add_vertex((Vec3f)q3.cast<float>());
5364 sq.add_triangle(0, 1, 2); sq.add_triangle(0, 2, 3);
5365 GLModel m; m.init_from(std::move(sq));
5366 m.set_color(m_rb_drag == i ? hot : ColorRGBA(0.30f, 0.80f, 0.34f, 1.0f)); // green
5367 m.render();
5368 }
5369}

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::cast(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::GLModel::init_from(), m_rb_active, m_rb_drag, m_rb_p0, m_rb_p1, m_rb_plane, m_rb_thickness, Slic3r::perp(), Slic3r::GUI::GLModel::render(), render_rib_gizmo(), Slic3r::GUI::rib_frame(), and Slic3r::GUI::GLModel::set_color().

Referenced by render(), and render_rib_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_shell_gizmo()

void Slic3r::GUI::DesignSketchTool::render_shell_gizmo ( )
private
6619{
6620 if (!m_sh_active) return;
6621 const Camera& cam = wxGetApp().plater()->get_camera();
6622 const Vec3d right = cam.get_dir_right().normalized();
6623 const Vec3d up = cam.get_dir_up().normalized();
6624 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6625 const double th = std::max(15.0 * upp, 1e-4);
6626 const double L = std::max(m_sh_thickness, 40.0 * upp); // WYSIWYG, floored to a handle
6627 const Vec3d tipw = m_sh_anchor + m_sh_dir * L;
6628
6629 const SketchPlane saved = m_plane;
6630 SketchPlane bb; bb.origin = m_sh_anchor; bb.x_axis = right; bb.y_axis = up; bb.normal = cam.get_dir_forward().normalized();
6631 m_plane = bb;
6632 const ColorRGBA teal(0.20f, 0.80f, 0.75f, 1.0f);
6633
6634 const Vec2d tip2((tipw - m_sh_anchor).dot(right), (tipw - m_sh_anchor).dot(up));
6635 if (tip2.norm() > 1e-6) {
6636 const Vec2d u = tip2.normalized();
6637 const Vec2d nrm(-u.y(), u.x());
6638 std::vector<std::pair<Vec2d, Vec2d>> segs;
6639 segs.emplace_back(Vec2d(0, 0), tip2);
6640 const double as = std::max(tip2.norm() * 0.20, th * 0.9);
6641 const Vec2d back = tip2 - u * as;
6642 segs.emplace_back(tip2, back + nrm * (as * 0.5));
6643 segs.emplace_back(tip2, back - nrm * (as * 0.5));
6645 draw_strokes(m_sh_stroke_model, segs, std::max(0.7 * upp, 1e-4), teal);
6646 DimAnnot da; da.kind = DimType::Distance; da.value = m_sh_thickness;
6647 draw_text(m_line_model, dim_text(da), tip2 + u * (th * 1.4), th, teal);
6648 }
6649 m_plane = saved;
6650}
GLModel m_sh_stroke_model
Definition DesignSketchTool.hpp:1562

References dim_text(), Distance, Slic3r::dot(), draw_strokes(), draw_text(), Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, L, m_line_model, m_plane, m_sh_active, m_sh_anchor, m_sh_dir, m_sh_stroke_model, m_sh_thickness, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, render_shell_gizmo(), Slic3r::GUI::DesignSketchTool::DimAnnot::value, Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_shell_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_solid_highlight()

void Slic3r::GUI::DesignSketchTool::render_solid_highlight ( )
private
4265{
4266 const ColorRGBA sel_cyan = design_selection_color();
4267
4268 for (const FaceHighlight& h : m_hl_faces)
4269 render_face_outline(h, false);
4270
4271 // The pre-highlight goes FIRST so the committed selection paints over it where the two
4272 // overlap — what you HAVE outranks what you would get. Suppressed entirely when they are the
4273 // same thing: two coats of the same colour on the same face reads as a rendering fault, and
4274 // a promise about a click that would change nothing is not worth making.
4275 const bool pre_is_sel = m_pre.kind == m_solid_sel && m_pre.body == m_sel_body
4276 && (m_pre.kind == SolidSel::Vertex ? (m_pre.vertex_pt - m_sel_vertex_pt).norm() < 1e-9
4277 : m_pre.kind == SolidSel::Edge ? m_pre.edge == m_sel_edge
4278 : m_pre.kind == SolidSel::Face ? m_pre.face == m_sel_face
4279 : true);
4280 if (m_pre.kind == SolidSel::Face && !pre_is_sel)
4281 // A hovered face gets its outline alone: a promise, not a selection.
4282 render_face_outline(cached_face_highlight(m_pre_hl, m_pre.body, { m_pre.face }), true);
4283 else if (m_pre.kind != SolidSel::None && !pre_is_sel)
4284 // The selection's own colour: a second hue would read as a distinct KIND of selection,
4285 // when it is the same selection one moment earlier.
4286 render_solid_sel(m_pre.kind, m_pre.edge_pts, m_pre.vertex_pt, sel_cyan);
4287
4288 // A picked body or face looks like the Feature tree's faces: the canvas fills it, this
4289 // outlines it.
4290 if (const std::vector<std::pair<int, int>> picked = picked_faces(); !picked.empty()) {
4291 std::vector<int> faces;
4292 for (const auto& bf : picked)
4293 faces.push_back(bf.second);
4295 return;
4296 }
4299 for (const std::vector<Vec3d>& pts : m_sel_edges_more_pts)
4300 render_solid_sel(SolidSel::Edge, pts, Vec3d::Zero(), sel_cyan);
4301}
const FaceHighlight & cached_face_highlight(FaceHighlight &cache, int body, std::vector< int > faces) const
Definition DesignSketchTool.cpp:3838
std::vector< std::pair< int, int > > picked_faces() const
Definition DesignSketchTool.cpp:3725
void render_face_outline(const FaceHighlight &h, bool quiet)
Definition DesignSketchTool.cpp:3852
void render_solid_sel(SolidSel kind, const std::vector< Vec3d > &edge_pts, const Vec3d &vertex_pt, const ColorRGBA &rgb)
Definition DesignSketchTool.cpp:4200

References cached_face_highlight(), Slic3r::GUI::design_selection_color(), Edge, Face, m_hl_faces, m_pre, m_pre_hl, m_sel_body, m_sel_edge, m_sel_edge_pts, m_sel_edges_more_pts, m_sel_face, m_sel_hl, m_sel_vertex_pt, m_solid_sel, None, picked_faces(), render_face_outline(), render_solid_highlight(), render_solid_sel(), and Vertex.

Referenced by render(), and render_solid_highlight().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_solid_sel()

void Slic3r::GUI::DesignSketchTool::render_solid_sel ( SolidSel kind,
const std::vector< Vec3d > & edge_pts,
const Vec3d & vertex_pt,
const ColorRGBA & rgb )
private
4202{
4205 // Opaque: the edge ribbon and the vertex square render with GL_BLEND OFF, so an alpha below 1
4206 // here would be silently ignored.
4207 const ColorRGBA cyan(rgb.r(), rgb.g(), rgb.b(), 1.0f);
4208
4209 if (kind == SolidSel::Edge && edge_pts.size() >= 2) {
4210 const Camera& cam = wxGetApp().plater()->get_camera();
4211 const Vec3d vd = cam.get_dir_forward();
4212 const double hw = 2.0 / std::max(cam.get_zoom(), 1e-6); // ~2 px ribbon half-width
4213 GLModel::Geometry g; g.format = { EPT::Triangles, EVL::P3 };
4214 unsigned int base = 0;
4215 for (size_t s = 1; s < edge_pts.size(); ++s) {
4216 const Vec3d a = edge_pts[s - 1], b = edge_pts[s];
4217 Vec3d dir = b - a; if (dir.norm() < 1e-9) continue; dir.normalize();
4218 Vec3d off = dir.cross(vd);
4219 if (off.norm() < 1e-9) off = dir.cross(cam.get_dir_up());
4220 if (off.norm() < 1e-9) continue;
4221 off.normalize(); off *= hw;
4222 g.add_vertex((Vec3f)(a + off).cast<float>());
4223 g.add_vertex((Vec3f)(b + off).cast<float>());
4224 g.add_vertex((Vec3f)(b - off).cast<float>());
4225 g.add_vertex((Vec3f)(a - off).cast<float>());
4226 g.add_triangle(base, base + 1, base + 2);
4227 g.add_triangle(base, base + 2, base + 3); base += 4;
4228 }
4229 if (base > 0) {
4231 m_solid_edge_model.reset();
4232 m_solid_edge_model.init_from(std::move(g));
4233 m_solid_edge_model.set_color(cyan);
4234 m_solid_edge_model.render();
4235 }
4236 } else if (kind == SolidSel::Vertex) {
4237 // A camera-facing square at the picked corner, sized in screen terms (the same
4238 // 1/zoom trick the edge ribbon uses) so it stays a constant dot at every zoom. A
4239 // selection you cannot see is not a selection (L5), which is why vertex picking waited
4240 // for this rather than shipping without a highlight.
4241 const Camera& cam = wxGetApp().plater()->get_camera();
4242 Vec3d right = cam.get_dir_right(), up = cam.get_dir_up();
4243 const double h = 4.5 / std::max(cam.get_zoom(), 1e-6); // ~4.5 px half-size
4244 right *= h; up *= h;
4245 const Vec3d c = vertex_pt;
4246 GLModel::Geometry g; g.format = { EPT::Triangles, EVL::P3 };
4247 g.add_vertex((Vec3f)(c - right - up).cast<float>());
4248 g.add_vertex((Vec3f)(c + right - up).cast<float>());
4249 g.add_vertex((Vec3f)(c + right + up).cast<float>());
4250 g.add_vertex((Vec3f)(c - right + up).cast<float>());
4251 g.add_triangle(0, 1, 2);
4252 g.add_triangle(0, 2, 3);
4254 m_solid_vertex_model.reset();
4255 m_solid_vertex_model.init_from(std::move(g));
4256 m_solid_vertex_model.set_color(cyan);
4257 m_solid_vertex_model.render();
4258 }
4259}
GLModel m_solid_vertex_model
Definition DesignSketchTool.hpp:1381

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::ColorRGBA::b(), Slic3r::cast(), Edge, Slic3r::GUI::GLModel::Geometry::format, Slic3r::ColorRGBA::g(), Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, m_solid_edge_model, m_solid_vertex_model, Slic3r::ColorRGBA::r(), render_solid_sel(), and Vertex.

Referenced by render_solid_highlight(), and render_solid_sel().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_tf_gizmo()

void Slic3r::GUI::DesignSketchTool::render_tf_gizmo ( double unit_per_px)
private
9326{
9327 m_tf_label_a = Vec2d(1e18, 1e18);
9328 m_tf_label_b = Vec2d(1e18, 1e18);
9329 if (!tf_ready()) return;
9330 const ColorRGBA ghostc(0.30f, 0.88f, 0.66f, 0.55f);
9332
9333 const ColorRGBA dc(0.30f, 0.88f, 0.66f, 1.0f);
9334 const ColorRGBA hot(1.0f, 0.85f, 0.2f, 1.0f);
9335 const double th = std::max(15.0 * unit_per_px, 1e-4);
9336 const Vec2d handle = tf_handle_pos();
9337
9338 // spoke from the pivot to the handle (+ arrowhead for the linear ops).
9339 std::vector<std::pair<Vec2d, Vec2d>> segs;
9340 segs.emplace_back(m_tf_pivot, handle);
9342 Vec2d dir = handle - m_tf_pivot; const double L = dir.norm();
9343 if (L > 1e-9) {
9344 dir /= L;
9345 const double as = std::max(L * 0.15, th * 0.8);
9346 const Vec2d nrm(-dir.y(), dir.x());
9347 const Vec2d back = handle - dir * as;
9348 segs.emplace_back(handle, back + nrm * (as * 0.5));
9349 segs.emplace_back(handle, back - nrm * (as * 0.5));
9350 }
9351 }
9352 draw_strokes(m_highlight_model, segs, 0.6, dc);
9353
9354 const double hs = 6.0 * unit_per_px; // screen-constant handle marker
9355 const std::vector<Vec2d> sq = { handle + Vec2d(-hs, -hs), handle + Vec2d(hs, -hs),
9356 handle + Vec2d(hs, hs), handle + Vec2d(-hs, hs) };
9357 draw_fill(m_fill_model, sq, m_tf_dragging ? hot : dc);
9358 draw_vertices(m_vertex_model, { m_tf_pivot }, dc, std::max(3.0 * unit_per_px, 1e-4));
9359
9360 // primary parameter label at the handle.
9361 std::string txt_a;
9363 DimAnnot a; a.kind = DimType::Angle; a.value = std::abs(m_tf_angle) * 180.0 / M_PI;
9364 txt_a = dim_text(a);
9365 } else if (m_mode == Mode::Scale) {
9366 char b[24]; std::snprintf(b, sizeof(b), "x%.2f", m_tf_scale);
9367 for (char& ch : b) if (ch == ',') ch = '.';
9368 txt_a = b;
9369 } else {
9370 DimAnnot a; a.kind = DimType::Distance; a.value = m_tf_delta.norm();
9371 txt_a = dim_text(a);
9372 }
9373 Vec2d outw = handle - m_tf_pivot; if (outw.norm() > 1e-9) outw.normalize(); else outw = Vec2d(1, 0);
9374 m_tf_label_a = handle + outw * (th * 1.2);
9375 draw_text(m_line_model, txt_a, m_tf_label_a, th, dc);
9376
9378 char cb[16]; std::snprintf(cb, sizeof(cb), "x%d", std::max(2, m_tf_count));
9379 m_tf_label_b = m_tf_pivot + Vec2d(th * 1.5, th * 1.5);
9380 draw_text(m_line_model, cb, m_tf_label_b, th, dc);
9381 }
9382}

References Angle, Array, dim_text(), Distance, draw_entities_preview(), draw_fill(), draw_strokes(), draw_text(), draw_vertices(), Slic3r::GUI::DesignSketchTool::DimAnnot::kind, L, m_fill_model, m_highlight_model, m_line_model, m_mode, M_PI, m_tf_angle, m_tf_count, m_tf_delta, m_tf_dragging, m_tf_ghost, m_tf_label_a, m_tf_label_b, m_tf_pivot, m_tf_scale, m_vertex_model, Move, PolarArray, render_tf_gizmo(), Rotate, Scale, tf_handle_pos(), tf_ready(), and Slic3r::GUI::DesignSketchTool::DimAnnot::value.

Referenced by render(), and render_tf_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_thread_gizmo()

void Slic3r::GUI::DesignSketchTool::render_thread_gizmo ( )
private
6440{
6441 if (!m_th_active) return;
6442 const Camera& cam = wxGetApp().plater()->get_camera();
6443 const Vec3d right = cam.get_dir_right().normalized();
6444 const Vec3d up = cam.get_dir_up().normalized();
6445 const double upp = 1.0 / std::max(cam.get_zoom(), 1e-6);
6446 const double th = std::max(15.0 * upp, 1e-4);
6447
6448 const Vec3d centre = m_th_plane.to_world(Vec2d(m_th_x, m_th_y));
6449 const Vec3d nrm = m_th_plane.normal.normalized();
6450 const Vec3d ddir = m_th_plane.x_axis.normalized(); // radius arrow runs along plane u
6451 const double r = std::max(0.01, m_th_radius);
6452
6453 const SketchPlane saved = m_plane;
6454
6455 // (1) Footprint circle on the plane at the nominal radius.
6456 {
6458 std::vector<std::pair<Vec2d, Vec2d>> segs;
6459 const int N = 48;
6460 for (int i = 0; i < N; ++i) {
6461 const double a0 = (2.0 * M_PI * i) / N, a1 = (2.0 * M_PI * (i + 1)) / N;
6462 segs.emplace_back(Vec2d(m_th_x + r * std::cos(a0), m_th_y + r * std::sin(a0)),
6463 Vec2d(m_th_x + r * std::cos(a1), m_th_y + r * std::sin(a1)));
6464 }
6466 draw_strokes(m_th_stroke_model, segs, std::max(0.6 * upp, 1e-4), ColorRGBA(0.55f, 0.80f, 0.30f, 1.0f));
6467 m_plane = saved;
6468 }
6469
6470 // (2) Billboarded handles.
6471 SketchPlane bb; bb.origin = centre; bb.x_axis = right; bb.y_axis = up; bb.normal = cam.get_dir_forward().normalized();
6472 m_plane = bb;
6473 const ColorRGBA green(0.55f, 0.80f, 0.30f, 1.0f);
6474 const ColorRGBA blue (0.30f, 0.55f, 1.0f, 1.0f);
6475
6476 auto arrow_to = [&](const Vec3d& tipw, const ColorRGBA& col, const DimAnnot& da) {
6477 const Vec2d tip2((tipw - centre).dot(right), (tipw - centre).dot(up));
6478 if (tip2.norm() <= 1e-6) return;
6479 const Vec2d u = tip2.normalized();
6480 const Vec2d nrm2(-u.y(), u.x());
6481 std::vector<std::pair<Vec2d, Vec2d>> segs;
6482 segs.emplace_back(Vec2d(0, 0), tip2);
6483 const double as = std::max(tip2.norm() * 0.20, th * 0.9);
6484 const Vec2d back = tip2 - u * as;
6485 segs.emplace_back(tip2, back + nrm2 * (as * 0.5));
6486 segs.emplace_back(tip2, back - nrm2 * (as * 0.5));
6488 draw_strokes(m_th_stroke_model, segs, std::max(0.7 * upp, 1e-4), col);
6489 draw_text(m_line_model, dim_text(da), tip2 + u * (th * 1.4), th, col);
6490 };
6491
6492 { // Radius arrow (R label), floored to a grabbable handle.
6493 const double L = std::max(r, 40.0 * upp);
6494 DimAnnot da; da.kind = DimType::Radius; da.value = m_th_radius;
6495 arrow_to(centre + ddir * L, green, da);
6496 }
6497 { // Length arrow along +normal.
6498 const double L = std::max(m_th_height, 40.0 * upp);
6499 DimAnnot da; da.kind = DimType::Distance; da.value = m_th_height;
6500 arrow_to(centre + nrm * L, blue, da);
6501 }
6502 { // Centre marker.
6503 const double s = 7.0 * upp;
6504 std::vector<std::pair<Vec2d, Vec2d>> segs;
6505 segs.emplace_back(Vec2d(-s, -s), Vec2d(s, -s));
6506 segs.emplace_back(Vec2d( s, -s), Vec2d(s, s));
6507 segs.emplace_back(Vec2d( s, s), Vec2d(-s, s));
6508 segs.emplace_back(Vec2d(-s, s), Vec2d(-s, -s));
6510 draw_strokes(m_th_stroke_model, segs, std::max(0.7 * upp, 1e-4), green);
6511 }
6512
6513 m_plane = saved;
6514}
GLModel m_th_stroke_model
Definition DesignSketchTool.hpp:1546

References dim_text(), Distance, Slic3r::dot(), draw_strokes(), draw_text(), Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_right(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_DEPTH_TEST, glDisable, glsafe, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, L, m_line_model, M_PI, m_plane, m_th_active, m_th_height, m_th_plane, m_th_radius, m_th_stroke_model, m_th_x, m_th_y, Slic3r::GUI::N, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, Radius, render_thread_gizmo(), Slic3r::GUI::DesignSketchTool::DimAnnot::value, Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_thread_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_view_helpers()

void Slic3r::GUI::DesignSketchTool::render_view_helpers ( )
private
4308{
4309 if (!m_show_planes && !m_show_axes) return;
4312 const Camera& cam = wxGetApp().plater()->get_camera();
4313 const Vec3d vd = cam.get_dir_forward();
4314 const double hw = 1.5 / std::max(cam.get_zoom(), 1e-6); // billboard ribbon half-width (px)
4315
4319
4320 if (m_show_planes) {
4321 const double H = 40.0; // half-extent (mm)
4322 SketchPlane pl[3]; // XY / XZ / YZ through the world origin
4323 pl[0].origin = Vec3d(0,0,0); pl[0].x_axis = Vec3d(1,0,0); pl[0].y_axis = Vec3d(0,1,0); pl[0].normal = Vec3d(0,0,1);
4324 pl[1].origin = Vec3d(0,0,0); pl[1].x_axis = Vec3d(1,0,0); pl[1].y_axis = Vec3d(0,0,1); pl[1].normal = Vec3d(0,1,0);
4325 pl[2].origin = Vec3d(0,0,0); pl[2].x_axis = Vec3d(0,1,0); pl[2].y_axis = Vec3d(0,0,1); pl[2].normal = Vec3d(1,0,0);
4326 GLModel::Geometry fill; fill.format = { EPT::Triangles, EVL::P3 };
4327 unsigned int fb = 0;
4328 for (const SketchPlane& p : pl) {
4329 const Vec3d c[4] = { p.to_world(Vec2d(-H,-H)), p.to_world(Vec2d(H,-H)),
4330 p.to_world(Vec2d(H,H)), p.to_world(Vec2d(-H,H)) };
4331 fill.add_vertex((Vec3f)c[0].cast<float>()); fill.add_vertex((Vec3f)c[1].cast<float>());
4332 fill.add_vertex((Vec3f)c[2].cast<float>()); fill.add_triangle(fb, fb+1, fb+2); fb += 3;
4333 fill.add_vertex((Vec3f)c[0].cast<float>()); fill.add_vertex((Vec3f)c[2].cast<float>());
4334 fill.add_vertex((Vec3f)c[3].cast<float>()); fill.add_triangle(fb, fb+1, fb+2); fb += 3;
4335 }
4336 if (fb > 0) { GLModel fm; fm.init_from(std::move(fill));
4337 fm.set_color(ColorRGBA(0.42f, 0.52f, 0.78f, 0.20f)); fm.render(); }
4338 }
4339
4340 if (m_show_axes) {
4341 const double L = 60.0; // axis length (mm)
4342 struct Ax { Vec3d dir; ColorRGBA col; };
4343 const Ax axes[3] = { { Vec3d(1,0,0), ColorRGBA(0.92f, 0.28f, 0.28f, 0.9f) },
4344 { Vec3d(0,1,0), ColorRGBA(0.30f, 0.80f, 0.34f, 0.9f) },
4345 { Vec3d(0,0,1), ColorRGBA(0.32f, 0.55f, 0.95f, 0.9f) } };
4346 for (const Ax& ax : axes) {
4347 // Lines don't rasterise under the reused software GL context, so each axis is a
4348 // thin view-facing ribbon (two triangles), like the datum-plane border.
4349 const Vec3d a = Vec3d(0,0,0), b = ax.dir * L;
4350 Vec3d dir = (b - a).normalized();
4351 Vec3d off = dir.cross(vd);
4352 if (off.norm() < 1e-9) off = dir.cross(cam.get_dir_up());
4353 if (off.norm() < 1e-9) continue;
4354 off.normalize(); off *= hw * 1.5;
4355 GLModel::Geometry g; g.format = { EPT::Triangles, EVL::P3 };
4356 g.add_vertex((Vec3f)(a + off).cast<float>()); g.add_vertex((Vec3f)(b + off).cast<float>());
4357 g.add_vertex((Vec3f)(b - off).cast<float>()); g.add_vertex((Vec3f)(a - off).cast<float>());
4358 g.add_triangle(0, 1, 2); g.add_triangle(0, 2, 3);
4359 GLModel m; m.init_from(std::move(g)); m.set_color(ax.col); m.render();
4360 }
4361 }
4363}

References Slic3r::GUI::GLModel::Geometry::add_triangle(), Slic3r::GUI::GLModel::Geometry::add_vertex(), Slic3r::cast(), Slic3r::GUI::GLModel::Geometry::format, Slic3r::GUI::Camera::get_dir_forward(), Slic3r::GUI::Camera::get_dir_up(), Slic3r::GUI::Camera::get_zoom(), GL_BLEND, GL_DEPTH_TEST, GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA, glBlendFunc, glDisable, glEnable, glsafe, Slic3r::GUI::GLModel::init_from(), L, m_show_axes, m_show_planes, Slic3r::SketchPlane::normal, Slic3r::SketchPlane::origin, Slic3r::GUI::GLModel::render(), render_view_helpers(), Slic3r::GUI::GLModel::set_color(), Slic3r::SketchPlane::x_axis, and Slic3r::SketchPlane::y_axis.

Referenced by render(), and render_view_helpers().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ render_xform_gizmo()

void Slic3r::GUI::DesignSketchTool::render_xform_gizmo ( )
private
8672{
8673 if (m_mode != Mode::TransformArt) return;
8674 Vec2d c[4]; xform_world_corners(c);
8675 const ColorRGBA box(0.30f, 0.88f, 0.66f, 1.0f);
8676 std::vector<std::pair<Vec2d, Vec2d>> segs;
8677 for (int i = 0; i < 4; ++i) segs.emplace_back(c[i], c[(i + 1) % 4]);
8678 draw_strokes(m_highlight_model, segs, 0.6, box);
8679 const Camera& cam = wxGetApp().plater()->get_camera();
8680 const double hs = 7.0 / std::max(cam.get_zoom(), 1e-6); // screen-constant half-size
8681 const ColorRGBA hcol(0.30f, 0.88f, 0.66f, 1.0f);
8682 const ColorRGBA hhot(1.0f, 0.85f, 0.2f, 1.0f);
8683 auto square = [&](const Vec2d& q, const ColorRGBA& col) {
8684 const std::vector<Vec2d> sq = { q + Vec2d(-hs, -hs), q + Vec2d(hs, -hs),
8685 q + Vec2d(hs, hs), q + Vec2d(-hs, hs) };
8686 draw_fill(m_fill_model, sq, col);
8687 };
8688 for (int i = 0; i < 4; ++i) square(c[i], m_xform_handle == i ? hhot : hcol);
8689 square(0.5 * (c[0] + c[2]), m_xform_handle == 4 ? hhot : hcol);
8690}

References draw_fill(), draw_strokes(), Slic3r::GUI::Camera::get_zoom(), m_fill_model, m_highlight_model, m_mode, m_xform_handle, render_xform_gizmo(), TransformArt, and xform_world_corners().

Referenced by render(), and render_xform_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ request_exit()

void Slic3r::GUI::DesignSketchTool::request_exit ( )
456{
457 if (abort_gesture()) return;
458 if (disarm_tool()) return;
459 if (live_sketch_has_work()) { if (on_exit_refused) on_exit_refused(); return; }
460 if (on_exit) on_exit();
461 else cancel();
462}
bool abort_gesture()
Definition DesignSketchTool.cpp:410
std::function< void()> on_exit
Definition DesignSketchTool.hpp:723
std::function< void()> on_exit_refused
Definition DesignSketchTool.hpp:726
bool disarm_tool()
Definition DesignSketchTool.cpp:435
bool live_sketch_has_work() const
Definition DesignSketchTool.hpp:151

References abort_gesture(), cancel(), disarm_tool(), live_sketch_has_work(), on_exit, and on_exit_refused.

Here is the call graph for this function:

◆ reset_autoedit()

void Slic3r::GUI::DesignSketchTool::reset_autoedit ( )
inline
628 {
629 m_awaiting_length = false;
630 m_autoedit_pending = false;
631 m_autoedit_dims.clear();
633 m_autoedit_seen = int(m_entities.size());
634 m_live_quotes.clear(); // rebuilt from current geometry on the next render
635 }

References m_autoedit_dim_idx, m_autoedit_dims, m_autoedit_pending, m_autoedit_seen, m_awaiting_length, m_entities, and m_live_quotes.

Referenced by add_imported_regions(), close_session_chrome(), delete_selected(), redo_last_entity(), set_tool(), and undo_last_entity().

Here is the caller graph for this function:

◆ reset_op()

void Slic3r::GUI::DesignSketchTool::reset_op ( )
private
8550{
8551 m_op_a = m_op_b = -1;
8552 m_op_value = 0.0;
8553 m_op_anchor = Vec2d(0, 0);
8554 m_op_dir = Vec2d(0, 0);
8555 m_op_label = Vec2d(1e18, 1e18);
8556 m_op_ghost.clear();
8557 m_op_dragging_arrow = false;
8558 m_mirror_targets.clear();
8559 m_op_chain.clear();
8560}

References m_mirror_targets, m_op_a, m_op_anchor, m_op_b, m_op_chain, m_op_dir, m_op_dragging_arrow, m_op_ghost, m_op_label, m_op_value, and reset_op().

Referenced by abort_gesture(), cancel(), confirm_op(), disarm_tool(), on_mouse_impl(), reset_op(), and set_tool().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reset_tf()

void Slic3r::GUI::DesignSketchTool::reset_tf ( )
private
9113{
9114 m_tf_targets.clear();
9115 m_tf_pivot = Vec2d(0, 0);
9116 m_tf_delta = Vec2d(0, 0);
9117 m_tf_angle = 0.0;
9118 m_tf_scale = 1.0;
9119 m_tf_count = 3;
9120 m_tf_handle_r = 1.0;
9121 m_tf_ghost.clear();
9122 m_tf_handle = -1;
9123 m_tf_dragging = false;
9124 m_tf_label_a = Vec2d(1e18, 1e18);
9125 m_tf_label_b = Vec2d(1e18, 1e18);
9126}
int m_tf_handle
Definition DesignSketchTool.hpp:1216

References m_tf_angle, m_tf_count, m_tf_delta, m_tf_dragging, m_tf_ghost, m_tf_handle, m_tf_handle_r, m_tf_label_a, m_tf_label_b, m_tf_pivot, m_tf_scale, m_tf_targets, and reset_tf().

Referenced by abort_gesture(), cancel(), confirm_transform(), disarm_tool(), on_mouse_impl(), reset_tf(), and set_tool().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ reset_xform()

void Slic3r::GUI::DesignSketchTool::reset_xform ( )
private
8573{
8574 m_xform_base.clear();
8575 m_xform_feat = -1;
8576 m_xform_handle = -1;
8577 m_xform_offset = Vec2d(0, 0);
8578 m_xform_sx = m_xform_sy = 1.0;
8579 m_xform_min = m_xform_max = Vec2d(0, 0);
8580}

References m_xform_base, m_xform_feat, m_xform_handle, m_xform_max, m_xform_min, m_xform_offset, m_xform_sx, m_xform_sy, and reset_xform().

Referenced by cancel(), reset_xform(), and set_tool().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resolve_live()

void Slic3r::GUI::DesignSketchTool::resolve_live ( )
private

References Slic3r::P0, and resolve_live_drag().

Referenced by add_entities_scripted(), add_imported_regions(), apply_dimension(), apply_segment_length(), begin_edit(), confirm_op(), confirm_transform(), delete_selected(), drag_arc_handle(), drag_ellipsearc_handle(), heal_coincidences(), infer_auto_constraints(), on_mouse_impl(), open_primary_autoedit(), place_dimension(), redo_last_entity(), remove_constraint(), set_arc_slot(), set_arc_sweep(), set_dimension_value(), set_ellipse_axis(), set_ellipsearc_sweep(), set_handle(), set_line_angle(), set_rounded_rect(), set_slot(), and set_slot_angle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resolve_live_drag()

void Slic3r::GUI::DesignSketchTool::resolve_live_drag ( int dragged_ei,
SketchPointRole dragged_role )
private
874{
875 const bool has = !m_constraints.empty();
876 m_entity_conflict.assign(m_entities.size(), 0);
877 if (has) {
878 // Dragging a line endpoint must move ONLY that endpoint (changing the line's angle +
879 // length), anchoring the other end — Onshape behaviour. Without this, a constraint on
880 // the line (e.g. a length dimension or an inferred H/V) lets the solver relocate the
881 // un-dragged endpoint too, so the whole line appears to shift. Temporarily Fix the
882 // opposite endpoint for this drag-solve only (set_point already moved just the grabbed
883 // point, so the other end's current coord is its anchor).
884 std::vector<SketchEntityConstraintDef> cons = m_constraints;
885 const bool line_end = dragged_ei >= 0 && dragged_ei < int(m_entities.size()) &&
886 m_entities[dragged_ei].type == SketchEntity::Type::Line &&
887 (dragged_role == SketchPointRole::P0 || dragged_role == SketchPointRole::P1);
888 if (line_end) {
889 SketchEntityConstraintDef fix;
890 fix.type = SketchConstraintType::Fix;
891 fix.ea = dragged_ei;
892 fix.ra = (dragged_role == SketchPointRole::P0) ? SketchPointRole::P1
894 cons.push_back(fix);
895 }
896 const SketchSolveResult r = (dragged_ei >= 0)
897 ? sketch_solve_drag(m_entities, cons, dragged_ei, dragged_role)
898 : sketch_solve(m_entities, cons);
899 m_dof = r.dof;
900 m_solve_ok = r.ok;
901 // Constraints the solver had to leave out (no representation for the part they name)
902 // are said once, when their number changes — resolve_live runs on every drag frame.
903 if (int(r.skipped.size()) != m_skipped_last) {
904 m_skipped_last = int(r.skipped.size());
905 if (m_skipped_last > 0)
906 notify(format(into_u8(_L_PLURAL("%1% constraint cannot act on this geometry (an ellipse or spline curve, "
907 "or a zero-size circle) and is ignored",
908 "%1% constraints cannot act on this geometry (an ellipse or spline curve, "
909 "or a zero-size circle) and are ignored", m_skipped_last)),
910 m_skipped_last), false);
911 }
912 // Flag every entity referenced by a conflicting constraint so render() can
913 // tint it red (Onshape/SolveSpace over-constrained feedback), and remember which
914 // DIMENSIONS those constraints drive: a label showing a value the geometry does not have
915 // is the one thing the user must be able to see, and r.bad names it.
916 m_bad_dims.clear();
917 for (int bi : r.bad) {
918 if (bi < 0 || bi >= int(m_constraints.size())) continue;
919 const SketchEntityConstraintDef& c = m_constraints[bi];
920 for (int e : {c.ea, c.eb, c.ec})
921 if (e >= 0 && e < int(m_entity_conflict.size())) m_entity_conflict[e] = 1;
922 for (int di = 0; di < int(m_dimensions.size()); ++di)
923 if (m_dimensions[di].con == bi) m_bad_dims.push_back(di);
924 }
925 } else {
926 m_dof = -1; m_solve_ok = true;
927 m_bad_dims.clear();
928 }
931}
void announce_loop_defects()
Definition DesignSketchTool.cpp:936
int m_skipped_last
Definition DesignSketchTool.hpp:1159
std::function< void(int dof, bool ok, bool has_constraints)> on_solve_state
Definition DesignSketchTool.hpp:548
SketchSolveResult sketch_solve_drag(std::vector< SketchEntity > &entities, const std::vector< SketchEntityConstraintDef > &constraints, int dragged_ei, SketchPointRole dragged_role)
Definition SketchSolver.cpp:678
SketchSolveResult sketch_solve(std::vector< SketchEntity > &entities, const std::vector< SketchEntityConstraintDef > &constraints)
Definition SketchSolver.cpp:672

References _L_PLURAL, announce_loop_defects(), Slic3r::SketchSolveResult::bad, Slic3r::SketchSolveResult::dof, Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, Slic3r::SketchEntityConstraintDef::ec, Slic3r::Fix, Slic3r::GUI::format(), Slic3r::GUI::into_u8(), Slic3r::SketchEntity::Line, m_bad_dims, m_constraints, m_dimensions, m_dof, m_entities, m_entity_conflict, m_skipped_last, m_solve_ok, notify(), Slic3r::SketchSolveResult::ok, on_solve_state, Slic3r::P0, Slic3r::P1, Slic3r::SketchEntityConstraintDef::ra, Slic3r::sketch_solve(), Slic3r::sketch_solve_drag(), Slic3r::SketchSolveResult::skipped, and Slic3r::SketchEntityConstraintDef::type.

Referenced by on_mouse_impl(), resolve_live(), and set_handle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resolve_solid_pick()

bool Slic3r::GUI::DesignSketchTool::resolve_solid_pick ( GLCanvas3D & canvas,
int mx,
int my,
SolidPick & out ) const
private
3951{
3952 out = SolidPick{};
3953 if (m_solid_bodies == nullptr || m_solid_mesh == nullptr) {
3954 dp_pick_trace("no solid data (bodies=%p mesh=%p)",
3955 (const void*) m_solid_bodies, (const void*) m_solid_mesh);
3956 return false;
3957 }
3958 const Linef3 r = canvas.mouse_ray(Point(mx, my));
3959 const Vec3d ro = r.a, rd = r.b - r.a;
3960
3961 // 1) nearest solid face under the cursor (ray vs display-mesh triangles). Resolve WHICH
3962 // body and which face-within-that-body via the per-triangle (tri_body, tri_face) tags.
3963 const indexed_triangle_set& its = m_solid_mesh->its;
3964 int best_face = -1, best_body = -1; double best_t = 1e30;
3965 for (size_t i = 0; i < its.indices.size(); ++i) {
3966 const auto& idx = its.indices[i];
3967 const Vec3d v0 = its.vertices[idx(0)].cast<double>();
3968 const Vec3d v1 = its.vertices[idx(1)].cast<double>();
3969 const Vec3d v2 = its.vertices[idx(2)].cast<double>();
3970 double t;
3971 if (ray_triangle(ro, rd, v0, v1, v2, t) && t < best_t) {
3972 const int cand_body = (m_solid_tri_body && i < m_solid_tri_body->size()) ? (*m_solid_tri_body)[i] : -1;
3973 if (!body_pickable(cand_body)) continue; // hidden bodies don't catch clicks
3974 best_t = t;
3975 best_face = (m_solid_tri_face && i < m_solid_tri_face->size()) ? (*m_solid_tri_face)[i] : -1;
3976 best_body = cand_body;
3977 }
3978 }
3979 dp_pick_trace("ray tris=%zu -> body=%d face=%d t=%.3f", its.indices.size(),
3980 best_body, best_face, best_t);
3981 if (best_face < 0 || best_body < 0 || best_body >= int(m_solid_bodies->size()))
3982 return false; // missed the solid
3983
3984 // ---- one click, one deterministic result ---------------------------------------------
3985 // NO CYCLE. A click selects the SMALLEST thing under the cursor: the edge if the pointer is
3986 // within tolerance of one, otherwise the face. The WHOLE body is taken by a left-drag
3987 // rubber band (pick_bodies_in_rectangle) — a different gesture for a different scale.
3988 //
3989 // What this replaces: click 1 = whole body, click 2 = face, click 3 = nearest edge, click 4
3990 // = back to whole. That made "click a face" a two-click gesture and "click an edge" a
3991 // three-click one, neither discoverable — the L5 violation §10 of the charter already
3992 // listed, and the real reason sketching on a face kept reading as broken however often the
3993 // plane resolution was fixed. Selection is the foundation the tool offer stands on: the
3994 // offer can only ever be as truthful as the selection beneath it.
3995 //
3996 // Tolerance is measured in SCREEN PIXELS. The old edge step compared a ray-to-segment
3997 // distance in millimetres, so the same gesture meant different things at different zooms —
3998 // the pointer is a screen object and its tolerance has to be one too.
3999 const Camera& cam = wxGetApp().plater()->get_camera();
4000 const wxPoint cursor(mx, my);
4001 // Vertex beats edge beats face, and the vertex tolerance is the larger of the two: a corner
4002 // sits ON its edges, so an equal radius would make vertices unreachable — every click near
4003 // one would resolve to the edge it lies on.
4004 const double kVertexTolPx = 11.0;
4005 const double kEdgeTolPx = 8.0;
4006
4007 auto seg_px = [](const wxPoint& p, const wxPoint& a, const wxPoint& b) { // 2D point→segment, px
4008 const double vx = b.x - a.x, vy = b.y - a.y;
4009 const double wx = p.x - a.x, wy = p.y - a.y;
4010 const double L2 = vx * vx + vy * vy;
4011 double t = (L2 > 1e-12) ? (wx * vx + wy * vy) / L2 : 0.0;
4012 t = std::max(0.0, std::min(1.0, t));
4013 return std::hypot(wx - t * vx, wy - t * vy);
4014 };
4015
4016 out.body = best_body;
4017 out.face = best_face;
4018
4019 {
4020 const TopoDS_Shape& bshape = (*m_solid_bodies)[out.body].shape;
4021 const TopoDS_Face face = GeometryEngine::face_by_index(bshape, out.face);
4022 double best_ed = 1e30; std::vector<Vec3d> ed_pts; TopoDS_Edge ed_edge; bool have_edge = false;
4023 double best_vd = 1e30; Vec3d vtx = Vec3d::Zero(); bool have_vtx = false;
4024 // Screen extent of the face, accumulated from the same edge samples the loop already
4025 // takes. A FIXED edge tolerance makes a narrow face unreachable: a 3 mm-wide plate is
4026 // barely wider on screen than the 8 px budget, so every point on it is "on an edge" and
4027 // the face level can never be picked — which also blocks the face-based Coord Sys that a
4028 // mate needs. The tolerances below shrink with the face so its middle stays its own.
4029 int fx0 = INT_MAX, fy0 = INT_MAX, fx1 = INT_MIN, fy1 = INT_MIN;
4030 if (!face.IsNull()) {
4031 for (const TopoDS_Edge& e : GeometryEngine::edges_of_face(face)) {
4032 std::vector<Vec3d> pts = GeometryEngine::sample_edge_world(e);
4033 for (Vec3d& q : pts) q = body_xform_pt(out.body, q); // follow a moved body
4034 if (pts.size() < 2) continue;
4035 // The polyline ends ARE the edge's vertices; every corner of the face is the
4036 // end of one of its edges, so this covers them without a separate topology walk.
4037 for (const Vec3d& v : {pts.front(), pts.back()}) {
4038 const wxPoint sp = world_to_screen_px(cam, v);
4039 if (sp.x < 0) continue;
4040 const double d = std::hypot(double(sp.x - cursor.x), double(sp.y - cursor.y));
4041 if (d < best_vd) { best_vd = d; vtx = v; have_vtx = true; }
4042 }
4043 double d = 1e30;
4044 for (size_t s = 1; s < pts.size(); ++s) {
4045 const wxPoint a = world_to_screen_px(cam, pts[s - 1]);
4046 const wxPoint b = world_to_screen_px(cam, pts[s]);
4047 if (a.x < 0 || b.x < 0) continue; // behind the camera
4048 fx0 = std::min({fx0, a.x, b.x}); fx1 = std::max({fx1, a.x, b.x});
4049 fy0 = std::min({fy0, a.y, b.y}); fy1 = std::max({fy1, a.y, b.y});
4050 d = std::min(d, seg_px(cursor, a, b));
4051 }
4052 if (d < best_ed) { best_ed = d; ed_pts = pts; ed_edge = e; have_edge = true; }
4053 }
4054 }
4055 // A third of the face's SHORTER on-screen side, so the two tolerances can never meet in
4056 // the middle. Only ever shrinks: a face big enough keeps the full budget.
4057 double vtol = kVertexTolPx, etol = kEdgeTolPx;
4058 if (fx1 > fx0 && fy1 > fy0) {
4059 const double narrow = double(std::min(fx1 - fx0, fy1 - fy0)) / 3.0;
4060 vtol = std::min(vtol, narrow);
4061 etol = std::min(etol, narrow);
4062 }
4063 if (have_vtx && best_vd <= vtol) {
4064 out.vertex_pt = vtx;
4065 out.kind = SolidSel::Vertex;
4066 } else if (have_edge && best_ed <= etol) {
4067 // Promote the face-relative pick to a STABLE GLOBAL edge id so dress-up ops
4068 // (fillet/chamfer) can target this exact edge across recomputes.
4069 out.edge = GeometryEngine::edge_index_of(bshape, ed_edge);
4070 out.edge_pts = std::move(ed_pts);
4071 out.kind = SolidSel::Edge;
4072 } else {
4073 out.kind = SolidSel::Face;
4074 }
4075 }
4076 return true;
4077}
static TopoDS_Face face_by_index(const TopoDS_Shape &shape, int index)
Definition GeometryEngine.cpp:534
static std::vector< TopoDS_Edge > edges_of_face(const TopoDS_Face &face)
Definition GeometryEngine.cpp:565
static std::vector< Vec3d > sample_edge_world(const TopoDS_Edge &edge, double chord_tol=0.05)
Definition GeometryEngine.cpp:575
static int edge_index_of(const TopoDS_Shape &shape, const TopoDS_Edge &edge)
Definition GeometryEngine.cpp:726
static bool ray_triangle(const Vec3d &ro, const Vec3d &rd, const Vec3d &v0, const Vec3d &v1, const Vec3d &v2, double &t)
Definition DesignSketchTool.cpp:10304

References Slic3r::Linef3::a, Slic3r::Linef3::b, Slic3r::GUI::DesignSketchTool::SolidPick::body, body_pickable(), body_xform_pt(), Slic3r::GUI::dp_pick_trace(), Edge, Slic3r::GUI::DesignSketchTool::SolidPick::edge, Slic3r::GeometryEngine::edge_index_of(), Slic3r::GUI::DesignSketchTool::SolidPick::edge_pts, Slic3r::GeometryEngine::edges_of_face(), Face, Slic3r::GUI::DesignSketchTool::SolidPick::face, Slic3r::GeometryEngine::face_by_index(), Slic3r::GUI::DesignSketchTool::SolidPick::kind, m_solid_bodies, m_solid_mesh, m_solid_tri_body, m_solid_tri_face, Slic3r::GUI::GLCanvas3D::mouse_ray(), Slic3r::GUI::ray_triangle(), resolve_solid_pick(), Slic3r::GeometryEngine::sample_edge_world(), Vertex, Slic3r::GUI::DesignSketchTool::SolidPick::vertex_pt, and Slic3r::GUI::world_to_screen_px().

Referenced by handle_solid_click(), resolve_solid_pick(), and update_solid_hover().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ revolving()

bool Slic3r::GUI::DesignSketchTool::revolving ( ) const
inline
460{ return m_rv_active; }

References m_rv_active.

◆ right_abandon()

bool Slic3r::GUI::DesignSketchTool::right_abandon ( )
10760{
10761 if (m_points.empty())
10762 return false; // hand it back, so the canvas opens the offer
10763 m_points.clear();
10764 m_has_cursor = false;
10765 return true;
10766}

References m_has_cursor, m_points, and right_abandon().

Referenced by on_mouse_impl(), and right_abandon().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ring_basis()

void Slic3r::GUI::DesignSketchTool::ring_basis ( int axis,
Vec3d & e,
Vec3d & u,
Vec3d & v ) const
private
5855{
5856 switch (axis) {
5857 case 0: e = Vec3d::UnitX(); u = Vec3d::UnitY(); v = Vec3d::UnitZ(); break;
5858 case 1: e = Vec3d::UnitY(); u = Vec3d::UnitZ(); v = Vec3d::UnitX(); break;
5859 default:e = Vec3d::UnitZ(); u = Vec3d::UnitX(); v = Vec3d::UnitY(); break;
5860 }
5861}

References ring_basis().

Referenced by arc_mouse_angle(), drag_move_arc(), hit_test_move_arc(), render_move_gizmo(), and ring_basis().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ rounded_rect_entities()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::rounded_rect_entities ( double xmin,
double ymin,
double xmax,
double ymax,
double r ) const
private
3155{
3156 std::vector<SketchEntity> out;
3157 auto line = [&](const Vec2d& p0, const Vec2d& p1) {
3158 SketchEntity e; e.type = SketchEntity::Type::Line; e.p0 = p0; e.p1 = p1;
3159 e.construction = m_construction; return e; };
3160 auto corner = [&](const Vec2d& O, const Vec2d& sharp, const Vec2d& start, const Vec2d& end) {
3161 const Vec2d thr = O + r * (sharp - O).normalized();
3162 return make_arc_through(O, r, start, end, thr, m_construction); };
3163 out.push_back(line({xmin + r, ymin}, {xmax - r, ymin})); // bottom
3164 out.push_back(corner({xmax - r, ymin + r}, {xmax, ymin}, {xmax - r, ymin}, {xmax, ymin + r})); // BR
3165 out.push_back(line({xmax, ymin + r}, {xmax, ymax - r})); // right
3166 out.push_back(corner({xmax - r, ymax - r}, {xmax, ymax}, {xmax, ymax - r}, {xmax - r, ymax})); // TR
3167 out.push_back(line({xmax - r, ymax}, {xmin + r, ymax})); // top
3168 out.push_back(corner({xmin + r, ymax - r}, {xmin, ymax}, {xmin + r, ymax}, {xmin, ymax - r})); // TL
3169 out.push_back(line({xmin, ymax - r}, {xmin, ymin + r})); // left
3170 out.push_back(corner({xmin + r, ymin + r}, {xmin, ymin}, {xmin, ymin + r}, {xmin + r, ymin})); // BL
3171 return out;
3172}

References Slic3r::SketchEntity::construction, Slic3r::SketchEntity::Line, m_construction, Slic3r::GUI::make_arc_through(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, rounded_rect_entities(), and Slic3r::SketchEntity::type.

Referenced by make_rounded_rect(), rounded_rect_entities(), and set_rounded_rect().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ screen_to_plane()

bool Slic3r::GUI::DesignSketchTool::screen_to_plane ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
Vec2d & out ) const
private
2532{
2533 Point pos(evt.GetX(), evt.GetY());
2534 Linef3 r = canvas.mouse_ray(pos);
2535 out = m_plane.project(r.a, r.vector());
2536 return true;
2537}

References Slic3r::Linef3::a, m_plane, Slic3r::GUI::GLCanvas3D::mouse_ray(), screen_to_plane(), Slic3r::Linef3::vector(), and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse_impl(), screen_to_plane(), and update_hover().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ screen_tol()

double Slic3r::GUI::DesignSketchTool::screen_tol ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
const Vec2d & at,
double px = kPickPx ) const
private
2593{
2594 // Project a point `px` screen pixels away and measure the gap in plane units.
2595 const Linef3 r2 = canvas.mouse_ray(Point(evt.GetX() + int(px), evt.GetY()));
2596 const Vec2d p2 = m_plane.project(r2.a, r2.vector());
2597 return std::max(1e-3, (p2 - at).norm());
2598}

References Slic3r::Linef3::a, m_plane, Slic3r::GUI::GLCanvas3D::mouse_ray(), screen_tol(), Slic3r::Linef3::vector(), and Slic3r::GUI::wxMouseEvent.

Referenced by infer_at(), on_mouse_impl(), screen_tol(), snap_chain_start(), and update_hover().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_at_screen()

bool Slic3r::GUI::DesignSketchTool::select_at_screen ( GLCanvas3D & canvas,
int sx,
int sy )
10659{
10660 if (!is_active()) return false;
10661 const Linef3 ray = canvas.mouse_ray(Point(sx, sy));
10662 const Linef3 ray8 = canvas.mouse_ray(Point(sx + 8, sy));
10663 const Vec2d p = m_plane.project(ray.a, ray.vector());
10664 const Vec2d p8 = m_plane.project(ray8.a, ray8.vector());
10665 const double tol = std::max(1e-3, (p8 - p).norm());
10666
10667 // A point handle beats the curve it belongs to, same precedence the left-click pick uses.
10668 int ei = -1; SketchPointRole role = SketchPointRole::P0;
10669 if (hit_test_point(p, tol, ei, role)) {
10670 // A Point ENTITY is its own handle: there is nothing else to select there. Taking the
10671 // handle branch for it filled m_point_sel and left m_selection empty — and the offer
10672 // counts only m_selection, so right-clicking a sketch point produced the EMPTY
10673 // vocabulary and every SkPoint row in the atlas was unreachable from the menu. Other
10674 // entities keep the handle pick: a line's endpoint is a drag target, not a thing with a
10675 // vocabulary of its own. lnri.
10676 if (ei >= 0 && ei < int(m_entities.size())
10677 && m_entities[ei].type == SketchEntity::Type::Point) {
10678 if (std::find(m_selection.begin(), m_selection.end(), ei) != m_selection.end())
10679 return false; // already selected: leave it alone
10680 m_selection.assign(1, ei);
10681 m_point_sel.clear();
10683 return true;
10684 }
10685 const auto pr = std::make_pair(ei, role);
10686 if (std::find(m_point_sel.begin(), m_point_sel.end(), pr) != m_point_sel.end())
10687 return false; // already selected: leave it alone
10688 m_selection.clear();
10689 m_point_sel.assign(1, pr);
10691 return true;
10692 }
10693
10694 const int hit = hit_test(p, tol);
10695 if (hit < 0) return false;
10696 if (std::find(m_selection.begin(), m_selection.end(), hit) != m_selection.end())
10697 return false; // already selected: leave it alone
10698 m_selection.assign(1, hit);
10699 m_point_sel.clear();
10701 return true;
10702}
bool is_active() const
Definition DesignSketchTool.hpp:181

References Slic3r::Linef3::a, hit_test(), hit_test_point(), is_active(), m_entities, m_plane, m_point_sel, m_selection, Slic3r::GUI::GLCanvas3D::mouse_ray(), on_selection_changed, Slic3r::P0, Slic3r::SketchEntity::Point, select_at_screen(), and Slic3r::Linef3::vector().

Referenced by select_at_screen().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_body()

void Slic3r::GUI::DesignSketchTool::select_body ( int body)
3654{
3655 // Hidden bodies aren't highlighted (the tint overlay would otherwise draw over a
3656 // body whose GLVolume is off, leaving a ghost after a hide).
3657 if (m_solid_bodies == nullptr || body < 0 || body >= int(m_solid_bodies->size())
3658 || !body_pickable(body)) {
3660 return;
3661 }
3662 m_sel_body = body;
3663 m_sel_shape = (*m_solid_bodies)[body].shape;
3664 m_sel_face = m_sel_edge = -1;
3665 m_sel_edge_pts.clear();
3666 m_sel_edges_more.clear();
3667 m_sel_edges_more_pts.clear();
3668 m_solid_sel = SolidSel::Whole; // the canvas fills just this body, render_solid_highlight outlines it
3669}

References body_pickable(), clear_solid_selection(), m_sel_body, m_sel_edge, m_sel_edge_pts, m_sel_edges_more, m_sel_edges_more_pts, m_sel_face, m_sel_shape, m_solid_bodies, m_solid_sel, select_body(), and Whole.

Referenced by handle_solid_click(), pick_bodies_in_rectangle(), and select_body().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ select_indices()

bool Slic3r::GUI::DesignSketchTool::select_indices ( const std::vector< int > & idx)
10480{
10481 m_selection.clear();
10482 m_point_sel.clear();
10483 const int n = int(m_entities.size());
10484 for (int i : idx)
10485 if (i >= 0 && i < n &&
10486 std::find(m_selection.begin(), m_selection.end(), i) == m_selection.end())
10487 m_selection.push_back(i);
10489 return !m_selection.empty();
10490}

References m_entities, m_point_sel, m_selection, on_selection_changed, and select_indices().

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_construction(), Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_delete(), Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_select(), and select_indices().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ selected_constrain_entities()

bool Slic3r::GUI::DesignSketchTool::selected_constrain_entities ( int & e0,
int & e1 ) const
inline
510{ e0 = m_pick0; e1 = m_pick1; return m_pick0 >= 0; }

References m_pick0, and m_pick1.

◆ selected_edges()

std::vector< int > Slic3r::GUI::DesignSketchTool::selected_edges ( ) const
3646{
3647 if (m_solid_sel != SolidSel::Edge || m_sel_edge < 0) return {};
3648 std::vector<int> out = m_sel_edges_more;
3649 out.push_back(m_sel_edge);
3650 return out;
3651}

References Edge, m_sel_edge, m_sel_edges_more, m_solid_sel, and selected_edges().

Referenced by handle_solid_click(), and selected_edges().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ selected_faces()

std::vector< std::pair< int, int > > Slic3r::GUI::DesignSketchTool::selected_faces ( ) const
3740{
3741 std::vector<std::pair<int, int>> out = picked_faces();
3742 for (const FaceHighlight& h : m_hl_faces)
3743 if (is_current_shape(h.body, h.shape))
3744 for (int f : h.faces)
3745 out.emplace_back(h.body, f);
3746 std::sort(out.begin(), out.end());
3747 out.erase(std::unique(out.begin(), out.end()), out.end());
3748 return out;
3749}

References Slic3r::f(), is_current_shape(), m_hl_faces, picked_faces(), and selected_faces().

Referenced by selected_faces(), and selection_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ selected_loop_entities()

std::vector< SketchEntity > Slic3r::GUI::DesignSketchTool::selected_loop_entities ( ) const
3428{
3429 if (m_display_pick < 0 || m_display_pick_region < 0) return {};
3430 for (const DisplaySketch& d : m_display_sketches) {
3431 if (d.feature != m_display_pick) continue;
3432 const std::vector<RegionLoop> loops = region_loops(d.entities);
3433 if (m_display_pick_region >= int(loops.size())) return {};
3434 // The region's OWN boundary plus every loop nested in it. Handing over only the outer
3435 // loop is what made a rectangle-with-a-circle extrude to a plain box: the circle was
3436 // never passed to the kernel, so build_sketch_face had one loop to work with and the
3437 // multi-loop path never ran.
3438 std::vector<SketchEntity> out;
3439 auto take = [&](int region) {
3440 if (region < 0 || region >= int(loops.size())) return;
3441 for (int ei : loops[region].ents)
3442 if (ei >= 0 && ei < int(d.entities.size())) out.push_back(d.entities[ei]);
3443 };
3445 for (int h : loops[m_display_pick_region].holes) take(h);
3446 return out;
3447 }
3448 return {};
3449}
static void take(Polyline &pl1, const Polyline &pl2, const Points &contour, size_t idx_start, size_t idx_end, bool clockwise)
Definition FillBase.cpp:642

References Slic3r::holes(), m_display_pick, m_display_pick_region, m_display_sketches, region_loops(), selected_loop_entities(), and Slic3r::take().

Referenced by selected_loop_entities(), and selection_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ selected_segment()

bool Slic3r::GUI::DesignSketchTool::selected_segment ( int & a,
int & b ) const
2523{
2524 if (m_sel_a < 0 || m_sel_b < 0)
2525 return false;
2526 a = m_sel_a;
2527 b = m_sel_b;
2528 return true;
2529}

References m_sel_a, m_sel_b, and selected_segment().

Referenced by selected_segment().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ selection()

const std::vector< int > & Slic3r::GUI::DesignSketchTool::selection ( ) const
inline
552{ return m_selection; }

References m_selection.

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_describe(), Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_select(), and Slic3r::GUI::anonymous_namespace{McpControl.cpp}::sketch_targets().

Here is the caller graph for this function:

◆ selection_box()

BoundingBoxf3 Slic3r::GUI::DesignSketchTool::selection_box ( ) const
3779{
3780 // The selected faces, a whole body's included.
3781 BoundingBoxf3 box = faces_box(selected_faces());
3782 if (m_solid_sel == SolidSel::Edge) {
3783 for (const Vec3d& p : m_sel_edge_pts)
3784 box.merge(p);
3785 for (const std::vector<Vec3d>& pts : m_sel_edges_more_pts)
3786 for (const Vec3d& p : pts)
3787 box.merge(p);
3788 } else if (m_solid_sel == SolidSel::Vertex)
3789 box.merge(m_sel_vertex_pt);
3790 // A committed sketch's picked region with its holes; a stroke outside any region, the sketch.
3791 if (m_display_pick >= 0)
3792 for (const DisplaySketch& d : m_display_sketches)
3793 if (d.feature == m_display_pick)
3794 box.merge(sketch_box(m_display_pick_region >= 0 ? selected_loop_entities() : d.entities, d.plane));
3795 if (m_active) {
3796 for (int i : m_selection)
3797 if (i >= 0 && i < int(m_entities.size()))
3798 box.merge(sketch_box({ m_entities[i] }, m_plane));
3799 for (const auto& [i, role] : m_point_sel)
3800 if (i >= 0 && i < int(m_entities.size())) {
3801 const SketchEntity& e = m_entities[i];
3802 box.merge(m_plane.to_world(role == SketchPointRole::Center ? e.center :
3803 role == SketchPointRole::P1 ? e.p1 : e.p0));
3804 }
3805 }
3806 return box;
3807}
std::vector< std::pair< int, int > > selected_faces() const
Definition DesignSketchTool.cpp:3739
BoundingBoxf3 faces_box(std::vector< std::pair< int, int > > faces) const
Definition DesignSketchTool.cpp:3751
std::vector< SketchEntity > selected_loop_entities() const
Definition DesignSketchTool.cpp:3427

References Slic3r::Center, Slic3r::SketchEntity::center, Edge, faces_box(), m_active, m_display_pick, m_display_pick_region, m_display_sketches, m_entities, m_plane, m_point_sel, m_sel_edge_pts, m_sel_edges_more_pts, m_sel_vertex_pt, m_selection, m_solid_sel, Slic3r::BoundingBox3Base< PointType >::merge(), Slic3r::SketchEntity::p0, Slic3r::P1, Slic3r::SketchEntity::p1, selected_faces(), selected_loop_entities(), selection_box(), sketch_box(), and Vertex.

Referenced by fit_box(), and selection_box().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ selection_valid()

bool Slic3r::GUI::DesignSketchTool::selection_valid ( ) const
private
634{
635 for (int i : m_selection)
636 if (i < 0 || i >= int(m_entities.size())) return false;
637 return true;
638}

References m_entities, and m_selection.

Referenced by dimension_kind(), open_selection_dimension_editor(), and toggle_selection_construction().

Here is the caller graph for this function:

◆ set_arc_slot()

void Slic3r::GUI::DesignSketchTool::set_arc_slot ( int fi,
double Rc,
double w )
private
2249{
2250 if (fi < 0 || fi >= int(m_features.size())) return;
2251 Feature& f = m_features[fi];
2252 if (f.begin < 0 || f.end > int(m_entities.size()) || f.end - f.begin != 4) return;
2253 const Vec2d center = f.c0;
2254 Vec2d dirS = f.c1 - center;
2255 const Vec2d Ec = m_entities[f.begin + 1].center; // cap@E centre = centreline end
2256 Vec2d dirE = Ec - center;
2257 if (dirS.squaredNorm() < 1e-12 || dirE.squaredNorm() < 1e-12) return;
2258 dirS.normalize(); dirE.normalize();
2259 if (!(Rc > 0.0 && w > 0.0)) { show_refusal(_u8L("The value must be greater than zero")); return; }
2260 if (w >= Rc) { // make_arc_slot needs w < Rc
2261 show_refusal(_u8L("The slot is too wide for its radius — the width must be less than twice the radius"));
2262 return;
2263 }
2264 std::vector<SketchEntity> rebuilt =
2265 make_arc_slot(center, center + Rc * dirS, center + Rc * dirE, w);
2266 if (int(rebuilt.size()) != 4) return;
2267 for (int i = 0; i < 4; ++i) {
2268 rebuilt[i].construction = m_entities[f.begin + i].construction;
2269 m_entities[f.begin + i] = rebuilt[i];
2270 }
2271 f.c1 = center + Rc * dirS; f.param = w;
2272 resolve_live();
2273}

References _u8L, Slic3r::center(), Slic3r::f(), m_entities, m_features, make_arc_slot(), resolve_live(), set_arc_slot(), and show_refusal().

Referenced by open_arc_slot_editor(), open_primary_autoedit(), and set_arc_slot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_arc_sweep()

void Slic3r::GUI::DesignSketchTool::set_arc_sweep ( int ei,
double deg )
private
2014{
2015 if (ei < 0 || ei >= int(m_entities.size())) return;
2016 SketchEntity& e = m_entities[ei];
2017 if (e.type != SketchEntity::Type::Arc || e.radius < 1e-6) return;
2018 if (!(deg > 0.0 && deg < 360.0)) { show_refusal(_u8L("The angle must be between 0° and 360°")); return; }
2019 double sweep = deg * M_PI / 180.0;
2020 const double sign = (e.end_angle >= e.start_angle) ? 1.0 : -1.0;
2021 e.end_angle = e.start_angle + sign * sweep;
2022 e.p1 = e.center + e.radius * Vec2d(std::cos(e.end_angle), std::sin(e.end_angle));
2023 resolve_live();
2024}

References _u8L, Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::center, Slic3r::SketchEntity::end_angle, m_entities, M_PI, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::radius, resolve_live(), set_arc_sweep(), show_refusal(), Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by open_arc_angle_editor(), open_primary_autoedit(), and set_arc_sweep().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_base_pick()

void Slic3r::GUI::DesignSketchTool::set_base_pick ( std::vector< SketchPlane > planes,
std::vector< int > bases,
std::vector< std::string > labels = {} )
5553{
5554 m_dbp_active = !planes.empty();
5555 m_dbp_planes = std::move(planes);
5556 m_dbp_base = std::move(bases);
5557 m_dbp_labels = std::move(labels);
5558 if (m_dbp_hover >= int(m_dbp_planes.size())) m_dbp_hover = -1;
5559}

References m_dbp_active, m_dbp_base, m_dbp_hover, m_dbp_labels, m_dbp_planes, and set_base_pick().

Referenced by set_base_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_body_edges_hidden()

void Slic3r::GUI::DesignSketchTool::set_body_edges_hidden ( bool h)
inline
243{ m_body_edges_hidden = h; }

References m_body_edges_hidden.

◆ set_constrain_entities()

void Slic3r::GUI::DesignSketchTool::set_constrain_entities ( const std::vector< SketchEntity > & ents)
inline
516{ m_entities = ents; }

References m_entities.

◆ set_constraint_glyphs()

void Slic3r::GUI::DesignSketchTool::set_constraint_glyphs ( std::vector< SketchEntityConstraintDef > v)
inline
522{ m_constrain_cons = std::move(v); }

References m_constrain_cons.

◆ set_constraint_highlight()

void Slic3r::GUI::DesignSketchTool::set_constraint_highlight ( std::vector< int > v)
inline
519{ m_constraint_hl = std::move(v); }

References m_constraint_hl.

◆ set_construction()

void Slic3r::GUI::DesignSketchTool::set_construction ( bool c)
inline
176{ m_construction = c; }

References m_construction.

◆ set_cut_gizmo()

void Slic3r::GUI::DesignSketchTool::set_cut_gizmo ( const SketchPlane & plane,
double offset,
const Vec3d & body_center,
double half_extent )
6832{
6833 m_ct_n = plane.normal.normalized();
6834 m_ct_u = plane.x_axis.normalized();
6835 m_ct_v = plane.y_axis.normalized();
6836 Vec3d rel = body_center - plane.origin;
6837 m_ct_base = plane.origin + (rel - rel.dot(m_ct_n) * m_ct_n); // body center projected into the cut plane
6839 m_ct_half = std::max(half_extent, 10.0);
6840 if (!m_ct_active) m_ct_drag = false;
6841 m_ct_active = true;
6842}

References m_ct_active, m_ct_base, m_ct_drag, m_ct_half, m_ct_n, m_ct_offset, m_ct_u, m_ct_v, Slic3r::offset(), plane(), and set_cut_gizmo().

Referenced by set_cut_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_datum_gizmo()

void Slic3r::GUI::DesignSketchTool::set_datum_gizmo ( const SketchPlane & plane,
double usize,
double vsize,
const Vec3d & base_origin,
const Vec3d & base_normal,
double offset,
bool offset_on )
4937{
4938 m_dz_active = true;
4939 m_dz_plane = plane;
4940 m_dz_usize = std::max(1.0, usize);
4941 m_dz_vsize = std::max(1.0, vsize);
4942 m_dz_anchor = base_origin;
4943 m_dz_normal = base_normal.normalized();
4945 m_dz_offset_on = offset_on;
4946}

References m_dz_active, m_dz_anchor, m_dz_normal, m_dz_offset, m_dz_offset_on, m_dz_plane, m_dz_usize, m_dz_vsize, Slic3r::offset(), plane(), and set_datum_gizmo().

Referenced by set_datum_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_datum_planes()

void Slic3r::GUI::DesignSketchTool::set_datum_planes ( std::vector< SketchPlane > planes,
std::vector< Vec2d > sizes = {} )
inline
430 {}) {
431 m_datum_planes = std::move(planes); m_datum_sizes = std::move(sizes);
432 }

◆ set_dimension_value()

void Slic3r::GUI::DesignSketchTool::set_dimension_value ( double v)
2384{
2385 if (m_pending_dim < 0 || m_pending_dim >= int(m_dimensions.size())) return;
2387 const bool positive = a.kind == DimType::Length || a.kind == DimType::Radius || a.kind == DimType::Diameter;
2388 if (!std::isfinite(v) || (positive && v <= 0.0) || (!positive && a.kind != DimType::Angle && v < 0.0)) {
2389 show_refusal(positive ? _u8L("The value must be greater than zero")
2390 : _u8L("The value must not be negative (zero means coincident)"));
2391 return;
2392 }
2393 a.value = v;
2394 if (a.con >= 0 && a.con < int(m_constraints.size()))
2395 m_constraints[a.con] = constraint_for(a);
2396 resolve_live();
2397 if (!m_solve_ok)
2398 notify(format(_u8L("%1% cannot be satisfied — the sketch is over-constrained"), dimtype_title(a.kind)));
2399 m_pending_dim = -1;
2400}

References _u8L, Angle, Slic3r::GUI::DesignSketchTool::DimAnnot::con, constraint_for(), Diameter, dimtype_title(), Slic3r::format(), Slic3r::GUI::DesignSketchTool::DimAnnot::kind, Length, m_constraints, m_dimensions, m_pending_dim, m_solve_ok, notify(), Radius, resolve_live(), set_dimension_value(), show_refusal(), and Slic3r::GUI::DesignSketchTool::DimAnnot::value.

Referenced by set_dimension_value().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_display_pick()

void Slic3r::GUI::DesignSketchTool::set_display_pick ( int feature,
int region )
inline
319{ m_display_pick = feature; m_display_pick_region = region; }

References m_display_pick, and m_display_pick_region.

◆ set_display_sketches()

void Slic3r::GUI::DesignSketchTool::set_display_sketches ( std::vector< DisplaySketch > ds)
inline
202{ m_display_sketches = std::move(ds); }

References m_display_sketches.

◆ set_draft_gizmo()

void Slic3r::GUI::DesignSketchTool::set_draft_gizmo ( const Vec3d & face_centroid,
const Vec3d & face_normal,
double angle )
6716{
6717 m_dr_center = face_centroid;
6718 m_dr_angle = std::min(89.0, std::max(-89.0, angle));
6719 m_dr_axis = Vec3d::UnitZ(); // pull direction is world +Z
6720 Vec3d ref = face_normal - face_normal.dot(m_dr_axis) * m_dr_axis; // horizontal component
6721 if (ref.norm() < 1e-6) ref = Vec3d::UnitX(); // fallback: face normal is parallel to Z
6722 m_dr_ref = ref / ref.norm();
6723 m_dr_radius = 12.0; // fixed world-size manipulator
6724 if (!m_dr_active) m_dr_drag = false;
6725 m_dr_active = true;
6726}
Vec3f face_normal(const stl_vertex vertex[3])
Definition TriangleMesh.hpp:349
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:138

References Slic3r::angle(), Slic3r::face_normal(), m_dr_active, m_dr_angle, m_dr_axis, m_dr_center, m_dr_drag, m_dr_radius, m_dr_ref, and set_draft_gizmo().

Referenced by set_draft_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_ellipse_axis()

void Slic3r::GUI::DesignSketchTool::set_ellipse_axis ( int ei,
bool major,
double v )
private
2097{
2098 if (ei < 0 || ei >= int(m_entities.size())) return;
2099 SketchEntity& e = m_entities[ei];
2100 if (e.type != SketchEntity::Type::Ellipse && e.type != SketchEntity::Type::EllipseArc) return;
2101 if (!(v > 0.0)) { show_refusal(_u8L("The value must be greater than zero")); return; }
2102 if (major ? v < e.rminor : v > e.radius) {
2103 show_refusal(_u8L("The semi-major axis cannot be shorter than the semi-minor axis"));
2104 return;
2105 }
2106 if (major) e.radius = v;
2107 else e.rminor = v;
2108 if (e.type == SketchEntity::Type::EllipseArc) { // endpoints ride the reshaped frame
2109 e.p0 = ellipse_point(e.center, e.radius, e.rminor, e.rotation, e.start_angle);
2110 e.p1 = ellipse_point(e.center, e.radius, e.rminor, e.rotation, e.end_angle);
2111 }
2112 resolve_live();
2113}

References _u8L, Slic3r::SketchEntity::center, Slic3r::SketchEntity::Ellipse, Slic3r::GUI::ellipse_point(), Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::end_angle, m_entities, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::radius, resolve_live(), Slic3r::SketchEntity::rminor, Slic3r::SketchEntity::rotation, set_ellipse_axis(), show_refusal(), Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by open_ellipse_axis_editor(), open_primary_autoedit(), and set_ellipse_axis().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_ellipsearc_sweep()

void Slic3r::GUI::DesignSketchTool::set_ellipsearc_sweep ( int ei,
double deg )
private
2118{
2119 if (ei < 0 || ei >= int(m_entities.size())) return;
2120 SketchEntity& e = m_entities[ei];
2121 if (e.type != SketchEntity::Type::EllipseArc) return;
2122 if (!(deg > 0.0 && deg < 360.0)) { show_refusal(_u8L("The angle must be between 0° and 360°")); return; }
2123 const double sweep = deg * M_PI / 180.0;
2124 const double sign = (e.end_angle >= e.start_angle) ? 1.0 : -1.0;
2125 e.end_angle = e.start_angle + sign * sweep;
2126 e.p1 = ellipse_point(e.center, e.radius, e.rminor, e.rotation, e.end_angle);
2127 resolve_live();
2128}

References _u8L, Slic3r::SketchEntity::center, Slic3r::GUI::ellipse_point(), Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::end_angle, m_entities, M_PI, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::radius, resolve_live(), Slic3r::SketchEntity::rminor, Slic3r::SketchEntity::rotation, set_ellipsearc_sweep(), show_refusal(), Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by open_primary_autoedit(), and set_ellipsearc_sweep().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_escalate_on_repick()

void Slic3r::GUI::DesignSketchTool::set_escalate_on_repick ( bool on)
inline
158{ m_escalate_repick = on; }

References m_escalate_repick.

◆ set_extrude_gizmo()

void Slic3r::GUI::DesignSketchTool::set_extrude_gizmo ( const SketchPlane & plane,
const Vec2d & centroid,
double depth,
double depth2,
bool two_sided,
bool flip )
4426{
4427 m_ex_active = true;
4428 m_ex_plane = plane;
4429 m_ex_centroid = centroid;
4430 m_ex_depth = std::max(0.0, depth);
4431 m_ex_depth2 = std::max(0.0, depth2);
4432 m_ex_two_sided = two_sided;
4433 m_ex_flip = flip;
4434}

References m_ex_active, m_ex_centroid, m_ex_depth, m_ex_depth2, m_ex_flip, m_ex_plane, m_ex_two_sided, plane(), and set_extrude_gizmo().

Referenced by set_extrude_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_fillet_gizmo()

bool Slic3r::GUI::DesignSketchTool::set_fillet_gizmo ( const Vec3d & body_centroid,
double radius )
6037{
6038 if (m_sel_edge_pts.size() < 2) { m_fl_active = false; return false; }
6039 const size_t n = m_sel_edge_pts.size();
6040 // True geometric midpoint along the edge: a straight edge often samples to just its two
6041 // endpoints, so the middle INDEX would land on an end. Walk the polyline to its half-length.
6042 double total = 0.0;
6043 for (size_t i = 1; i < n; ++i) total += (m_sel_edge_pts[i] - m_sel_edge_pts[i - 1]).norm();
6045 Vec3d t = m_sel_edge_pts[n - 1] - m_sel_edge_pts[0];
6046 const double half = 0.5 * total;
6047 double acc = 0.0;
6048 for (size_t i = 1; i < n; ++i) {
6049 const Vec3d seg = m_sel_edge_pts[i] - m_sel_edge_pts[i - 1];
6050 const double L = seg.norm();
6051 if (acc + L >= half && L > 1e-12) {
6052 m_fl_anchor = m_sel_edge_pts[i - 1] + seg * ((half - acc) / L);
6053 t = seg;
6054 break;
6055 }
6056 acc += L;
6057 }
6058 if (t.norm() < 1e-9) return false;
6059 t.normalize();
6060 Vec3d r = m_fl_anchor - body_centroid; // radial offset from the body centre
6061 r -= r.dot(t) * t; // strip the along-edge component
6062 if (r.norm() < 1e-6) { // edge passes through the centroid
6063 r = t.cross(Vec3d::UnitZ());
6064 if (r.norm() < 1e-6) r = t.cross(Vec3d::UnitX());
6065 }
6066 m_fl_dir = r.normalized();
6067 m_fl_radius = std::max(0.01, radius);
6068 if (!m_fl_active) m_fl_drag = false; // re-anchored every preview: preserve an in-progress drag
6069 m_fl_active = true;
6070 return true;
6071}

References L, m_fl_active, m_fl_anchor, m_fl_dir, m_fl_drag, m_fl_radius, m_sel_edge_pts, and set_fillet_gizmo().

Referenced by set_fillet_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_handle()

void Slic3r::GUI::DesignSketchTool::set_handle ( const Handle & h,
const Vec2d & target )
private
1083{
1084 if (h.ei < 0 || h.ei >= int(m_entities.size())) return;
1085 SketchEntity& e = m_entities[h.ei];
1086 switch (h.role) {
1087 case HandleRole::P0:
1089 case HandleRole::P1:
1091 case HandleRole::Center:
1094 const double r = (target - e.center).norm();
1095 if (r > 1e-6) e.radius = r;
1096 resolve_live();
1097 break;
1098 }
1099 case HandleRole::MajorAxis: {
1100 // The major grip defines the major-axis vector: sets semi-major a + orientation phi.
1101 const Vec2d d = target - e.center;
1102 const double a = d.norm();
1103 if (a > 1e-6) {
1104 e.rotation = std::atan2(d.y(), d.x());
1105 e.radius = std::max(a, e.rminor); // keep OCCT invariant a >= b
1106 }
1107 if (e.type == SketchEntity::Type::EllipseArc) { // endpoints ride the reshaped frame
1108 e.p0 = ellipse_point(e.center, e.radius, e.rminor, e.rotation, e.start_angle);
1109 e.p1 = ellipse_point(e.center, e.radius, e.rminor, e.rotation, e.end_angle);
1110 }
1111 resolve_live();
1112 break;
1113 }
1114 case HandleRole::MinorAxis: {
1115 // The minor grip sets semi-minor b = perpendicular distance to the major axis.
1116 const Vec2d um(std::cos(e.rotation), std::sin(e.rotation));
1117 const Vec2d un(-um.y(), um.x());
1118 const double b = std::abs((target - e.center).dot(un));
1119 if (b > 1e-6) e.rminor = std::min(b, e.radius);
1120 if (e.type == SketchEntity::Type::EllipseArc) {
1121 e.p0 = ellipse_point(e.center, e.radius, e.rminor, e.rotation, e.start_angle);
1122 e.p1 = ellipse_point(e.center, e.radius, e.rminor, e.rotation, e.end_angle);
1123 }
1124 resolve_live();
1125 break;
1126 }
1128 // Move one control pole; the end poles mirror p0/p1 (kept in sync for picking).
1129 const int k = h.ctrl_index;
1130 if (k >= 0 && k < int(e.ctrl.size())) {
1131 e.ctrl[k] = target;
1132 if (k == 0) e.p0 = target;
1133 if (k == int(e.ctrl.size()) - 1) e.p1 = target;
1134 }
1135 resolve_live();
1136 break;
1137 }
1138 default: break;
1139 }
1140}

References BSplineCtrl, Center, Slic3r::Center, Slic3r::SketchEntity::center, Slic3r::SketchEntity::ctrl, Slic3r::GUI::DesignSketchTool::Handle::ctrl_index, Slic3r::GUI::DesignSketchTool::Handle::ei, Slic3r::GUI::ellipse_point(), Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::end_angle, m_entities, MajorAxis, MinorAxis, P0, Slic3r::P0, Slic3r::SketchEntity::p0, P1, Slic3r::P1, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::radius, RadiusHandle, resolve_live(), resolve_live_drag(), Slic3r::SketchEntity::rminor, Slic3r::GUI::DesignSketchTool::Handle::role, Slic3r::SketchEntity::rotation, set_point(), Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_helix_gizmo()

void Slic3r::GUI::DesignSketchTool::set_helix_gizmo ( const SketchPlane & plane,
double radius,
double pitch,
double height,
double taper,
bool left_handed )
5103{
5104 m_hx_active = true;
5105 m_hx_plane = plane;
5106 m_hx_radius = radius;
5107 m_hx_pitch = pitch;
5109 m_hx_taper = taper;
5110 m_hx_left = left_handed;
5111}
coord_t height(const BoundingBox &box)
Definition Arrange.cpp:1185

References m_hx_active, m_hx_height, m_hx_left, m_hx_pitch, m_hx_plane, m_hx_radius, m_hx_taper, plane(), and set_helix_gizmo().

Referenced by set_helix_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_highlight_faces()

void Slic3r::GUI::DesignSketchTool::set_highlight_faces ( const std::vector< std::pair< int, int > > & faces)
3672{
3673 std::map<int, std::vector<int>> by_body;
3674 for (const auto& [b, f] : faces)
3675 if (body_shape(b) != nullptr)
3676 by_body[b].push_back(f);
3677 // Reuse each body's entry, so re-sending the same faces resamples nothing.
3678 std::vector<FaceHighlight> next;
3679 for (auto& [b, fs] : by_body) {
3680 FaceHighlight h;
3681 for (FaceHighlight& old : m_hl_faces)
3682 if (old.body == b)
3683 h = std::move(old);
3684 cached_face_highlight(h, b, std::move(fs));
3685 next.push_back(std::move(h));
3686 }
3687 m_hl_faces = std::move(next);
3688}

References body_shape(), cached_face_highlight(), Slic3r::f(), m_hl_faces, and set_highlight_faces().

Referenced by set_highlight_faces().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_highlight_sketches()

void Slic3r::GUI::DesignSketchTool::set_highlight_sketches ( std::vector< std::pair< int, ColorRGBA > > hl)
inline
203{ m_hl_sketches = std::move(hl); }
std::vector< std::pair< int, ColorRGBA > > m_hl_sketches
Definition DesignSketchTool.hpp:1272

References m_hl_sketches.

◆ set_hole_face_bounds()

void Slic3r::GUI::DesignSketchTool::set_hole_face_bounds ( bool has,
double umin,
double umax,
double vmin,
double vmax )
6198{
6199 m_hl_has_bounds = has;
6200 m_hl_umin = umin; m_hl_umax = umax; m_hl_vmin = vmin; m_hl_vmax = vmax;
6201}
double m_hl_vmax
Definition DesignSketchTool.hpp:1512
double m_hl_umax
Definition DesignSketchTool.hpp:1512

References m_hl_has_bounds, m_hl_umax, m_hl_umin, m_hl_vmax, m_hl_vmin, and set_hole_face_bounds().

Referenced by set_hole_face_bounds().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_hole_gizmo()

void Slic3r::GUI::DesignSketchTool::set_hole_gizmo ( const SketchPlane & plane,
double x,
double y,
double diameter,
double depth,
bool through )
6180{
6181 m_hl_plane = plane;
6182 m_hl_x = x;
6183 m_hl_y = y;
6184 m_hl_diameter = std::max(0.01, diameter);
6185 m_hl_depth = std::max(0.01, depth);
6186 m_hl_through = through;
6187 if (!m_hl_active) m_hl_drag = -1; // re-pushed every preview: preserve an in-progress drag
6188 m_hl_active = true;
6189}

References m_hl_active, m_hl_depth, m_hl_diameter, m_hl_drag, m_hl_plane, m_hl_through, m_hl_x, m_hl_y, plane(), and set_hole_gizmo().

Referenced by set_hole_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_inline_busy()

void Slic3r::GUI::DesignSketchTool::set_inline_busy ( bool b)
inline
147{ m_awaiting_length = b; }

References m_awaiting_length.

◆ set_line_angle()

void Slic3r::GUI::DesignSketchTool::set_line_angle ( int ei,
double deg )
private
1487{
1488 if (ei < 0 || ei >= int(m_entities.size())) return;
1489 SketchEntity& e = m_entities[ei];
1490 if (e.type != SketchEntity::Type::Line) return;
1491 const double L = (e.p1 - e.p0).norm();
1492 if (L < 1e-9) return;
1493 drop_orientation_constraints(ei, ei + 1); // a typed angle overrides an inferred H/V
1494 const double r = deg * M_PI / 180.0;
1495 e.p1 = e.p0 + Vec2d(std::cos(r), std::sin(r)) * L; // rotate about P0, keep length
1496 resolve_live();
1497}

References drop_orientation_constraints(), L, Slic3r::SketchEntity::Line, m_entities, M_PI, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, resolve_live(), and Slic3r::SketchEntity::type.

Referenced by open_angle_editor(), and open_primary_autoedit().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_mate_connectors()

void Slic3r::GUI::DesignSketchTool::set_mate_connectors ( std::vector< MateConnectorGlyph > g)
inline
446{ m_mate_connectors = std::move(g); }

References m_mate_connectors.

◆ set_mate_links()

void Slic3r::GUI::DesignSketchTool::set_mate_links ( std::vector< std::pair< Vec3d, Vec3d > > l)
inline
450{ m_mate_links = std::move(l); }

References m_mate_links.

◆ set_move_gizmo()

void Slic3r::GUI::DesignSketchTool::set_move_gizmo ( int body,
const Vec3d & pivot,
const Transform3d & base_xform,
double body_radius = 0.0 )
5806{
5807 m_mv_active = true;
5808 m_mv_body = body;
5809 m_mv_base = pivot; // body's world centroid at Move-open = rotation pivot
5810 m_mv_base_xform = base_xform; // pose the deltas compose onto
5811 m_mv_offset = Vec3d::Zero();
5812 m_mv_rot = Eigen::Matrix3d::Identity();
5813 m_mv_drag = -1;
5814 m_mv_radius = std::max(body_radius, 0.0);
5815 // The selection is held while the gizmo is up (see on_mouse_impl): no press half-way to a
5816 // pick, and no hover outline promising a click that will not be taken.
5817 m_pick_pending = false;
5818 m_pre = SolidPick{};
5819}

References m_mv_active, m_mv_base, m_mv_base_xform, m_mv_body, m_mv_drag, m_mv_offset, m_mv_radius, m_mv_rot, m_pick_pending, m_pre, and set_move_gizmo().

Referenced by set_move_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_on_cut_offset_changed()

void Slic3r::GUI::DesignSketchTool::set_on_cut_offset_changed ( std::function< void(double)> cb)
inline
473{ m_on_cut_offset_changed = std::move(cb); }

References m_on_cut_offset_changed.

◆ set_on_draft_angle_changed()

void Slic3r::GUI::DesignSketchTool::set_on_draft_angle_changed ( std::function< void(double)> cb)
inline
467{ m_on_draft_angle_changed = std::move(cb); }

References m_on_draft_angle_changed.

◆ set_pattern_gizmo()

void Slic3r::GUI::DesignSketchTool::set_pattern_gizmo ( const SketchPlane & plane,
const Vec3d & body_centroid,
bool circular,
int count,
int dir,
double spacing,
double angle )
7090{
7091 m_pt_circular = circular;
7092 m_pt_base = body_centroid;
7093 m_pt_count = std::max(1, count);
7094 m_pt_spacing = std::max(0.01, spacing);
7095 m_pt_angle = std::min(360.0, std::max(1.0, angle));
7096 m_pt_dirw = (dir == 1 ? plane.y_axis : plane.x_axis).normalized();
7097 m_pt_origin = plane.origin;
7098 m_pt_normal = plane.normal.normalized();
7099 // Circular arc center = foot of the body centroid on the rotation axis; ref = perpendicular dir.
7100 const double axial = (body_centroid - plane.origin).dot(m_pt_normal);
7101 m_pt_ccenter = plane.origin + axial * m_pt_normal;
7102 Vec3d ref = body_centroid - m_pt_ccenter;
7103 double r = ref.norm();
7104 if (r < 1e-6) { ref = m_pt_dirw; r = 1.0; } // body centred on the axis: nominal radius
7105 m_pt_cref = ref / ref.norm();
7106 m_pt_radius = std::max(r, 1.0);
7107 if (!m_pt_active) m_pt_drag = false; // re-pushed every preview: keep an in-progress drag
7108 m_pt_active = true;
7109}
Vec3d m_pt_origin
Definition DesignSketchTool.hpp:1620

References Slic3r::angle(), count, Slic3r::dot(), m_pt_active, m_pt_angle, m_pt_base, m_pt_ccenter, m_pt_circular, m_pt_count, m_pt_cref, m_pt_dirw, m_pt_drag, m_pt_normal, m_pt_origin, m_pt_radius, m_pt_spacing, plane(), and set_pattern_gizmo().

Referenced by set_pattern_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_pick_only_body()

void Slic3r::GUI::DesignSketchTool::set_pick_only_body ( int b)
inline
240{ m_pick_only_body = b; }

References m_pick_only_body.

◆ set_point()

void Slic3r::GUI::DesignSketchTool::set_point ( int ei,
SketchPointRole role,
const Vec2d & v )
private
1160{
1161 if (ei < 0 || ei >= int(m_entities.size())) return;
1162 SketchEntity& e = m_entities[ei];
1163 switch (e.type) {
1165 if (role == SketchPointRole::P0) e.p0 = v;
1166 else if (role == SketchPointRole::P1) e.p1 = v;
1167 break;
1169 e.p0 = v;
1170 break;
1172 // p0 mirrors the centre for circles, which is the convention the solver both writes
1173 // (SketchSolver.cpp:110) and restores after every solve (:421). Moving only e.center
1174 // left the two disagreeing for the whole duration of a live drag, so anything reading
1175 // p0 in that window saw the pre-drag position.
1176 if (role == SketchPointRole::Center) { e.center = v; e.p0 = v; }
1177 break;
1180 if (role == SketchPointRole::Center) {
1181 const Vec2d d = v - e.center; // rigid translate, keep radius/angles
1182 e.center = v; e.p0 += d; e.p1 += d;
1183 }
1184 break;
1186 if (role == SketchPointRole::Center) { e.center = v; e.p0 = v; }
1187 break;
1189 // P0/P1 drag the end poles; Center rigidly translates the whole curve.
1190 if (role == SketchPointRole::P0 && !e.ctrl.empty()) { e.ctrl.front() = v; e.p0 = v; }
1191 else if (role == SketchPointRole::P1 && !e.ctrl.empty()) { e.ctrl.back() = v; e.p1 = v; }
1192 else if (role == SketchPointRole::Center) {
1193 const Vec2d d = v - (e.ctrl.empty() ? e.p0 : e.ctrl.front());
1194 for (auto& cp : e.ctrl) cp += d;
1195 e.p0 += d; e.p1 += d;
1196 }
1197 break;
1198 }
1199}

References Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::BSpline, Slic3r::Center, Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::SketchEntity::ctrl, Slic3r::SketchEntity::Ellipse, Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::Line, m_entities, Slic3r::P0, Slic3r::SketchEntity::p0, Slic3r::P1, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::Point, and Slic3r::SketchEntity::type.

Referenced by heal_coincidences(), on_mouse_impl(), and set_handle().

Here is the caller graph for this function:

◆ set_polygon_angle()

void Slic3r::GUI::DesignSketchTool::set_polygon_angle ( int fi,
double deg )
private
1914{
1915 if (fi < 0 || fi >= int(m_features.size())) return;
1916 Feature& f = m_features[fi];
1917 if (f.begin < 0 || f.begin >= int(m_entities.size())) return;
1918 const Vec2d c = f.c0;
1919 const Vec2d sp = m_entities[f.begin].p0 - c; // centre -> vertex0
1920 if (sp.squaredNorm() < 1e-12) return;
1921 const double cur = std::atan2(sp.y(), sp.x());
1922 const double da = deg * M_PI / 180.0 - cur;
1923 drop_orientation_constraints(f.begin, f.end); // rotation invalidates edge H/V
1924 const double ca = std::cos(da), sa = std::sin(da);
1925 // -> Vec2d is REQUIRED: an auto return deduces an Eigen expression template that holds
1926 // a reference to the destroyed `c + Vec2d(...)` temporary (dangling -> garbage coords).
1927 auto rot = [&](const Vec2d& pt) -> Vec2d { const Vec2d r = pt - c;
1928 return c + Vec2d(r.x() * ca - r.y() * sa, r.x() * sa + r.y() * ca); };
1929 for (int i = f.begin; i < f.end && i < int(m_entities.size()); ++i) {
1930 SketchEntity& e = m_entities[i];
1931 if (e.type != SketchEntity::Type::Line) continue;
1932 e.p0 = rot(e.p0); e.p1 = rot(e.p1);
1933 }
1934 // Do NOT re-solve: the rotated geometry is already a correct regular polygon, and the
1935 // inferred loop (redundant Coincident, now with no H/V anchor) collapses to a point
1936 // under libslvs. We only drop the stale edge H/V (above) so a later commit-solve stays
1937 // sane; the display renders the mutated entities directly.
1938}

References drop_orientation_constraints(), Slic3r::f(), Slic3r::SketchEntity::Line, m_entities, m_features, M_PI, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, set_polygon_angle(), and Slic3r::SketchEntity::type.

Referenced by open_polygon_angle_editor(), open_primary_autoedit(), and set_polygon_angle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_polygon_circumscribed()

void Slic3r::GUI::DesignSketchTool::set_polygon_circumscribed ( bool c)
inline

◆ set_polygon_radius()

void Slic3r::GUI::DesignSketchTool::set_polygon_radius ( int fi,
double R )
private
1978{
1979 if (fi < 0 || fi >= int(m_features.size()) || R < 1e-6) return;
1980 Feature& f = m_features[fi];
1981 if (f.begin < 0 || f.begin >= int(m_entities.size())) return;
1982 const Vec2d c = f.c0;
1983 const double curR = (m_entities[f.begin].p0 - c).norm();
1984 if (curR < 1e-9) return;
1985 const double s = R / curR; // uniform scale about the centre
1986 for (int i = f.begin; i < f.end && i < int(m_entities.size()); ++i) {
1987 SketchEntity& e = m_entities[i];
1988 if (e.type != SketchEntity::Type::Line) continue;
1989 e.p0 = c + (e.p0 - c) * s;
1990 e.p1 = c + (e.p1 - c) * s;
1991 }
1992 f.param = R;
1993 // Geometric only (no solve): consistent with the rotation edits, and avoids collapsing
1994 // the loop if its H/V anchors were already dropped by a prior rotation.
1995}

References Slic3r::f(), Slic3r::SketchEntity::Line, m_entities, m_features, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, set_polygon_radius(), and Slic3r::SketchEntity::type.

Referenced by set_polygon_radius(), and set_polygon_side().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_polygon_side()

void Slic3r::GUI::DesignSketchTool::set_polygon_side ( int fi,
double side )
private
1757{
1758 if (fi < 0 || fi >= int(m_features.size())) return;
1759 if (!(side > 0.0)) { show_refusal(_u8L("The value must be greater than zero")); return; }
1760 const int n = std::max(3, m_features[fi].sides);
1761 const double R = side / (2.0 * std::sin(M_PI / double(n)));
1762 set_polygon_radius(fi, R);
1763}
void set_polygon_radius(int fi, double R)
Definition DesignSketchTool.cpp:1977

References _u8L, m_features, M_PI, set_polygon_radius(), set_polygon_side(), and show_refusal().

Referenced by open_polygon_side_editor(), open_primary_autoedit(), and set_polygon_side().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_polygon_sides()

void Slic3r::GUI::DesignSketchTool::set_polygon_sides ( int n)
inline
177{ m_polygon_sides = (n < 3 ? 3 : n); }

References m_polygon_sides.

◆ set_profile_points()

void Slic3r::GUI::DesignSketchTool::set_profile_points ( const std::vector< Vec2d > & pts)
inline
490{ m_points = pts; }

References m_points.

◆ set_rect_angle()

void Slic3r::GUI::DesignSketchTool::set_rect_angle ( int fi,
double deg )
private
2135{
2136 if (fi < 0 || fi >= int(m_features.size())) return;
2137 Feature& f = m_features[fi];
2138 if (f.begin < 0 || f.end > int(m_entities.size()) || f.end <= f.begin) return;
2139 const SketchEntity& e0 = m_entities[f.begin];
2140 const Vec2d d0 = e0.p1 - e0.p0;
2141 if (d0.squaredNorm() < 1e-12) return;
2142 const double da = deg * M_PI / 180.0 - std::atan2(d0.y(), d0.x());
2143 drop_orientation_constraints(f.begin, f.end);
2144 const Vec2d pivot = f.c0;
2145 const double ca = std::cos(da), sa = std::sin(da);
2146 // -> Vec2d REQUIRED (see set_polygon_angle): an auto return deduces an Eigen expression
2147 // template referencing the destroyed temporary -> dangling.
2148 auto rot = [&](const Vec2d& pt) -> Vec2d { const Vec2d r = pt - pivot;
2149 return pivot + Vec2d(r.x() * ca - r.y() * sa, r.x() * sa + r.y() * ca); };
2150 for (int i = f.begin; i < f.end && i < int(m_entities.size()); ++i) {
2151 SketchEntity& e = m_entities[i];
2152 e.p0 = rot(e.p0); e.p1 = rot(e.p1);
2153 }
2154 f.c1 = rot(f.c1); // keep the opposite corner consistent for later W/H quotes
2155}

References drop_orientation_constraints(), Slic3r::f(), m_entities, m_features, M_PI, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, and set_rect_angle().

Referenced by open_primary_autoedit(), and set_rect_angle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_revolve_gizmo()

void Slic3r::GUI::DesignSketchTool::set_revolve_gizmo ( const SketchPlane & plane,
const Vec2d & centroid,
const Vec3d & axis_origin,
const Vec3d & axis_dir,
double angle,
bool flip )
6940{
6941 const Vec3d ax = axis_dir.normalized();
6942 const Vec3d cw = plane.to_world(centroid);
6943 const double axial = (cw - axis_origin).dot(ax);
6944 m_rv_center = axis_origin + axial * ax; // foot of the centroid on the axis line
6945 Vec3d ref = cw - m_rv_center; // perpendicular to ax by construction
6946 double r = ref.norm();
6947 if (r < 1e-6) { ref = plane.normal.normalized(); r = std::max(plane.normal.norm(), 1.0); }
6948 m_rv_axis = ax;
6949 m_rv_ref = ref / ref.norm();
6950 m_rv_radius = std::max(r, 1.0);
6951 m_rv_angle = std::min(360.0, std::max(1.0, std::abs(angle)));
6952 m_rv_flip = flip;
6953 if (!m_rv_active) m_rv_drag = false; // re-pushed every preview: keep an in-progress drag
6954 m_rv_active = true;
6955}

References Slic3r::angle(), Slic3r::dot(), m_rv_active, m_rv_angle, m_rv_axis, m_rv_center, m_rv_drag, m_rv_flip, m_rv_radius, m_rv_ref, plane(), and set_revolve_gizmo().

Referenced by set_revolve_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_rib_gizmo()

void Slic3r::GUI::DesignSketchTool::set_rib_gizmo ( const SketchPlane & plane,
const Vec2d & p0,
const Vec2d & p1,
double thickness )
5279{
5280 m_rb_active = true;
5281 m_rb_plane = plane;
5282 m_rb_p0 = p0;
5283 m_rb_p1 = p1;
5284 m_rb_thickness = thickness;
5285}

References m_rb_active, m_rb_p0, m_rb_p1, m_rb_plane, m_rb_thickness, plane(), and set_rib_gizmo().

Referenced by set_rib_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_rounded_rect()

void Slic3r::GUI::DesignSketchTool::set_rounded_rect ( int fi,
double w,
double h,
double r )
private
2207{
2208 if (fi < 0 || fi >= int(m_features.size())) return;
2209 Feature& f = m_features[fi];
2210 if (f.begin < 0 || f.end > int(m_entities.size()) || f.end <= f.begin) return;
2211 if (!(w > 0.0 && h > 0.0 && r > 0.0)) { show_refusal(_u8L("The value must be greater than zero")); return; }
2212 if (r >= std::min(w, h) * 0.5) {
2213 show_refusal(_u8L("The corner radius must be less than half the shorter side"));
2214 return;
2215 }
2216 const double xmin = std::min(f.c0.x(), f.c1.x()), ymin = std::min(f.c0.y(), f.c1.y());
2217 const double xmax = xmin + w, ymax = ymin + h;
2218 std::vector<SketchEntity> rebuilt = rounded_rect_entities(xmin, ymin, xmax, ymax, r);
2219 if (int(rebuilt.size()) != f.end - f.begin) return; // count must match to keep con refs
2220 for (int i = 0; i < int(rebuilt.size()); ++i) {
2221 rebuilt[i].construction = m_entities[f.begin + i].construction; // preserve flag
2222 m_entities[f.begin + i] = rebuilt[i];
2223 }
2224 f.c0 = Vec2d(xmin, ymin); f.c1 = Vec2d(xmax, ymax); f.param = r;
2225 resolve_live();
2226}

References _u8L, Slic3r::f(), m_entities, m_features, resolve_live(), rounded_rect_entities(), set_rounded_rect(), and show_refusal().

Referenced by open_primary_autoedit(), open_rounded_rect_editor(), and set_rounded_rect().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_shell_gizmo()

void Slic3r::GUI::DesignSketchTool::set_shell_gizmo ( const Vec3d & face_centroid,
const Vec3d & inward_dir,
double thickness )
6604{
6605 m_sh_anchor = face_centroid;
6606 if (inward_dir.norm() > 1e-9) m_sh_dir = inward_dir.normalized();
6607 m_sh_thickness = std::max(0.01, thickness);
6608 if (!m_sh_active) m_sh_drag = false; // re-pushed every preview: preserve an in-progress drag
6609 m_sh_active = true;
6610}

References m_sh_active, m_sh_anchor, m_sh_dir, m_sh_drag, m_sh_thickness, and set_shell_gizmo().

Referenced by set_shell_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_show_axes()

void Slic3r::GUI::DesignSketchTool::set_show_axes ( bool s)
inline
220{ m_show_axes = s; }

References m_show_axes.

◆ set_show_planes()

void Slic3r::GUI::DesignSketchTool::set_show_planes ( bool s)
inline
219{ m_show_planes = s; }

References m_show_planes.

◆ set_slot()

void Slic3r::GUI::DesignSketchTool::set_slot ( int fi,
double length,
double w )
private
2299{
2300 if (fi < 0 || fi >= int(m_features.size())) return;
2301 Feature& f = m_features[fi];
2302 if (f.begin < 0 || f.end > int(m_entities.size()) || f.end - f.begin != 4) return;
2303 Vec2d dir = f.c1 - f.c0;
2304 if (dir.squaredNorm() < 1e-12) return;
2305 dir.normalize();
2306 if (!(length > 0.0 && w > 0.0)) { show_refusal(_u8L("The value must be greater than zero")); return; }
2307 const Vec2d c0 = f.c0, c1 = f.c0 + length * dir;
2308 std::vector<SketchEntity> rebuilt = make_slot(c0, c1, w);
2309 if (int(rebuilt.size()) != 4) return;
2310 for (int i = 0; i < 4; ++i) {
2311 rebuilt[i].construction = m_entities[f.begin + i].construction;
2312 m_entities[f.begin + i] = rebuilt[i];
2313 }
2314 f.c1 = c1; f.param = w;
2315 resolve_live();
2316}
double length(const Points &pts)
Definition MultiPoint.hpp:181

References _u8L, Slic3r::f(), Slic3r::length(), m_entities, m_features, make_slot(), resolve_live(), set_slot(), and show_refusal().

Referenced by open_primary_autoedit(), open_slot_editor(), and set_slot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_slot_angle()

void Slic3r::GUI::DesignSketchTool::set_slot_angle ( int fi,
double deg )
private
2320{
2321 if (fi < 0 || fi >= int(m_features.size())) return;
2322 Feature& f = m_features[fi];
2323 if (f.begin < 0 || f.end > int(m_entities.size()) || f.end - f.begin != 4) return;
2324 const double L = (f.c1 - f.c0).norm();
2325 if (L < 1e-9) return;
2326 const double a = deg * M_PI / 180.0;
2327 const Vec2d c1 = f.c0 + L * Vec2d(std::cos(a), std::sin(a));
2328 std::vector<SketchEntity> rebuilt = make_slot(f.c0, c1, f.param);
2329 if (int(rebuilt.size()) != 4) return;
2330 for (int i = 0; i < 4; ++i) {
2331 rebuilt[i].construction = m_entities[f.begin + i].construction;
2332 m_entities[f.begin + i] = rebuilt[i];
2333 }
2334 f.c1 = c1;
2335 resolve_live();
2336}

References Slic3r::f(), L, m_entities, m_features, M_PI, make_slot(), resolve_live(), and set_slot_angle().

Referenced by open_primary_autoedit(), open_slot_editor(), and set_slot_angle().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_solid_pick()

void Slic3r::GUI::DesignSketchTool::set_solid_pick ( const std::vector< CadBody > * bodies,
const TriangleMesh * mesh,
const std::vector< int > * tri_face,
const std::vector< int > * tri_body,
const std::vector< bool > * visible = nullptr,
const std::vector< Transform3d > * xform = nullptr )
3457{
3458 // Treat no bodies or an empty mesh as "no solid" so has_display()/picking stay off.
3459 if (bodies == nullptr || bodies->empty() || mesh == nullptr || mesh->its.indices.empty()) {
3460 m_solid_bodies = nullptr; m_solid_mesh = nullptr; m_solid_tri_face = nullptr; m_solid_tri_body = nullptr;
3461 m_solid_visible = nullptr; m_solid_xform = nullptr;
3462 } else {
3463 m_solid_bodies = bodies; m_solid_mesh = mesh; m_solid_tri_face = tri_face; m_solid_tri_body = tri_body;
3464 m_solid_visible = visible; m_solid_xform = xform;
3465 }
3468}
void refresh_body_edges()
Definition DesignSketchTool.cpp:3480

References clear_solid_selection(), Slic3r::TriangleMesh::its, m_solid_bodies, m_solid_mesh, m_solid_tri_body, m_solid_tri_face, m_solid_visible, m_solid_xform, refresh_body_edges(), and set_solid_pick().

Referenced by set_solid_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_thread_gizmo()

void Slic3r::GUI::DesignSketchTool::set_thread_gizmo ( const SketchPlane & plane,
double x,
double y,
double radius,
double height )
6423{
6424 m_th_plane = plane;
6425 m_th_x = x;
6426 m_th_y = y;
6427 m_th_radius = std::max(0.01, radius);
6428 m_th_height = std::max(0.01, height);
6429 if (!m_th_active) m_th_drag = -1; // re-pushed every preview: preserve an in-progress drag
6430 m_th_active = true;
6431}

References m_th_active, m_th_drag, m_th_height, m_th_plane, m_th_radius, m_th_x, m_th_y, plane(), and set_thread_gizmo().

Referenced by set_thread_gizmo().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_tool()

void Slic3r::GUI::DesignSketchTool::set_tool ( Mode mode)
256{
257 // A READY edit-op carries the user's typed or dragged value, so switching tools commits it
258 // rather than dropping it — the same rule Tab follows in the dimension editor. Discarding it
259 // here is most of why Fillet looked like it simply did not work: every documented route (type
260 // the radius, or drag the arrow) left the op ready-but-pending, and the next tool click threw
261 // the value away and reverted the corner to sharp, with nothing on screen saying so.
262 // This MUST run before m_mode is reassigned: op_ready() and confirm_op() both switch on
263 // m_mode, so after the assignment they would test the tool being switched TO. That read
264 // op_ready()==0 with a=0 b=3 val=28.205 sitting right there — picked, valued, and dropped.
265 // Charter 4.2: "starting another operation while a valid feature is pending commits it" —
266 // the ghost is on screen, so switching away keeps it. Esc is the discard (disarm_tool drops
267 // the pending op/transform before it gets here).
268 if (op_ready()) confirm_op();
269 // And the same rule for the transform gizmo: a ready edit-op committed here while a pending
270 // transform was silently dropped, which is the same "the value was set, the ghost was drawn,
271 // and nothing was written" failure the comment above records for Fillet.
273
274 // An OPEN inline value field freezes the canvas (on_mouse_impl returns early while
275 // m_awaiting_length) and blocks every keyboard shortcut (in_text includes inline_busy()).
276 // Drawing a rectangle opens one automatically for its Width/Height, so after a rectangle the
277 // sketch was STUCK: pressing C did nothing because the key never reached this function, and
278 // clicking on the canvas did nothing because the canvas was frozen. Committing here accepts
279 // the typed value and closes the field, which is the same rule the ready-edit-op above
280 // follows — leaving a tool must not silently discard what the user entered.
282
283 // Switch the active drawing tool without dropping accumulated entities.
284 m_mode = mode;
285 m_points.clear();
286 m_has_cursor = false;
287 m_cursor_snap = InferenceSnap{}; // the previous tool's snap marker is not this tool's
288 // DRAIN THE QUEUED DIMENSIONS, do not just resync the baseline. on_inline_commit() above
289 // commits the field that is open, and the commit callback installed by
290 // open_next_autoedit_dim does `++m_autoedit_dim_idx; CallAfter(open_next_autoedit_dim)` —
291 // so the switch's OWN commit schedules the next queued field, which then opens on top of the
292 // tool the user just armed. Measured: draw a rectangle, its Width field opens, arm Line from
293 // the offer; Width commits, the status line reads "Line — click start, then end", and the
294 // rectangle's Height field is sitting over it. (The keyboard cannot reproduce it: in_text
295 // includes inline_busy(), so letters are swallowed while a field is open — the switch has to
296 // come from the menu, the toolbar or the MCP socket.)
297 //
298 // reset_autoedit() is the existing helper for exactly this and its comment already says it
299 // "mirrors set_tool's resync" — the three lines that used to be here were that mirror drifting
300 // out of step, missing the two members that matter. The already-queued CallAfter then finds
301 // m_autoedit_dim_idx == -1 and returns through the guard at the top of open_next_autoedit_dim.
302 //
303 // The current value is COMMITTED rather than cancelled, matching the ready-edit-op rule a few
304 // lines above and Tab in the dimension editor. Esc is the gesture that means keep-as-drawn; a
305 // tool switch is not Esc.
307
308 // An abandoned gesture must not leave its half-open Feature behind. begin_feature() pushes a
309 // Feature with end == begin immediately and end_feature() is what fills it in — and pops it
310 // when the gesture appended nothing. Switching tools mid-gesture skips end_feature entirely,
311 // so a zero-span Feature stays in m_features for good and m_open_feature stays set, which
312 // also gates the auto-edit trigger for whatever is drawn next.
313 if (m_open_feature >= 0 && m_open_feature < int(m_features.size())
315 m_features.pop_back(); // always the last one: begin_feature pushed it
316 m_open_feature = -1;
317
318 // Constrain-mode picks and the imported-art transform outlived the tool that made them.
319 // Neither can misfire while another mode is active, which is why this is quieter than the
320 // dimension picks — but coming BACK to Constrain resurrected picks made before leaving,
321 // possibly against entities deleted in between. Reset them the way begin_constrain does.
322 m_sel_a = m_sel_b = -1;
323 m_constrain_entities = false;
324 reset_xform(); // cancel() already does this; a tool switch is just as much a leave
325 // A READY edit-op carries the user's typed or dragged value, so switching tools commits it
326 // rather than dropping it — the same rule Tab follows in the dimension editor. Discarding it
327 // here is most of why Fillet looked like it simply did not work: every documented route (type
328 // the radius, or drag the arrow) left the op ready-but-pending, and the next tool click threw
329 // the value away and reverted the corner to sharp, with nothing on screen saying so.
330 reset_op(); // drop any in-progress (not yet ready) edit-op gizmo
331 reset_tf(); // drop any in-progress transform gizmo
332 // A pick that survives the tool that made it is invisible, and the first sign of it is a
333 // constraint or a dimension landing on geometry the user did not choose. Drop the modal
334 // picks left armed by the tool we are leaving: the Dimension tool's first pick, the
335 // Constrain tool's picks, and the individual point selection.
336 m_dim_has0 = false;
337 m_dim_e0 = -1;
339 m_pick0 = m_pick1 = m_pick2 = -1;
340 m_point_sel.clear();
341 m_selection.clear();
343}

References confirm_op(), confirm_transform(), m_constrain_entities, m_cursor_snap, m_dim_e0, m_dim_has0, m_dim_r0, m_features, m_has_cursor, m_mode, m_open_feature, m_pick0, m_pick1, m_pick2, m_point_sel, m_points, m_sel_a, m_sel_b, m_selection, mode(), on_inline_commit, on_selection_changed, op_ready(), Slic3r::P0, reset_autoedit(), reset_op(), reset_tf(), reset_xform(), and tf_ready().

Referenced by disarm_tool().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ shelling()

bool Slic3r::GUI::DesignSketchTool::shelling ( ) const
inline
424{ return m_sh_active; }

References m_sh_active.

◆ show_refusal()

void Slic3r::GUI::DesignSketchTool::show_refusal ( const std::string & why)
404{
405 if (inline_editor != nullptr && inline_editor->refuse(why)) return;
406 notify(why);
407}

References inline_editor, and notify().

Referenced by apply_dimension(), arm_polyline_segment_edit(), open_op_editor(), open_primary_autoedit(), open_tf_editor_a(), open_tf_editor_count(), set_arc_slot(), set_arc_sweep(), set_dimension_value(), set_ellipse_axis(), set_ellipsearc_sweep(), set_polygon_side(), set_rounded_rect(), and set_slot().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sketch_box()

BoundingBoxf3 Slic3r::GUI::DesignSketchTool::sketch_box ( const std::vector< SketchEntity > & entities,
const SketchPlane & plane )
static
3768{
3769 BoundingBoxf3 box;
3770 for (const SketchEntity& e : entities) {
3771 bool closed = false;
3772 for (const Vec2d& p : entity_polyline(e, closed))
3773 box.merge(plane.to_world(p));
3774 }
3775 return box;
3776}

References entities(), entity_polyline(), Slic3r::BoundingBox3Base< PointType >::merge(), plane(), and sketch_box().

Referenced by fit_box(), selection_box(), sketch_box(), and Slic3r::GUI::DesignPanel::zoom_to_feature().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sketch_has_selection()

bool Slic3r::GUI::DesignSketchTool::sketch_has_selection ( ) const
inline
555{ return !m_selection.empty() || !m_point_sel.empty(); }

References m_point_sel, and m_selection.

◆ sketch_hl_color()

const ColorRGBA * Slic3r::GUI::DesignSketchTool::sketch_hl_color ( int feature) const
private
9501{
9502 for (const auto& h : m_hl_sketches) if (h.first == feature) return &h.second;
9503 return nullptr;
9504}

References m_hl_sketches, and sketch_hl_color().

Referenced by render(), and sketch_hl_color().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ snap_chain_start()

bool Slic3r::GUI::DesignSketchTool::snap_chain_start ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
Vec2d & p ) const
private
2549{
2550 if (m_mode != Mode::Polyline || m_points.size() < 3) return false;
2551 if ((p - m_points[0]).norm() > screen_tol(canvas, evt, p)) return false;
2552 p = m_points[0];
2553 InferenceSnap s;
2554 s.kind = InferenceSnap::Kind::Endpoint; // renders the same hint as any endpoint snap
2555 s.point = m_points[0];
2556 const_cast<DesignSketchTool*>(this)->m_cursor_snap = s;
2557 return true;
2558}
@ Endpoint
Definition SketchInference.hpp:20

References Slic3r::InferenceSnap::Endpoint, Slic3r::InferenceSnap::kind, m_cursor_snap, m_mode, m_points, Slic3r::InferenceSnap::point, Polyline, screen_tol(), snap_chain_start(), and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse_impl(), and snap_chain_start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ snap_dir()

Vec2d Slic3r::GUI::DesignSketchTool::snap_dir ( const Vec2d & anchor,
const Vec2d & raw,
bool & locked ) const
private
2561{
2562 locked = false;
2563 if (m_snap_off) return raw;
2564
2565 const Vec2d d = raw - anchor;
2566 const double r = d.norm();
2567 if (r < 1e-9) return raw;
2568
2569 const double tol_deg = 5.0; // inference half-window
2570 double ang = std::atan2(d.y(), d.x()) * 180.0 / M_PI; // (-180,180]
2571 if (ang < 0.0) ang += 360.0; // [0,360)
2572
2573 // Base angles within one quadrant, replicated every 90 deg up to 360.
2574 static const double base[] = {0.0, 30.0, 45.0, 60.0};
2575 double best_cand = ang, best_diff = 1e30;
2576 for (int q = 0; q < 4; ++q) {
2577 for (double b : base) {
2578 const double cand = b + 90.0 * q;
2579 double diff = std::abs(ang - cand);
2580 if (diff > 180.0) diff = 360.0 - diff;
2581 if (diff < best_diff) { best_diff = diff; best_cand = cand; }
2582 }
2583 }
2584 if (best_diff > tol_deg) return raw;
2585
2586 locked = true;
2587 const double rad = best_cand * M_PI / 180.0;
2588 return anchor + r * Vec2d(std::cos(rad), std::sin(rad));
2589}

References Slic3r::diff(), M_PI, m_snap_off, and snap_dir().

Referenced by on_mouse_impl(), and snap_dir().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ snap_vertex()

Vec2d Slic3r::GUI::DesignSketchTool::snap_vertex ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
const Vec2d & raw,
bool & snapped ) const
private
2632{
2633 const InferenceSnap s = infer_at(canvas, evt, raw);
2634 // Cache the target so render() can draw a snap hint; only endpoint/centre/origin
2635 // count as a "vertex" snap for the callers that gate angle inference on it.
2636 const_cast<DesignSketchTool*>(this)->m_cursor_snap = s;
2637 snapped = s.snapped(); // any hard snap moves the cursor + suppresses angle lock
2638 return s.point;
2639}
InferenceSnap infer_at(GLCanvas3D &canvas, const wxMouseEvent &evt, const Vec2d &raw) const
Definition DesignSketchTool.cpp:2600

References infer_at(), m_cursor_snap, Slic3r::InferenceSnap::point, snap_vertex(), Slic3r::InferenceSnap::snapped(), and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse_impl(), and snap_vertex().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ solve_ok()

bool Slic3r::GUI::DesignSketchTool::solve_ok ( ) const
inline

◆ start_cut_drag()

void Slic3r::GUI::DesignSketchTool::start_cut_drag ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
6922{
6923 m_ct_drag = true;
6925 const double p = hole_axis_proj(canvas, evt, m_ct_base, m_ct_n);
6926 m_ct_grab_proj = std::isnan(p) ? 0.0 : p;
6927}

References hole_axis_proj(), m_ct_base, m_ct_drag, m_ct_grab_proj, m_ct_grab_val, m_ct_n, m_ct_offset, start_cut_drag(), and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse_impl(), and start_cut_drag().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_fillet_drag()

void Slic3r::GUI::DesignSketchTool::start_fillet_drag ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
6144{
6145 m_fl_drag = true;
6146 m_fl_press_x = evt.GetX();
6147 m_fl_press_y = evt.GetY();
6149 const double p = fillet_axis_proj(canvas, evt);
6150 m_fl_grab_proj = std::isnan(p) ? 0.0 : p;
6151}

References fillet_axis_proj(), m_fl_drag, m_fl_grab_proj, m_fl_grab_radius, m_fl_press_x, m_fl_press_y, m_fl_radius, start_fillet_drag(), and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse_impl(), and start_fillet_drag().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_hole_drag()

void Slic3r::GUI::DesignSketchTool::start_hole_drag ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int which )
private
6340{
6341 m_hl_drag = which;
6342 m_hl_press_x = evt.GetX();
6343 m_hl_press_y = evt.GetY();
6344 const Vec3d centre = m_hl_plane.to_world(Vec2d(m_hl_x, m_hl_y));
6345 if (which == 0) {
6346 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6347 m_hl_grab_uv = m_hl_plane.project(r.a, r.b - r.a);
6350 } else if (which == 1 || which == 2) {
6351 const Vec3d dir = (which == 1) ? m_hl_plane.x_axis.normalized() : m_hl_plane.normal.normalized();
6352 const double p = hole_axis_proj(canvas, evt, centre, dir);
6353 m_hl_grab_proj = std::isnan(p) ? 0.0 : p;
6354 m_hl_grab_val = (which == 1) ? m_hl_diameter * 0.5 : m_hl_depth;
6355 }
6356 // which == 3/4 (X/Y dim labels) are edit-only: a stationary click opens the inline editor.
6357}

References Slic3r::Linef3::a, Slic3r::Linef3::b, hole_axis_proj(), m_hl_depth, m_hl_diameter, m_hl_drag, m_hl_grab_proj, m_hl_grab_uv, m_hl_grab_val, m_hl_grab_x, m_hl_grab_y, m_hl_plane, m_hl_press_x, m_hl_press_y, m_hl_x, m_hl_y, Slic3r::GUI::GLCanvas3D::mouse_ray(), start_hole_drag(), and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse_impl(), and start_hole_drag().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_shell_drag()

void Slic3r::GUI::DesignSketchTool::start_shell_drag ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
6664{
6665 m_sh_drag = true;
6666 m_sh_press_x = evt.GetX();
6667 m_sh_press_y = evt.GetY();
6669 const double p = hole_axis_proj(canvas, evt, m_sh_anchor, m_sh_dir);
6670 m_sh_grab_proj = std::isnan(p) ? 0.0 : p;
6671}

References hole_axis_proj(), m_sh_anchor, m_sh_dir, m_sh_drag, m_sh_grab_proj, m_sh_grab_val, m_sh_press_x, m_sh_press_y, m_sh_thickness, start_shell_drag(), and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse_impl(), and start_shell_drag().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_thread_drag()

void Slic3r::GUI::DesignSketchTool::start_thread_drag ( GLCanvas3D & canvas,
const wxMouseEvent & evt,
int which )
private
6541{
6542 m_th_drag = which;
6543 m_th_press_x = evt.GetX();
6544 m_th_press_y = evt.GetY();
6545 const Vec3d centre = m_th_plane.to_world(Vec2d(m_th_x, m_th_y));
6546 if (which == 0) {
6547 const Linef3 r = canvas.mouse_ray(Point(evt.GetX(), evt.GetY()));
6548 m_th_grab_uv = m_th_plane.project(r.a, r.b - r.a);
6551 } else {
6552 const Vec3d dir = (which == 1) ? m_th_plane.x_axis.normalized() : m_th_plane.normal.normalized();
6553 const double p = hole_axis_proj(canvas, evt, centre, dir);
6554 m_th_grab_proj = std::isnan(p) ? 0.0 : p;
6555 m_th_grab_val = (which == 1) ? m_th_radius : m_th_height;
6556 }
6557}

References Slic3r::Linef3::a, Slic3r::Linef3::b, hole_axis_proj(), m_th_drag, m_th_grab_proj, m_th_grab_uv, m_th_grab_val, m_th_grab_x, m_th_grab_y, m_th_height, m_th_plane, m_th_press_x, m_th_press_y, m_th_radius, m_th_x, m_th_y, Slic3r::GUI::GLCanvas3D::mouse_ray(), start_thread_drag(), and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse_impl(), and start_thread_drag().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ take_right_click()

bool Slic3r::GUI::DesignSketchTool::take_right_click ( GLCanvas3D & canvas)
10783{
10784 auto press = std::exchange(m_right_press, {});
10785 return press && on_mouse_impl(*press, canvas);
10786}

References m_right_press, on_mouse_impl(), and take_right_click().

Referenced by take_right_click().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ tf_handle_pos()

Vec2d Slic3r::GUI::DesignSketchTool::tf_handle_pos ( ) const
private
9240{
9241 switch (m_mode) {
9242 case Mode::Move:
9243 case Mode::Array: return m_tf_pivot + m_tf_delta;
9244 case Mode::Rotate:
9245 case Mode::PolarArray: return m_tf_pivot + m_tf_handle_r * Vec2d(std::cos(m_tf_angle), std::sin(m_tf_angle));
9246 case Mode::Scale: return m_tf_pivot + Vec2d(m_tf_scale * m_tf_handle_r, 0.0);
9247 default: return m_tf_pivot;
9248 }
9249}

References Array, m_mode, m_tf_angle, m_tf_delta, m_tf_handle_r, m_tf_pivot, m_tf_scale, Move, PolarArray, Rotate, Scale, and tf_handle_pos().

Referenced by hit_test_tf_handle(), render_tf_gizmo(), and tf_handle_pos().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ tf_pick()

void Slic3r::GUI::DesignSketchTool::tf_pick ( int ei)
private
9168{
9169 if (ei < 0 || ei >= int(m_entities.size())) return;
9170 auto it = std::find(m_tf_targets.begin(), m_tf_targets.end(), ei);
9171 if (it == m_tf_targets.end()) m_tf_targets.push_back(ei); // toggle-select like Mirror
9172 else m_tf_targets.erase(it);
9174 // Seed sensible starting parameters (mirrors the retired card defaults so the ghost is
9175 // immediately visible). Only seed while still at the neutral value, so re-picking more
9176 // targets keeps a value the user already dialled in.
9177 if (!m_tf_targets.empty()) {
9178 const double step = std::max(m_tf_handle_r * 1.5, 1.0);
9179 switch (m_mode) {
9180 case Mode::Move:
9181 if (m_tf_delta.norm() < 1e-9) m_tf_delta = Vec2d(step, 0.0);
9182 break;
9183 case Mode::Array:
9184 if (m_tf_delta.norm() < 1e-9) {
9185 Vec2d d(step, 0.0); // default: perpendicular to a single line, else +X
9186 if (m_tf_targets.size() == 1) {
9187 const SketchEntity& e = m_entities[m_tf_targets[0]];
9188 if (e.type == SketchEntity::Type::Line) {
9189 Vec2d t = e.p1 - e.p0;
9190 if (t.norm() > 1e-9) { t.normalize(); d = Vec2d(-t.y(), t.x()) * step; }
9191 }
9192 }
9193 m_tf_delta = d;
9194 }
9195 break;
9196 case Mode::Rotate: if (std::abs(m_tf_angle) < 1e-9) m_tf_angle = M_PI / 4.0; break; // 45°
9197 case Mode::PolarArray: if (std::abs(m_tf_angle) < 1e-9) m_tf_angle = 2.0 * M_PI; break; // 360°
9198 case Mode::Scale: if (std::abs(m_tf_scale - 1.0) < 1e-9) m_tf_scale = 2.0; break;
9199 default: break;
9200 }
9201 }
9203 m_selection = m_tf_targets; // reuse the existing selection highlight
9205}
void compute_tf_pivot()
Definition DesignSketchTool.cpp:9133

References Array, compute_tf_pivot(), Slic3r::SketchEntity::Line, m_entities, m_mode, M_PI, m_selection, m_tf_angle, m_tf_delta, m_tf_handle_r, m_tf_scale, m_tf_targets, Move, on_selection_changed, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, PolarArray, recompute_tf_ghost(), Rotate, Scale, tf_pick(), and Slic3r::SketchEntity::type.

Referenced by on_mouse_impl(), and tf_pick().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ tf_ready()

bool Slic3r::GUI::DesignSketchTool::tf_ready ( ) const
private
9128{ return !m_tf_targets.empty(); }

References m_tf_targets, and tf_ready().

Referenced by confirm_pending(), confirm_transform(), finish(), hit_test_tf_handle(), on_mouse_impl(), open_tf_editor_a(), open_tf_editor_count(), render_tf_gizmo(), set_tool(), and tf_ready().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ threading()

bool Slic3r::GUI::DesignSketchTool::threading ( ) const
inline
415{ return m_th_active; }

References m_th_active.

◆ toggle_selection_construction()

int Slic3r::GUI::DesignSketchTool::toggle_selection_construction ( )
613{
614 if (!selection_valid() || m_selection.empty()) return 0;
615 std::vector<bool> hit(m_entities.size(), false);
616 for (int i : m_selection) {
617 const int f = feature_of(i);
618 if (f >= 0)
619 for (int k = m_features[f].begin; k < m_features[f].end; ++k) hit[k] = true;
620 else
621 hit[i] = true;
622 }
623 // One direction for the whole batch: any real geometry in it -> all become construction.
624 bool any_real = false;
625 for (size_t i = 0; i < hit.size(); ++i)
626 if (hit[i] && !m_entities[i].construction) { any_real = true; break; }
627 int n = 0;
628 for (size_t i = 0; i < hit.size(); ++i)
629 if (hit[i] && m_entities[i].construction != any_real) { m_entities[i].construction = any_real; ++n; }
630 return n;
631}

References begin(), Slic3r::f(), feature_of(), m_entities, m_features, m_selection, and selection_valid().

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_construction().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ toggle_show_axes()

bool Slic3r::GUI::DesignSketchTool::toggle_show_axes ( )
inline
222{ m_show_axes = !m_show_axes; return m_show_axes; }

References m_show_axes.

◆ toggle_show_planes()

bool Slic3r::GUI::DesignSketchTool::toggle_show_planes ( )
inline

References m_show_planes.

◆ try_add_constraints()

bool Slic3r::GUI::DesignSketchTool::try_add_constraints ( const std::vector< SketchEntityConstraintDef > & cands)
2653{
2654 if (cands.empty()) return true;
2655 const size_t mark = m_constraints.size();
2656 for (const auto& c : cands) m_constraints.push_back(c);
2659 return true;
2660 }
2661 m_constraints.resize(mark); // roll back the conflicting batch
2662 // No re-solve to "restore": a failed solve no longer touches the geometry
2663 // (SketchSolver.cpp only writes back on success), so m_entities still holds the
2664 // prior solved state exactly. pl5.
2665 return false;
2666}
bool solve_sketch_entities(std::vector< SketchEntity > &entities, const std::vector< SketchEntityConstraintDef > &constraints)
Definition CadDocument.cpp:616

References m_constraints, m_entities, on_constraints_changed, Slic3r::solve_sketch_entities(), and try_add_constraints().

Referenced by confirm_op(), confirm_transform(), heal_coincidences(), infer_auto_constraints(), and try_add_constraints().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ undo_last_entity()

bool Slic3r::GUI::DesignSketchTool::undo_last_entity ( )
497{
498 if (!m_active || m_entities.empty()) return false;
499 if (!can_redo_entity()) m_sketch_redo.clear(); // the sketch moved on since the last undo
501 const int last = int(m_entities.size()) - 1;
502 int begin = last;
503 for (const Feature& f : m_features)
504 if (f.begin <= last && last < f.end && f.end == last + 1) begin = std::min(begin, f.begin);
505 m_selection.clear();
506 for (int i = begin; i <= last; ++i) m_selection.push_back(i);
509 snap.after_entities = m_entities.size();
510 snap.after_constraints = m_constraints.size();
511 m_sketch_redo.push_back(std::move(snap));
512 return true;
513}
void delete_selected()
Definition DesignSketchTool.cpp:515

References Slic3r::GUI::DesignSketchTool::SketchSnap::after_constraints, Slic3r::GUI::DesignSketchTool::SketchSnap::after_entities, begin(), can_redo_entity(), delete_selected(), Slic3r::f(), m_active, m_constraints, m_dimensions, m_entities, m_features, m_selection, m_sketch_redo, and reset_autoedit().

Here is the call graph for this function:

◆ update_hover()

bool Slic3r::GUI::DesignSketchTool::update_hover ( GLCanvas3D & canvas,
wxMouseEvent & evt )
private
1060{
1061 if (!evt.Moving()) return false;
1062 Vec2d p;
1063 screen_to_plane(canvas, evt, p);
1064 // Zoom-aware pick tolerance: project a point a few px away and measure in plane units.
1065 // The SAME budget a click grabs with: a handle that looks un-hovered must not be grabbable.
1066 const double tol = screen_tol(canvas, evt, p, kPickPx);
1067 const bool had = m_has_hover_handle;
1068 const Handle prev = m_hover_handle;
1069 Handle h;
1072 return (had != m_has_hover_handle) ||
1073 (m_has_hover_handle && (prev.ei != h.ei || prev.role != h.role));
1074}

References Slic3r::GUI::DesignSketchTool::Handle::ei, hit_test_handle(), kPickPx, m_has_hover_handle, m_hover_handle, Slic3r::GUI::DesignSketchTool::Handle::role, screen_to_plane(), screen_tol(), and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse_impl().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ update_solid_hover()

bool Slic3r::GUI::DesignSketchTool::update_solid_hover ( GLCanvas3D & canvas,
const wxMouseEvent & evt )
private
4180{
4181 SolidPick p;
4182 if (!resolve_solid_pick(canvas, evt.GetX(), evt.GetY(), p))
4183 p = SolidPick{}; // off the solid: no promise to make
4184 // Compared AT THE LEVEL THAT WAS PICKED, for the same reason the click's escalation is
4185 // (see same_pick above): an edge pick carries whichever face the ray happened to cross, and
4186 // that face changes as the pointer slides along the edge without the answer changing at all.
4187 const bool same = p.kind == m_pre.kind && p.body == m_pre.body
4188 && (p.kind == SolidSel::Vertex ? (p.vertex_pt - m_pre.vertex_pt).norm() < 1e-9
4189 : p.kind == SolidSel::Edge ? p.edge == m_pre.edge
4190 : p.kind == SolidSel::Face ? p.face == m_pre.face
4191 : true);
4192 if (same) return false;
4193 m_pre = std::move(p);
4194 return true;
4195}
SolidSel kind
Definition DesignSketchTool.hpp:1316

References Slic3r::GUI::DesignSketchTool::SolidPick::body, Edge, Slic3r::GUI::DesignSketchTool::SolidPick::edge, Face, Slic3r::GUI::DesignSketchTool::SolidPick::face, Slic3r::GUI::DesignSketchTool::SolidPick::kind, m_pre, resolve_solid_pick(), update_solid_hover(), Vertex, Slic3r::GUI::DesignSketchTool::SolidPick::vertex_pt, and Slic3r::GUI::wxMouseEvent.

Referenced by on_mouse_impl(), and update_solid_hover().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ upsert_constraint()

int Slic3r::GUI::DesignSketchTool::upsert_constraint ( const SketchEntityConstraintDef & c)
private
1291{
1292 auto same_operands = [&](const SketchEntityConstraintDef& o) {
1293 if (o.ea == c.ea && o.ra == c.ra && o.eb == c.eb && o.rb == c.rb) return true;
1294 return o.ea == c.eb && o.ra == c.rb && o.eb == c.ea && o.rb == c.ra;
1295 };
1296 for (int i = 0; i < int(m_constraints.size()); ++i)
1297 if (m_constraints[i].type == c.type && same_operands(m_constraints[i])) {
1298 m_constraints[i] = c;
1299 return i;
1300 }
1301 m_constraints.push_back(c);
1302 return int(m_constraints.size()) - 1;
1303}

References Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, m_constraints, Slic3r::SketchEntityConstraintDef::ra, Slic3r::SketchEntityConstraintDef::rb, and Slic3r::SketchEntityConstraintDef::type.

Referenced by upsert_dimension_constraint().

Here is the caller graph for this function:

◆ upsert_dimension()

int Slic3r::GUI::DesignSketchTool::upsert_dimension ( const DimAnnot & a)
private
1326{
1327 for (int i = 0; i < int(m_dimensions.size()); ++i) {
1328 const DimAnnot& o = m_dimensions[i];
1329 if (o.kind == a.kind && ((o.ea == a.ea && o.eb == a.eb) || (o.ea == a.eb && o.eb == a.ea))) {
1330 const Vec2d keep = m_dimensions[i].label_pos; // don't teleport a placed label
1331 m_dimensions[i] = a;
1332 m_dimensions[i].label_pos = keep;
1333 return i;
1334 }
1335 }
1336 m_dimensions.push_back(a);
1337 return int(m_dimensions.size()) - 1;
1338}

References Slic3r::GUI::DesignSketchTool::DimAnnot::ea, Slic3r::GUI::DesignSketchTool::DimAnnot::eb, Slic3r::GUI::DesignSketchTool::DimAnnot::kind, and m_dimensions.

Referenced by open_primary_autoedit(), and place_dimension().

Here is the caller graph for this function:

◆ upsert_dimension_constraint()

int Slic3r::GUI::DesignSketchTool::upsert_dimension_constraint ( const SketchEntityConstraintDef & c)
private
1309{
1310 const bool zero_case = (c.type == SketchConstraintType::Coincident);
1311 const bool dist_case = (c.type == SketchConstraintType::Distance);
1312 if (zero_case || dist_case) {
1313 erase_constraints([&](int, const SketchEntityConstraintDef& d) {
1314 const bool same = (d.ea == c.ea && d.eb == c.eb) || (d.ea == c.eb && d.eb == c.ea);
1315 if (!same) return false;
1316 return zero_case ? (d.type == SketchConstraintType::Distance)
1317 : (d.type == SketchConstraintType::Coincident);
1318 });
1319 }
1320 return upsert_constraint(c);
1321}
int upsert_constraint(const SketchEntityConstraintDef &c)
Definition DesignSketchTool.cpp:1290
@ Coincident
Definition CadDocument.hpp:28

References Slic3r::Coincident, Slic3r::Distance, Slic3r::SketchEntityConstraintDef::ea, Slic3r::SketchEntityConstraintDef::eb, erase_constraints(), Slic3r::SketchEntityConstraintDef::type, and upsert_constraint().

Referenced by open_primary_autoedit(), place_dimension(), and record_dimension_constraint().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ value_field_open()

bool Slic3r::GUI::DesignSketchTool::value_field_open ( ) const
inline
123{ return m_awaiting_length; }

References m_awaiting_length.

Referenced by Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_describe().

Here is the caller graph for this function:

◆ xform_world_corners()

void Slic3r::GUI::DesignSketchTool::xform_world_corners ( Vec2d out[4]) const
private
8611{
8612 const double x0 = m_xform_min.x() * m_xform_sx + m_xform_offset.x();
8613 const double x1 = m_xform_max.x() * m_xform_sx + m_xform_offset.x();
8614 const double y0 = m_xform_min.y() * m_xform_sy + m_xform_offset.y();
8615 const double y1 = m_xform_max.y() * m_xform_sy + m_xform_offset.y();
8616 out[0] = Vec2d(x0, y0); out[1] = Vec2d(x1, y0);
8617 out[2] = Vec2d(x1, y1); out[3] = Vec2d(x0, y1);
8618}

References m_xform_max, m_xform_min, m_xform_offset, m_xform_sx, m_xform_sy, and xform_world_corners().

Referenced by hit_test_xform_handle(), on_mouse_impl(), render_xform_gizmo(), and xform_world_corners().

Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ inline_editor

class SketchInlineEditor* Slic3r::GUI::DesignSketchTool::inline_editor {nullptr}
194{nullptr};

Referenced by render(), and show_refusal().

◆ kLabelPx

double Slic3r::GUI::DesignSketchTool::kLabelPx = 24.0
staticconstexprprivate

Referenced by on_mouse_impl().

◆ kPickPx

double Slic3r::GUI::DesignSketchTool::kPickPx = 8.0
staticconstexprprivate

Referenced by on_mouse_impl(), and update_hover().

◆ kToolPickPx

double Slic3r::GUI::DesignSketchTool::kToolPickPx = 24.0
staticconstexprprivate

Referenced by on_mouse_impl().

◆ m_active

◆ m_autoedit_dim_idx

int Slic3r::GUI::DesignSketchTool::m_autoedit_dim_idx {-1}
private
1098{-1}; // index into m_autoedit_dims (-1 = idle)

Referenced by arm_polyline_segment_edit(), open_next_autoedit_dim(), open_primary_autoedit(), render(), and reset_autoedit().

◆ m_autoedit_dims

std::vector<AutoEditStep> Slic3r::GUI::DesignSketchTool::m_autoedit_dims
private

◆ m_autoedit_label_pos

Vec2d Slic3r::GUI::DesignSketchTool::m_autoedit_label_pos {1e18, 1e18}
private
1104{1e18, 1e18};

Referenced by draw_text(), and render().

◆ m_autoedit_pending

bool Slic3r::GUI::DesignSketchTool::m_autoedit_pending {false}
private
1087{false};// a new entity just committed -> open editor

Referenced by begin(), render(), and reset_autoedit().

◆ m_autoedit_seen

int Slic3r::GUI::DesignSketchTool::m_autoedit_seen {-1}
private
1086{-1}; // entity count baseline for draw-then-edit

Referenced by add_entities_scripted(), begin(), render(), and reset_autoedit().

◆ m_awaiting_length

bool Slic3r::GUI::DesignSketchTool::m_awaiting_length {false}
private

◆ m_bad_dims

std::vector<int> Slic3r::GUI::DesignSketchTool::m_bad_dims
private

◆ m_body_edges

std::vector<std::vector<std::vector<Vec3d> > > Slic3r::GUI::DesignSketchTool::m_body_edges
private

◆ m_body_edges_hidden

bool Slic3r::GUI::DesignSketchTool::m_body_edges_hidden {false}
private

◆ m_body_edges_model

GLModel Slic3r::GUI::DesignSketchTool::m_body_edges_model
private

Referenced by render_body_edges().

◆ m_body_edges_shape

std::vector<TopoDS_Shape> Slic3r::GUI::DesignSketchTool::m_body_edges_shape
private

◆ m_body_edges_tol

std::vector<double> Slic3r::GUI::DesignSketchTool::m_body_edges_tol
private

◆ m_chain_dup_tol

double Slic3r::GUI::DesignSketchTool::m_chain_dup_tol {1e-9}
private
1160{1e-9}; // plane units ~3 px at the last chain click (double-click repeat)

Referenced by end_chain(), and on_mouse_impl().

◆ m_constrain_cons

std::vector<SketchEntityConstraintDef> Slic3r::GUI::DesignSketchTool::m_constrain_cons
private

◆ m_constrain_entities

bool Slic3r::GUI::DesignSketchTool::m_constrain_entities {false}
private

◆ m_constraint_hl

std::vector<int> Slic3r::GUI::DesignSketchTool::m_constraint_hl
private

◆ m_constraints

◆ m_construction

◆ m_ct_active

bool Slic3r::GUI::DesignSketchTool::m_ct_active {false}
private

◆ m_ct_base

Vec3d Slic3r::GUI::DesignSketchTool::m_ct_base {Vec3d::Zero()}
private
1597{Vec3d::Zero()}; // body centre projected into the cut plane

Referenced by drag_cut_arrow(), hit_test_cut_arrow(), render_cut_gizmo(), set_cut_gizmo(), and start_cut_drag().

◆ m_ct_drag

bool Slic3r::GUI::DesignSketchTool::m_ct_drag {false}
private

◆ m_ct_grab_proj

double Slic3r::GUI::DesignSketchTool::m_ct_grab_proj {0.0}
private
1605{0.0};

Referenced by drag_cut_arrow(), and start_cut_drag().

◆ m_ct_grab_val

double Slic3r::GUI::DesignSketchTool::m_ct_grab_val {0.0}
private
1604{0.0};

Referenced by drag_cut_arrow(), and start_cut_drag().

◆ m_ct_half

double Slic3r::GUI::DesignSketchTool::m_ct_half {10.0}
private
1602{10.0};

Referenced by render_cut_gizmo(), and set_cut_gizmo().

◆ m_ct_n

Vec3d Slic3r::GUI::DesignSketchTool::m_ct_n {Vec3d::UnitZ()}
private
1598{Vec3d::UnitZ()}; // cut plane normal (unit)

Referenced by drag_cut_arrow(), hit_test_cut_arrow(), render_cut_gizmo(), set_cut_gizmo(), and start_cut_drag().

◆ m_ct_offset

double Slic3r::GUI::DesignSketchTool::m_ct_offset {0.0}
private

◆ m_ct_rect_model

GLModel Slic3r::GUI::DesignSketchTool::m_ct_rect_model
private

Referenced by render_cut_gizmo().

◆ m_ct_stroke_model

GLModel Slic3r::GUI::DesignSketchTool::m_ct_stroke_model
private

Referenced by render_cut_gizmo().

◆ m_ct_u

Vec3d Slic3r::GUI::DesignSketchTool::m_ct_u {Vec3d::UnitX()}
private
1599{Vec3d::UnitX()}; // cut plane U axis (unit)

Referenced by render_cut_gizmo(), and set_cut_gizmo().

◆ m_ct_v

Vec3d Slic3r::GUI::DesignSketchTool::m_ct_v {Vec3d::UnitY()}
private
1600{Vec3d::UnitY()}; // cut plane V axis (unit)

Referenced by render_cut_gizmo(), and set_cut_gizmo().

◆ m_cursor

Vec2d Slic3r::GUI::DesignSketchTool::m_cursor {0,0}
private
1080{0,0};

Referenced by build_readout(), on_mouse_impl(), and render().

◆ m_cursor_locked

bool Slic3r::GUI::DesignSketchTool::m_cursor_locked {false}
private
1084{false}; // rubber-band segment is angle-locked

Referenced by on_mouse_impl(), and render().

◆ m_cursor_snap

InferenceSnap Slic3r::GUI::DesignSketchTool::m_cursor_snap
private

◆ m_datum_planes

std::vector<SketchPlane> Slic3r::GUI::DesignSketchTool::m_datum_planes
private

Referenced by has_display(), and render_datum_planes().

◆ m_datum_sizes

std::vector<Vec2d> Slic3r::GUI::DesignSketchTool::m_datum_sizes
private

Referenced by render_datum_planes().

◆ m_dbp_active

bool Slic3r::GUI::DesignSketchTool::m_dbp_active {false}
private

◆ m_dbp_base

std::vector<int> Slic3r::GUI::DesignSketchTool::m_dbp_base
private

◆ m_dbp_hover

int Slic3r::GUI::DesignSketchTool::m_dbp_hover {-1}
private

◆ m_dbp_labels

std::vector<std::string> Slic3r::GUI::DesignSketchTool::m_dbp_labels
private

◆ m_dbp_planes

std::vector<SketchPlane> Slic3r::GUI::DesignSketchTool::m_dbp_planes
private

◆ m_dim_e0

int Slic3r::GUI::DesignSketchTool::m_dim_e0 {-1}
private
1239{-1}; // first picked point's entity (Dimension)

Referenced by abort_gesture(), delete_selected(), on_mouse_impl(), and set_tool().

◆ m_dim_has0

bool Slic3r::GUI::DesignSketchTool::m_dim_has0 {false}
private
1241{false}; // a first point is pending

Referenced by abort_gesture(), begin(), cancel(), delete_selected(), emit_step_hint(), finish(), has_pending_picks(), on_mouse_impl(), and set_tool().

◆ m_dim_label_seq

int Slic3r::GUI::DesignSketchTool::m_dim_label_seq {0}
private
1261{0};

Referenced by draw_dim_label(), and render().

◆ m_dim_r0

SketchPointRole Slic3r::GUI::DesignSketchTool::m_dim_r0 {SketchPointRole::P0}
private

◆ m_dimensions

◆ m_display_pick

int Slic3r::GUI::DesignSketchTool::m_display_pick {-1}
private
1273{-1}; // FEATURE index of the click-selected display sketch (-1 none)

Referenced by clear_display_pick(), display_pick(), on_mouse_impl(), render(), selected_loop_entities(), selection_box(), and set_display_pick().

◆ m_display_pick_region

int Slic3r::GUI::DesignSketchTool::m_display_pick_region {-1}
private
1382{-1}; // selected closed-region index within that feature (-1 none)

Referenced by clear_display_pick(), display_pick_region(), on_mouse_impl(), render(), selected_loop_entities(), selection_box(), and set_display_pick().

◆ m_display_sketches

std::vector<DisplaySketch> Slic3r::GUI::DesignSketchTool::m_display_sketches
private

◆ m_dof

int Slic3r::GUI::DesignSketchTool::m_dof {-1}
private
1234{-1}; // remaining DoF; 0 = fully constrained, <0 = unknown

Referenced by begin(), cancel(), dof(), render(), and resolve_live_drag().

◆ m_dr_active

bool Slic3r::GUI::DesignSketchTool::m_dr_active {false}
private

◆ m_dr_angle

double Slic3r::GUI::DesignSketchTool::m_dr_angle {5.0}
private
1586{5.0}; // current sweep magnitude (deg, [-89, 89])

Referenced by drag_draft_arc(), hit_test_draft_handle(), render_draft_gizmo(), and set_draft_gizmo().

◆ m_dr_axis

Vec3d Slic3r::GUI::DesignSketchTool::m_dr_axis {Vec3d::UnitZ()}
private
1583{Vec3d::UnitZ()}; // draft axis = world +Z (pull direction)

Referenced by drag_draft_arc(), hit_test_draft_handle(), render_draft_gizmo(), and set_draft_gizmo().

◆ m_dr_center

Vec3d Slic3r::GUI::DesignSketchTool::m_dr_center {Vec3d::Zero()}
private
1582{Vec3d::Zero()}; // arc center = face centroid (world)

Referenced by drag_draft_arc(), hit_test_draft_handle(), render_draft_gizmo(), and set_draft_gizmo().

◆ m_dr_drag

bool Slic3r::GUI::DesignSketchTool::m_dr_drag {false}
private
1587{false};

Referenced by clear_draft_gizmo(), on_mouse_impl(), and set_draft_gizmo().

◆ m_dr_press_x

int Slic3r::GUI::DesignSketchTool::m_dr_press_x {0}
private
1588{0}, m_dr_press_y{0};

Referenced by on_mouse_impl().

◆ m_dr_press_y

int Slic3r::GUI::DesignSketchTool::m_dr_press_y {0}
private
1588{0}, m_dr_press_y{0};

Referenced by on_mouse_impl().

◆ m_dr_radius

double Slic3r::GUI::DesignSketchTool::m_dr_radius {10.0}
private
1585{10.0}; // arc radius (world)

Referenced by hit_test_draft_handle(), render_draft_gizmo(), and set_draft_gizmo().

◆ m_dr_ref

Vec3d Slic3r::GUI::DesignSketchTool::m_dr_ref {Vec3d::UnitX()}
private
1584{Vec3d::UnitX()}; // angle-0 reference dir (perp to axis)

Referenced by drag_draft_arc(), hit_test_draft_handle(), render_draft_gizmo(), and set_draft_gizmo().

◆ m_dr_stroke_model

GLModel Slic3r::GUI::DesignSketchTool::m_dr_stroke_model
private

Referenced by render_draft_gizmo().

◆ m_drag_ei

int Slic3r::GUI::DesignSketchTool::m_drag_ei {-1}
private
1110{-1}; // entity whose point is being dragged

Referenced by on_mouse_impl(), and render_live_quotes().

◆ m_drag_handle

Handle Slic3r::GUI::DesignSketchTool::m_drag_handle
private

◆ m_drag_poly_fi

int Slic3r::GUI::DesignSketchTool::m_drag_poly_fi {-1}
private
1111{-1}; // >=0 if the grabbed point is a polygon

Referenced by on_mouse_impl().

◆ m_drag_rect_anchor

Vec2d Slic3r::GUI::DesignSketchTool::m_drag_rect_anchor {0,0}
private
1114{0,0}; // the fixed (opposite) corner

Referenced by drag_rect_corner(), and on_mouse_impl().

◆ m_drag_rect_fi

int Slic3r::GUI::DesignSketchTool::m_drag_rect_fi {-1}
private
1113{-1}; // >=0 if dragging an axis-aligned rect corner

Referenced by on_mouse_impl().

◆ m_drag_role

SketchPointRole Slic3r::GUI::DesignSketchTool::m_drag_role {SketchPointRole::P0}
private

Referenced by on_mouse_impl().

◆ m_drag_slot_c1

bool Slic3r::GUI::DesignSketchTool::m_drag_slot_c1 {false}
private
1116{false}; // true=cap@c1, false=cap@c0

Referenced by drag_slot_handle(), and on_mouse_impl().

◆ m_drag_slot_fi

int Slic3r::GUI::DesignSketchTool::m_drag_slot_fi {-1}
private
1115{-1}; // >=0 if dragging a slot cap centre

Referenced by on_mouse_impl().

◆ m_dragging_handle

bool Slic3r::GUI::DesignSketchTool::m_dragging_handle {false}
private
1122{false};// a handle grab is in progress

Referenced by on_mouse_impl(), and render_live_quotes().

◆ m_dragging_point

bool Slic3r::GUI::DesignSketchTool::m_dragging_point {false}
private
1109{false}; // a point grab is in progress (Mode::Select)

Referenced by on_mouse_impl(), and render_live_quotes().

◆ m_dz_active

bool Slic3r::GUI::DesignSketchTool::m_dz_active {false}
private

◆ m_dz_anchor

Vec3d Slic3r::GUI::DesignSketchTool::m_dz_anchor {Vec3d::Zero()}
private
1407{Vec3d::Zero()}; // base-plane origin (offset arrow tail)

Referenced by drag_datum_handle(), hit_test_datum_handle(), render_datum_gizmo(), and set_datum_gizmo().

◆ m_dz_drag

int Slic3r::GUI::DesignSketchTool::m_dz_drag {-1}
private
1405{-1}; // 0=+u,1=-u,2=+v,3=-v handle, 4=offset tip, -1 none

Referenced by clear_datum_gizmo(), and on_mouse_impl().

◆ m_dz_normal

Vec3d Slic3r::GUI::DesignSketchTool::m_dz_normal {0.0, 0.0, 1.0}
private
1408{0.0, 0.0, 1.0}; // base normal (offset arrow direction)

Referenced by drag_datum_handle(), hit_test_datum_handle(), render_datum_gizmo(), and set_datum_gizmo().

◆ m_dz_offset

double Slic3r::GUI::DesignSketchTool::m_dz_offset {0.0}
private
1409{0.0}; // current signed offset along the base normal

Referenced by drag_datum_handle(), hit_test_datum_handle(), render_datum_gizmo(), and set_datum_gizmo().

◆ m_dz_offset_on

bool Slic3r::GUI::DesignSketchTool::m_dz_offset_on {false}
private
1410{false}; // draw/allow the offset arrow (Offset-from-base only)

Referenced by hit_test_datum_handle(), render_datum_gizmo(), and set_datum_gizmo().

◆ m_dz_plane

SketchPlane Slic3r::GUI::DesignSketchTool::m_dz_plane
private

◆ m_dz_press_x

int Slic3r::GUI::DesignSketchTool::m_dz_press_x {0}
private
1406{0}, m_dz_press_y{0};

Referenced by on_mouse_impl().

◆ m_dz_press_y

int Slic3r::GUI::DesignSketchTool::m_dz_press_y {0}
private
1406{0}, m_dz_press_y{0};

Referenced by on_mouse_impl().

◆ m_dz_usize

double Slic3r::GUI::DesignSketchTool::m_dz_usize {60.0}
private
1403{60.0}; // current u extent (full width)

Referenced by drag_datum_handle(), hit_test_datum_handle(), render_datum_gizmo(), and set_datum_gizmo().

◆ m_dz_vsize

double Slic3r::GUI::DesignSketchTool::m_dz_vsize {60.0}
private
1404{60.0}; // current v extent (full height)

Referenced by drag_datum_handle(), hit_test_datum_handle(), render_datum_gizmo(), and set_datum_gizmo().

◆ m_entities

std::vector<SketchEntity> Slic3r::GUI::DesignSketchTool::m_entities
private

Referenced by add_entities_scripted(), add_imported_regions(), announce_loop_defects(), append_entities(), apply_angle_between(), apply_dimension(), apply_live_trim(), apply_segment_length(), begin(), begin_constrain(), begin_constrain_entities(), begin_edit(), begin_feature(), build_constraint_glyphs(), build_handles(), can_redo_entity(), can_undo_entity(), cancel(), closed_regions(), compute_tf_pivot(), compute_trim_preview(), confirm_op(), confirm_transform(), connected_loop(), constrain_value_anchor(), delete_selected(), dimension_current(), dimension_kind(), drag_arc_handle(), drag_ellipsearc_handle(), drag_polygon_vertex(), drag_rect_corner(), drag_slot_handle(), draw_dim_quote(), end_chain(), end_feature(), entities(), finish(), first_selected_type(), fit_box(), has_entities(), heal_coincidences(), hit_test(), hit_test_point(), infer_at(), infer_auto_constraints(), keep_segment_as_drawn(), live_sketch_has_work(), loop_report(), make_tangent_arc(), measure_dim(), on_mouse_impl(), op_chain_entities(), op_corner(), op_pick(), open_angle_editor(), open_arc_angle_editor(), open_ellipse_axis_editor(), open_polygon_angle_editor(), open_polygon_side_editor(), open_primary_autoedit(), point_at(), push_circle(), push_line(), push_point(), rebuild_features_from_entities(), recompute_op_ghost(), recompute_tf_ghost(), record_dimension_constraint(), redo_last_entity(), region_at(), render(), render_live_quotes(), reset_autoedit(), resolve_live_drag(), select_at_screen(), select_indices(), selection_box(), selection_valid(), set_arc_slot(), set_arc_sweep(), set_constrain_entities(), set_ellipse_axis(), set_ellipsearc_sweep(), set_handle(), set_line_angle(), set_point(), set_polygon_angle(), set_polygon_radius(), set_rect_angle(), set_rounded_rect(), set_slot(), set_slot_angle(), tf_pick(), toggle_selection_construction(), try_add_constraints(), and undo_last_entity().

◆ m_entity_conflict

std::vector<char> Slic3r::GUI::DesignSketchTool::m_entity_conflict
private

◆ m_escalate_repick

bool Slic3r::GUI::DesignSketchTool::m_escalate_repick {true}
private
1339{true}; // re-picking the same sub-element takes the whole body

Referenced by handle_solid_click(), and set_escalate_on_repick().

◆ m_ex_active

bool Slic3r::GUI::DesignSketchTool::m_ex_active {false}
private

◆ m_ex_arrow_model

GLModel Slic3r::GUI::DesignSketchTool::m_ex_arrow_model
private

Referenced by render_extrude_gizmo().

◆ m_ex_centroid

Vec2d Slic3r::GUI::DesignSketchTool::m_ex_centroid {0,0}
private
1387{0,0}; // arrow base in plane coords (profile centroid)

Referenced by drag_extrude_arrow(), hit_test_extrude_arrow(), render_extrude_gizmo(), and set_extrude_gizmo().

◆ m_ex_depth

double Slic3r::GUI::DesignSketchTool::m_ex_depth {0.0}
private
1388{0.0}; // primary depth (= m_distance)

Referenced by drag_extrude_arrow(), hit_test_extrude_arrow(), open_extrude_editor(), render_extrude_gizmo(), and set_extrude_gizmo().

◆ m_ex_depth2

double Slic3r::GUI::DesignSketchTool::m_ex_depth2 {0.0}
private
1389{0.0}; // second-side depth (TwoSided, = m_distance2)

Referenced by drag_extrude_arrow(), hit_test_extrude_arrow(), open_extrude_editor(), render_extrude_gizmo(), and set_extrude_gizmo().

◆ m_ex_drag

int Slic3r::GUI::DesignSketchTool::m_ex_drag {-1}
private
1392{-1}; // 0 = primary arrow, 1 = second arrow, -1 = none

Referenced by clear_extrude_gizmo(), and on_mouse_impl().

◆ m_ex_flip

bool Slic3r::GUI::DesignSketchTool::m_ex_flip {false}
private

◆ m_ex_plane

SketchPlane Slic3r::GUI::DesignSketchTool::m_ex_plane
private

◆ m_ex_press_x

int Slic3r::GUI::DesignSketchTool::m_ex_press_x {0}
private
1393{0}, m_ex_press_y{0}; // press px to tell click-to-edit from drag

Referenced by on_mouse_impl().

◆ m_ex_press_y

int Slic3r::GUI::DesignSketchTool::m_ex_press_y {0}
private
1393{0}, m_ex_press_y{0}; // press px to tell click-to-edit from drag

Referenced by on_mouse_impl().

◆ m_ex_two_sided

bool Slic3r::GUI::DesignSketchTool::m_ex_two_sided {false}
private

◆ m_features

◆ m_fill_model

GLModel Slic3r::GUI::DesignSketchTool::m_fill_model
private

◆ m_fl_active

bool Slic3r::GUI::DesignSketchTool::m_fl_active {false}
private

◆ m_fl_anchor

Vec3d Slic3r::GUI::DesignSketchTool::m_fl_anchor {Vec3d::Zero()}
private
1484{Vec3d::Zero()}; // edge midpoint (world, already body-transformed)

Referenced by fillet_axis_proj(), hit_test_fillet_arrow(), render_fillet_gizmo(), and set_fillet_gizmo().

◆ m_fl_arrow_model

GLModel Slic3r::GUI::DesignSketchTool::m_fl_arrow_model
private

Referenced by render_fillet_gizmo().

◆ m_fl_dir

Vec3d Slic3r::GUI::DesignSketchTool::m_fl_dir {Vec3d::UnitZ()}
private
1485{Vec3d::UnitZ()}; // unit radius direction (perp to edge, outward)

Referenced by fillet_axis_proj(), hit_test_fillet_arrow(), render_fillet_gizmo(), and set_fillet_gizmo().

◆ m_fl_drag

bool Slic3r::GUI::DesignSketchTool::m_fl_drag {false}
private

◆ m_fl_grab_proj

double Slic3r::GUI::DesignSketchTool::m_fl_grab_proj {0.0}
private
1489{0.0}; // axis projection at grab (relative drag reference)

Referenced by drag_fillet_arrow(), and start_fillet_drag().

◆ m_fl_grab_radius

double Slic3r::GUI::DesignSketchTool::m_fl_grab_radius {1.0}
private
1490{1.0}; // radius at grab (relative drag reference)

Referenced by drag_fillet_arrow(), and start_fillet_drag().

◆ m_fl_press_x

int Slic3r::GUI::DesignSketchTool::m_fl_press_x {0}
private
1488{0}, m_fl_press_y{0};

Referenced by on_mouse_impl(), and start_fillet_drag().

◆ m_fl_press_y

int Slic3r::GUI::DesignSketchTool::m_fl_press_y {0}
private
1488{0}, m_fl_press_y{0};

Referenced by on_mouse_impl(), and start_fillet_drag().

◆ m_fl_radius

double Slic3r::GUI::DesignSketchTool::m_fl_radius {1.0}
private

◆ m_glyph_hits

std::vector<GlyphHit> Slic3r::GUI::DesignSketchTool::m_glyph_hits
private

◆ m_glyph_r

double Slic3r::GUI::DesignSketchTool::m_glyph_r {0.0}
private
1257{0.0}; // badge half-size in plane units (hit radius)

Referenced by build_constraint_glyphs(), and remove_constraint_near().

◆ m_has_cursor

◆ m_has_hover_handle

bool Slic3r::GUI::DesignSketchTool::m_has_hover_handle {false}
private
1124{false};// cursor is near a handle (highlight it)

Referenced by render(), and update_hover().

◆ m_highlight_model

GLModel Slic3r::GUI::DesignSketchTool::m_highlight_model
private

◆ m_hl_active

bool Slic3r::GUI::DesignSketchTool::m_hl_active {false}
private

◆ m_hl_depth

double Slic3r::GUI::DesignSketchTool::m_hl_depth {10.0}
private

◆ m_hl_diameter

double Slic3r::GUI::DesignSketchTool::m_hl_diameter {6.0}
private

◆ m_hl_drag

int Slic3r::GUI::DesignSketchTool::m_hl_drag {-1}
private
1513{-1}; // 0=centre, 1=diameter, 2=depth, 3=X-dim, 4=Y-dim, -1=none

Referenced by clear_hole_gizmo(), drag_hole_handle(), on_mouse_impl(), set_hole_gizmo(), and start_hole_drag().

◆ m_hl_faces

std::vector<FaceHighlight> Slic3r::GUI::DesignSketchTool::m_hl_faces
private

◆ m_hl_grab_proj

double Slic3r::GUI::DesignSketchTool::m_hl_grab_proj {0.0}
private
1515{0.0}; // diameter/depth axis projection at grab (relative)

Referenced by drag_hole_handle(), and start_hole_drag().

◆ m_hl_grab_uv

Vec2d Slic3r::GUI::DesignSketchTool::m_hl_grab_uv {0.0, 0.0}
private
1517{0.0, 0.0}; // centre drag: plane-projected grab point

Referenced by drag_hole_handle(), and start_hole_drag().

◆ m_hl_grab_val

double Slic3r::GUI::DesignSketchTool::m_hl_grab_val {0.0}
private
1516{0.0}; // radius (diameter drag) or depth at grab

Referenced by drag_hole_handle(), and start_hole_drag().

◆ m_hl_grab_x

double Slic3r::GUI::DesignSketchTool::m_hl_grab_x {0.0}
private
1518{0.0}, m_hl_grab_y{0.0}; // centre drag: x/y at grab

Referenced by drag_hole_handle(), and start_hole_drag().

◆ m_hl_grab_y

double Slic3r::GUI::DesignSketchTool::m_hl_grab_y {0.0}
private
1518{0.0}, m_hl_grab_y{0.0}; // centre drag: x/y at grab

Referenced by drag_hole_handle(), and start_hole_drag().

◆ m_hl_has_bounds

bool Slic3r::GUI::DesignSketchTool::m_hl_has_bounds {false}
private
1511{false};

Referenced by open_hole_editor(), and set_hole_face_bounds().

◆ m_hl_plane

SketchPlane Slic3r::GUI::DesignSketchTool::m_hl_plane
private

◆ m_hl_press_x

int Slic3r::GUI::DesignSketchTool::m_hl_press_x {0}
private
1514{0}, m_hl_press_y{0};

Referenced by on_mouse_impl(), and start_hole_drag().

◆ m_hl_press_y

int Slic3r::GUI::DesignSketchTool::m_hl_press_y {0}
private
1514{0}, m_hl_press_y{0};

Referenced by on_mouse_impl(), and start_hole_drag().

◆ m_hl_sketches

std::vector<std::pair<int, ColorRGBA> > Slic3r::GUI::DesignSketchTool::m_hl_sketches
private

◆ m_hl_stroke_model

GLModel Slic3r::GUI::DesignSketchTool::m_hl_stroke_model
private

Referenced by render_hole_gizmo().

◆ m_hl_through

bool Slic3r::GUI::DesignSketchTool::m_hl_through {true}
private

◆ m_hl_umax

double Slic3r::GUI::DesignSketchTool::m_hl_umax {0}
private
1512{0}, m_hl_umax{0}, m_hl_vmin{0}, m_hl_vmax{0};

Referenced by set_hole_face_bounds().

◆ m_hl_umin

double Slic3r::GUI::DesignSketchTool::m_hl_umin {0}
private
1512{0}, m_hl_umax{0}, m_hl_vmin{0}, m_hl_vmax{0};

Referenced by open_hole_editor(), and set_hole_face_bounds().

◆ m_hl_vmax

double Slic3r::GUI::DesignSketchTool::m_hl_vmax {0}
private
1512{0}, m_hl_umax{0}, m_hl_vmin{0}, m_hl_vmax{0};

Referenced by set_hole_face_bounds().

◆ m_hl_vmin

double Slic3r::GUI::DesignSketchTool::m_hl_vmin {0}
private
1512{0}, m_hl_umax{0}, m_hl_vmin{0}, m_hl_vmax{0};

Referenced by open_hole_editor(), and set_hole_face_bounds().

◆ m_hl_x

double Slic3r::GUI::DesignSketchTool::m_hl_x {0.0}
private
1505{0.0}, m_hl_y{0.0}; // centre on the plane (u/v mm)

Referenced by drag_hole_handle(), hit_test_hole_handle(), open_hole_editor(), render_hole_gizmo(), set_hole_gizmo(), and start_hole_drag().

◆ m_hl_y

double Slic3r::GUI::DesignSketchTool::m_hl_y {0.0}
private
1505{0.0}, m_hl_y{0.0}; // centre on the plane (u/v mm)

Referenced by drag_hole_handle(), hit_test_hole_handle(), open_hole_editor(), render_hole_gizmo(), set_hole_gizmo(), and start_hole_drag().

◆ m_hover_handle

Handle Slic3r::GUI::DesignSketchTool::m_hover_handle
private

Referenced by render(), and update_hover().

◆ m_hx_active

bool Slic3r::GUI::DesignSketchTool::m_hx_active {false}
private

◆ m_hx_drag

int Slic3r::GUI::DesignSketchTool::m_hx_drag {-1}
private
1424{-1}; // 0=radius, 1=height, 2=pitch, -1 none

Referenced by clear_helix_gizmo(), on_mouse_impl(), and render_helix_gizmo().

◆ m_hx_height

double Slic3r::GUI::DesignSketchTool::m_hx_height {20.0}
private

◆ m_hx_left

bool Slic3r::GUI::DesignSketchTool::m_hx_left {false}
private
1423{false};

Referenced by helix_point(), and set_helix_gizmo().

◆ m_hx_pitch

double Slic3r::GUI::DesignSketchTool::m_hx_pitch {2.0}
private

◆ m_hx_plane

SketchPlane Slic3r::GUI::DesignSketchTool::m_hx_plane
private

◆ m_hx_press_x

int Slic3r::GUI::DesignSketchTool::m_hx_press_x {0}
private
1425{0}, m_hx_press_y{0};

Referenced by on_mouse_impl().

◆ m_hx_press_y

int Slic3r::GUI::DesignSketchTool::m_hx_press_y {0}
private
1425{0}, m_hx_press_y{0};

Referenced by on_mouse_impl().

◆ m_hx_radius

double Slic3r::GUI::DesignSketchTool::m_hx_radius {10.0}
private
1419{10.0};

Referenced by drag_helix_handle(), helix_point(), and set_helix_gizmo().

◆ m_hx_taper

double Slic3r::GUI::DesignSketchTool::m_hx_taper {0.0}
private
1422{0.0}; // DEGREES (cone half-angle), as the kernel reads it

Referenced by helix_point(), and set_helix_gizmo().

◆ m_label_rects

std::vector<LabelRect> Slic3r::GUI::DesignSketchTool::m_label_rects
private

Referenced by draw_dim_label(), and render().

◆ m_last_mouse_x

◆ m_last_mouse_y

◆ m_line_model

◆ m_live_arc_angle_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_arc_angle_label {0,0}
private
1131{0,0}; // arc sweep-angle quote label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_arc_ei

int Slic3r::GUI::DesignSketchTool::m_live_arc_ei {-1}
private
1132{-1}; // the arc it belongs to (geometric edit)

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_aslot_fi

int Slic3r::GUI::DesignSketchTool::m_live_aslot_fi {-1}
private
1145{-1}; // the arc-slot Feature (rebuild edits)

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_aslot_r_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_aslot_r_label {0,0}
private
1143{0,0}; // arc-slot centreline-radius label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_aslot_w_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_aslot_w_label {0,0}
private
1144{0,0}; // arc-slot width label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_ellipse_ei

int Slic3r::GUI::DesignSketchTool::m_live_ellipse_ei {-1}
private
1136{-1}; // the ellipse the labels belong to

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_ellipse_major_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_ellipse_major_label {0,0}
private
1133{0,0}; // ellipse semi-major quote label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_ellipse_minor_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_ellipse_minor_label {0,0}
private
1134{0,0}; // ellipse semi-minor quote label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_ellipsearc_sweep_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_ellipsearc_sweep_label {0,0}
private
1135{0,0}; // elliptical-arc sweep quote label

Referenced by open_primary_autoedit(), and render_live_quotes().

◆ m_live_obrect_angle_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_obrect_angle_label {0,0}
private
1137{0,0}; // oblique-rect orientation quote label

Referenced by open_primary_autoedit(), and render_live_quotes().

◆ m_live_obrect_fi

int Slic3r::GUI::DesignSketchTool::m_live_obrect_fi {-1}
private
1138{-1}; // an OBLIQUE rect Feature (angle editable)

Referenced by open_primary_autoedit(), and render_live_quotes().

◆ m_live_poly_angle_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_poly_angle_label {0,0}
private
1129{0,0}; // polygon orientation quote label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_poly_fi

int Slic3r::GUI::DesignSketchTool::m_live_poly_fi {-1}
private
1130{-1}; // their Feature (geometric edits)

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_poly_side_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_poly_side_label {0,0}
private
1128{0,0}; // polygon side-length quote label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_quotes

std::vector<DimAnnot> Slic3r::GUI::DesignSketchTool::m_live_quotes
private

◆ m_live_rrect_fi

int Slic3r::GUI::DesignSketchTool::m_live_rrect_fi {-1}
private
1142{-1}; // the rounded-rect Feature (rebuild edits)

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_rrect_h_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_rrect_h_label {0,0}
private
1140{0,0}; // rounded-rect height quote label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_rrect_r_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_rrect_r_label {0,0}
private
1141{0,0}; // rounded-rect fillet-radius label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_rrect_w_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_rrect_w_label {0,0}
private
1139{0,0}; // rounded-rect width quote label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_slot_angle_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_slot_angle_label {0,0}
private
1148{0,0}; // straight-slot centreline angle label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_slot_fi

int Slic3r::GUI::DesignSketchTool::m_live_slot_fi {-1}
private
1149{-1}; // the straight-slot Feature (rebuild edits)

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_slot_len_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_slot_len_label {0,0}
private
1146{0,0}; // straight-slot inter-centre distance label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_live_slot_w_label

Vec2d Slic3r::GUI::DesignSketchTool::m_live_slot_w_label {0,0}
private
1147{0,0}; // straight-slot radius (half-width) label

Referenced by on_mouse_impl(), open_primary_autoedit(), and render_live_quotes().

◆ m_loop_defect_shown

bool Slic3r::GUI::DesignSketchTool::m_loop_defect_shown {false}
private
786{false};

Referenced by announce_loop_defects().

◆ m_mate_connectors

std::vector<MateConnectorGlyph> Slic3r::GUI::DesignSketchTool::m_mate_connectors
private

◆ m_mate_links

std::vector<std::pair<Vec3d, Vec3d> > Slic3r::GUI::DesignSketchTool::m_mate_links
private

◆ m_mc_fill_model

GLModel Slic3r::GUI::DesignSketchTool::m_mc_fill_model
private

Referenced by render_mate_face().

◆ m_mc_stroke_model

GLModel Slic3r::GUI::DesignSketchTool::m_mc_stroke_model
private

Referenced by render_mate_connectors().

◆ m_mirror_targets

std::vector<int> Slic3r::GUI::DesignSketchTool::m_mirror_targets
private

◆ m_mode

◆ m_mv_active

bool Slic3r::GUI::DesignSketchTool::m_mv_active {false}
private

◆ m_mv_arc_a0

double Slic3r::GUI::DesignSketchTool::m_mv_arc_a0 {0.0}
private
1465{0.0}; // mouse angle on the ring at drag start

Referenced by drag_move_arc(), and on_mouse_impl().

◆ m_mv_arrow_model

GLModel Slic3r::GUI::DesignSketchTool::m_mv_arrow_model
private

Referenced by render_move_gizmo().

◆ m_mv_base

Vec3d Slic3r::GUI::DesignSketchTool::m_mv_base {Vec3d::Zero()}
private
1460{Vec3d::Zero()}; // pivot = body's world centroid at Move-open

Referenced by arc_mouse_angle(), compose_move_xform(), drag_move_arrow(), grab_move_arrow(), hit_test_move_arc(), hit_test_move_arrow(), render_move_gizmo(), and set_move_gizmo().

◆ m_mv_base_xform

Transform3d Slic3r::GUI::DesignSketchTool::m_mv_base_xform {Transform3d::Identity()}
private
1462{Transform3d::Identity()}; // pose when Move opened

Referenced by compose_move_xform(), and set_move_gizmo().

◆ m_mv_body

int Slic3r::GUI::DesignSketchTool::m_mv_body {-1}
private

◆ m_mv_drag

int Slic3r::GUI::DesignSketchTool::m_mv_drag {-1}
private
1466{-1}; // 0..2 = X/Y/Z arrow, 3..5 = X/Y/Z ring, -1 none

Referenced by clear_move_gizmo(), drag_move_arrow(), grab_move_arrow(), on_mouse_impl(), and set_move_gizmo().

◆ m_mv_grab_along

double Slic3r::GUI::DesignSketchTool::m_mv_grab_along {0.0}
private
1469{0.0}; // arrow grab point's distance from the anchor; NaN = unknown

Referenced by drag_move_arrow(), and grab_move_arrow().

◆ m_mv_offset

Vec3d Slic3r::GUI::DesignSketchTool::m_mv_offset {Vec3d::Zero()}
private

◆ m_mv_press_x

int Slic3r::GUI::DesignSketchTool::m_mv_press_x {0}
private
1468{0}, m_mv_press_y{0};

Referenced by on_mouse_impl().

◆ m_mv_press_y

int Slic3r::GUI::DesignSketchTool::m_mv_press_y {0}
private
1468{0}, m_mv_press_y{0};

Referenced by on_mouse_impl().

◆ m_mv_radius

double Slic3r::GUI::DesignSketchTool::m_mv_radius {0.0}
private
1467{0.0}; // body bounding-sphere radius (mm); 0 = unknown

Referenced by move_gizmo_arm(), and set_move_gizmo().

◆ m_mv_rot

Eigen::Matrix3d Slic3r::GUI::DesignSketchTool::m_mv_rot {Eigen::Matrix3d::Identity()}
private
1463{Eigen::Matrix3d::Identity()}; // accumulated delta rotation (world, about pivot)

Referenced by clear_move_gizmo(), compose_move_xform(), drag_move_arc(), on_mouse_impl(), and set_move_gizmo().

◆ m_mv_rot_start

Eigen::Matrix3d Slic3r::GUI::DesignSketchTool::m_mv_rot_start {Eigen::Matrix3d::Identity()}
private
1464{Eigen::Matrix3d::Identity()}; // rot snapshot at arc-drag start

Referenced by drag_move_arc(), and on_mouse_impl().

◆ m_on_cut_offset_changed

std::function<void(double)> Slic3r::GUI::DesignSketchTool::m_on_cut_offset_changed
private

◆ m_on_draft_angle_changed

std::function<void(double)> Slic3r::GUI::DesignSketchTool::m_on_draft_angle_changed
private

◆ m_op_a

int Slic3r::GUI::DesignSketchTool::m_op_a {-1}
private

◆ m_op_anchor

Vec2d Slic3r::GUI::DesignSketchTool::m_op_anchor {0,0}
private
1173{0,0}; // arrow base (corner vertex / entity midpoint)

Referenced by drag_op_arrow(), hit_test_op_arrow(), recompute_op_ghost(), render_op_gizmo(), and reset_op().

◆ m_op_b

int Slic3r::GUI::DesignSketchTool::m_op_b {-1}
private

◆ m_op_chain

std::vector<int> Slic3r::GUI::DesignSketchTool::m_op_chain
private

◆ m_op_dir

Vec2d Slic3r::GUI::DesignSketchTool::m_op_dir {0,0}
private
1174{0,0}; // unit arrow direction (inward bisector / outward normal)

Referenced by drag_op_arrow(), hit_test_op_arrow(), recompute_op_ghost(), render_op_gizmo(), and reset_op().

◆ m_op_dragging_arrow

bool Slic3r::GUI::DesignSketchTool::m_op_dragging_arrow {false}
private
1177{false}; // arrowhead drag in progress

Referenced by on_mouse_impl(), and reset_op().

◆ m_op_ghost

std::vector<SketchEntity> Slic3r::GUI::DesignSketchTool::m_op_ghost
private

◆ m_op_label

Vec2d Slic3r::GUI::DesignSketchTool::m_op_label {1e18,1e18}
private
1175{1e18,1e18}; // cached arrow-label centre, for picking

Referenced by on_mouse_impl(), render_op_gizmo(), and reset_op().

◆ m_op_value

double Slic3r::GUI::DesignSketchTool::m_op_value {0.0}
private
1172{0.0}; // radius / setback / signed offset distance

Referenced by confirm_op(), drag_op_arrow(), hit_test_op_arrow(), op_pick(), open_op_editor(), recompute_op_ghost(), render_op_gizmo(), and reset_op().

◆ m_open_feature

int Slic3r::GUI::DesignSketchTool::m_open_feature {-1}
private
1161{-1}; // index of the Feature being built, or -1

Referenced by begin(), begin_feature(), cancel(), delete_selected(), end_feature(), finish(), rebuild_features_from_entities(), render(), and set_tool().

◆ m_pending_dim

int Slic3r::GUI::DesignSketchTool::m_pending_dim {-1}
private

◆ m_pick0

int Slic3r::GUI::DesignSketchTool::m_pick0 {-1}
private

◆ m_pick0_pt

Vec2d Slic3r::GUI::DesignSketchTool::m_pick0_pt {0,0}
private
1250{0,0}; // plane-coords of the slot-0 pick (trim/extend)

Referenced by on_mouse_impl(), and pick0_point().

◆ m_pick1

◆ m_pick2

int Slic3r::GUI::DesignSketchTool::m_pick2 {-1}
private

◆ m_pick_only_body

int Slic3r::GUI::DesignSketchTool::m_pick_only_body {-1}
private
1283{-1}; // >=0: only this body catches clicks (body-focus x-ray for CoordSys picking)

Referenced by body_pickable(), render_body_edges(), and set_pick_only_body().

◆ m_pick_pending

bool Slic3r::GUI::DesignSketchTool::m_pick_pending = false

Referenced by on_mouse_impl(), and set_move_gizmo().

◆ m_pick_press_x

int Slic3r::GUI::DesignSketchTool::m_pick_press_x = 0

Referenced by on_mouse_impl().

◆ m_pick_press_y

int Slic3r::GUI::DesignSketchTool::m_pick_press_y = 0

Referenced by on_mouse_impl().

◆ m_plane

◆ m_point_sel

◆ m_points

◆ m_polygon_circumscribed

bool Slic3r::GUI::DesignSketchTool::m_polygon_circumscribed {false}
private
1079{false};

Referenced by make_polygon(), and set_polygon_circumscribed().

◆ m_polygon_sides

int Slic3r::GUI::DesignSketchTool::m_polygon_sides {6}
private
1078{6};

Referenced by on_mouse_impl(), render(), and set_polygon_sides().

◆ m_pre

SolidPick Slic3r::GUI::DesignSketchTool::m_pre
private

◆ m_pre_hl

FaceHighlight Slic3r::GUI::DesignSketchTool::m_pre_hl
private

◆ m_pt_active

bool Slic3r::GUI::DesignSketchTool::m_pt_active {false}
private

◆ m_pt_angle

double Slic3r::GUI::DesignSketchTool::m_pt_angle {360.0}
private

◆ m_pt_base

Vec3d Slic3r::GUI::DesignSketchTool::m_pt_base {Vec3d::Zero()}
private
1618{Vec3d::Zero()}; // target body centroid (world): linear anchor / radius ref

Referenced by drag_pattern_handle(), hit_test_pattern_handle(), render_pattern_gizmo(), and set_pattern_gizmo().

◆ m_pt_ccenter

Vec3d Slic3r::GUI::DesignSketchTool::m_pt_ccenter {Vec3d::Zero()}
private
1623{Vec3d::Zero()}; // circular arc center (foot of body centroid on the axis)

Referenced by drag_pattern_handle(), hit_test_pattern_handle(), render_pattern_gizmo(), and set_pattern_gizmo().

◆ m_pt_circular

bool Slic3r::GUI::DesignSketchTool::m_pt_circular {false}
private

◆ m_pt_count

int Slic3r::GUI::DesignSketchTool::m_pt_count {3}
private

◆ m_pt_cref

Vec3d Slic3r::GUI::DesignSketchTool::m_pt_cref {Vec3d::UnitX()}
private
1622{Vec3d::UnitX()}; // circular angle-0 reference dir (perp to normal, toward body)

Referenced by drag_pattern_handle(), hit_test_pattern_handle(), render_pattern_gizmo(), and set_pattern_gizmo().

◆ m_pt_dirw

Vec3d Slic3r::GUI::DesignSketchTool::m_pt_dirw {Vec3d::UnitX()}
private
1619{Vec3d::UnitX()}; // linear march direction (world)

Referenced by drag_pattern_handle(), hit_test_pattern_handle(), render_pattern_gizmo(), and set_pattern_gizmo().

◆ m_pt_drag

bool Slic3r::GUI::DesignSketchTool::m_pt_drag {false}
private
1628{false};

Referenced by clear_pattern_gizmo(), on_mouse_impl(), and set_pattern_gizmo().

◆ m_pt_normal

Vec3d Slic3r::GUI::DesignSketchTool::m_pt_normal {Vec3d::UnitZ()}
private
1621{Vec3d::UnitZ()}; // circular rotation axis (world)

Referenced by drag_pattern_handle(), hit_test_pattern_handle(), render_pattern_gizmo(), and set_pattern_gizmo().

◆ m_pt_origin

Vec3d Slic3r::GUI::DesignSketchTool::m_pt_origin {Vec3d::Zero()}
private
1620{Vec3d::Zero()}; // circular rotation axis origin (world)

Referenced by set_pattern_gizmo().

◆ m_pt_press_x

int Slic3r::GUI::DesignSketchTool::m_pt_press_x {0}
private
1629{0}, m_pt_press_y{0};

Referenced by on_mouse_impl().

◆ m_pt_press_y

int Slic3r::GUI::DesignSketchTool::m_pt_press_y {0}
private
1629{0}, m_pt_press_y{0};

Referenced by on_mouse_impl().

◆ m_pt_radius

double Slic3r::GUI::DesignSketchTool::m_pt_radius {10.0}
private
1624{10.0}; // circular arc radius (world)

Referenced by hit_test_pattern_handle(), render_pattern_gizmo(), and set_pattern_gizmo().

◆ m_pt_spacing

double Slic3r::GUI::DesignSketchTool::m_pt_spacing {20.0}
private

◆ m_pt_stroke_model

GLModel Slic3r::GUI::DesignSketchTool::m_pt_stroke_model
private

Referenced by render_pattern_gizmo().

◆ m_rb_active

bool Slic3r::GUI::DesignSketchTool::m_rb_active {false}
private

◆ m_rb_drag

int Slic3r::GUI::DesignSketchTool::m_rb_drag {-1}
private
1439{-1}; // 0 = +perp handle, 1 = -perp handle, -1 none

Referenced by clear_rib_gizmo(), on_mouse_impl(), and render_rib_gizmo().

◆ m_rb_p0

Vec2d Slic3r::GUI::DesignSketchTool::m_rb_p0 {Vec2d::Zero()}
private
1436{Vec2d::Zero()}; // rib line endpoints, in plane coords

Referenced by drag_rib_handle(), hit_test_rib_handle(), render_rib_gizmo(), and set_rib_gizmo().

◆ m_rb_p1

Vec2d Slic3r::GUI::DesignSketchTool::m_rb_p1 {Vec2d::Zero()}
private
1437{Vec2d::Zero()};

Referenced by drag_rib_handle(), hit_test_rib_handle(), render_rib_gizmo(), and set_rib_gizmo().

◆ m_rb_plane

SketchPlane Slic3r::GUI::DesignSketchTool::m_rb_plane
private

◆ m_rb_thickness

double Slic3r::GUI::DesignSketchTool::m_rb_thickness {2.0}
private

◆ m_render_scale

float Slic3r::GUI::DesignSketchTool::m_render_scale {1.0f}
private
1269{1.0f}; // canvas scale for Measure-style dim labels

Referenced by draw_dim_label(), hit_test_base_pick(), and render().

◆ m_right_press

std::optional<wxMouseEvent> Slic3r::GUI::DesignSketchTool::m_right_press
private

◆ m_rubber

GLSelectionRectangle Slic3r::GUI::DesignSketchTool::m_rubber
private

◆ m_rv_active

bool Slic3r::GUI::DesignSketchTool::m_rv_active {false}
private

◆ m_rv_angle

double Slic3r::GUI::DesignSketchTool::m_rv_angle {360.0}
private
1570{360.0}; // current sweep magnitude (deg, 1..360)

Referenced by drag_revolve_arc(), hit_test_revolve_handle(), open_revolve_editor(), render_revolve_gizmo(), and set_revolve_gizmo().

◆ m_rv_axis

Vec3d Slic3r::GUI::DesignSketchTool::m_rv_axis {Vec3d::UnitX()}
private
1567{Vec3d::UnitX()}; // revolve axis unit dir (world)

Referenced by drag_revolve_arc(), hit_test_revolve_handle(), render_revolve_gizmo(), and set_revolve_gizmo().

◆ m_rv_center

Vec3d Slic3r::GUI::DesignSketchTool::m_rv_center {Vec3d::Zero()}
private
1566{Vec3d::Zero()}; // arc center on the axis (world)

Referenced by drag_revolve_arc(), hit_test_revolve_handle(), render_revolve_gizmo(), and set_revolve_gizmo().

◆ m_rv_drag

bool Slic3r::GUI::DesignSketchTool::m_rv_drag {false}
private
1572{false};

Referenced by clear_revolve_gizmo(), on_mouse_impl(), and set_revolve_gizmo().

◆ m_rv_flip

bool Slic3r::GUI::DesignSketchTool::m_rv_flip {false}
private
1571{false}; // sweep sense (matches the kernel's negative-angle flip)

Referenced by drag_revolve_arc(), hit_test_revolve_handle(), render_revolve_gizmo(), and set_revolve_gizmo().

◆ m_rv_press_x

int Slic3r::GUI::DesignSketchTool::m_rv_press_x {0}
private
1573{0}, m_rv_press_y{0};

Referenced by on_mouse_impl().

◆ m_rv_press_y

int Slic3r::GUI::DesignSketchTool::m_rv_press_y {0}
private
1573{0}, m_rv_press_y{0};

Referenced by on_mouse_impl().

◆ m_rv_radius

double Slic3r::GUI::DesignSketchTool::m_rv_radius {10.0}
private
1569{10.0}; // arc radius = profile perpendicular distance (world)

Referenced by hit_test_revolve_handle(), render_revolve_gizmo(), and set_revolve_gizmo().

◆ m_rv_ref

Vec3d Slic3r::GUI::DesignSketchTool::m_rv_ref {Vec3d::UnitY()}
private
1568{Vec3d::UnitY()}; // angle-0 reference dir (perp to axis, toward profile)

Referenced by drag_revolve_arc(), hit_test_revolve_handle(), render_revolve_gizmo(), and set_revolve_gizmo().

◆ m_rv_stroke_model

GLModel Slic3r::GUI::DesignSketchTool::m_rv_stroke_model
private

Referenced by render_revolve_gizmo().

◆ m_sel_a

int Slic3r::GUI::DesignSketchTool::m_sel_a {-1}
private
1244{-1}; // picked segment endpoints (legacy Constrain mode)

Referenced by abort_gesture(), begin(), begin_constrain(), begin_constrain_entities(), cancel(), has_pending_picks(), on_mouse_impl(), render(), selected_segment(), and set_tool().

◆ m_sel_b

int Slic3r::GUI::DesignSketchTool::m_sel_b {-1}
private

◆ m_sel_body

int Slic3r::GUI::DesignSketchTool::m_sel_body {-1}
private

◆ m_sel_edge

int Slic3r::GUI::DesignSketchTool::m_sel_edge {-1}
private

◆ m_sel_edge_pts

std::vector<Vec3d> Slic3r::GUI::DesignSketchTool::m_sel_edge_pts
private

◆ m_sel_edges_more

std::vector<int> Slic3r::GUI::DesignSketchTool::m_sel_edges_more
private

◆ m_sel_edges_more_pts

std::vector<std::vector<Vec3d> > Slic3r::GUI::DesignSketchTool::m_sel_edges_more_pts
private

◆ m_sel_face

int Slic3r::GUI::DesignSketchTool::m_sel_face {-1}
private

◆ m_sel_hl

FaceHighlight Slic3r::GUI::DesignSketchTool::m_sel_hl
private

◆ m_sel_shape

TopoDS_Shape Slic3r::GUI::DesignSketchTool::m_sel_shape
private

◆ m_sel_vertex_pt

Vec3d Slic3r::GUI::DesignSketchTool::m_sel_vertex_pt {Vec3d::Zero()}
private
1310{Vec3d::Zero()}; // world point of a picked vertex

Referenced by handle_solid_click(), render_solid_highlight(), and selection_box().

◆ m_selection

◆ m_sh_active

bool Slic3r::GUI::DesignSketchTool::m_sh_active {false}
private

◆ m_sh_anchor

Vec3d Slic3r::GUI::DesignSketchTool::m_sh_anchor {Vec3d::Zero()}
private
1550{Vec3d::Zero()}; // picked face centroid (world)

Referenced by drag_shell_arrow(), hit_test_shell_arrow(), render_shell_gizmo(), set_shell_gizmo(), and start_shell_drag().

◆ m_sh_dir

Vec3d Slic3r::GUI::DesignSketchTool::m_sh_dir {Vec3d::UnitZ()}
private
1551{Vec3d::UnitZ()}; // inward unit direction (-outward normal)

Referenced by drag_shell_arrow(), hit_test_shell_arrow(), render_shell_gizmo(), set_shell_gizmo(), and start_shell_drag().

◆ m_sh_drag

bool Slic3r::GUI::DesignSketchTool::m_sh_drag {false}
private

◆ m_sh_grab_proj

double Slic3r::GUI::DesignSketchTool::m_sh_grab_proj {0.0}
private
1555{0.0};

Referenced by drag_shell_arrow(), and start_shell_drag().

◆ m_sh_grab_val

double Slic3r::GUI::DesignSketchTool::m_sh_grab_val {2.0}
private
1556{2.0};

Referenced by drag_shell_arrow(), and start_shell_drag().

◆ m_sh_press_x

int Slic3r::GUI::DesignSketchTool::m_sh_press_x {0}
private
1554{0}, m_sh_press_y{0};

Referenced by on_mouse_impl(), and start_shell_drag().

◆ m_sh_press_y

int Slic3r::GUI::DesignSketchTool::m_sh_press_y {0}
private
1554{0}, m_sh_press_y{0};

Referenced by on_mouse_impl(), and start_shell_drag().

◆ m_sh_stroke_model

GLModel Slic3r::GUI::DesignSketchTool::m_sh_stroke_model
private

Referenced by render_shell_gizmo().

◆ m_sh_thickness

double Slic3r::GUI::DesignSketchTool::m_sh_thickness {2.0}
private

◆ m_show_axes

bool Slic3r::GUI::DesignSketchTool::m_show_axes {false}
private

◆ m_show_handles

bool Slic3r::GUI::DesignSketchTool::m_show_handles {false}
private
1121{false}; // draw + interact with handles

Referenced by render().

◆ m_show_planes

bool Slic3r::GUI::DesignSketchTool::m_show_planes {false}
private

◆ m_sketch_redo

std::vector<SketchSnap> Slic3r::GUI::DesignSketchTool::m_sketch_redo
private

◆ m_skipped_last

int Slic3r::GUI::DesignSketchTool::m_skipped_last {0}
private
1159{0}; // constraints the last solve could not apply (reported on change)

Referenced by resolve_live_drag().

◆ m_snap_off

bool Slic3r::GUI::DesignSketchTool::m_snap_off {false}
private
1082{false}; // Shift held -> suppress angle snapping

Referenced by on_mouse_impl(), and snap_dir().

◆ m_solid_bodies

const std::vector<CadBody>* Slic3r::GUI::DesignSketchTool::m_solid_bodies {nullptr}
private

◆ m_solid_edge_model

GLModel Slic3r::GUI::DesignSketchTool::m_solid_edge_model
private

◆ m_solid_mesh

const TriangleMesh* Slic3r::GUI::DesignSketchTool::m_solid_mesh {nullptr}
private

◆ m_solid_sel

◆ m_solid_tri_body

const std::vector<int>* Slic3r::GUI::DesignSketchTool::m_solid_tri_body {nullptr}
private

◆ m_solid_tri_face

const std::vector<int>* Slic3r::GUI::DesignSketchTool::m_solid_tri_face {nullptr}
private
1280{nullptr};

Referenced by faces_box(), resolve_solid_pick(), and set_solid_pick().

◆ m_solid_vertex_model

GLModel Slic3r::GUI::DesignSketchTool::m_solid_vertex_model
private

Referenced by render_solid_sel().

◆ m_solid_visible

const std::vector<bool>* Slic3r::GUI::DesignSketchTool::m_solid_visible {nullptr}
private
1282{nullptr}; // per-body visibility; hidden bodies aren't pickable

Referenced by body_pickable(), render_body_edges(), and set_solid_pick().

◆ m_solid_xform

const std::vector<Transform3d>* Slic3r::GUI::DesignSketchTool::m_solid_xform {nullptr}
private
1284{nullptr}; // per-body display transform (for edge sampling)

Referenced by body_xform_pt(), and set_solid_pick().

◆ m_solve_ok

bool Slic3r::GUI::DesignSketchTool::m_solve_ok {true}
private
1235{true}; // solver consistent (no conflicting constraints)

Referenced by apply_dimension(), begin(), cancel(), render(), resolve_live_drag(), set_dimension_value(), and solve_ok().

◆ m_step_last

int Slic3r::GUI::DesignSketchTool::m_step_last {-1}
private
1168{-1};

Referenced by emit_step_hint().

◆ m_step_mode_last

int Slic3r::GUI::DesignSketchTool::m_step_mode_last {-1}
private
1167{-1};

Referenced by begin(), cancel(), and emit_step_hint().

◆ m_step_picks_last

int Slic3r::GUI::DesignSketchTool::m_step_picks_last {-1}
private
1169{-1};

Referenced by emit_step_hint().

◆ m_tf_angle

double Slic3r::GUI::DesignSketchTool::m_tf_angle {0.0}
private
1211{0.0}; // Rotate angle / PolarArray total sweep (rad)

Referenced by confirm_transform(), drag_tf_handle(), open_tf_editor_a(), recompute_tf_ghost(), render_tf_gizmo(), reset_tf(), tf_handle_pos(), and tf_pick().

◆ m_tf_count

int Slic3r::GUI::DesignSketchTool::m_tf_count {3}
private
1213{3}; // Array/PolarArray copy count (incl. original)

Referenced by confirm_transform(), open_tf_editor_count(), recompute_tf_ghost(), render_tf_gizmo(), and reset_tf().

◆ m_tf_delta

Vec2d Slic3r::GUI::DesignSketchTool::m_tf_delta {0,0}
private
1210{0,0}; // Move translation / Array per-step vector

Referenced by confirm_transform(), drag_tf_handle(), open_tf_editor_a(), recompute_tf_ghost(), render_tf_gizmo(), reset_tf(), tf_handle_pos(), and tf_pick().

◆ m_tf_dragging

bool Slic3r::GUI::DesignSketchTool::m_tf_dragging {false}
private
1217{false};

Referenced by on_mouse_impl(), render_tf_gizmo(), and reset_tf().

◆ m_tf_ghost

std::vector<SketchEntity> Slic3r::GUI::DesignSketchTool::m_tf_ghost
private

◆ m_tf_handle

int Slic3r::GUI::DesignSketchTool::m_tf_handle {-1}
private
1216{-1}; // 0 = primary drag handle grabbed, -1 = none

Referenced by reset_tf().

◆ m_tf_handle_r

double Slic3r::GUI::DesignSketchTool::m_tf_handle_r {1.0}
private
1214{1.0}; // ring/handle reference radius (set on pick)

Referenced by compute_tf_pivot(), drag_tf_handle(), reset_tf(), tf_handle_pos(), and tf_pick().

◆ m_tf_label_a

Vec2d Slic3r::GUI::DesignSketchTool::m_tf_label_a {1e18,1e18}
private
1218{1e18,1e18}; // primary-param label centre (picking)

Referenced by on_mouse_impl(), render_tf_gizmo(), and reset_tf().

◆ m_tf_label_b

Vec2d Slic3r::GUI::DesignSketchTool::m_tf_label_b {1e18,1e18}
private
1219{1e18,1e18}; // count label centre (Array/PolarArray)

Referenced by on_mouse_impl(), render_tf_gizmo(), and reset_tf().

◆ m_tf_pivot

Vec2d Slic3r::GUI::DesignSketchTool::m_tf_pivot {0,0}
private
1209{0,0}; // rotate/scale/polar pivot = set centroid

Referenced by compute_tf_pivot(), confirm_transform(), drag_tf_handle(), recompute_tf_ghost(), render_tf_gizmo(), reset_tf(), and tf_handle_pos().

◆ m_tf_scale

double Slic3r::GUI::DesignSketchTool::m_tf_scale {1.0}
private

◆ m_tf_targets

std::vector<int> Slic3r::GUI::DesignSketchTool::m_tf_targets
private

◆ m_th_active

bool Slic3r::GUI::DesignSketchTool::m_th_active {false}
private

◆ m_th_drag

int Slic3r::GUI::DesignSketchTool::m_th_drag {-1}
private
1535{-1}; // 0=centre, 1=radius, 2=length, -1=none

Referenced by clear_thread_gizmo(), drag_thread_handle(), on_mouse_impl(), set_thread_gizmo(), and start_thread_drag().

◆ m_th_grab_proj

double Slic3r::GUI::DesignSketchTool::m_th_grab_proj {0.0}
private
1537{0.0};

Referenced by drag_thread_handle(), and start_thread_drag().

◆ m_th_grab_uv

Vec2d Slic3r::GUI::DesignSketchTool::m_th_grab_uv {0.0, 0.0}
private
1539{0.0, 0.0};

Referenced by drag_thread_handle(), and start_thread_drag().

◆ m_th_grab_val

double Slic3r::GUI::DesignSketchTool::m_th_grab_val {0.0}
private
1538{0.0};

Referenced by drag_thread_handle(), and start_thread_drag().

◆ m_th_grab_x

double Slic3r::GUI::DesignSketchTool::m_th_grab_x {0.0}
private
1540{0.0}, m_th_grab_y{0.0};

Referenced by drag_thread_handle(), and start_thread_drag().

◆ m_th_grab_y

double Slic3r::GUI::DesignSketchTool::m_th_grab_y {0.0}
private
1540{0.0}, m_th_grab_y{0.0};

Referenced by drag_thread_handle(), and start_thread_drag().

◆ m_th_height

double Slic3r::GUI::DesignSketchTool::m_th_height {10.0}
private

◆ m_th_plane

SketchPlane Slic3r::GUI::DesignSketchTool::m_th_plane
private

◆ m_th_press_x

int Slic3r::GUI::DesignSketchTool::m_th_press_x {0}
private
1536{0}, m_th_press_y{0};

Referenced by on_mouse_impl(), and start_thread_drag().

◆ m_th_press_y

int Slic3r::GUI::DesignSketchTool::m_th_press_y {0}
private
1536{0}, m_th_press_y{0};

Referenced by on_mouse_impl(), and start_thread_drag().

◆ m_th_radius

double Slic3r::GUI::DesignSketchTool::m_th_radius {5.0}
private

◆ m_th_stroke_model

GLModel Slic3r::GUI::DesignSketchTool::m_th_stroke_model
private

Referenced by render_thread_gizmo().

◆ m_th_x

double Slic3r::GUI::DesignSketchTool::m_th_x {0.0}
private

◆ m_th_y

double Slic3r::GUI::DesignSketchTool::m_th_y {0.0}
private

◆ m_vertex_model

GLModel Slic3r::GUI::DesignSketchTool::m_vertex_model
private

Referenced by render(), and render_tf_gizmo().

◆ m_xform_anchor

Vec2d Slic3r::GUI::DesignSketchTool::m_xform_anchor {0,0}
private
1194{0,0};

Referenced by drag_xform_handle(), and on_mouse_impl().

◆ m_xform_base

std::vector<std::vector<std::vector<Vec2d> > > Slic3r::GUI::DesignSketchTool::m_xform_base
private

◆ m_xform_feat

int Slic3r::GUI::DesignSketchTool::m_xform_feat {-1}
private
1189{-1};

Referenced by begin_imported_transform(), emit_xform(), and reset_xform().

◆ m_xform_handle

int Slic3r::GUI::DesignSketchTool::m_xform_handle {-1}
private

◆ m_xform_max

Vec2d Slic3r::GUI::DesignSketchTool::m_xform_max {0,0}
private
1190{0,0}, m_xform_max{0,0}; // bbox of m_xform_base (untransformed)

Referenced by begin_imported_transform(), drag_xform_handle(), reset_xform(), and xform_world_corners().

◆ m_xform_min

Vec2d Slic3r::GUI::DesignSketchTool::m_xform_min {0,0}
private
1190{0,0}, m_xform_max{0,0}; // bbox of m_xform_base (untransformed)

Referenced by begin_imported_transform(), drag_xform_handle(), reset_xform(), and xform_world_corners().

◆ m_xform_offset

Vec2d Slic3r::GUI::DesignSketchTool::m_xform_offset {0,0}
private

◆ m_xform_sx

double Slic3r::GUI::DesignSketchTool::m_xform_sx {1.0}
private

◆ m_xform_sy

double Slic3r::GUI::DesignSketchTool::m_xform_sy {1.0}
private

◆ on_body_move_changed

std::function<void(int body, const Transform3d& xform)> Slic3r::GUI::DesignSketchTool::on_body_move_changed

◆ on_commit

std::function<void(const SketchProfile&, const SketchPlane&)> Slic3r::GUI::DesignSketchTool::on_commit

◆ on_commit_entities

std::function<void(const std::vector<SketchEntity>&, const std::vector<SketchEntityConstraintDef>&, const SketchPlane&)> Slic3r::GUI::DesignSketchTool::on_commit_entities

Referenced by finish().

◆ on_constraints_changed

std::function<void()> Slic3r::GUI::DesignSketchTool::on_constraints_changed

◆ on_cursor_metrics

std::function<void(double length, double angle_deg, bool locked)> Slic3r::GUI::DesignSketchTool::on_cursor_metrics

Referenced by on_mouse_impl().

◆ on_datum_base_picked

std::function<void(int base)> Slic3r::GUI::DesignSketchTool::on_datum_base_picked

Referenced by on_mouse_impl().

◆ on_datum_offset_changed

std::function<void(double offset)> Slic3r::GUI::DesignSketchTool::on_datum_offset_changed

Referenced by drag_datum_handle().

◆ on_datum_size_changed

std::function<void(double usize, double vsize)> Slic3r::GUI::DesignSketchTool::on_datum_size_changed

Referenced by drag_datum_handle().

◆ on_dimension_pick_complete

std::function<void(double current)> Slic3r::GUI::DesignSketchTool::on_dimension_pick_complete

Referenced by open_value_editor().

◆ on_display_sketch_activated

std::function<void(int feature)> Slic3r::GUI::DesignSketchTool::on_display_sketch_activated

Referenced by on_mouse_impl().

◆ on_display_sketch_selected

std::function<void(int feature, int region, int entity)> Slic3r::GUI::DesignSketchTool::on_display_sketch_selected

Referenced by on_mouse_impl().

◆ on_empty_pick

std::function<void()> Slic3r::GUI::DesignSketchTool::on_empty_pick

◆ on_exit

std::function<void()> Slic3r::GUI::DesignSketchTool::on_exit

Referenced by request_exit().

◆ on_exit_refused

std::function<void()> Slic3r::GUI::DesignSketchTool::on_exit_refused

Referenced by request_exit().

◆ on_extrude_depth_changed

std::function<void(double depth, bool second)> Slic3r::GUI::DesignSketchTool::on_extrude_depth_changed

◆ on_face_selected

std::function<void(int)> Slic3r::GUI::DesignSketchTool::on_face_selected

Referenced by on_mouse_impl().

◆ on_fillet_radius_changed

std::function<void(double radius)> Slic3r::GUI::DesignSketchTool::on_fillet_radius_changed

◆ on_helix_changed

std::function<void(double radius, double pitch, double height)> Slic3r::GUI::DesignSketchTool::on_helix_changed

Referenced by drag_helix_handle().

◆ on_hole_changed

std::function<void(double x, double y, double diameter, double depth)> Slic3r::GUI::DesignSketchTool::on_hole_changed

◆ on_imported_transform

std::function<void(int feat, Vec2d offset, double scale_x, double scale_y)> Slic3r::GUI::DesignSketchTool::on_imported_transform

Referenced by emit_xform().

◆ on_inline_commit

std::function<void()> Slic3r::GUI::DesignSketchTool::on_inline_commit

Referenced by on_mouse_impl(), and set_tool().

◆ on_inline_dismiss

std::function<void()> Slic3r::GUI::DesignSketchTool::on_inline_dismiss

◆ on_inline_edit

◆ on_notice

std::function<void(const std::string& msg, bool error)> Slic3r::GUI::DesignSketchTool::on_notice

Referenced by notify().

◆ on_pattern_changed

std::function<void(double value)> Slic3r::GUI::DesignSketchTool::on_pattern_changed

◆ on_readout

std::function<void(const std::string&)> Slic3r::GUI::DesignSketchTool::on_readout

Referenced by close_session_chrome(), and render().

◆ on_revolve_angle_changed

std::function<void(double angle)> Slic3r::GUI::DesignSketchTool::on_revolve_angle_changed

◆ on_rib_thickness_changed

std::function<void(double thickness)> Slic3r::GUI::DesignSketchTool::on_rib_thickness_changed

Referenced by drag_rib_handle().

◆ on_segment_drawn

std::function<void(double length, double angle_deg)> Slic3r::GUI::DesignSketchTool::on_segment_drawn

◆ on_selection_changed

◆ on_shell_thickness_changed

std::function<void(double thickness)> Slic3r::GUI::DesignSketchTool::on_shell_thickness_changed

◆ on_solid_selection_changed

std::function<void(int level, int body, int face, int edge)> Slic3r::GUI::DesignSketchTool::on_solid_selection_changed

◆ on_solve_state

std::function<void(int dof, bool ok, bool has_constraints)> Slic3r::GUI::DesignSketchTool::on_solve_state

Referenced by resolve_live_drag().

◆ on_step_changed

std::function<void(Mode mode, int step, int picks)> Slic3r::GUI::DesignSketchTool::on_step_changed

Referenced by emit_step_hint().

◆ on_thread_changed

std::function<void(double x, double y, double radius, double height)> Slic3r::GUI::DesignSketchTool::on_thread_changed

◆ render_overlays

std::function<void()> Slic3r::GUI::DesignSketchTool::render_overlays

Referenced by render().

◆ selected_base

std::function<int()> Slic3r::GUI::DesignSketchTool::selected_base

Referenced by render_base_pick().


The documentation for this class was generated from the following files: