Ejemplo n.º 1
0
 def drawtri(ia, ib, ic, div):
     a, b, c = vertices[ia], vertices[ib], vertices[ic]
     if (div <= 0):
         # Store faces here
         faces.extend([ia, ib, ic])
     else:
         # Create new points
         ab = Point(0, 0, 0)
         ac = Point(0, 0, 0)
         bc = Point(0, 0, 0)
         for i in range(3):
             ab[i] = (a[i] + b[i]) / 2.0
             ac[i] = (a[i] + c[i]) / 2.0
             bc[i] = (b[i] + c[i]) / 2.0
         ab = ab.normalize()
         ac = ac.normalize()
         bc = bc.normalize()
         # Add new points
         i_offset = len(vertices)
         vertices.append(ab)
         vertices.append(ac)
         vertices.append(bc)
         iab, iac, ibc = i_offset + 0, i_offset + 1, i_offset + 2
         #
         drawtri(ia, iab, iac, div - 1)
         drawtri(ib, ibc, iab, div - 1)
         drawtri(ic, iac, ibc, div - 1)
         drawtri(iab, ibc, iac, div - 1)
Ejemplo n.º 2
0
 def _OnDoubleClick(self, event):
     
     # use OnDown method to test if and which node was clicked
     self._OnDown(event)
     
     if self._selectedNode is None:
         # create new node?
         pos = self.position
         x, y = event.x, event.y
         if x>-5 and x<pos.width+5 and y>-5 and y<pos.height-5:
             pos = Point(event.x, event.y) / Point(self.position.size)
             self._nodes.append( pos )
     else:
         # remove point
         self._nodes.pop(self._selectedNode)
     # Update
     self._UpdateFull()
Ejemplo n.º 3
0
    def __init__(self):

        # Set current and reference direction (default up)
        self._refDirection = Point(0, 0, 1)
        self._direction = Point(0, 0, 1)

        # Create transformations
        self._scaleTransform = misc.Transform_Scale()
        self._translateTransform = misc.Transform_Translate()
        self._rotateTransform = misc.Transform_Rotate()
        self._directionTransform = misc.Transform_Rotate()

        # Append transformations to THE list
        self.transformations.append(self._translateTransform)
        self.transformations.append(self._directionTransform)
        self.transformations.append(self._rotateTransform)
        self.transformations.append(self._scaleTransform)
Ejemplo n.º 4
0
 def _OnMotion(self, event):
     
     # should we proceed?
     if self._selectedNode is None:
         return
     if self._selectedNode >= len(self._nodes):
         self._OnUp()
         return
     
     # calculate and limit new position
     x, y = event.x, event.y
     pos = Point(x,y) / Point(self.position.size)
     if pos.x<0: pos.x=0
     if pos.y<0: pos.y=0
     if pos.x>1: pos.x = 1
     if pos.y>1: pos.y = 1
     
     # Change node's position
     self._nodes[self._selectedNode,0] = pos.x
     self._nodes[self._selectedNode,1] = pos.y
     
     # Apply to line
     self._NodesToLine(self._nodes, self._line)
     
     # Draw (fast)        
     self.Draw(True)
Ejemplo n.º 5
0
 def _OnDown(self, event):
     
     # calculate distance of mouse to all points
     p = Point(event.x, event.y)
     dists = p.distance( self._nodes * Point(self.position.size) )
     
     # is one close enough?
     i = -1
     if self._nodes: # or .min() will not work
         tmp = dists.min()
         if tmp <= self._snapWidth:
             i, = np.where(dists==tmp)
     
     # if so, store that point
     if i>= 0:
         self._selectedNode = i
     else:
         self._selectedNode = None
Ejemplo n.º 6
0
        def fset(self, value):
            # Store direction
            if isinstance(value, (list, tuple)) and len(value) == 3:
                self._direction = Point(*tuple(value))
            elif is_Point(value) and value.ndim == 3:
                self._direction = value
            else:
                raise ValueError(
                    'Direction should be a 3D Point or 3-element tuple.')

            # Normalize
            if self._direction.norm() == 0:
                raise ValueError(
                    'Direction vector must have a non-zero length.')
            self._direction = self._direction.normalize()

            # Create ref point
            refPoint = self._refDirection

            # Convert to rotation. The cross product of two vectors results
            # in a vector normal to both vectors. This is the axis of rotation
            # over which the minimal rotation is achieved.
            axis = self._direction.cross(refPoint)
            if axis.norm() < 0.01:
                if self._direction.z > 0:
                    # No rotation
                    self._directionTransform.ax = 0.0
                    self._directionTransform.ay = 0.0
                    self._directionTransform.az = 1.0
                    self._directionTransform.angle = 0.0
                else:
                    # Flipped
                    self._directionTransform.ax = 1.0
                    self._directionTransform.ay = 0.0
                    self._directionTransform.az = 0.0
                    self._directionTransform.angle = 180.0
            else:
                axis = axis.normalize()
                angle = -refPoint.angle(self._direction)
                self._directionTransform.ax = axis.x
                self._directionTransform.ay = axis.y
                self._directionTransform.az = axis.z
                self._directionTransform.angle = angle * 180 / np.pi
Ejemplo n.º 7
0
 def _OnMouseMotion(self, event):
     
     # Handle or pass?
     if not (self._interact_down and self._screenVec):
         return
     
     # Get vector relative to reference position
     refPos = Point(self._refPos)
     pos = Point(event.x, event.y)
     vec = pos - refPos
     
     # Length of reference vector, and its normalized version
     screenVec = Point(self._screenVec)
     L = screenVec.norm()
     V = screenVec.normalize()
     
     # Number of indexes to change
     n = vec.dot(V) / L
     
     # Apply!        
     self.index = int(self._refIndex + n)
Ejemplo n.º 8
0
 def drawtri(ia, ib, ic, div):
     a, b, c = vertices[ia] , vertices[ib], vertices[ic]
     if (div<=0):
         # Store faces here
         faces.extend([ia, ib, ic])
     else:
         # Create new points
         ab = Point(0,0,0)
         ac = Point(0,0,0)
         bc = Point(0,0,0)
         for i in range(3):
             ab[i]=(a[i]+b[i])/2.0;
             ac[i]=(a[i]+c[i])/2.0;
             bc[i]=(b[i]+c[i])/2.0;
         ab = ab.normalize(); ac = ac.normalize(); bc = bc.normalize()
         # Add new points
         i_offset = len(vertices)
         vertices.append(ab)
         vertices.append(ac)
         vertices.append(bc)
         iab, iac, ibc = i_offset+0, i_offset+1, i_offset+2
         #
         drawtri(ia, iab, iac, div-1)
         drawtri(ib, ibc, iab, div-1)
         drawtri(ic, iac, ibc, div-1)
         drawtri(iab, ibc, iac, div-1)
Ejemplo n.º 9
0
 def drawtri(a, b, c, div):
     if (div <= 0):
         vertices.append(a)
         vertices.append(b)
         vertices.append(c)
     else:
         ab = Point(0, 0, 0)
         ac = Point(0, 0, 0)
         bc = Point(0, 0, 0)
         for i in range(3):
             ab[i] = (a[i] + b[i]) / 2.0
             ac[i] = (a[i] + c[i]) / 2.0
             bc[i] = (b[i] + c[i]) / 2.0
         ab = ab.normalize()
         ac = ac.normalize()
         bc = bc.normalize()
         drawtri(a, ab, ac, div - 1)
         drawtri(b, bc, ab, div - 1)
         drawtri(c, ac, bc, div - 1)
         drawtri(ab, bc, ac, div - 1)
Ejemplo n.º 10
0
 def __init__(self):
     
     # Set current and reference direction (default up)
     self._refDirection = Point(0,0,1)
     self._direction = Point(0,0,1)
     
     # Create transformations
     self._scaleTransform = misc.Transform_Scale()
     self._translateTransform = misc.Transform_Translate()
     self._rotateTransform = misc.Transform_Rotate()
     self._directionTransform = misc.Transform_Rotate()
     
     # Append transformations to THE list
     self.transformations.append(self._translateTransform)
     self.transformations.append(self._directionTransform)
     self.transformations.append(self._rotateTransform)
     self.transformations.append(self._scaleTransform)
Ejemplo n.º 11
0
 def fset(self, value):
     # Store direction
     if isinstance(value, (list, tuple)) and len(value) == 3:
         self._direction = Point(*tuple(value))
     elif is_Point(value) and value.ndim == 3:
         self._direction = value
     else:
         raise ValueError('Direction should be a 3D Point or 3-element tuple.')
     
     # Normalize
     if self._direction.norm()==0:
         raise ValueError('Direction vector must have a non-zero length.')            
     self._direction = self._direction.normalize()
     
     # Create ref point
     refPoint = self._refDirection
     
     # Convert to rotation. The cross product of two vectors results
     # in a vector normal to both vectors. This is the axis of rotation
     # over which the minimal rotation is achieved.
     axis = self._direction.cross(refPoint)
     if axis.norm() < 0.01:
         if self._direction.z > 0:
             # No rotation
             self._directionTransform.ax = 0.0
             self._directionTransform.ay = 0.0
             self._directionTransform.az = 1.0
             self._directionTransform.angle = 0.0
         else:
             # Flipped
             self._directionTransform.ax = 1.0
             self._directionTransform.ay = 0.0
             self._directionTransform.az = 0.0
             self._directionTransform.angle = 180.0
     else:
         axis = axis.normalize()
         angle = -refPoint.angle(self._direction)
         self._directionTransform.ax = axis.x
         self._directionTransform.ay = axis.y
         self._directionTransform.az = axis.z
         self._directionTransform.angle = angle * 180 / np.pi
Ejemplo n.º 12
0
 def drawtri(a, b, c, div):
     if (div<=0):
         vertices.append(a)
         vertices.append(b)
         vertices.append(c)
     else:
         ab = Point(0,0,0)
         ac = Point(0,0,0)
         bc = Point(0,0,0)
         for i in range(3):
             ab[i]=(a[i]+b[i])/2.0;
             ac[i]=(a[i]+c[i])/2.0;
             bc[i]=(b[i]+c[i])/2.0;
         ab = ab.normalize(); ac = ac.normalize(); bc = bc.normalize()
         drawtri(a, ab, ac, div-1)
         drawtri(b, bc, ab, div-1)
         drawtri(c, ac, bc, div-1)
         drawtri(ab, bc, ac, div-1)
Ejemplo n.º 13
0
 def _OnMouseMotion(self, event):
     
     # Handle or pass?
     if not (self._interact_down and self._screenVec):
         return
     
     # Get vector relative to reference position
     refPos = Point(self._refPos)
     pos = Point(event.x, event.y)
     vec = pos - refPos
     
     # Length of reference vector, and its normalized version
     screenVec = Point(self._screenVec)
     L = screenVec.norm()
     V = screenVec.normalize()
     
     # Number of indexes to change
     n = vec.dot(V) / L
     
     # Apply!
     self.index = int(self._refIndex + n)
Ejemplo n.º 14
0
def lineToMesh(pp, radius, vertex_num, values=None):
    """ lineToMesh(pp, radius, vertex_num, values=None)
    
    From a line, create a mesh that represents the line as a tube with
    given diameter. Returns a BaseMesh instance.
    
    Parameters
    ----------
    pp : 3D Pointset
        The points along the line. If the first and last point are the same,
        the mesh-line is closed.
    radius : scalar
        The radius of the tube that is created. Radius can also be a
        sequence of values (containing a radius for each point).
    vertex_num : int
        The number of vertices to create along the circumference of the tube.
    values : list or numpy array (optional)
        A value per point. Can be Nx1, Nx2, Nx3 or Nx4. A list of scalars
        can also be given. The values are propagated to the mesh vertices
        and supplied as input to the Mesh constructor. This allows for example
        to define the color for the tube.
    
    """

    # we need this quite a bit
    pi = np.pi

    # process radius
    if hasattr(radius, '__len__'):
        if len(radius) != len(pp):
            raise ValueError('Len of radii much match len of points.')
        else:
            radius = np.array(radius, dtype=np.float32)
    else:
        radius = radius * np.ones((len(pp), ), dtype=np.float32)

    # calculate vertex points for 2D circle
    angles = np.arange(0, pi * 2 - 0.0001, pi * 2 / vertex_num)
    angle_cos = np.cos(angles)
    angle_sin = np.sin(angles)
    vertex_num2 = len(angles)  # just to be sure

    # calculate distance between two line pieces (for smooth cylinders)
    dists = pp[1:].distance(pp[:-1])
    bufdist = min(radius.max(), dists.min() / 2.2)

    # check if line is closed
    lclosed = np.all(pp[0] == pp[-1])

    # calculate normal vectors on each line point
    normals = pp[:-1].subtract(pp[1:]).copy()
    if lclosed:
        normals.append(pp[0] - pp[1])
    else:
        normals.append(pp[-2] - pp[-1])
    normals = -1 * normals.normalize()

    # create list to store vertices
    vertices = Pointset(3)
    surfaceNormals = Pointset(3)

    # And a list for the values
    if values is None:
        vvalues = None
    elif isinstance(values, list):
        if len(values) != len(pp):
            raise ValueError('There must be as many values as points.')
        vvalues = Pointset(1)
    elif isinstance(values, np.ndarray):
        if values.ndim != 2:
            raise ValueError('Values must be Nx1, Nx2, Nx3 or Nx4.')
        if values.shape[0] != len(pp):
            raise ValueError('There must be as many values as points.')
        vvalues = Pointset(values.shape[1])
    elif vv.utils.pypoints.is_Pointset(values):
        if values.ndim > 4:
            raise ValueError('Can specify one to four values per point.')
        if len(values) != len(pp):
            raise ValueError('There must be as many values as points.')
        vvalues = Pointset(values.ndim)
    else:
        raise ValueError('Invalid value for values.')

    # Number of triangelized cylinder elements added to plot the 3D line
    n_cylinders = 0

    # Init a and b
    a, b = Point(0, 0, 1), Point(0, 1, 0)

    # Calculate the 3D circle coordinates of the first circle/cylinder
    a, b = getSpanVectors(normals[0], a, b)
    circm = getCircle(angle_cos, angle_sin, a, b)

    # If not a closed line, add half sphere made with 5 cylinders at line start
    if not lclosed:
        for j in range(5, 0, -1):
            # Translate the circle on it's position on the line
            r = (1 - (j / 5.0)**2)**0.5
            circmp = float(r * radius[0]) * circm + (
                pp[0] - (j / 5.0) * bufdist * normals[0])
            # Calc normals
            circmn = (pp[0].subtract(circmp)).normalize()
            # Store the vertex list
            vertices.extend(circmp)
            surfaceNormals.extend(-1 * circmn)
            if vvalues is not None:
                for iv in range(vertex_num2):
                    vvalues.append(values[0])
            n_cylinders += 1

    # Loop through all line pieces
    for i in range(len(pp) - 1):

        ## Create main cylinder between two line points
        # which consists of two connected circles.

        # get normal and point
        normal1 = normals[i]
        point1 = pp[i]

        # calculate the 3D circle coordinates
        a, b = getSpanVectors(normal1, a, b)
        circm = getCircle(angle_cos, angle_sin, a, b)

        # Translate the circle, and store
        circmp = float(radius[i]) * circm + (point1 + bufdist * normal1)
        vertices.extend(circmp)
        surfaceNormals.extend(circm)
        if vvalues is not None:
            for iv in range(vertex_num2):
                vvalues.append(values[i])
        n_cylinders += 1

        # calc second normal and line
        normal2 = normals[i + 1]
        point2 = pp[i + 1]

        # Translate the circle, and store
        circmp = float(radius[i + 1]) * circm + (point2 - bufdist * normal1)
        vertices.extend(circmp)
        surfaceNormals.extend(circm)
        if vvalues is not None:
            for iv in range(vertex_num2):
                vvalues.append(values[i + 1])
        n_cylinders += 1

        ## Create in between circle to smoothly connect line pieces

        if not lclosed and i == len(pp) - 2:
            break

        # get normal and point
        normal12 = (normal1 + normal2).normalize()
        tmp = (point2 + bufdist * normal2) + (point2 - bufdist * normal1)
        point12 = 0.5858 * point2 + 0.4142 * (0.5 * tmp)

        # Calculate the 3D circle coordinates
        a, b = getSpanVectors(normal12, a, b)
        circm = getCircle(angle_cos, angle_sin, a, b)

        # Translate the circle, and store
        circmp = float(radius[i + 1]) * circm + point12
        vertices.extend(circmp)
        surfaceNormals.extend(circm)
        if vvalues is not None:
            for iv in range(vertex_num2):
                vvalues.append(0.5 * (values[i] + values[i + 1]))
        n_cylinders += 1

    # If not a closed line, add half sphere made with 5 cylinders at line start
    # Otherwise add the starting circle to the line end.
    if not lclosed:
        for j in range(0, 6):
            # Translate the circle on it's position on the line
            r = (1 - (j / 5.0)**2)**0.5
            circmp = float(r * radius[-1]) * circm + (
                pp[-1] + (j / 5.0) * bufdist * normals[-1])
            # Calc normals
            circmn = (pp[-1].subtract(circmp)).normalize()
            # Store the vertex list
            vertices.extend(circmp)
            surfaceNormals.extend(-1 * circmn)
            if vvalues is not None:
                for iv in range(vertex_num2):
                    vvalues.append(values[-1])
            n_cylinders += 1
    else:
        # get normal and point
        normal1 = normals[-1]
        point1 = pp[-1]

        # calculate the 3D circle coordinates
        a, b = getSpanVectors(normal1, a, b)
        circm = getCircle(angle_cos, angle_sin, a, b)

        # Translate the circle, and store
        circmp = float(radius[0]) * circm + (point1 + bufdist * normal1)
        vertices.extend(circmp)
        surfaceNormals.extend(circm)
        if vvalues is not None:
            for iv in range(vertex_num2):
                vvalues.append(values[-1])
        n_cylinders += 1

    # almost done, determine quad faces ...

    # define single faces
    #firstFace = [0, 1, vertex_num+1, vertex_num]
    #lastFace = [vertex_num-1, 0, vertex_num, 2*vertex_num-1]
    firstFace = [vertex_num, vertex_num + 1, 1, 0]
    lastFace = [2 * vertex_num - 1, vertex_num, 0, vertex_num - 1]

    # define single round
    oneRound = []
    for i in range(vertex_num - 1):
        oneRound.extend([val + i for val in firstFace])
    oneRound.extend(lastFace)
    oneRound = np.array(oneRound, dtype=np.uint32)

    # calculate face data
    parts = []
    for i in range(n_cylinders - 1):
        parts.append(oneRound + i * vertex_num)
    faces = np.concatenate(parts)
    faces.shape = faces.shape[0] // 4, 4

    # Done!
    return BaseMesh(vertices, faces, surfaceNormals, vvalues)
Ejemplo n.º 15
0
 def fget(self):
     d = self._translateTransform
     return Point(d.dx, d.dy, d.dz)
Ejemplo n.º 16
0
 def fget(self):
     s = self._scaleTransform
     return Point(s.sx, s.sy, s.sz)
Ejemplo n.º 17
0
class OrientationForWobjects_mixClass(object):
    """ OrientationForWobjects_mixClass()
    
    This class can be mixed with a wobject class to enable easy 
    orientation of the objects in space. It makes use of the 
    tranformation list that each wobject has. 
    
    The functionality provided by this class is not made part of the
    Wobject class because it does not make sense for all kind of wobjects
    (for example lines and images). The OrientableMesh is a class that
    inherits from this class.
    
    """
    def __init__(self):

        # Set current and reference direction (default up)
        self._refDirection = Point(0, 0, 1)
        self._direction = Point(0, 0, 1)

        # Create transformations
        self._scaleTransform = misc.Transform_Scale()
        self._translateTransform = misc.Transform_Translate()
        self._rotateTransform = misc.Transform_Rotate()
        self._directionTransform = misc.Transform_Rotate()

        # Append transformations to THE list
        self.transformations.append(self._translateTransform)
        self.transformations.append(self._directionTransform)
        self.transformations.append(self._rotateTransform)
        self.transformations.append(self._scaleTransform)

    @misc.PropWithDraw
    def scaling():
        """ Get/Set the scaling of the object. Can be set using
        a 3-element tuple, a 3D point, or a scalar. The getter always
        returns a Point.
        """
        def fget(self):
            s = self._scaleTransform
            return Point(s.sx, s.sy, s.sz)

        def fset(self, value):
            if isinstance(value, (float, int)):
                self._scaleTransform.sx = float(value)
                self._scaleTransform.sy = float(value)
                self._scaleTransform.sz = float(value)
            elif isinstance(value, (list, tuple)) and len(value) == 3:
                self._scaleTransform.sx = float(value[0])
                self._scaleTransform.sy = float(value[1])
                self._scaleTransform.sz = float(value[2])
            elif is_Point(value) and value.ndim == 3:
                self._scaleTransform.sx = value.x
                self._scaleTransform.sy = value.y
                self._scaleTransform.sz = value.z
            else:
                raise ValueError(
                    'Scaling should be a scalar, 3D Point, or 3-element tuple.'
                )

        return locals()

    @misc.PropWithDraw
    def translation():
        """ Get/Set the transaltion of the object. Can be set using
        a 3-element tuple or a 3D point. The getter always returns
        a Point.
        """
        def fget(self):
            d = self._translateTransform
            return Point(d.dx, d.dy, d.dz)

        def fset(self, value):
            if isinstance(value, (list, tuple)) and len(value) == 3:
                self._translateTransform.dx = value[0]
                self._translateTransform.dy = value[1]
                self._translateTransform.dz = value[2]
            elif is_Point(value) and value.ndim == 3:
                self._translateTransform.dx = value.x
                self._translateTransform.dy = value.y
                self._translateTransform.dz = value.z
            else:
                raise ValueError(
                    'Translation should be a 3D Point or 3-element tuple.')

        return locals()

    @misc.PropWithDraw
    def direction():
        """ Get/Set the direction (i.e. orientation) of the object. Can 
        be set using a 3-element tuple or a 3D point. The getter always 
        returns a Point. 
        """
        def fget(self):
            return self._direction.copy()

        def fset(self, value):
            # Store direction
            if isinstance(value, (list, tuple)) and len(value) == 3:
                self._direction = Point(*tuple(value))
            elif is_Point(value) and value.ndim == 3:
                self._direction = value
            else:
                raise ValueError(
                    'Direction should be a 3D Point or 3-element tuple.')

            # Normalize
            if self._direction.norm() == 0:
                raise ValueError(
                    'Direction vector must have a non-zero length.')
            self._direction = self._direction.normalize()

            # Create ref point
            refPoint = self._refDirection

            # Convert to rotation. The cross product of two vectors results
            # in a vector normal to both vectors. This is the axis of rotation
            # over which the minimal rotation is achieved.
            axis = self._direction.cross(refPoint)
            if axis.norm() < 0.01:
                if self._direction.z > 0:
                    # No rotation
                    self._directionTransform.ax = 0.0
                    self._directionTransform.ay = 0.0
                    self._directionTransform.az = 1.0
                    self._directionTransform.angle = 0.0
                else:
                    # Flipped
                    self._directionTransform.ax = 1.0
                    self._directionTransform.ay = 0.0
                    self._directionTransform.az = 0.0
                    self._directionTransform.angle = 180.0
            else:
                axis = axis.normalize()
                angle = -refPoint.angle(self._direction)
                self._directionTransform.ax = axis.x
                self._directionTransform.ay = axis.y
                self._directionTransform.az = axis.z
                self._directionTransform.angle = angle * 180 / np.pi

        return locals()

    @misc.PropWithDraw
    def rotation():
        """ Get/Set the rotation of the object (in degrees, around its 
        direction vector).
        """
        def fget(self):
            return self._rotateTransform.angle

        def fset(self, value):
            self._rotateTransform.angle = float(value)

        return locals()
Ejemplo n.º 18
0
class OrientationForWobjects_mixClass(object):
    """ OrientationForWobjects_mixClass()
    
    This class can be mixed with a wobject class to enable easy 
    orientation of the objects in space. It makes use of the 
    tranformation list that each wobject has. 
    
    The functionality provided by this class is not made part of the
    Wobject class because it does not make sense for all kind of wobjects
    (for example lines and images). The OrientableMesh is a class that
    inherits from this class.
    
    """
    
    def __init__(self):
        
        # Set current and reference direction (default up)
        self._refDirection = Point(0,0,1)
        self._direction = Point(0,0,1)
        
        # Create transformations
        self._scaleTransform = misc.Transform_Scale()
        self._translateTransform = misc.Transform_Translate()
        self._rotateTransform = misc.Transform_Rotate()
        self._directionTransform = misc.Transform_Rotate()
        
        # Append transformations to THE list
        self.transformations.append(self._translateTransform)
        self.transformations.append(self._directionTransform)
        self.transformations.append(self._rotateTransform)
        self.transformations.append(self._scaleTransform)
    
    
    @misc.PropWithDraw
    def scaling():
        """ Get/Set the scaling of the object. Can be set using
        a 3-element tuple, a 3D point, or a scalar. The getter always
        returns a Point.
        """
        def fget(self):
            s = self._scaleTransform
            return Point(s.sx, s.sy, s.sz)
        def fset(self, value):
            if isinstance(value, (float, int)):
                self._scaleTransform.sx = float(value)
                self._scaleTransform.sy = float(value)
                self._scaleTransform.sz = float(value)
            elif isinstance(value, (list, tuple)) and len(value) == 3:                
                self._scaleTransform.sx = float(value[0])
                self._scaleTransform.sy = float(value[1])
                self._scaleTransform.sz = float(value[2])
            elif is_Point(value) and value.ndim == 3:
                self._scaleTransform.sx = value.x
                self._scaleTransform.sy = value.y
                self._scaleTransform.sz = value.z
            else:
                raise ValueError('Scaling should be a scalar, 3D Point, or 3-element tuple.')
        return locals()
    
    
    @misc.PropWithDraw
    def translation():
        """ Get/Set the transaltion of the object. Can be set using
        a 3-element tuple or a 3D point. The getter always returns
        a Point.
        """
        def fget(self):
            d = self._translateTransform
            return Point(d.dx, d.dy, d.dz)
        def fset(self, value):
            if isinstance(value, (list, tuple)) and len(value) == 3:                
                self._translateTransform.dx = value[0]
                self._translateTransform.dy = value[1]
                self._translateTransform.dz = value[2]
            elif is_Point(value) and value.ndim == 3:
                self._translateTransform.dx = value.x
                self._translateTransform.dy = value.y
                self._translateTransform.dz = value.z
            else:
                raise ValueError('Translation should be a 3D Point or 3-element tuple.')
        return locals()
    
    
    @misc.PropWithDraw
    def direction():
        """ Get/Set the direction (i.e. orientation) of the object. Can 
        be set using a 3-element tuple or a 3D point. The getter always 
        returns a Point. 
        """
        def fget(self):
            return self._direction.copy()
        def fset(self, value):
            # Store direction
            if isinstance(value, (list, tuple)) and len(value) == 3:
                self._direction = Point(*tuple(value))
            elif is_Point(value) and value.ndim == 3:
                self._direction = value
            else:
                raise ValueError('Direction should be a 3D Point or 3-element tuple.')
            
            # Normalize
            if self._direction.norm()==0:
                raise ValueError('Direction vector must have a non-zero length.')            
            self._direction = self._direction.normalize()
            
            # Create ref point
            refPoint = self._refDirection
            
            # Convert to rotation. The cross product of two vectors results
            # in a vector normal to both vectors. This is the axis of rotation
            # over which the minimal rotation is achieved.
            axis = self._direction.cross(refPoint)
            if axis.norm() < 0.01:
                if self._direction.z > 0:
                    # No rotation
                    self._directionTransform.ax = 0.0
                    self._directionTransform.ay = 0.0
                    self._directionTransform.az = 1.0
                    self._directionTransform.angle = 0.0
                else:
                    # Flipped
                    self._directionTransform.ax = 1.0
                    self._directionTransform.ay = 0.0
                    self._directionTransform.az = 0.0
                    self._directionTransform.angle = 180.0
            else:
                axis = axis.normalize()
                angle = -refPoint.angle(self._direction)
                self._directionTransform.ax = axis.x
                self._directionTransform.ay = axis.y
                self._directionTransform.az = axis.z
                self._directionTransform.angle = angle * 180 / np.pi
        return locals()
    
    
    @misc.PropWithDraw
    def rotation():
        """ Get/Set the rotation of the object (in degrees, around its 
        direction vector).
        """
        def fget(self):
            return self._rotateTransform.angle
        def fset(self, value):
            self._rotateTransform.angle = float(value)
        return locals()
Ejemplo n.º 19
0
def solidRing(translation=None,
              scaling=None,
              direction=None,
              rotation=None,
              thickness=0.25,
              N=16,
              M=16,
              axesAdjust=True,
              axes=None):
    """ solidRing(translation=None, scaling=None, direction=None, rotation=None,
                thickness=0.25, N=16, M=16, axesAdjust=True, axes=None)
    
    Creates a solid ring with quad faces oriented at the origin. 
    Returns an OrientableMesh instance.
    
    Parameters
    ----------
    Note that translation, scaling, and direction can also be given
    using a Point instance.
    translation : (dx, dy, dz), optional
        The translation in world units of the created world object.
    scaling: (sx, sy, sz), optional
        The scaling in world units of the created world object.
    direction: (nx, ny, nz), optional
        Normal vector that indicates the direction of the created world object.
    rotation: scalar, optional
        The anle (in degrees) to rotate the created world object around its
        direction vector.
    thickness : scalar
        The tickness of the ring, represented as a fraction of the radius.
    N : int
        The number of subdivisions around its axis. If smaller
        than 8, flat shading is used instead of smooth shading. 
    M : int
        The number of subdivisions along its axis. If smaller
        than 8, flat shading is used instead of smooth shading. 
    axesAdjust : bool
        If True, this function will call axes.SetLimits(), and set
        the camera type to 3D. If daspectAuto has not been set yet, 
        it is set to False.
    axes : Axes instance
        Display the bars in the given axes, or the current axes if not given.
    
    """

    # Note that the number of vertices around the axis is N+1. This
    # would not be necessary per see, but it helps create a nice closed
    # texture when it is mapped. There are N number of faces though.
    # Similarly, to obtain M faces along the axis, we need M+1
    # vertices.

    # Quick access
    pi2 = np.pi * 2
    cos = np.cos
    sin = np.sin
    sl = M + 1

    # Determine where the stitch is, depending on M
    if M <= 8:
        rotOffset = 0.5 / M
    else:
        rotOffset = 0.0

    # Calculate vertices, normals and texcords
    vertices = Pointset(3)
    normals = Pointset(3)
    texcords = Pointset(2)
    # Cone
    for n in range(N + 1):
        v = float(n) / N
        a = pi2 * v
        # Obtain outer and center position of "tube"
        po = Point(sin(a), cos(a), 0)
        pc = po * (1.0 - 0.5 * thickness)
        # Create two vectors that span the the circle orthogonal to the tube
        p1 = (pc - po)
        p2 = Point(0, 0, 0.5 * thickness)
        # Sample around tube
        for m in range(M + 1):
            u = float(m) / (M)
            b = pi2 * (u + rotOffset)
            dp = cos(b) * p1 + sin(b) * p2
            vertices.append(pc + dp)
            normals.append(dp.normalize())
            texcords.append(v, u)

    # Calculate indices
    indices = []
    for j in range(N):
        for i in range(M):
            #indices.extend([j*sl+i, j*sl+i+1, (j+1)*sl+i+1, (j+1)*sl+i])
            indices.extend([(j + 1) * sl + i, (j + 1) * sl + i + 1,
                            j * sl + i + 1, j * sl + i])

    # Make indices a numpy array
    indices = np.array(indices, dtype=np.uint32)

    ## Visualize

    # Create axes
    if axes is None:
        axes = vv.gca()

    # Create mesh
    m = vv.OrientableMesh(axes,
                          vertices,
                          indices,
                          normals,
                          values=texcords,
                          verticesPerFace=4)
    #
    if translation is not None:
        m.translation = translation
    if scaling is not None:
        m.scaling = scaling
    if direction is not None:
        m.direction = direction
    if rotation is not None:
        m.rotation = rotation

    # If necessary, use flat shading
    if N < 8 or M < 8:
        m.faceShading = 'flat'

    # Adjust axes
    if axesAdjust:
        if axes.daspectAuto is None:
            axes.daspectAuto = False
        axes.cameraType = '3d'
        axes.SetLimits()

    # Done
    axes.Draw()
    return m
Ejemplo n.º 20
0
 def OnDraw(self):
     
     # Get colormaps that apply
     par = self.parent
     if par is None:
         return
     elif isinstance(par, (BaseFigure, Axes)):
         mapables = par.FindObjects(Colormapable)
     elif isinstance(par, ColormapEditor):
         mapables = par.GetMapables()
     elif isinstance(par, ClimEditor):
         mapables = par.GetMapables()
     else:
         mapables = []
     
     # Get the last one
     mapable = None
     if mapables:
         mapable = mapables[-1]
     
     
     # get dimensions        
     w,h = self.position.size
     
     # Calc map direction
     if w > h:
         texCords = [0,0,1,1]
     else:
         texCords = [1,0,0,1]
     
     
     # draw plane
     if mapable:
         # Use it's colormap texture
         mapable._EnableColormap()
         # Disable alpha channel (by not blending)
         gl.glDisable(gl.GL_BLEND)
         gl.glColor(1.0, 1.0, 1.0, 1.0)
         # Draw quads
         gl.glBegin(gl.GL_QUADS)
         gl.glTexCoord1f(texCords[0]); gl.glVertex2f(0,0)
         gl.glTexCoord1f(texCords[1]); gl.glVertex2f(0,h)
         gl.glTexCoord1f(texCords[2]); gl.glVertex2f(w,h)
         gl.glTexCoord1f(texCords[3]); gl.glVertex2f(w,0)
         gl.glEnd()
         
         # Clean up
         gl.glEnable(gl.GL_BLEND)
         gl.glFlush()
         mapable._DisableColormap()
     
     # prepare                
     gl.glDisable(gl.GL_LINE_SMOOTH)
     
     # draw edges        
     if self.edgeWidth and self.edgeColor:
         clr = self.edgeColor
         gl.glColor(clr[0], clr[1], clr[2], 1.0)
         gl.glLineWidth(self.edgeWidth)
         #
         gl.glBegin(gl.GL_LINE_LOOP)
         gl.glVertex2f(0,0)
         gl.glVertex2f(0,h)
         gl.glVertex2f(w,h)
         gl.glVertex2f(w,0)
         gl.glEnd()
     
     if hasattr(mapable, 'clim'):
         # Draw ticks
         if w>h:
             p0 = Point(0, h)
             p1 = Point(w, h)
             delta = Point(0,3)
             halign, valign = 0, 0
             xoffset, yoffset = -8, -2
         else:
             p0 = Point(w, h)
             p1 = Point(w, 0)
             delta = Point(3,0)
             halign, valign = -1, 0
             xoffset, yoffset = 5, -8
         
         # Get tickmarks
         ticks, ticksPos, ticksText = GetTicks(p0, p1, mapable.clim)
         
         newLabelPool = {}
         linePieces = Pointset(2)
         for tick, pos, text in zip(ticks, ticksPos, ticksText):
             pos2 = pos + delta
             
             # Add line piece
             linePieces.append(pos); linePieces.append(pos2)
             
             # Create or reuse label
             if tick in self._labelPool:
                 label = self._labelPool.pop(tick)
             else:
                 label = Label(self, ' '+text+' ')
                 label.bgcolor = ''
             
             # Position label and set text alignment
             newLabelPool[tick] = label
             label.halign, label.valign = halign, valign
             label.position.x = pos2.x + xoffset
             label.position.w = 16
             label.position.y = pos2.y + yoffset
         
         # Clean up label pool
         for label in list(self._labelPool.values()):
             label.Destroy()
         self._labelPool = newLabelPool
         
         # Draw line pieces
         # prepare
         gl.glLineWidth(1)
         gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
         gl.glVertexPointerf(linePieces.data)
         gl.glDrawArrays(gl.GL_LINES, 0, len(linePieces))
         gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
     # clean up        
     gl.glEnable(gl.GL_LINE_SMOOTH)
Ejemplo n.º 21
0
 def OnDraw(self):
     
     # Draw bg color and edges
     Box.OnDraw(self)
     
     # Margin
     d1 = 2
     d2 = d1+1
     
     # Get normalize limits
     t1, t2 = self._getNormalizedSliderLimits()
     
     # Get widget shape
     w, h = self.position.size
     
     # Calculate real dimensions of patch
     if w > h:
         x1, x2 = max(d2, t1*w), min(w-d1, t2*w)
         y1, y2 = d1, h-d2
         #
         dots1 = self._dots1 + Point(x1, 0)
         dots2 = self._dots2 + Point(x2, 0)
         #
         diff = abs(x1-x2)
         #
         self._label.textAngle = 0
     else:
         x1, x2 = d2, w-d1
         y1, y2 = max(d1, t1*h), min(h-d2, t2*h)
         #
         dots1 = self._dots1 + Point(0, y1)
         dots2 = self._dots2 + Point(0, y2)
         #
         diff = abs(y1-y2)
         #
         self._label.textAngle = -90
     
     # Draw slider bit
     clr = self._bgcolor
     #if max(clr[0], clr[1], clr[2]) < 0.7:
     if clr[0] + clr[1] + clr[2] < 1.5:
         gl.glColor(1, 1, 1, 0.25)
     else:
         gl.glColor(0, 0, 0, 0.25)
     #
     gl.glBegin(gl.GL_POLYGON)
     gl.glVertex2f(x1,y1)
     gl.glVertex2f(x1,y2)
     gl.glVertex2f(x2,y2)
     gl.glVertex2f(x2,y1)
     gl.glEnd()
     
     
     # Draw dots
     if True:
         
         # Prepare
         gl.glColor(0,0,0,1)
         gl.glPointSize(1)
         gl.glDisable(gl.GL_POINT_SMOOTH)
         
         # Draw
         gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
         if isinstance(self, RangeSlider) and diff>5:
             gl.glVertexPointerf(dots1.data)
             gl.glDrawArrays(gl.GL_POINTS, 0, len(dots1))
         if diff>5:
             gl.glVertexPointerf(dots2.data)
             gl.glDrawArrays(gl.GL_POINTS, 0, len(dots2))
         gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
     
     
     if self._showTicks:
         
         # Reset color to black
         gl.glColor(0,0,0,1)
         
         # Draw ticks
         if w>h:
             p0 = Point(0, h)
             p1 = Point(w, h)
             delta = Point(0,3)
             halign, valign = 0, 0
             xoffset, yoffset = -8, -2
         else:
             p0 = Point(w, h)
             p1 = Point(w, 0)
             delta = Point(3,0)
             halign, valign = -1, 0
             xoffset, yoffset = 5, -8
         
         # Get tickmarks
         ticks, ticksPos, ticksText = GetTicks(p0, p1, self._fullRange)
         
         newLabelPool = {}
         linePieces = Pointset(2)
         for tick, pos, text in zip(ticks, ticksPos, ticksText):
             pos2 = pos + delta
             
             # Add line piece
             linePieces.append(pos); linePieces.append(pos2)
             
             # Create or reuse label
             if tick in self._labelPool:
                 label = self._labelPool.pop(tick)
             else:
                 label = Label(self, ' '+text+' ')
                 label.bgcolor = ''
                 label.textColor = self._textColor
             
             # Position label and set text alignment
             newLabelPool[tick] = label
             label.halign, label.valign = halign, valign
             label.position.x = pos2.x + xoffset
             label.position.w = 16
             label.position.y = pos2.y + yoffset
         
         # Clean up label pool
         for label in list(self._labelPool.values()):
             label.Destroy()
         self._labelPool = newLabelPool
         
         # Draw line pieces
         gl.glLineWidth(1)
         gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
         gl.glVertexPointerf(linePieces.data)
         gl.glDrawArrays(gl.GL_LINES, 0, len(linePieces))
         gl.glDisableClientState(gl.GL_VERTEX_ARRAY)