summaryrefslogtreecommitdiff
path: root/cad/src/graphics/drawables/DirectionArrow.py
blob: e2fc567116dd99189c5f9e3dd4e449313fe05fe9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# Copyright 2007-2008 Nanorex, Inc.  See LICENSE file for details. 
"""
DirectionArrow.py

@author: Ninad
@version: $Id$
@copyright: 2007-2008 Nanorex, Inc.  See LICENSE file for details.

History:
ninad 2007-06-12: Created this class (initially) to support the implementation 
of 'offset plane' (was created in Plane.py) 
ninad 2007-08-20: Split it out of Plane.py into this new file. 

TODO:
- Need to implement some grid plane features. 
- Plane should be selectable when clicked anywhere inside. 
"""

from OpenGL.GL import glPushName
from OpenGL.GL import glPopName
from OpenGL.GL import glPushMatrix
from OpenGL.GL import glTranslatef
from OpenGL.GL import glRotatef
from OpenGL.GL import glPopMatrix

from graphics.drawing.CS_draw_primitives import drawDirectionArrow

from geometry.VQT import V, norm, vlen
from math        import pi
from utilities.constants import gray, orange
from utilities.debug import print_compact_traceback
from graphics.drawables.DragHandler import DragHandler_API
from graphics.drawables.Selobj import Selobj_API

import foundation.env as env


ONE_RADIAN = 180.0 / pi
# One radian = 57.29577951 degrees
# This is for optimization since this computation occurs repeatedly
# in very tight drawning loops. --Mark 2007-08-14


class DirectionArrow(DragHandler_API, Selobj_API):
    """
    The DirectionArrow class provides a 3D direction arrow that can be
    interacted with in the 3D graphics area. The direction arrow object
    is created in its parent class. (class corresponding to self.parent)

    Example: Used to generate a plane offset to the selected plane, 
             in the direction indicated by the direction arrow.
             Clicking on the arrow reverses its direction and 
             thus the direction of the plane placement.
    """
    def __init__(self, parent, glpane, tailPoint, defaultDirection):
        """
        Creates a direction arrow.

        @param parent: The parent object.
        @type  parent:

        @param glpane: The 3D graphics area object.
        @type  glpane: L{GLPane}

        @param tailPoint: The origin of the arrow.
        @type  tailPoint: V

        @param defaultDirection: The direction of the arrow.
        @type  defaultDirection: 
        """
        self.parent = parent
        self.glpane = glpane
        self.tailPoint = tailPoint  
        self.direction = defaultDirection        
        self.glname = glpane.alloc_my_glselect_name(self) #bruce 080917 revised
        self.flipDirection = False
        self.drawRequested = False

    def setDrawRequested(self, bool_request = False):
        """
        Sets the draw request for drawing the direction arrow. 
        This class's draw method is called in the parent class's draw method
        This functions sets the flag that decides whether to draw direction 
        arrow (the flag  value is returned using isDrawRequested method.
        @param bool_request: Default is False. (request to draw direction arrow)
        @type  bool_request: bool
        """
        self.drawRequested = bool_request

    def isDrawRequested(self): 
        """ 
        Returns the flag that decides whether to draw the direction arrow. 
        @return B{self.drawRequested} (boolean value)
        @rtype  instance variable B{self.drawRequested}
        """
        return self.drawRequested 

    def draw(self):
        """ 
        Draw the direction arrow. (This method is called inside of the 
        parent object's drawing code.
        """
        try:
            glPushName(self.glname)
            if self.flipDirection:
                self._draw(flipDirection = self.flipDirection)    
            else:
                self._draw()
        except:
            glPopName()
            print_compact_traceback("ignoring exception when drawing handle %r: " % self)
        else:
            glPopName()        
        pass

    def _draw(self, flipDirection = False, highlighted = False):
        """ Main drawing code. 
        @param flipDirection: This flag decides the direction in which the 
               arrow is drawn. This value is set in the leftClick method. 
               The default value is 'False'
        @type   flipDirection: bool
        @param highlighted: Decids the color of the arrow based on whether 
               it is highlighted. The default value is 'False'
        @type  highlighted: bool

        """

        if highlighted:
            color = orange
        else:
            color = gray

        if flipDirection:
            #@NOTE: Remember we are drawing the arrow inside of the _draw_geometry 
            #so its drawing it in the translated coordinate system (translated
            #at the center of the Plane. So we should do the following. 
            #(i.e. use V(0,0,1)). This will change if we decide to draw the 
            #direction arrow outside of the parent object 
            #requesting this drawing.--ninad 20070612
            #Using headPoint = self.tailPoint + V(0,0,1) * 2.0 etc along with 
            #the transformation matrix in self.draw_in_abs_coordinate()
            #fixes bug 2702 and 2703 -- Ninad 2008-06-11
            headPoint = self.tailPoint + V(0,0,1) * 2.0
            ##headPoint = self.tailPoint + 2.0 * norm(self.parent.getaxis())
        else:            
            headPoint = self.tailPoint - V(0,0,1) * 2.0
            ##headPoint = self.tailPoint - 2.0 * self.parent.getaxis()



        vec = vlen(headPoint - self.tailPoint)
        vec = self.glpane.scale*0.07*vec
        tailRadius = vlen(vec)*0.16

        drawDirectionArrow(color, 
                           self.tailPoint, 
                           headPoint,
                           tailRadius,
                           self.glpane.scale,
                           flipDirection = flipDirection)

    def draw_in_abs_coords(self, glpane, color):
        """
        Draw the handle as a highlighted object.
        @param glpane: B{GLPane} object
        @type  glpane: L{GLPane}
        @param color: Highlight color 
        """    
        q = self.parent.quat 	 
        glPushMatrix() 	 
        glTranslatef( self.parent.center[0], 	 
                      self.parent.center[1], 	 
                      self.parent.center[2]) 	 
        glRotatef( q.angle * ONE_RADIAN, 	 
                   q.x, 	 
                   q.y, 	 
                   q.z)

        if self.flipDirection:            
            self._draw(flipDirection = self.flipDirection, 
                       highlighted   = True)    
        else:
            self._draw(highlighted   = True)

        glPopMatrix()

    ###=========== Drag Handler interface Starts =============###
    #@TODO Need some documentation. Basically it implements the drag handler 
    #interface described in DragHandler.py See also exprs.Highlightable.py
    # -- ninad 20070612
    def handles_updates(self): 
        return True

    def DraggedOn(self, event, mode): 
        return

    def ReleasedOn(self, selobj, event, mode): 
        pass

    # =========== Drag Handler interface Ends =============

    # ============== selobj interface Starts ==============

    #@TODO Need some documentation. Basically it implements the selobj 
    # interface mentioned in exprs.Highlightable.py -- ninad 2007-06-12

    def leftClick(self, point, event, mode):
        """
        Left clicking on the DirectionArrow flips its direction.

        @param point: not used for now.
        @type  point: V

        @param event: Left down event.
        @type  event: QEvent

        @param mode: Current mode program is in.
        @type  mode: L{anyMode}
        """
        self.flipDirection = not self.flipDirection
        mode.update_selobj(event)
        mode.o.gl_update()
        return self               

    def mouseover_statusbar_message(self):
        """
        Returns the statusbar message to display when the cursor is over the
        direction arrow in the 3D graphics area.

        @return: The statusbar message
        @rtype:  str
        """
        msg1 = "Click on arrow to flip its direction"
        return msg1 

    def highlight_color_for_modkeys(self, modkeys):
        return orange

    # Copied Bruce's code from class Highlightable with some mods. 
    # Need to see if selobj_still_ok() is needed. OK for now.
    # --Ninad 2007-05-31
    def selobj_still_ok(self, glpane):
        res = self.__class__ is DirectionArrow
        if res:
            our_selobj = self
            glname     = self.glname
            owner      = glpane.assy.object_for_glselect_name(glname)
            if owner is not our_selobj:
                res = False
                # Do debug prints.
                print "%r no longer owns glname %r, instead %r does" \
                      % (self, glname, owner) # [perhaps never seen as of 061121]
                pass
            pass
        if not res and env.debug():
            print "debug: selobj_still_ok is false for %r" % self
        return res

        ###============== selobj interface Ends===============###

    pass