Changeset 34f23c8 in sasview for src/sas/sasgui/perspectives/simulation
- Timestamp:
- Mar 20, 2019 10:06:22 AM (6 years ago)
- Branches:
- ticket-1249
- Children:
- 9305b46
- Parents:
- 09d7021
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/sas/sasgui/perspectives/simulation/SimCanvas.py
r959eb01 r34f23c8 2 2 This software was developed by the University of Tennessee as part of the 3 3 Distributed Data Analysis of Neutron Scattering Experiments (DANSE) 4 project funded by the US National Science Foundation. 4 project funded by the US National Science Foundation. 5 5 6 6 See the license text in license.txt … … 32 32 except ImportError: 33 33 haveOpenGL = False 34 34 35 35 # Color set 36 DEFAULT_COLOR = [1.0, 1.0, 0.0, .2] 36 DEFAULT_COLOR = [1.0, 1.0, 0.0, .2] 37 37 COLOR_RED = [1.0, 0.0, 0.0, .2] 38 38 COLOR_GREEN = [0.0, 1.0, 0.0, .2] … … 48 48 class SimPanel(wx.Panel): 49 49 """ 50 3D viewer to support real-space simulation. 50 3D viewer to support real-space simulation. 51 51 """ 52 52 window_name = "3dview" 53 53 window_caption = "3D viewer" 54 54 55 55 def __init__(self, parent, id = -1, plots = None, standalone=False, **kwargs): 56 56 wx.Panel.__init__(self, parent, id = id, **kwargs) 57 57 self.parent = parent 58 58 59 59 #Add a sizer 60 60 mainSizer = wx.BoxSizer(wx.VERTICAL) 61 61 sliderSizer = wx.BoxSizer(wx.HORIZONTAL) 62 63 self.canvas = CanvasBase(self) 62 63 self.canvas = CanvasBase(self) 64 64 self.canvas.SetMinSize((200,2100)) 65 65 … … 72 72 self.SetSizer(mainSizer) 73 73 self.Bind(wx.EVT_CONTEXT_MENU, self._on_context_menu) 74 75 74 75 76 76 def _on_context_menu(self, event): 77 77 """ … … 83 83 slicerpop.Append(id, '&Reset 3D View') 84 84 wx.EVT_MENU(self, id, self.canvas.resetView) 85 85 86 86 pos = event.GetPosition() 87 87 pos = self.ScreenToClient(pos) 88 self.PopupMenu(slicerpop, pos) 89 88 self.PopupMenu(slicerpop, pos) 89 90 90 class CanvasBase(glcanvas.GLCanvas): 91 91 """ … … 94 94 window_name = "Simulation" 95 95 window_caption = "Simulation" 96 96 97 97 def __init__(self, parent): 98 98 glcanvas.GLCanvas.__init__(self, parent, -1) … … 113 113 self.Bind(wx.EVT_MOTION, self.OnMouseMotion) 114 114 self.Bind(wx.EVT_MOUSEWHEEL, self._onMouseWheel) 115 115 116 116 self.initialized = False 117 117 self.shapes = [] 118 118 self.parent = parent 119 119 120 120 # Reference vectors 121 121 self.x_vec = [1,0,0] 122 122 self.y_vec = [0,1,0] 123 123 124 124 self.mouse_down = False 125 125 self.scale = 1.0 126 126 self.zoom = 1.0 127 127 self.translation = [0,0,0] 128 128 129 129 # Bind to Edit events 130 130 self.parent.Bind(ShapeParameters.EVT_EDIT_SHAPE, self._onEditShape) 131 131 132 132 def resetView(self, evt=None): 133 133 """ … … 140 140 glLoadIdentity() 141 141 self.Refresh() 142 142 143 143 def _onEditShape(self, evt): 144 144 evt.Skip() … … 158 158 event.Skip() 159 159 160 def OnPaint(self, event): 160 def OnPaint(self, event): 161 161 size = self.GetClientSize() 162 162 side = size.width 163 163 if size.height<size.width: 164 164 side = size.height 165 165 166 166 if self.GetContext(): 167 167 glViewport(0, 0, side, side) 168 168 self.SetMinSize((side,side)) 169 169 170 170 dc = wx.PaintDC(self) 171 171 self.SetCurrent() … … 174 174 self.init = True 175 175 self.OnDraw() 176 event.Skip() 177 176 event.Skip() 177 178 178 def _onMouseWheel(self, evt): 179 179 # Initialize mouse position so we don't have unwanted rotation 180 180 self.x, self.y = self.lastx, self.lasty = evt.GetPosition() 181 181 self.tr_x, self.tr_y = self.tr_lastx, self.tr_lasty = evt.GetPosition() 182 182 183 183 scale = 1.15 184 184 if evt.GetWheelRotation()<0: 185 185 scale = 1.0/scale 186 187 self.zoom *= scale 188 186 187 self.zoom *= scale 188 189 189 glScale(scale, scale, scale) 190 190 self.Refresh(False) 191 191 192 192 def OnMouseDown(self, evt): 193 193 self.SetFocus() … … 214 214 slicerpop.Append(id, '&Reset 3D View') 215 215 wx.EVT_MENU(self, id, self.resetView) 216 216 217 217 pos = event.GetPosition() 218 218 #pos = self.ScreenToClient(pos) 219 self.PopupMenu(slicerpop, pos) 219 self.PopupMenu(slicerpop, pos) 220 220 221 221 def OnMouseMotion(self, evt): … … 223 223 self.tr_lastx, self.tr_lasty = self.tr_x, self.tr_y 224 224 x, y = evt.GetPosition() 225 225 226 226 # Min distance to do anything 227 227 if math.fabs(self.lastx-x)>10 or math.fabs(self.lasty-y)>10: 228 228 229 229 self.lastx, self.lasty = self.x, self.y 230 231 230 231 232 232 if math.fabs(self.lastx-x)>math.fabs(self.lasty-y): 233 233 self.x = x 234 234 else: 235 235 self.y = y 236 236 237 237 #self.x, self.y = evt.GetPosition() 238 238 self.Refresh(False) 239 239 240 240 elif evt.Dragging() and evt.RightIsDown(): 241 241 self.lastx, self.lasty = self.x, self.y … … 243 243 self.tr_x, self.tr_y = evt.GetPosition() 244 244 self.Refresh(False) 245 246 def InitGL( self ): 245 246 def InitGL( self ): 247 247 glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA) 248 248 #glShadeModel(GL_FLAT); 249 249 250 250 glMatrixMode(GL_PROJECTION) 251 251 252 252 glLight(GL_LIGHT0, GL_AMBIENT, [.2, .2, .2, 0]) 253 253 254 254 # Object color 255 255 #glLight(GL_LIGHT0, GL_DIFFUSE, COLOR_BLUE) 256 256 257 257 glLight(GL_LIGHT0, GL_POSITION, [1.0, 1.0, -1.0, 0.0]) 258 259 258 259 260 260 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [1, 1, 1, 0]) 261 261 glEnable(GL_LIGHTING) … … 263 263 glEnable(GL_BLEND) 264 264 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 265 265 266 266 glEnable ( GL_ALPHA_TEST ) ; 267 267 glAlphaFunc ( GL_GREATER, 0 ) ; 268 268 glPixelStorei(GL_PACK_ALIGNMENT, 1) 269 269 glPixelStorei(GL_UNPACK_ALIGNMENT, 1) 270 270 271 271 glEnable(GL_NORMALIZE) 272 272 glDepthFunc(GL_LESS) … … 276 276 #glClear (GL_COLOR_BUFFER_BIT); 277 277 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 278 279 278 279 280 280 gluPerspective(0, 1.0, 0.1, 60.0); 281 281 … … 296 296 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 297 297 # use a fresh transformation matrix 298 298 299 299 # get the max object size to re-scale 300 300 max_size = 1.0 … … 305 305 if l>max_size: 306 306 max_size = l 307 307 308 308 max_size *= 1.05 309 309 scale = self.scale/max_size 310 310 glScale(scale, scale, scale) 311 311 self.scale = max_size 312 312 313 313 self.drawAxes() 314 314 315 315 if self.mouse_down: 316 316 if math.fabs((self.x - self.lastx))>math.fabs((self.y - self.lasty)): 317 angle = 10.0*(self.x - self.lastx) / math.fabs(self.x - self.lastx) 317 angle = 10.0*(self.x - self.lastx) / math.fabs(self.x - self.lastx) 318 318 glRotate(angle, self.y_vec[0], self.y_vec[1], self.y_vec[2]); 319 319 self._rot_y(angle) 320 320 elif math.fabs(self.y - self.lasty)>0: 321 angle = 10.0*(self.y - self.lasty) / math.fabs(self.y - self.lasty) 321 angle = 10.0*(self.y - self.lasty) / math.fabs(self.y - self.lasty) 322 322 glRotate(angle, self.x_vec[0], self.x_vec[1], self.x_vec[2]); 323 323 self._rot_x(angle) … … 325 325 self.lasty = self.y 326 326 self.lastx = self.x 327 328 w, h = self.GetVirtualSizeTuple()329 327 328 w, h = self.GetVirtualSize() 329 330 330 # Translate in the x-y plane 331 331 vx = self.x_vec[0] * 2.0*float(self.tr_x - self.tr_lastx)/w \ … … 335 335 vz = self.x_vec[2] * 2.0*float(self.tr_x - self.tr_lastx)/w \ 336 336 + self.y_vec[2] * 2.0*float(self.tr_lasty - self.tr_y)/h 337 338 glTranslate(self.scale*vx/self.zoom, self.scale*vy/self.zoom, self.scale*vz/self.zoom) 339 337 338 glTranslate(self.scale*vx/self.zoom, self.scale*vy/self.zoom, self.scale*vz/self.zoom) 339 340 340 # push into visible buffer 341 341 self.SwapBuffers() 342 342 343 343 def _matrix_mult(self, v, axis, angle): 344 344 c = math.cos(angle) 345 s = math.sin(angle) 345 s = math.sin(angle) 346 346 x = axis[0] 347 347 y = axis[1] … … 351 351 vz = v[0]*(x*z*(1-c)-y*s) + v[1]*(y*z*(1-c)+x*s) + v[2]*(z*z*(1-c)+c) 352 352 return [vx, vy, vz] 353 353 354 354 def _rot_y(self, theta): 355 355 """ 356 356 Rotate the view by theta around the y-axis 357 357 """ 358 angle = theta/180.0*math.pi 358 angle = theta/180.0*math.pi 359 359 axis = self.y_vec 360 360 self.x_vec = self._matrix_mult(self.x_vec, self.y_vec, -angle) 361 361 362 362 def _rot_x(self, theta): 363 363 """ … … 366 366 angle = theta/180.0*math.pi 367 367 self.y_vec = self._matrix_mult(self.y_vec, self.x_vec, -angle) 368 369 368 369 370 370 def addShape(self, shape, name=None): 371 371 """ … … 403 403 404 404 def drawAxes(self): 405 """ 405 """ 406 406 Draw 3D axes 407 407 """ 408 408 pos = self.scale * 0.7 409 409 410 410 # Z-axis is red 411 zaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01, 411 zaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01, 412 412 l_cyl=self.scale*0.1, l_cone=self.scale*0.05) 413 413 zaxis.color = COLOR_RED 414 414 zaxis.draw() 415 415 416 416 # Y-axis is yellow 417 yaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01, 417 yaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01, 418 418 l_cyl=self.scale*0.1, l_cone=self.scale*0.05) 419 419 yaxis.color = COLOR_YELLOW 420 420 yaxis.rotate(-90,0,0) 421 421 yaxis.draw() 422 422 423 423 # X-axis is green 424 xaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01, 424 xaxis= Arrow(x=pos, y=-pos, z=0, r_cyl=self.scale*0.005, r_cone=self.scale*0.01, 425 425 l_cyl=self.scale*0.1, l_cone=self.scale*0.05) 426 426 xaxis.color = COLOR_GREEN 427 427 xaxis.rotate(0,-90,0) 428 428 xaxis.draw() 429 429 430 430 glLight(GL_LIGHT0, GL_DIFFUSE, DEFAULT_COLOR) 431 431 … … 445 445 self.theta_y = 0 446 446 self.theta_z = 0 447 447 448 448 # Params 449 449 self.params = {} … … 453 453 self.details['contrast'] = 'A-2' 454 454 self.details['order'] = ' ' 455 455 456 456 self.highlighted = False 457 457 self.color = DEFAULT_COLOR 458 458 459 459 def get_volume(self): 460 460 return 0 461 461 462 462 def get_length(self): 463 463 return 1.0 464 464 465 465 def highlight(self, value=False): 466 466 self.highlighted = value 467 467 468 468 def rotate(self, alpha, beta, gamma): 469 """ 469 """ 470 470 Set the rotation angles of the shape 471 471 @param alpha: angle around the x-axis [degrees] … … 476 476 self.theta_y = beta 477 477 self.theta_z = gamma 478 478 479 479 def _rotate(self): 480 480 """ 481 481 Perform the OpenGL rotation 482 482 483 483 Note that the rotation order is reversed. 484 484 We do Y, X, Z do be compatible with simulation... 485 485 """ 486 486 487 487 glRotated(self.theta_z, 0, 0, 1) 488 488 glRotated(self.theta_x, 1, 0, 0) 489 489 glRotated(self.theta_y, 0, 1, 0) 490 490 491 491 def _pre_draw(self): 492 492 if self.highlighted: … … 506 506 self.l_cyl = l_cyl 507 507 self.l_cone = l_cone 508 508 509 509 def draw(self): 510 510 self._pre_draw() 511 511 glPushMatrix() 512 512 glTranslate(self.x, self.y, self.z) 513 513 514 514 # Perform rotation 515 515 glRotate(self.theta_x, 1, 0, 0) … … 520 520 qobj = gluNewQuadric(); 521 521 gluCylinder(qobj, self.r_cyl, self.r_cyl, self.l_cyl, 15, 5); 522 522 523 523 glTranslate(0, 0, self.z+self.l_cyl) 524 524 525 525 # Draw cone of the arrow 526 526 glutSolidCone(self.r_cone, self.l_cone, 30, 5) 527 527 528 528 # Translate back to original position 529 529 glTranslate(-self.x, -self.y, -self.z) … … 538 538 self.radius = radius 539 539 self.height = height 540 540 541 541 def draw(self): 542 542 glPushMatrix() … … 556 556 self.params['radius'] = radius 557 557 self.details['radius'] = 'A' 558 558 559 559 def get_volume(self): 560 560 return 4.0/3.0*math.pi*self.params['radius']*self.params['radius']*self.params['radius'] 561 561 562 562 def get_length(self): 563 563 return 2.0*self.params['radius'] 564 564 565 565 def draw(self): 566 566 self._pre_draw() … … 584 584 """ 585 585 Cylinder shape, by default the cylinder is oriented along 586 the z-axis. 587 586 the z-axis. 587 588 588 The reference point of the cylinder is the center of the 589 589 bottom circle. … … 596 596 self.details['radius'] = 'A' 597 597 self.details['length'] = 'A' 598 598 599 599 def get_volume(self): 600 600 return math.pi*self.params['radius']*self.params['radius']*self.params['length'] 601 601 602 602 def get_length(self): 603 603 if self.params['length']>2.0*self.params['radius']: … … 605 605 else: 606 606 return 2.0*self.params['radius'] 607 607 608 608 def draw(self): 609 609 self._pre_draw() 610 610 glPushMatrix() 611 611 612 612 glTranslate(self.x, self.y, self.z) 613 self._rotate() 613 self._rotate() 614 614 qobj = gluNewQuadric(); 615 615 # gluCylinder(qobj, r_base, r_top, L, div around z, div along z) … … 619 619 glPopMatrix() 620 620 glLight(GL_LIGHT0, GL_DIFFUSE, DEFAULT_COLOR) 621 621 622 622 def accept(self, visitor): 623 623 return visitor.fromCylinder(self) 624 624 625 625 def accept_update(self, visitor): 626 626 return visitor.update_cylinder(self) 627 627 628 628 # Fill the shape list 629 629 SHAPE_LIST.append(dict(name='Sphere', id=wx.NewId(), cl=Sphere)) 630 630 SHAPE_LIST.append(dict(name='Cylinder', id=wx.NewId(), cl=Cylinder)) 631 631 632 632 def getShapes(): 633 633 """ … … 635 635 """ 636 636 return SHAPE_LIST 637 637 638 638 def getShapeClass(id): 639 639 """ … … 647 647 return shape[0]['cl'] 648 648 return None 649 649 650 650 def getShapeClassByName(name): 651 651 """
Note: See TracChangeset
for help on using the changeset viewer.