Esempio n. 1
0
    def normalise(self, tessellate=None):
        """Normalise this polygon to a set of triangle vertices

        tesselate -- callable which can accept a Polygon instance
            and return a list of vertices representing a
            tesselated polygon triangle-set.  (And only a triangle-
            set, no triangle-fans or triangle-strips).
        """
        if self.normalised is not None:
            return self.normalised
        if tessellate is None:
            tessellate = polygontessellator.PolygonTessellator().tessellate
        if (len(self) > 4 or
            (len(self) == 4 and utilities.coplanar([v.point for v in self]))):
            ### we would like to cache this partial solution somewhere
            ## but at the moment I don't see how to do it usefully,
            ## given that there may be a different tessellation required
            ## if the vertex positions change
            ##			if not self.ccw:
            ##				self.reverse()
            self[:] = tessellate(self)
        elif len(self) == 4:
            a, b, c, d = self
            self[:] = [a, b, c, a, c, d]
        elif len(self) < 3:
            log.info(
                repr(
                    DegeneratePolygon(
                        self,
                        self.node,
                        """Less than 3 vertices specified in indices""",
                    )))
        ### doing a sanity check an excluding degenerate polygons exclusively...
        return self.checkVertices()
Esempio n. 2
0
    def tessellate(self, polygons=None, sources=None):
        """Tessellate our arrays into triangle-only arrays

        The return value is a list of triangle vertices, with
        each vertex represented by a Vertex instance (see below).

        In addition to tessellation, this function is responsible
        for turning the index-format structures into a set of
        polygons (i.e. identifying the individual polygons within
        the indexed face set).
        """
        # check to see that there's something to do
        if (not len(self.target.coordIndex)) or (not self.target.coord) or (
                not len(self.target.coord.point)):
            return []

        tessellate = polygontessellator.PolygonTessellator().tessellate
        vertices = []
        if polygons is None:
            polygons = self.polygons(sources=sources)
        for polygon in polygons:
            polygon.normalise(tessellate)
            vertices.extend(polygon)
        return vertices
Esempio n. 3
0
class SolidGlyph(OutlineGlyph):
    """Glyph composed of triangle geometry"""
    tess = polygontessellator.PolygonTessellator()
    DEBUG_RENDER_EXTRUSION_NORMALS = 0
    DEBUG_RENDER_OUTLINES = 0

    def renderExtrusion(self, scale=400.0, distance=1.0):
        """Render the extrusion of the font backward by distance (using GLE)

        This is pretty simple, save that there's no good
        way to specify the normals for the edge properly :( ,
        basically anything we do is going to look weird because
        we can only specify one normal for each vertex on
        the outline.
        """
        gleSetJoinStyle(TUBE_CONTOUR_CLOSED | TUBE_JN_RAW)
        ## TTF defines everything in clockwise order, GLE assumes CCW,
        ## so need to reverse the rendering mode...
        glFrontFace(GL_CW)
        try:
            data = self._calculateExtrusionData(scale)
            for points, normals in data:
                gleExtrusion(
                    points,
                    normals,
                    array((0, 1, 0), 'd'),  # up
                    array([(0, 0, 1), (0, 0, 0), (0, 0, -distance),
                           (0, 0, -distance - 1.0)], 'd'),  # spine
                    None,
                )
                if __debug__:
                    if self.DEBUG_RENDER_EXTRUSION_NORMALS:
                        glBegin(GL_LINES)
                        try:
                            for ((x, y), (dx, dy)) in zip(points, normals):
                                glColor(0, 1, 0)
                                glVertex2d(x, y)
                                glColor(1, 0, 0)
                                glVertex2d(x + dx, y + dy)
                        finally:
                            glEnd()

        finally:
            glFrontFace(GL_CCW)
        return data

    def _calculateExtrusionData(self, scale=400.0):
        """Calculate extrusion points + normals for the glyph"""
        def calculateNormal(first, second, third):
            """Calculate an approximate 2D normal for a 3-point set"""
            (x1, y1) = first
            (x2, y2) = second
            (x3, y3) = third
            x, y = -(y3 - y1), (x3 - x1)
            l = sqrt(x * x + y * y)
            if l == 0:
                # a null 3-point set, we'll skip this point & normal
                return None
            return x / l, y / l

        result = []
        for contour in self.outlines:
            contour = asarray(contour, 'd') / scale
            points = []
            clen = len(contour)
            normals = []
            for i in range(clen):
                last = contour[((i - 1) + clen) % clen]
                current = contour[i]
                next = contour[((i + 1) + clen) % clen]
                normal = calculateNormal(last, current, next)
                if normal:
                    normals.append(normal)
                    points.append(current)
            result.append((asarray(points, 'd'), asarray(normals, 'd')))
        return result

    def renderCap(self, scale=400.0, front=1):
        """The cap is generated with GLU tessellation routines...
        """
        if self.DEBUG_RENDER_CONTOUR_HULLS:
            self.renderContours(scale)
        if self.DEBUG_RENDER_CONTROL_POINTS:
            self.renderControlPoints(scale)
        contours = self._calculateCapData(scale)
        if front:
            glNormal(0, 0, 1)
            glFrontFace(GL_CCW)
        else:
            glNormal(0, 0, -1)
            glFrontFace(GL_CW)
        try:
            try:
                glEnableClientState(GL_VERTEX_ARRAY)
                for type, vertices in contours:
                    glVertexPointerd(vertices)
                    glDrawArrays(type, 0, len(vertices))
            finally:
                glDisableClientState(GL_VERTEX_ARRAY)
        finally:
            glFrontFace(GL_CCW)
        return contours

    def _calculateCapData(self, scale=400.0):
        """Calculate the tessellated data-sets for this glyph"""
        vertices = [[
            vertex.Vertex(point=(x / scale, y / scale, 0.0))
            for (x, y) in outline
        ] for outline in self.outlines]
        gluTessNormal(self.tess.controller, 0, 0, 1.0)
        contours = self.tess.tessContours(vertices, forceTriangles=0)
        return [(t, asarray([v.point for v in vertices], 'd'))
                for t, vertices in contours]
Esempio n. 4
0
 def OnInit(self):
     self.tess = polygontessellator.PolygonTessellator()
     glEnable(GL_COLOR_MATERIAL)
Esempio n. 5
0
class SolidGlyph( OutlineGlyph ):
    """Glyph composed of triangle geometry"""
    tess = polygontessellator.PolygonTessellator()
    DEBUG_RENDER_EXTRUSION_NORMALS = 0
    DEBUG_RENDER_OUTLINES = 0
    def renderExtrusion( self, scale=400.0, distance=1.0):
        """Render the extrusion of the font backward by distance (using GLE)

        This is pretty simple, save that there's no good
        way to specify the normals for the edge properly :( ,
        basically anything we do is going to look weird because
        we can only specify one normal for each vertex on
        the outline.
        """
        gleSetJoinStyle( TUBE_CONTOUR_CLOSED|TUBE_JN_RAW )
        ## TTF defines everything in clockwise order, GLE assumes CCW,
        ## so need to reverse the rendering mode...
        glFrontFace( GL_CW )
        try:
            data = self._calculateExtrusionData( scale )
            for points, normals in data:
                gleExtrusion(
                    points, normals,
                    array((0,1,0),'d'), # up
                    array([(0,0,1),(0,0,0),(0,0,-distance),(0,0,-distance-1.0)],'d'), # spine
                    None,
                )
                if __debug__:
                    if self.DEBUG_RENDER_EXTRUSION_NORMALS:
                        glBegin( GL_LINES )
                        try:
                            for ((x,y), (dx,dy)) in map( None, points, normals ):
                                glColor( 0,1,0)
                                glVertex2d( x,y )
                                glColor( 1,0,0)
                                glVertex2d( x+dx,y+dy )
                        finally:
                            glEnd()
                    
        finally:
            glFrontFace( GL_CCW )
        return data
    def _calculateExtrusionData( self, scale = 400.0 ):
        """Calculate extrusion points + normals for the glyph"""
        def calculateNormal((x1,y1),(x2,y2),(x3,y3)):
            """Calculate an approximate 2D normal for a 3-point set"""
            x,y = -(y3-y1),(x3-x1)
            l = sqrt(x*x+y*y)
            if l == 0:
                # a null 3-point set, we'll skip this point & normal
                return None
            return x/l,y/l
        result = []
        for contour in self.outlines:
            contour = asarray( contour, 'd' )/scale
            points = []
            clen = len(contour)
            normals = []
            for i in range( clen):
                last = contour[((i-1)+clen)%clen]
                current = contour[i]
                next = contour[((i+1)+clen)%clen]
                normal = calculateNormal(last, current, next)
                if normal:
                    normals.append( normal )
                    points.append( current )
            result.append( (asarray(points,'d'), asarray(normals,'d')) )
        return result