"Fossies" - the Fresh Open Source Software Archive

Member "veusz-3.1/veusz/widgets/scene3d.py" (13 Jun 2018, 9832 Bytes) of package /linux/privat/veusz-3.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "scene3d.py" see the Fossies "Dox" file reference documentation.

    1 # -*- coding: utf-8 -*-
    2 
    3 #    Copyright (C) 2018 Jeremy S. Sanders
    4 #    Email: Jeremy Sanders <jeremy@jeremysanders.net>
    5 #
    6 #    This program is free software; you can redistribute it and/or modify
    7 #    it under the terms of the GNU General Public License as published by
    8 #    the Free Software Foundation; either version 2 of the License, or
    9 #    (at your option) any later version.
   10 #
   11 #    This program is distributed in the hope that it will be useful,
   12 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 #    GNU General Public License for more details.
   15 #
   16 #    You should have received a copy of the GNU General Public License along
   17 #    with this program; if not, write to the Free Software Foundation, Inc.,
   18 #    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   19 ##############################################################################
   20 
   21 from __future__ import division, print_function
   22 
   23 import math
   24 import numpy as N
   25 
   26 from .. import qtall as qt
   27 from .. import document
   28 from .. import setting
   29 from . import widget
   30 from . import controlgraph
   31 from ..helpers import threed
   32 
   33 def _(text, disambiguation=None, context='Scene3D'):
   34     """Translate text."""
   35     return qt.QCoreApplication.translate(context, text, disambiguation)
   36 
   37 # define 2nd and 3rd lighting classes
   38 class Lighting3D_2(setting.Lighting3D):
   39     def __init__(self, name, **args):
   40         setting.Lighting3D.__init__(self, name, **args)
   41         self.get('enable').newDefault(False)
   42         self.get('color').newDefault('red')
   43         self.get('x').newDefault(2)
   44 class Lighting3D_3(setting.Lighting3D):
   45     def __init__(self, name, **args):
   46         setting.Lighting3D.__init__(self, name, **args)
   47         self.get('enable').newDefault(False)
   48         self.get('color').newDefault('blue')
   49         self.get('x').newDefault(-2)
   50 
   51 class Scene3D(widget.Widget):
   52     """3D scene containing other widgets."""
   53 
   54     typename='scene3d'
   55     allowusercreation = True
   56     description = _('3d scene')
   57 
   58     @classmethod
   59     def addSettings(klass, s):
   60         """Construct list of settings."""
   61         widget.Widget.addSettings(s)
   62 
   63         s.add( setting.FloatSlider(
   64             'xRotation',
   65             0,
   66             minval=-180, maxval=180, step=15, tick=45,
   67             descr=_(u'Rotation around x axis (°)'),
   68             usertext=_('X rotation') ))
   69         s.add( setting.FloatSlider(
   70             'yRotation',
   71             35.,
   72             minval=-180, maxval=180, step=15, tick=45,
   73             descr=_(u'Rotation around y axis (°)'),
   74             usertext=_('Y rotation') ))
   75         s.add( setting.FloatSlider(
   76             'zRotation',
   77             0,
   78             minval=-180, maxval=180, step=15, tick=45,
   79             descr=_(u'Rotation around z axis (°)'),
   80             usertext=_('Z rotation') ))
   81 
   82         s.add( setting.FloatSlider(
   83             'distance',
   84             5,
   85             minval=1, maxval=50, step=0.5, tick=5, scale=0.1,
   86             descr=_(u'Viewing distance'),
   87             usertext=_('Distance') ))
   88 
   89         s.add( setting.FloatOrAuto(
   90             'size',
   91             'Auto',
   92             minval=0,
   93             descr=_('Automatic or fixed graph size scaling value'),
   94             usertext=_('Size'),
   95             formatting=True ))
   96 
   97         s.add( setting.Choice(
   98             'rendermode',
   99             ('painters', 'bsp'),
  100             'painters',
  101             uilist=("Fast (Painter's)",
  102                     "Accurate (BSP)"),
  103             usertext=_('Render method'),
  104             descr=_('Method used to draw 3D plot') ))
  105 
  106         s.add( setting.Distance(
  107                 'leftMargin',
  108                 '1cm',
  109                 descr=_('Distance from left of graph to edge'),
  110                 usertext=_('Left margin'),
  111                 formatting=True) )
  112         s.add( setting.Distance(
  113                 'rightMargin',
  114                 '1cm',
  115                 descr=_('Distance from right of graph to edge'),
  116                 usertext=_('Right margin'),
  117                 formatting=True) )
  118         s.add( setting.Distance(
  119                 'topMargin',
  120                 '1cm',
  121                 descr=_('Distance from top of graph to edge'),
  122                 usertext=_('Top margin'),
  123                 formatting=True) )
  124         s.add( setting.Distance(
  125                 'bottomMargin',
  126                 '1cm',
  127                 descr=_('Distance from bottom of graph to edge'),
  128                 usertext=_('Bottom margin'),
  129                 formatting=True) )
  130 
  131         s.add(setting.Lighting3D(
  132             'Lighting1',
  133             descr=_('Lighting (1)'),
  134             usertext=_('Lighting (1)')),
  135                pixmap = 'settings_lighting' )
  136         s.add(Lighting3D_2(
  137             'Lighting2',
  138             descr=_('Lighting (2)'),
  139             usertext=_('Lighting (2)')),
  140                pixmap = 'settings_lighting' )
  141         s.add(Lighting3D_3(
  142             'Lighting3',
  143             descr=_('Lighting (3)'),
  144             usertext=_('Lighting (3)')),
  145                pixmap = 'settings_lighting' )
  146 
  147     @classmethod
  148     def allowedParentTypes(self):
  149         from . import page, grid
  150         return (page.Page, grid.Grid)
  151 
  152     def getMargins(self, painthelper):
  153         """Use settings to compute margins."""
  154         s = self.settings
  155         return ( s.get('leftMargin').convert(painthelper),
  156                  s.get('topMargin').convert(painthelper),
  157                  s.get('rightMargin').convert(painthelper),
  158                  s.get('bottomMargin').convert(painthelper) )
  159 
  160     def makeObjects(self, painter, bounds, painthelper):
  161         """Make objects, returning root"""
  162 
  163         s = self.settings
  164 
  165         # do no painting if hidden
  166         if s.hide:
  167             return
  168 
  169         root = threed.ObjectContainer()
  170         root.objM = threed.rotate3M4(
  171             s.xRotation/180.*math.pi,
  172             s.yRotation/180.*math.pi,
  173             s.zRotation/180.*math.pi)
  174 
  175         # build 3d scene from children
  176         for c in self.children:
  177            obj = c.drawToObject(painter, painthelper)
  178            if obj:
  179                root.addObject(obj)
  180 
  181         return root
  182 
  183     def makeScene(self, painter):
  184         """Make Scene and Camera objects."""
  185 
  186         s = self.settings
  187 
  188         camera = threed.Camera()
  189         # camera necessary to make x,y,z coordinates point in the
  190         # right direction, with the origin in the lower left towards
  191         # the viewer
  192         camera.setPointing(
  193             threed.Vec3(0,  0, -s.distance),
  194             threed.Vec3(0,  0,  0),
  195             threed.Vec3(0, -1,  0))
  196         camera.setPerspective(90, 1, 100)
  197 
  198         mode = {
  199             'painters': threed.Scene.RENDER_PAINTERS,
  200             'bsp': threed.Scene.RENDER_BSP,
  201         }[s.rendermode]
  202         scene = threed.Scene(mode)
  203 
  204         # add lighting if enabled
  205         for light in s.Lighting1, s.Lighting2, s.Lighting3:
  206             if light.enable:
  207                 scene.addLight(
  208                     # FIXME: z and y negative here to make direction
  209                     # correct relative to camera origin
  210                     threed.Vec3(light.x, -light.y, -light.z),
  211                     light.get('color').color(painter),
  212                     light.intensity*0.01)
  213 
  214         return scene, camera
  215 
  216     def draw(self, parentposn, painthelper, outerbounds=None):
  217         '''Update the margins before drawing.'''
  218 
  219         bounds = self.computeBounds(parentposn, painthelper)
  220 
  221         painter = painthelper.painter(self, bounds)
  222         painthelper.setControlGraph(self, [
  223             controlgraph.ControlMarginBox(
  224                 self, bounds, outerbounds, painthelper)])
  225 
  226         root = self.makeObjects(painter, bounds, painthelper)
  227         if root is None:
  228             return bounds
  229 
  230         scene, camera = self.makeScene(painter)
  231 
  232         # def ptToScreen(pt):
  233         #     pt_v = (camera.viewM*root.objM)*threed.Vec4(pt[0],pt[1],pt[2],1)
  234         #     pt_proj = threed.calcProjVec(camera.perspM, pt_v)
  235         #     pt_screen = threed.projVecToScreen(scene.screenM, pt_proj)
  236         #     return pt_screen,qt.QPointF(pt_screen.get(0), pt_screen.get(1))
  237 
  238         # finally render the scene
  239         scale = self.settings.size
  240         if scale == 'Auto':
  241             scale = -1
  242         with painter:
  243             scene.render(
  244                 root,
  245                 painter, camera,
  246                 bounds[0], bounds[1], bounds[2], bounds[3], scale)
  247 
  248         #     painter.setPen(qt.QPen(qt.Qt.red))
  249         #     origin = ptToScreen((0,0,0))[1]
  250         #     for axpt in ((0.5,0,0),(0,0.5,0),(0,0,0.5)):
  251         #         painter.drawLine(origin, ptToScreen(axpt)[1])
  252 
  253         # axx = threed.Vec4(0,0.5,0,1)
  254         # threed.solveInverseRotation(camera.viewM, camera.perspM, scene.screenM, axx, ptToScreen((0,0.5,0))[0])
  255 
  256     def identifyWidgetAtPoint(self, painthelper, bounds, scaling, x, y):
  257         painter = document.PainterRoot()
  258         painter.updateMetaData(painthelper)
  259 
  260         root = self.makeObjects(painter, bounds, painthelper)
  261         if root is None:
  262             return self
  263         scene, camera = self.makeScene(painter)
  264 
  265         sizescale = self.settings.size
  266         if sizescale == 'Auto':
  267             sizescale = -1
  268         widgetid = scene.idPixel(
  269             root, painter, camera,
  270             bounds[0], bounds[1], bounds[2], bounds[3], sizescale,
  271             scaling, x, y)
  272 
  273         # recursive check id of children against returned value
  274         widget = [self]
  275         def checkwidget(r):
  276             for c in r.children:
  277                 if id(c) == widgetid:
  278                     widget[0] = c
  279                 checkwidget(c)
  280 
  281         checkwidget(self)
  282         return widget[0]
  283 
  284     def updateControlItem(self, cgi):
  285         """Area moved or resized - call helper routine to move self."""
  286         cgi.setWidgetMargins()
  287 
  288 document.thefactory.register(Scene3D)