@@ -105,6 +105,10 @@ def __init__(self, parent=None):
105105 self ._pan_start : Optional [QPoint ] = None
106106 self .robot_length_m = ELEMENT_RECT_WIDTH_M
107107 self .robot_width_m = ELEMENT_RECT_HEIGHT_M
108+ self .robot_protrusion_front_m = 0.0
109+ self .robot_protrusion_back_m = 0.0
110+ self .robot_protrusion_left_m = 0.0
111+ self .robot_protrusion_right_m = 0.0
108112 self ._field_offset : float = FIELD_OFFSET_M # 0.5m for 2026
109113 self .graphics_scene = QGraphicsScene (self )
110114 self .setScene (self .graphics_scene )
@@ -189,6 +193,16 @@ def set_robot_dimensions(self, length_m: float, width_m: float):
189193 try :
190194 self .robot_length_m = float (length_m )
191195 self .robot_width_m = float (width_m )
196+ cfg = {}
197+ if hasattr (self , "_project_manager" ) and self ._project_manager :
198+ if hasattr (self ._project_manager , "config_as_dict" ):
199+ cfg = self ._project_manager .config_as_dict ()
200+ else :
201+ cfg = dict (getattr (self ._project_manager , "config" , {}) or {})
202+ self .robot_protrusion_front_m = max (0.0 , float (cfg .get ("robot_protrusion_front_meters" , 0.0 )))
203+ self .robot_protrusion_back_m = max (0.0 , float (cfg .get ("robot_protrusion_back_meters" , 0.0 )))
204+ self .robot_protrusion_left_m = max (0.0 , float (cfg .get ("robot_protrusion_left_meters" , 0.0 )))
205+ self .robot_protrusion_right_m = max (0.0 , float (cfg .get ("robot_protrusion_right_meters" , 0.0 )))
192206 except Exception :
193207 return
194208 self ._rebuild_items ()
@@ -197,7 +211,7 @@ def set_robot_dimensions(self, length_m: float, width_m: float):
197211 try :
198212 self ._ensure_sim_robot_item ()
199213 if self ._sim_robot_item :
200- self ._sim_robot_item .set_dimensions (self .robot_length_m , self .robot_width_m )
214+ self ._sim_robot_item .set_dimensions (self .robot_length_m , self .robot_width_m , self . robot_protrusion_front_m , self . robot_protrusion_back_m , self . robot_protrusion_left_m , self . robot_protrusion_right_m )
201215 except Exception :
202216 pass
203217
@@ -671,9 +685,23 @@ def _model_from_scene(self, x_s: float, y_s: float) -> Tuple[float, float]:
671685 """
672686 return float (x_s - self ._field_offset ), float (FIELD_WIDTH_METERS - y_s - self ._field_offset )
673687
688+ def _robot_half_extents (self ) -> Tuple [float , float ]:
689+ half_x = max (0.0 , self .robot_length_m * 0.5 + self .robot_protrusion_front_m )
690+ half_x_back = max (0.0 , self .robot_length_m * 0.5 + self .robot_protrusion_back_m )
691+ half_y = max (0.0 , self .robot_width_m * 0.5 + self .robot_protrusion_left_m )
692+ half_y_right = max (0.0 , self .robot_width_m * 0.5 + self .robot_protrusion_right_m )
693+ return max (half_x , half_x_back ), max (half_y , half_y_right )
694+
674695 def _clamp_scene_coords (self , x_s : float , y_s : float ) -> Tuple [float , float ]:
675696 return max (0.0 , min (x_s , FIELD_LENGTH_METERS )), max (0.0 , min (y_s , FIELD_WIDTH_METERS ))
676697
698+ def _clamp_scene_coords_with_robot_perimeter (self , x_s : float , y_s : float ) -> Tuple [float , float ]:
699+ hx , hy = self ._robot_half_extents ()
700+ return (
701+ max (hx , min (x_s , FIELD_LENGTH_METERS - hx )),
702+ max (hy , min (y_s , FIELD_WIDTH_METERS - hy )),
703+ )
704+
677705 def _constrain_scene_coords_for_index (
678706 self , index : int , x_s : float , y_s : float
679707 ) -> Tuple [float , float ]:
@@ -685,7 +713,7 @@ def _constrain_scene_coords_for_index(
685713 except Exception :
686714 return x_s , y_s
687715 if kind not in ("rotation" , "event_trigger" ):
688- return x_s , y_s
716+ return self . _clamp_scene_coords_with_robot_perimeter ( x_s , y_s )
689717 prev_pos , next_pos = self ._find_neighbor_item_positions (index )
690718 if prev_pos is None or next_pos is None :
691719 return x_s , y_s
@@ -700,7 +728,7 @@ def _constrain_scene_coords_for_index(
700728 t = max (0.0 , min (1.0 , t ))
701729 proj_x = ax + t * dx
702730 proj_y = ay + t * dy
703- return self ._clamp_scene_coords (proj_x , proj_y )
731+ return self ._clamp_scene_coords_with_robot_perimeter (proj_x , proj_y )
704732
705733 def _find_neighbor_item_positions (
706734 self , index : int
@@ -821,7 +849,7 @@ def _ensure_sim_robot_item(self):
821849 self ._sim_robot_item = item
822850 item .setVisible (False )
823851 try :
824- item .set_dimensions (self .robot_length_m , self .robot_width_m )
852+ item .set_dimensions (self .robot_length_m , self .robot_width_m , self . robot_protrusion_front_m , self . robot_protrusion_back_m , self . robot_protrusion_left_m , self . robot_protrusion_right_m )
825853 except Exception :
826854 pass
827855 except Exception :
0 commit comments