11from panda3d .core import LPoint3 , LVector3 , OrthographicLens , LineSegs , NodePath
22from direct .interval .IntervalGlobal import Parallel , LerpFunc , Sequence , Func
33
4+
45class CameraController :
56 """
67 Orthographic camera controller for the 3D view.
@@ -11,7 +12,7 @@ class CameraController:
1112 ``cmd_zoom``, ``cmd_center`` and ``cmd_align_plane``.
1213 """
1314
14- #TODO: check settings maybe a configuration error
15+ # TODO: check settings maybe a configuration error
1516 def __init__ (self , base , scene , settings ):
1617 """
1718 Set up the orthographic camera and its node hierarchy.
@@ -51,11 +52,10 @@ def __init__(self, base, scene, settings):
5152 self .key_pan_speed = 2.0
5253
5354 # Task pour maintenir le marqueur et le gizmo
54- taskMgr .add (self .update_task , "CameraUpdateTask" )
55+ self . taskMgr .add (self .update_task , "CameraUpdateTask" )
5556 # Configure la camera par rapport au contenu de la scene
5657 self .refresh_scene ()
5758
58-
5959 def refresh_scene (self ):
6060 """
6161 Recompute camera parameters from the current scene geometry.
@@ -67,7 +67,8 @@ def refresh_scene(self):
6767 bounds = self .scene .geom_node .getBounds ()
6868 center = bounds .getCenter ()
6969 radius = bounds .getRadius ()
70- if radius <= 0 : radius = 1 # Sécurité si modèle vide
70+ if radius <= 0 :
71+ radius = 1 # Sécurité si modèle vide
7172
7273 # 2. Positionner le pivot au centre de l'objet
7374 self .focal_node .setPos (center )
@@ -100,10 +101,12 @@ def create_marker(self):
100101 """
101102 ls = LineSegs ()
102103 ls .setThickness (2 )
103- for i , col in enumerate ([(1 ,0 , 0 , 1 ), (0 ,1 , 0 , 1 ), (0 ,0 , 1 , 1 )]):
104+ for i , col in enumerate ([(1 , 0 , 0 , 1 ), (0 , 1 , 0 , 1 ), (0 , 0 , 1 , 1 )]):
104105 ls .setColor (col )
105- v = LVector3 (0 ,0 ,0 ); v [i ] = 0.5
106- ls .moveTo (0 ,0 ,0 ); ls .drawTo (v )
106+ v = LVector3 (0 , 0 , 0 )
107+ v [i ] = 0.5
108+ ls .moveTo (0 , 0 , 0 )
109+ ls .drawTo (v )
107110 return NodePath (ls .create ())
108111
109112 def handle_rotate (self , dx , dy ):
@@ -114,7 +117,8 @@ def handle_rotate(self, dx, dy):
114117 dx: Normalised horizontal delta (screen space, -1..1).
115118 dy: Normalised vertical delta (screen space, -1..1).
116119 """
117- if self .is_animating : return
120+ if self .is_animating :
121+ return
118122 sens = 100.0
119123 new_h = self .focal_node .getH () - dx * sens
120124 new_p = self .focal_node .getP () + dy * sens
@@ -131,7 +135,8 @@ def handle_pan(self, dx, dy):
131135 dx: Normalised horizontal delta (screen space, -1..1).
132136 dy: Normalised vertical delta (screen space, -1..1).
133137 """
134- if self .is_animating : return
138+ if self .is_animating :
139+ return
135140
136141 # Largeur de la vue actuelle
137142 fs = self .lens .getFilmSize ().getX ()
@@ -155,7 +160,8 @@ def handle_zoom(self, factor):
155160 factor: Multiplier applied to the current film size
156161 (< 1 zooms in, > 1 zooms out).
157162 """
158- if self .is_animating : return
163+ if self .is_animating :
164+ return
159165
160166 # 1. Calculer la nouvelle taille de vue
161167 current_size = self .lens .getFilmSize ().getX ()
@@ -180,21 +186,20 @@ def recenter(self):
180186 Only the pivot position is animated; rotation and zoom are left
181187 unchanged so the user keeps their current viewing angle.
182188 """
183- if self .is_animating : return
189+ if self .is_animating :
190+ return
184191 self .is_animating = True
185192
186193 # On récupère le centre réel de l'objet calculé dans analyze_model
187194 # target_pos est un LPoint3 (le centre géométrique du modèle)
188195 target_pos = self .model_center
189196
190- duration = 0.4 # Un peu plus rapide pour un recadrage fluide
197+ duration = 0.4 # Un peu plus rapide pour un recadrage fluide
191198
192199 # On ne crée qu'UN SEUL intervalle : la position.
193200 # On ne touche NI au HPR (rotation) NI au FilmSize (zoom).
194201 self .cam_anim = self .focal_node .posInterval (
195- duration ,
196- target_pos ,
197- blendType = 'easeInOut'
202+ duration , target_pos , blendType = "easeInOut"
198203 )
199204 # Séquence pour déverrouiller à la fin
200205 Sequence (self .cam_anim , Func (self ._unlock )).start ()
@@ -214,43 +219,46 @@ def align_to_plane(self, axis):
214219 axis: One of ``"x"`` (right view), ``"y"`` (front view) or
215220 ``"z"`` (top view).
216221 """
217- if self .is_animating : return
222+ if self .is_animating :
223+ return
218224
219225 # 1. Définir les rotations cibles (Heading, Pitch, Roll)
220- if axis == "z" : # Vue de dessus (Top)
226+ if axis == "z" : # Vue de dessus (Top)
221227 target_hpr = LPoint3 (0 , - 90 , 0 )
222- elif axis == "y" : # Vue de face (Front)
228+ elif axis == "y" : # Vue de face (Front)
223229 target_hpr = LPoint3 (0 , 0 , 0 )
224- elif axis == "x" : # Vue de côté (Right)
230+ elif axis == "x" : # Vue de côté (Right)
225231 target_hpr = LPoint3 (90 , 0 , 0 )
226232 else :
227233 return
228234
229235 self .is_animating = True
230236
231237 duration = 0.5
232- # 2. Animation fluide de la rotation du pivot
238+ # 2. Animation fluide de la rotation du pivot
233239 # On peut aussi combiner cela avec un recentrage automatique
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
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+ )
236246 self .transition = Parallel (
237247 # 1. Aligne la rotation sur l'axe demandé
238- self .focal_node .hprInterval (duration , target_hpr , blendType = 'easeInOut' ),
239-
248+ self .focal_node .hprInterval (duration , target_hpr , blendType = "easeInOut" ),
240249 # 2. Déplace le pivot vers le centre réel du modèle
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' ),
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+ ),
247258 )
248259
249260 # On lance et on déverrouille à la fin
250- Sequence (
251- self .transition ,
252- Func (self ._unlock )
253- ).start ()
261+ Sequence (self .transition , Func (self ._unlock )).start ()
254262
255263 # Parallel(
256264 # self.focal_node.hprInterval(duration, target_hpr, blendType='easeInOut'),
@@ -265,7 +273,6 @@ def align_to_plane(self, axis):
265273
266274 # taskMgr.doMethodLater(duration, self._unlock, "UnlockTask")
267275
268-
269276 def update_task (self , task ):
270277 """
271278 Per-frame task: keep the pivot marker and gizmo in sync with the camera.
@@ -276,7 +283,6 @@ def update_task(self, task):
276283 # Le marqueur suit le pivot
277284 self .marker .setPos (self .focal_node .getPos ())
278285 # Mise à jour du Gizmo (orientation de la caméra vers le monde)
279- if hasattr (self .scene , ' gizmo' ):
286+ if hasattr (self .scene , " gizmo" ):
280287 self .scene .gizmo .update (self .base .camera .getQuat (self .base .render ))
281288 return task .cont
282-
0 commit comments