11from panda3d .core import LPoint3 , LVector3 , OrthographicLens , LineSegs , NodePath
22from direct .interval .IntervalGlobal import Parallel , LerpFunc , Sequence , Func
33
4-
54class CameraController :
65 """
76 Orthographic camera controller for the 3D view.
@@ -12,7 +11,7 @@ class CameraController:
1211 ``cmd_zoom``, ``cmd_center`` and ``cmd_align_plane``.
1312 """
1413
15- # TODO: check settings maybe a configuration error
14+ #TODO: check settings maybe a configuration error
1615 def __init__ (self , base , scene , settings ):
1716 """
1817 Set up the orthographic camera and its node hierarchy.
@@ -52,10 +51,11 @@ def __init__(self, base, scene, settings):
5251 self .key_pan_speed = 2.0
5352
5453 # Task pour maintenir le marqueur et le gizmo
55- self . taskMgr .add (self .update_task , "CameraUpdateTask" )
54+ taskMgr .add (self .update_task , "CameraUpdateTask" )
5655 # Configure la camera par rapport au contenu de la scene
5756 self .refresh_scene ()
5857
58+
5959 def refresh_scene (self ):
6060 """
6161 Recompute camera parameters from the current scene geometry.
@@ -67,8 +67,7 @@ def refresh_scene(self):
6767 bounds = self .scene .geom_node .getBounds ()
6868 center = bounds .getCenter ()
6969 radius = bounds .getRadius ()
70- if radius <= 0 :
71- radius = 1 # Sécurité si modèle vide
70+ if radius <= 0 : radius = 1 # Sécurité si modèle vide
7271
7372 # 2. Positionner le pivot au centre de l'objet
7473 self .focal_node .setPos (center )
@@ -101,12 +100,10 @@ def create_marker(self):
101100 """
102101 ls = LineSegs ()
103102 ls .setThickness (2 )
104- for i , col in enumerate ([(1 , 0 , 0 , 1 ), (0 , 1 , 0 , 1 ), (0 , 0 , 1 , 1 )]):
103+ for i , col in enumerate ([(1 ,0 , 0 , 1 ), (0 ,1 , 0 , 1 ), (0 ,0 , 1 , 1 )]):
105104 ls .setColor (col )
106- v = LVector3 (0 , 0 , 0 )
107- v [i ] = 0.5
108- ls .moveTo (0 , 0 , 0 )
109- ls .drawTo (v )
105+ v = LVector3 (0 ,0 ,0 ); v [i ] = 0.5
106+ ls .moveTo (0 ,0 ,0 ); ls .drawTo (v )
110107 return NodePath (ls .create ())
111108
112109 def handle_rotate (self , dx , dy ):
@@ -117,8 +114,7 @@ def handle_rotate(self, dx, dy):
117114 dx: Normalised horizontal delta (screen space, -1..1).
118115 dy: Normalised vertical delta (screen space, -1..1).
119116 """
120- if self .is_animating :
121- return
117+ if self .is_animating : return
122118 sens = 100.0
123119 new_h = self .focal_node .getH () - dx * sens
124120 new_p = self .focal_node .getP () + dy * sens
@@ -135,8 +131,7 @@ def handle_pan(self, dx, dy):
135131 dx: Normalised horizontal delta (screen space, -1..1).
136132 dy: Normalised vertical delta (screen space, -1..1).
137133 """
138- if self .is_animating :
139- return
134+ if self .is_animating : return
140135
141136 # Largeur de la vue actuelle
142137 fs = self .lens .getFilmSize ().getX ()
@@ -160,8 +155,7 @@ def handle_zoom(self, factor):
160155 factor: Multiplier applied to the current film size
161156 (< 1 zooms in, > 1 zooms out).
162157 """
163- if self .is_animating :
164- return
158+ if self .is_animating : return
165159
166160 # 1. Calculer la nouvelle taille de vue
167161 current_size = self .lens .getFilmSize ().getX ()
@@ -186,20 +180,21 @@ def recenter(self):
186180 Only the pivot position is animated; rotation and zoom are left
187181 unchanged so the user keeps their current viewing angle.
188182 """
189- if self .is_animating :
190- return
183+ if self .is_animating : return
191184 self .is_animating = True
192185
193186 # On récupère le centre réel de l'objet calculé dans analyze_model
194187 # target_pos est un LPoint3 (le centre géométrique du modèle)
195188 target_pos = self .model_center
196189
197- duration = 0.4 # Un peu plus rapide pour un recadrage fluide
190+ duration = 0.4 # Un peu plus rapide pour un recadrage fluide
198191
199192 # On ne crée qu'UN SEUL intervalle : la position.
200193 # On ne touche NI au HPR (rotation) NI au FilmSize (zoom).
201194 self .cam_anim = self .focal_node .posInterval (
202- duration , target_pos , blendType = "easeInOut"
195+ duration ,
196+ target_pos ,
197+ blendType = 'easeInOut'
203198 )
204199 # Séquence pour déverrouiller à la fin
205200 Sequence (self .cam_anim , Func (self ._unlock )).start ()
@@ -219,46 +214,43 @@ def align_to_plane(self, axis):
219214 axis: One of ``"x"`` (right view), ``"y"`` (front view) or
220215 ``"z"`` (top view).
221216 """
222- if self .is_animating :
223- return
217+ if self .is_animating : return
224218
225219 # 1. Définir les rotations cibles (Heading, Pitch, Roll)
226- if axis == "z" : # Vue de dessus (Top)
220+ if axis == "z" : # Vue de dessus (Top)
227221 target_hpr = LPoint3 (0 , - 90 , 0 )
228- elif axis == "y" : # Vue de face (Front)
222+ elif axis == "y" : # Vue de face (Front)
229223 target_hpr = LPoint3 (0 , 0 , 0 )
230- elif axis == "x" : # Vue de côté (Right)
224+ elif axis == "x" : # Vue de côté (Right)
231225 target_hpr = LPoint3 (90 , 0 , 0 )
232226 else :
233227 return
234228
235229 self .is_animating = True
236230
237231 duration = 0.5
238- # 2. Animation fluide de la rotation du pivot
232+ # 2. Animation fluide de la rotation du pivot
239233 # On peut aussi combiner cela avec un recentrage automatique
240- center = LPoint3 (* self .scene .bounds ["center" ])
241- max_dim = (
242- max (self .scene .bounds ["size" ])
243- if max (self .scene .bounds ["size" ]) > 0
244- else 1.0
245- )
234+ center = LPoint3 (* self .scene .bounds ['center' ])
235+ max_dim = max (self .scene .bounds ['size' ]) if max (self .scene .bounds ['size' ]) > 0 else 1.0
246236 self .transition = Parallel (
247237 # 1. Aligne la rotation sur l'axe demandé
248- self .focal_node .hprInterval (duration , target_hpr , blendType = "easeInOut" ),
238+ self .focal_node .hprInterval (duration , target_hpr , blendType = 'easeInOut' ),
239+
249240 # 2. Déplace le pivot vers le centre réel du modèle
250- self .focal_node .posInterval (duration , center , blendType = "easeInOut" ),
251- LerpFunc (
252- lambda s : self .lens .setFilmSize (s ),
253- fromData = self .lens .getFilmSize ().getX (),
254- toData = max_dim * 1.5 ,
255- duration = duration ,
256- blendType = "easeInOut" ,
257- ),
241+ self .focal_node .posInterval (duration , center , blendType = 'easeInOut' ),
242+ LerpFunc (lambda s : self .lens .setFilmSize (s ),
243+ fromData = self .lens .getFilmSize ().getX (),
244+ toData = max_dim * 1.5 ,
245+ duration = duration ,
246+ blendType = 'easeInOut' ),
258247 )
259248
260249 # On lance et on déverrouille à la fin
261- Sequence (self .transition , Func (self ._unlock )).start ()
250+ Sequence (
251+ self .transition ,
252+ Func (self ._unlock )
253+ ).start ()
262254
263255 # Parallel(
264256 # self.focal_node.hprInterval(duration, target_hpr, blendType='easeInOut'),
@@ -273,6 +265,7 @@ def align_to_plane(self, axis):
273265
274266 # taskMgr.doMethodLater(duration, self._unlock, "UnlockTask")
275267
268+
276269 def update_task (self , task ):
277270 """
278271 Per-frame task: keep the pivot marker and gizmo in sync with the camera.
@@ -283,6 +276,7 @@ def update_task(self, task):
283276 # Le marqueur suit le pivot
284277 self .marker .setPos (self .focal_node .getPos ())
285278 # Mise à jour du Gizmo (orientation de la caméra vers le monde)
286- if hasattr (self .scene , " gizmo" ):
279+ if hasattr (self .scene , ' gizmo' ):
287280 self .scene .gizmo .update (self .base .camera .getQuat (self .base .render ))
288281 return task .cont
282+
0 commit comments