Пример #1
0
class Render(object):
    def __init__(self, width=None, height=None):
        self.x = 0
        self.y = 0
        self.view = {}
        self.color = color(255, 255, 255)

        if (width == None and height == None):
            self.bmp = None
            self.width = width
            self.height = height
        else:
            self.glCreateWindow(width, height)

    def glInit(self):
        pass

    def glCreateWindow(self, width, height):
        self.bmp = Bitmap(width, height)
        self.width = width
        self.height = height

    def glViewPort(self, x, y, width, height):
        self.view['x'] = x
        self.view['y'] = y
        self.view['width'] = width - 1
        self.view['height'] = height - 1

    def glClear(self):
        self.bmp.clear()

    def glClearColor(self, r, g, b):
        for i in range(self.height):
            for j in range(self.width):
                self.bmp.point(
                    i, j, color(trunc(r * 255), trunc(g * 255),
                                trunc(b * 255)))

    def glVertex(self, x, y):
        self.x = trunc(self.view['x'] + (self.view['width'] / 2) * (x + 1))
        self.y = trunc(self.view['y'] + (self.view['height'] / 2) * (y + 1))

        # print(self.x)
        # print(self.y)

        self.bmp.point(self.y, self.x, self.color)

    def glColor(self, r, g, b):
        self.color = color(floor(r * 255), floor(g * 255), floor(b * 255))
        # self.bmp.point(self.x, self.y, color(trunc(r * 255), trunc(g * 255), trunc(b * 255)))

    def glFinish(self, name='out'):
        self.bmp.write(name + '.bmp')

    def display(self, name='out'):
        self.glFinish(name)

        try:
            from wand.image import Image
            from wand.display import display

            with Image(filename=name + '.bmp') as image:
                display(image)
        except Exception as e:
            print(e)
            pass  # do nothing if no wand is installed
Пример #2
0
class ModulenControl(PanelModules, ControlBase):
    def __init__(self, parent, remote):
        """ remote is instance of HubProtocol for communication with remote"""
        PanelModules.__init__(self, parent)
        ControlBase.__init__(self)
        self.remote = remote
        self.scaleX = 1
        self.scaleY = 1
        self.drawMode = 0
        self.hubList = hubs.HubListModel(self.scrolledWindowHubs, self)
        listHubsSizer = wx.BoxSizer(wx.VERTICAL)
        listHubsSizer.Add(self.hubList, 1, wx.ALL | wx.EXPAND, 5)
        self.scrolledWindowHubs.SetSizer(listHubsSizer)
        listHubsSizer.Fit(self.scrolledWindowHubs)

        self.fanbotList = hubs.FanbotListModel(self.scrolledWindowFanbots, self)
        listFanbotsSizer = wx.BoxSizer(wx.VERTICAL)
        listFanbotsSizer.Add(self.fanbotList, 1, wx.ALL | wx.EXPAND, 5)
        self.scrolledWindowFanbots.SetSizer(listFanbotsSizer)
        listFanbotsSizer.Fit(self.scrolledWindowFanbots)

        self.pointCurrent = wx.Point(0, 0)
        self.pointPrevious = wx.Point(0, 0)
        self.currenthub = None

        self.compressedFrame = array.array("B", [0] * 125)

        self.bitmap = Bitmap(FanbotConfig.width, FanbotConfig.height)
        self.bitmap.clear()

        for hub in self.hubList.hubs:
            self.showHub(hub)

        self.timerAnimate = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.timerAnimateHandler, self.timerAnimate)
        self.animateIdx = 0

        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.timerDiscover, self.timer)
        self.timerDiscoverCount = 0

    def buttonResetDiscOnButtonClick(self, event):
        self.remote.sendCommand(HubProtocol.RESET)
        self.hubList.resetDiscovery()

    def buttonDiscoverOnButtonClick(self, event):
        self.remote.sendCommand(HubProtocol.REQUEST_ID)
        self.timer.Start(2000)
        self.timerDiscoverCount = 2
        self.sendMessage("Discover module. Even geduld aub... ")

    def timerDiscover(self, event):
        if self.timerDiscoverCount == 0:
            self.timer.Stop()

        else:
            self.timerDiscoverCount -= 1
            self.remote.sendCommand(HubProtocol.REQUEST_ID)
            self.hubList.refresh()

    def buttonClearListOnButtonClick(self, event):
        self.listModules.Clear()

    def buttonResetConfigOnButtonClick(self, event):
        if self.currenthub:
            self.resetHub(self.currenthub)
            self.remote.sendConfig(self.currenthub.idAsArray(), self.currenthub.config)

    def buttonSetConfigOnButtonClick(self, event):
        if self.currenthub:
            hub = self.currenthub
            print "buttonSetConfigOnButtonClick, currenthub: ", hub.id
            self.remote.sendConfig(hub.idAsArray(), hub.config)

    def buttonSetConfigAllOnButtonClick(self, event):
        print "buttonSetConfigAllButtonClick"
        for hub in self.hubList.hubs:
            self.remote.sendConfig(hub.idAsArray(), hub.config)
            time.sleep(0.100)

    def panelModulesCanvasOnSize(self, event):
        rect = self.panelModulesCanvas.GetRect()

        self.scaleX = rect.GetWidth() / self.bitmap.width
        self.scaleY = rect.GetHeight() / self.bitmap.height
        # print 'Scale x:y',self.scaleX,':',self.scaleY
        self.Refresh()

    def panelModulesCanvasOnPaint(self, event):
        dc = wx.PaintDC(self.panelModulesCanvas)
        dc.BeginDrawing()
        dc.SetUserScale(self.scaleX, self.scaleY)
        dc.Clear()
        dc.DrawBitmap(self.bitmap.getBitmap(), 0, 0)
        dc.EndDrawing()

    def panelModulesCanvasOnMouseEvents(self, event):
        point = None
        canvas = self.panelModulesCanvas
        if event:
            # set mouse cursor
            canvas.SetCursor(wx.StockCursor(wx.CURSOR_ARROW))
            # get device context of canvas
            dc = wx.ClientDC(canvas)
            dc.SetUserScale(self.scaleX, self.scaleY)

            point = event.GetLogicalPosition(dc)
            if point.x < 0 or point.x >= FanbotConfig.width or point.y < 0 or point.y >= FanbotConfig.height:
                # print 'x,y out of bounds: ',point.x ,':',point.y
                return
            if self.checkBoxMatrix.IsChecked():
                """ set the snapto grid to horizontal 4 and vertical 6"""
                point.x /= 4
                point.x *= 4
                point.y /= 6
                point.y *= 6

            self.labelPosition.SetLabel("%s : %s" % (point.x, point.y))
            self.pointCurrent = point
            # print "mouse event X : " ,point.x , " Y: ",point.y

        if event.LeftDown():
            self.panelModulesCanvas.Refresh()
            self.pointPrevious = self.pointCurrent
            if self.checkBoxMatrix.IsChecked():
                self.matrixHubConfig(point.x, point.y)
            else:
                self.updateHubConfig(point.x, point.y)

        elif event.LeftIsDown() and not self.checkBoxMatrix.IsChecked():
            if self.pointPrevious.x == self.pointCurrent.x and self.pointPrevious.y == self.pointCurrent.y:
                return
            self.pointPrevious = self.pointCurrent
            # print "Dragging to X : " ,point.x , " Y: ",point.y
            cur = wx.StockCursor(wx.CURSOR_CROSS)
            canvas.SetCursor(cur)
            self.updateHubConfig(point.x, point.y)

    def updateHubConfig(self, x, y):
        hub = self.currenthub
        if hub:
            if hub.canAddConfigItem():
                if self.bitmap.pixelSetWhite(x, y):
                    hub.setConfig(x, y)
                    self.panelModulesCanvas.Refresh()

    def matrixHubConfig(self, x, y):
        hub = self.currenthub
        if hub:
            if hub.canAddConfigItem():
                hub.resetConfig()
                for y in range(self.pointCurrent.y, self.pointCurrent.y + 6):
                    for x in range(self.pointCurrent.x, self.pointCurrent.x + 4):
                        self.bitmap.pixelSetWhite(x, y)
                        self.currenthub.setConfig(x, y)
                        self.panelModulesCanvas.Refresh()

    def handleCommand(self, opcode, payload):
        """ Handle incoming data from remote hubs or hubsimulator"""
        print "Modulen: Received opcode: %04x -- %s" % (opcode, payload)

        id = ""
        if len(payload) >= 4:
            for i in range(4):
                id = "%02x%s" % (payload[i], id)

        if opcode == HubProtocol.ID_REPORT:
            if len(payload) != 4:
                print "Error: incorrect length from hub received"
                return
            self.sendMessage("Discovered hub: " + id)
            print "Modulen: Received ID_REPORT from %s" % (id)
            hub = self.hubList.addHub(id)
            hub.discoverd = True
            hub.responsive = True
            # self.remote.sendCommand( HubProtocol.TAG_ID,4,hub.idAsArray() ) # remove tagging, as it messes up frames
        elif opcode == HubProtocol.STATUS_REPORT:
            hub = self.currenthub
            if hub:
                hub.setFanbots(payload)
                self.fanbotList.setFanbots(hub.fanbots)
            self.labelHubId.SetLabel("Hub: " + id)

    def hubSelected(self, hub):
        """Callback function called from the hubs list control"""
        self.showHub(self.currenthub)
        print "selected hub:", hub.id
        self.currenthub = hub

        config = hub.config
        for i in range(0, len(config)):
            tuple = hub.getConfigColor(i)
            if tuple[0] >= 0:
                x = tuple[0]
                y = tuple[1]
                self.bitmap.setPixel(x, y, 0xFFFFFF)
        self.fanbotList.setFanbots(None)
        self.labelHubId.SetLabel("Hub: ")
        self.panelModulesCanvas.Refresh()
        self.remote.sendCommand(HubProtocol.REQUEST_STATUS, 4, hub.idAsArray())
        time.sleep(0.2)
        if 0 == self.sliderAnimateHub.GetValue():
            self.createHubBitmap()
            self.remote.sendFanbotFrame(self.compressedFrame)

    def fanbbotSelected(self, item):
        mappedindex = Hub.fanbotMapping[item] - 1
        print "Selected fanbot index: %d mapped onto index %d" % (item, mappedindex)
        if 0 == self.sliderAnimateHub.GetValue():
            self.createFanbotBitmap(mappedindex)
            self.remote.sendFanbotFrame(self.compressedFrame)

    def showHub(self, hub):
        """for the given hub, show the pixels in the bitmap, in the color of he hub"""
        if hub:
            config = hub.config
            for i in range(0, len(config)):
                tuple = hub.getConfigColor(i)
                if tuple[0] >= 0:
                    x = tuple[0]
                    y = tuple[1]
                    self.bitmap.setPixel(x, y, tuple[2])

    def resetHub(self, hub):
        """for the given hub, make all its pixels gray, and then reset config"""
        if hub:
            print "reset hub:", hub.id
            config = hub.config
            for i in range(0, len(config)):
                tuple = hub.getConfigColor(i)
                if tuple[0] >= 0:
                    x = tuple[0]
                    y = tuple[1]
                    self.bitmap.pixelSetGray(x, y)
            hub.resetConfig()
            self.panelModulesCanvas.Refresh()

    def sliderAnimateHubOnScroll(self, event):
        speed = self.sliderAnimateHub.GetValue()
        if speed == 0:
            self.timerAnimate.Stop()
        else:
            self.timerAnimate.Start(250 - speed * 25)

    def timerAnimateHandler(self, event):
        """  """
        hub = self.currenthub
        if hub:
            self.animateIdx += 1
            if self.animateIdx >= 24:
                self.animateIdx = 0
            self.createFanbotBitmap(Hub.fanbotMapping[self.animateIdx] - 1)
        self.remote.sendFanbotFrame(self.compressedFrame)

    def createHubBitmap(self):
        hub = self.currenthub
        maxFrameLen = len(self.compressedFrame)
        if hub:
            for i in range(maxFrameLen):
                self.compressedFrame[i] = 0
            for i in range(24):
                pixelIdx = hub.config[i]
                if pixelIdx >= 0:
                    byteIdx = pixelIdx / 8
                    if byteIdx >= maxFrameLen:
                        return
                    bitIdx = pixelIdx % 8
                    self.compressedFrame[byteIdx] |= 1 << bitIdx

    def createFanbotBitmap(self, idx):
        hub = self.currenthub
        maxFrameLen = len(self.compressedFrame)
        if hub:
            for i in range(maxFrameLen):
                self.compressedFrame[i] = 0
            if idx >= 24:
                return
            pixelIdx = hub.config[idx]
            if pixelIdx >= 0:
                byteIdx = pixelIdx / 8
                if byteIdx >= maxFrameLen:
                    return
                bitIdx = pixelIdx % 8
                self.compressedFrame[byteIdx] = 1 << bitIdx
Пример #3
0
class Render(object):
    def __init__(self, width = None, height = None):
        self.x = 0
        self.y = 0
        self.view = {}
        self.color = color(255, 255, 255)

        if (width == None and height == None):
            self.bmp = None
            self.width = width
            self.height = height
        else:
            self.glCreateWindow(width, height)

    def glInit(self):
        pass

    def glCreateWindow(self, width, height):
        self.bmp = Bitmap(width, height)
        self.width = width
        self.height = height

    def glViewPort(self, x, y, width, height):
        self.view['x'] = x
        self.view['y'] = y
        self.view['width'] = width - 1
        self.view['height'] = height - 1

    def glClear(self):
        self.bmp.clear()

    def glClearColor(self, r, g, b):
        for i in range(self.height):
            for j in range(self.width):
                self.bmp.point(i, j, color(trunc(r * 255), trunc(g * 255), trunc(b * 255)))

    def glVertex(self, x, y):
        self.x = ceil(self.view['x'] + (self.view['width'] / 2) * (x + 1))
        self.y = ceil(self.view['y'] + (self.view['height'] / 2) * (y + 1))

        self.glVertexC(self.x, self.y)

    def glVertexC(self, x, y):
        self.bmp.point(y, x, self.color)

    def glColor(self, r, g, b):
        self.color = color(floor(r * 255), floor(g * 255), floor(b * 255))

    def glFinish(self, name = 'out'):
        self.bmp.write(name+'.bmp')

    def glLine(self, x0p, y0p, x1p, y1p):
        x0 = round(self.view['x'] + (self.view['width'] / 2) * (x0p + 1))
        y0 = round(self.view['y'] + (self.view['height'] / 2) * (y0p + 1))
        x1 = round(self.view['x'] + (self.view['width'] / 2) * (x1p + 1))
        y1 = round(self.view['y'] + (self.view['height'] / 2) * (y1p + 1))

        self.glLineC(x0, y0, x1, y1)

    def glLineC(self, x0, y0, x1, y1):

        dx = abs(x1 - x0)
        dy = abs(y1 - y0)

        if x1 < x0:
            x0, x1 = x1, x0
            y0, y1 = y1, y0

        px = 2 * dy - dx
        py = 2 * dx - dy

        if dx >= dy:
            y = y0
            for x in range(x0, x1 + 1):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if px < 0:
                    px += 2 * dy
                else:
                    y += 1 if y0 < y1 else -1
                    px += 2 * (dy - dx)

        else:
            x = x0
            step = 1 if y0 < y1 else -1
            for y in range(y0, y1, step):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if py < 0:
                    py += 2 * dx
                else:
                    x += 1 if x0 < x1 else -1
                    py += 2 * (dx - dy)


    def loadObj(self, filename, translateX=0, translateY=0, scale=1, triangle=0):
        with open(filename) as file:
            faces, vertices = obj.processObj(file)

        for face in faces:

            faceLen = len(face)
            faceVer = []
            for i in range(faceLen):
                faceVer.append(transform_vertex(
                    vertices[face[i][0] - 1],
                    translateX=translateX,
                    translateY=translateY,
                    scale=scale
                ))

            loopLen = faceLen - 2
            for i in range(loopLen):
                self.glColor(ran.random(), ran.random(), ran.random())
                if triangle == 0:
                    self.barycentric_triangle(faceVer[0], faceVer[i+1], faceVer[i+2])
                elif triangle == 1:
                    self.line_sweeping_triangle2(faceVer[0], faceVer[i+1], faceVer[i+2])

    def display(self, name = 'out'):
        self.glFinish(name)

        try:
            from wand.image import Image
            from wand.display import display

            with Image(filename = name + '.bmp') as image:
                display(image)
        except Exception as e:
            print(e)
            pass  # do nothing if no wand is installed


    def line_sweeping_triangle(self, A, B, C):
        if (A[1] > B[1]):
            A, B = B, A
        if (B[1] > C[1]):
            B, C = C, B
        if (A[1] > B[1]):
            A, B = B, A

        self.glLineC(A[0], A[1], B[0], B[1])
        self.glLineC(A[0], A[1], C[0], C[1])
        self.glLineC(B[0], B[1], C[0], C[1])

        for i in range(A[1], B[1]):
            x0 = round(x(A, C, i))
            x1 = round(x(A, B, i))
            self.glLineC(x0, i, x1, i)

        for i in range(B[1], C[1]):
            x0 = round(x(A, C, i))
            x1 = round(x(B, C, i))
            self.glLineC(x0, i, x1, i)

    def line_sweeping_triangle2(self, A, B, C):
        if (A[1] > B[1]):
            A, B = B, A
        if (B[1] > C[1]):
            B, C = C, B
        if (A[1] > B[1]):
            A, B = B, A

        total_height = C[1] - A[1]
        first_height = B[1] - A[1]
        second_height = C[1] - B[1]

        if total_height == 0:
            return

        # if first_height:
        for i in range(A[1], B[1]):
            alpha = (i - A[1]) / total_height
            beta = (i - A[1]) / first_height
            v0 = vector_sum(A, vector_linear_mul(vector_subs(C, A), alpha))
            v1 = vector_sum(A, vector_linear_mul(vector_subs(B, A), beta))
            if v0[0] > v1[0]:
                v0, v1 = v1, v0

            for j in range(round(v0[0]), round(v1[0])):
                self.glVertexC(j, i)

        for i in range(B[1], C[1]):
            alpha = (i - A[1]) / total_height
            beta = (i - B[1]) / second_height
            v0 = vector_sum(A, vector_linear_mul(vector_subs(C, A), alpha))
            v1 = vector_sum(B, vector_linear_mul(vector_subs(C, B), beta))
            if v0[0] > v1[0]:
                v0, v1 = v1, v0

            for j in range(round(v0[0]), round(v1[0])):
                self.glVertexC(j, i)

    def barycentric_triangle(self, A, B, C):
        x_min, x_max, y_min, y_max = bounding_box(A, B, C)

        for i in range(x_min, x_max + 1):
            for j in range(y_min, y_max + 1):
                if barycentric(A, B, C, [i, j, 0]):
                    self.glVertexC(i, j)
Пример #4
0
class Render(object):
    def __init__(self, width=None, height=None):
        self.x = 0
        self.y = 0
        self.view = {}
        self.color = color(255, 255, 255)

        if (width == None and height == None):
            self.bmp = None
            self.width = width
            self.height = height
        else:
            self.glCreateWindow(width, height)

    def glInit(self):
        pass

    def glCreateWindow(self, width, height):
        self.bmp = Bitmap(width, height)
        self.width = width
        self.height = height

    def glViewPort(self, x, y, width, height):
        self.view['x'] = x
        self.view['y'] = y
        self.view['width'] = width - 1
        self.view['height'] = height - 1

    def glClear(self):
        self.bmp.clear()

    def glClearColor(self, r, g, b):
        for i in range(self.height):
            for j in range(self.width):
                self.bmp.point(
                    i, j, color(trunc(r * 255), trunc(g * 255),
                                trunc(b * 255)))

    def glVertex(self, x, y):
        self.x = ceil(self.view['x'] + (self.view['width'] / 2) * (x + 1))
        self.y = ceil(self.view['y'] + (self.view['height'] / 2) * (y + 1))

        self.glVertexC(self.x, self.y)

    def glVertexC(self, x, y):
        self.bmp.point(y, x, self.color)

    def glColorC(self, r, g, b):
        self.color = color(r, g, b)

    def glColorFull(self, color):
        self.color = color

    def glColor(self, r, g, b):
        self.color = color(floor(r * 255), floor(g * 255), floor(b * 255))

    def glFinish(self, name='out'):
        self.bmp.write(name + '.bmp')

    def glLine(self, x0p, y0p, x1p, y1p):
        x0 = round(self.view['x'] + (self.view['width'] / 2) * (x0p + 1))
        y0 = round(self.view['y'] + (self.view['height'] / 2) * (y0p + 1))
        x1 = round(self.view['x'] + (self.view['width'] / 2) * (x1p + 1))
        y1 = round(self.view['y'] + (self.view['height'] / 2) * (y1p + 1))

        self.glLineC(x0, y0, x1, y1)

    def glLineC(self, x0, y0, x1, y1):

        dx = abs(x1 - x0)
        dy = abs(y1 - y0)

        if x1 < x0:
            x0, x1 = x1, x0
            y0, y1 = y1, y0

        px = 2 * dy - dx
        py = 2 * dx - dy

        if dx >= dy:
            y = y0
            for x in range(x0, x1 + 1):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if px < 0:
                    px += 2 * dy
                else:
                    y += 1 if y0 < y1 else -1
                    px += 2 * (dy - dx)

        else:
            x = x0
            step = 1 if y0 < y1 else -1
            for y in range(y0, y1, step):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if py < 0:
                    py += 2 * dx
                else:
                    x += 1 if x0 < x1 else -1
                    py += 2 * (dx - dy)

    def loadObj(self,
                filename,
                translate=[0, 0, 0],
                scale=[1, 1, 1],
                rotate=[0, 0, 0],
                texture=None,
                light=[0, 0, 1]):
        with open(filename) as file:
            faces, vertices, textures_coor = obj.processObj(file)

        self.calcModelMat(rotate, scale, translate)

        for i in range(len(vertices)):
            vertices[i] = self.transform(vertices[i])

        # light = [0.3, 0.1, 0.6]
        # light = [0, 0, 1]
        asdf = 0
        for face in faces:
            asdf += 1
            print(asdf)
            #Se obtienen las coordenadas de los vertices
            faceLen = len(face)
            faceVer = []
            faceTex = []
            for i in range(faceLen):
                faceVer.append(vertices[face[i][0] - 1])
                # faceVer.append(transform_vertex(
                # vertices[face[i][0] - 1],
                # translateX=translateX,
                # translateY=translateY,
                # scale=scale
                # ))
                if texture:
                    faceTex.append(textures_coor[face[i][1] - 1])

            #Se obtiene la intensidad
            dot = cross_product(vector_subs(faceVer[1], faceVer[0]),
                                vector_subs(faceVer[2], faceVer[0]))
            norm = normalize(dot)
            light_int = dot_product(norm, light)

            #Se recorren todos los vertices de cada cara
            loopLen = faceLen - 2
            if faceLen <= 4:
                for i in range(loopLen):

                    if light_int > 0:
                        if not texture:
                            self.glColor(light_int, light_int, light_int)

                            tex_coor_temp = None
                        else:
                            tex_coor_temp = (faceTex[0], faceTex[i + 1],
                                             faceTex[i + 2])

                        self.barycentric_triangle(faceVer[0],
                                                  faceVer[i + 1],
                                                  faceVer[i + 2],
                                                  tex_coor=tex_coor_temp,
                                                  texture=texture,
                                                  intensity=light_int)

    def calcViewportMat(self, x=0, y=0):
        res = [[self.width / 2, 0, 0, x + self.width / 2],
               [0, self.height / 2, 0, y + self.height / 2], [0, 0, 100, 100],
               [0, 0, 0, 1]]

        self.viewport_matrix = res

    def calcModelMat(self,
                     rotate=[0, 0, 0],
                     scale=[1, 1, 1],
                     translate=[0, 0, 0]):
        rotate_x = [[1, 0, 0, 0], [0, cos(rotate[0]), -sin(rotate[0]), 0],
                    [0, sin(rotate[0]), cos(rotate[0]), 0], [0, 0, 0, 1]]

        rotate_y = [[cos(rotate[1]), 0, sin(rotate[1]), 0], [0, 1, 0, 0],
                    [-sin(rotate[1]), 0, cos(rotate[1]), 0], [0, 0, 0, 1]]

        rotate_z = [[cos(rotate[2]), -sin(rotate[2]), 0, 0],
                    [sin(rotate[2]), cos(rotate[2]), 0, 0], [0, 0, 1, 0],
                    [0, 0, 0, 1]]

        rotate_all = matmul(matmul(rotate_x, rotate_y), rotate_z)

        translation = [[1, 0, 0, translate[0]], [0, 1, 0, translate[1]],
                       [0, 0, 1, translate[2]], [0, 0, 0, 1]]

        scale_mat = [[scale[0], 0, 0, 0], [0, scale[1], 0, 0],
                     [0, 0, scale[2], 0], [0, 0, 0, 1]]

        self.model_matrix = matmul(matmul(translation, rotate_all), scale_mat)

    def calcViewMat(self, x, y, z, center):

        view_mat = [[x[0], x[1], x[2], -center[0]],
                    [y[0], y[1], y[2], -center[1]],
                    [z[0], z[1], z[2], -center[2]], [0, 0, 0, 1]]

        self.view_matrix = view_mat

    def calcProjectionMat(self, c):
        proj = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, c, 1]]

        self.proj_matrix = proj

    def transform(self, vertex):
        vertex = [[vertex[0]], [vertex[1]], [vertex[2]], [1]]

        homog_mat = matmul(
            matmul(
                matmul(matmul(self.viewport_matrix, self.proj_matrix),
                       self.view_matrix), self.model_matrix), vertex)

        trans_vertex = [
            round(homog_mat[0][0] / homog_mat[3][0]),
            round(homog_mat[1][0] / homog_mat[3][0]),
            round(homog_mat[2][0] / homog_mat[3][0])
        ]

        return trans_vertex

    def lookAt(self, cameraPos, cameraTarget, up):
        z = normalize(vector_subs(cameraPos, cameraTarget))
        x = normalize(cross_product(up, z))
        y = normalize(cross_product(z, x))

        self.calcViewMat(x, y, z, cameraTarget)
        self.calcProjectionMat(
            -1 / vec_length(vector_subs(cameraPos, cameraTarget)))
        self.calcViewportMat()

    def barycentric_triangle(self,
                             A,
                             B,
                             C,
                             tex_coor=(),
                             texture=None,
                             intensity=1):
        x_min, x_max, y_min, y_max = bounding_box(A, B, C)

        for i in range(x_min, x_max + 1):
            for j in range(y_min, y_max + 1):
                if i < 0 or j < 0:
                    continue
                u, v, w = barycentric2(A, B, C, [i, j])

                if u >= 0 and v >= 0 and w >= 0:

                    if texture:
                        tex_A, tex_B, tex_C = tex_coor
                        tex_x = tex_A[0] * u + tex_B[0] * v + tex_C[0] * w
                        tex_y = tex_A[1] * u + tex_B[1] * v + tex_C[1] * w

                        self.glColorFull(
                            texture.getColor(tex_x, tex_y, intensity))

                    P_z = dot_product([u, v, w], [A[2], B[2], C[2]])

                    if j < len(self.bmp.zbuffer) and i < len(
                            self.bmp.zbuffer[j]) and self.bmp.getZbuffer(
                                i, j) < P_z:
                        self.bmp.setZbuffer(i, j, P_z)
                        self.glVertexC(i, j)
Пример #5
0
			while (sqr(z.x) + sqr(z.y) < max) and (n < iter) do
			begin
				t := z;
				{z^2 + c}
				z.x := sqr(t.x) - sqr(t.y) + c.x;
				z.y := 2*t.x*t.y + c.y;
				Inc(n);
   			end;
			if n < iter then begin
                          col := n*6 mod 255;
                          PaintBox1.Canvas.Pixels[mx+x,my+y]:=RGBToColor(col,0,0);
			end;"""
size = 511
b = Bitmap(size + 1, size + 1)

b.clear()
max = 60
iter = 100
c = complex(0.11, -0.66)
Mx = My = size // 2
for y in range(-My, My + 1):
    for x in range(-Mx, Mx + 1):
        n = 0
        z = complex(x * 0.009, y * 0.009)
        while (z.real**2 + z.imag**2) < max and n < iter:
            t = z
            z = complex(pow(t, 2) + c.real, 2 * t + c.imag)
            n += 1
        if n < iter:
            col = n * 30 % 255
            b.setPixel(Mx + x, My + y, (col, 0, 0))
Пример #6
0
class Render(object):
    def __init__(self, width=None, height=None):
        self.x = 0
        self.y = 0
        self.view = {}
        self.color = color(255, 255, 255)

        if (width == None and height == None):
            self.bmp = None
            self.width = width
            self.height = height
        else:
            self.glCreateWindow(width, height)

    def glInit(self):
        pass

    def glCreateWindow(self, width, height):
        self.bmp = Bitmap(width, height)
        self.width = width
        self.height = height

    def glViewPort(self, x, y, width, height):
        self.view['x'] = x
        self.view['y'] = y
        self.view['width'] = width - 1
        self.view['height'] = height - 1

    def glClear(self):
        self.bmp.clear()

    def glClearColor(self, r, g, b):
        for i in range(self.height):
            for j in range(self.width):
                self.bmp.point(
                    i, j, color(trunc(r * 255), trunc(g * 255),
                                trunc(b * 255)))

    def glVertex(self, x, y):
        self.x = ceil(self.view['x'] + (self.view['width'] / 2) * (x + 1))
        self.y = ceil(self.view['y'] + (self.view['height'] / 2) * (y + 1))

        self.glVertexC(self.x, self.y)

    def glVertexC(self, x, y):
        self.bmp.point(y, x, self.color)

    def glColorC(self, r, g, b):
        self.color = color(r, g, b)

    def glColorFull(self, color):
        self.color = color

    def glColor(self, r, g, b):
        self.color = color(floor(r * 255), floor(g * 255), floor(b * 255))

    def glFinish(self, name='out'):
        self.bmp.write(name + '.bmp')

    def glLine(self, x0p, y0p, x1p, y1p):
        x0 = round(self.view['x'] + (self.view['width'] / 2) * (x0p + 1))
        y0 = round(self.view['y'] + (self.view['height'] / 2) * (y0p + 1))
        x1 = round(self.view['x'] + (self.view['width'] / 2) * (x1p + 1))
        y1 = round(self.view['y'] + (self.view['height'] / 2) * (y1p + 1))

        self.glLineC(x0, y0, x1, y1)

    def glLineC(self, x0, y0, x1, y1):

        dx = abs(x1 - x0)
        dy = abs(y1 - y0)

        if x1 < x0:
            x0, x1 = x1, x0
            y0, y1 = y1, y0

        px = 2 * dy - dx
        py = 2 * dx - dy

        if dx >= dy:
            y = y0
            for x in range(x0, x1 + 1):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if px < 0:
                    px += 2 * dy
                else:
                    y += 1 if y0 < y1 else -1
                    px += 2 * (dy - dx)

        else:
            x = x0
            step = 1 if y0 < y1 else -1
            for y in range(y0, y1, step):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if py < 0:
                    py += 2 * dx
                else:
                    x += 1 if x0 < x1 else -1
                    py += 2 * (dx - dy)

    def loadObj(self,
                filename,
                translateX=0,
                translateY=0,
                scale=1,
                texture=None,
                light=[0, 0, 1]):
        with open(filename) as file:
            faces, vertices, textures_coor = obj.processObj(file)

        # light = [0.3, 0.1, 0.6]
        # light = [0, 0, 1]

        for face in faces:

            #Se obtienen las coordenadas de los vertices
            faceLen = len(face)
            faceVer = []
            faceTex = []
            for i in range(faceLen):
                faceVer.append(
                    transform_vertex(vertices[face[i][0] - 1],
                                     translateX=translateX,
                                     translateY=translateY,
                                     scale=scale))
                faceTex.append(textures_coor[face[i][1] - 1])

            #Se obtiene la intensidad
            dot = cross_product(vector_subs(faceVer[1], faceVer[0]),
                                vector_subs(faceVer[2], faceVer[0]))
            norm = normalize(dot)
            light_int = dot_product(norm, light)

            #Se recorren todos los vertices de cada cara
            loopLen = faceLen - 2
            for i in range(loopLen):

                if light_int > 0:
                    if not texture:
                        self.glColor(light_int, light_int, light_int)

                    self.barycentric_triangle(faceVer[0],
                                              faceVer[i + 1],
                                              faceVer[i + 2],
                                              tex_coor=(faceTex[0],
                                                        faceTex[i + 1],
                                                        faceTex[i + 2]),
                                              texture=texture,
                                              intensity=light_int)

    def display(self, name='out'):
        self.glFinish(name)

        try:
            from wand.image import Image
            from wand.display import display

            with Image(filename=name + '.bmp') as image:
                display(image)
        except Exception as e:
            print(e)
            pass

    def barycentric_triangle(self,
                             A,
                             B,
                             C,
                             tex_coor=(),
                             texture=None,
                             intensity=1):
        x_min, x_max, y_min, y_max = bounding_box(A, B, C)

        for i in range(x_min, x_max + 1):
            for j in range(y_min, y_max + 1):
                u, v, w = barycentric2(A, B, C, [i, j])

                if u >= 0 and v >= 0 and w >= 0:

                    if texture:
                        tex_A, tex_B, tex_C = tex_coor
                        tex_x = tex_A[0] * u + tex_B[0] * v + tex_C[0] * w
                        tex_y = tex_A[1] * u + tex_B[1] * v + tex_C[1] * w

                        self.glColorFull(
                            texture.getColor(tex_x, tex_y, intensity))

                    P_z = dot_product([u, v, w], [A[2], B[2], C[2]])

                    if self.bmp.getZbuffer(i, j) < P_z:
                        self.bmp.setZbuffer(i, j, P_z)
                        self.glVertexC(i, j)
Пример #7
0
class Render(object):
    def __init__(self, width = None, height = None):
        self.x = 0
        self.y = 0
        self.view = {}
        self.color = color(255, 255, 255)

        if (width == None and height == None):
            self.bmp = None
            self.width = width
            self.height = height
        else:
            self.glCreateWindow(width, height)

    def glInit(self):
        pass

    def glCreateWindow(self, width, height):
        self.bmp = Bitmap(width, height)
        self.width = width
        self.height = height

    def glViewPort(self, x, y, width, height):
        self.view['x'] = x
        self.view['y'] = y
        self.view['width'] = width - 1
        self.view['height'] = height - 1

    def glClear(self):
        self.bmp.clear()

    def glClearColor(self, r, g, b):
        for i in range(self.height):
            for j in range(self.width):
                self.bmp.point(i, j, color(trunc(r * 255), trunc(g * 255), trunc(b * 255)))

    def glVertex(self, x, y):
        self.x = ceil(self.view['x'] + (self.view['width'] / 2) * (x + 1))
        self.y = ceil(self.view['y'] + (self.view['height'] / 2) * (y + 1))

        self.glVertexC(self.x, self.y)

    def glVertexC(self, x, y):
        self.bmp.point(y, x, self.color)

    def glColor(self, r, g, b):
        self.color = color(floor(r * 255), floor(g * 255), floor(b * 255))

    def glFinish(self, name = 'out'):
        self.bmp.write(name+'.bmp')

    def glLine(self, x0p, y0p, x1p, y1p):
        x0 = round(self.view['x'] + (self.view['width'] / 2) * (x0p + 1))
        y0 = round(self.view['y'] + (self.view['height'] / 2) * (y0p + 1))
        x1 = round(self.view['x'] + (self.view['width'] / 2) * (x1p + 1))
        y1 = round(self.view['y'] + (self.view['height'] / 2) * (y1p + 1))

        self.glLineC(x0, y0, x1, y1)

    def glLineC(self, x0, y0, x1, y1):

        dx = abs(x1 - x0)
        dy = abs(y1 - y0)

        if x1 < x0:
            x0, x1 = x1, x0
            y0, y1 = y1, y0

        px = 2 * dy - dx
        py = 2 * dx - dy

        if dx >= dy:
            y = y0
            for x in range(x0, x1 + 1):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if px < 0:
                    px += 2 * dy
                else:
                    y += 1 if y0 < y1 else -1
                    px += 2 * (dy - dx)

        else:
            x = x0
            step = 1 if y0 < y1 else -1
            for y in range(y0, y1, step):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if py < 0:
                    py += 2 * dx
                else:
                    x += 1 if x0 < x1 else -1
                    py += 2 * (dx - dy)


    def loadObj(self, filename, translateX=0, translateY=0, scale=1, triangle=0):
        with open(filename) as file:
            faces, vertices = obj.processObj(file)

        light = [0.2, 0.3, 0.5]

        for face in faces:

            faceLen = len(face)
            faceVer = []
            for i in range(faceLen):
                faceVer.append(transform_vertex(
                    vertices[face[i][0] - 1],
                    translateX=translateX,
                    translateY=translateY,
                    scale=scale
                ))

            loopLen = faceLen - 2
            for i in range(loopLen):
                dot = cross_product(vector_subs(faceVer[i+1], faceVer[0]), vector_subs(faceVer[i+2], faceVer[0]))

                norm = normalize(dot)

                light_int = dot_product(norm, light)

                if light_int > 0:
                    self.glColor(light_int, light_int, light_int)
                    self.barycentric_triangle(faceVer[0], faceVer[i+1], faceVer[i+2])

    def display(self, name = 'out'):
        self.glFinish(name)

        try:
            from wand.image import Image
            from wand.display import display

            with Image(filename = name + '.bmp') as image:
                display(image)
        except Exception as e:
            print(e)
            pass  # do nothing if no wand is installed


    # def line_sweeping_triangle(self, A, B, C):
    #     if (A[1] > B[1]):
    #         A, B = B, A
    #     if (B[1] > C[1]):
    #         B, C = C, B
    #     if (A[1] > B[1]):
    #         A, B = B, A
    #
    #     self.glLineC(A[0], A[1], B[0], B[1])
    #     self.glLineC(A[0], A[1], C[0], C[1])
    #     self.glLineC(B[0], B[1], C[0], C[1])
    #
    #     for i in range(A[1], B[1]):
    #         x0 = round(x(A, C, i))
    #         x1 = round(x(A, B, i))
    #         self.glLineC(x0, i, x1, i)
    #
    #     for i in range(B[1], C[1]):
    #         x0 = round(x(A, C, i))
    #         x1 = round(x(B, C, i))
    #         self.glLineC(x0, i, x1, i)

    def barycentric_triangle(self, A, B, C):
        x_min, x_max, y_min, y_max = bounding_box(A, B, C)

        for i in range(x_min, x_max + 1):
            for j in range(y_min, y_max + 1):
                u, v, w = barycentric2(A, B, C, [i, j])

                if u >= 0 and v >= 0 and w >= 0:
                    P_z = dot_product([u, v, w], [A[2], B[2], C[2]])

                    if self.bmp.getZbuffer(i, j) < P_z:
                        self.bmp.setZbuffer(i, j, P_z)
                        self.glVertexC(i, j)
Пример #8
0
class Render(object):
    def __init__(self, width = None, height = None):
        self.x = 0
        self.y = 0
        self.view = {}
        self.color = color(255, 255, 255)

        if (width == None and height == None):
            self.bmp = None
            self.width = width
            self.height = height
        else:
            self.glCreateWindow(width, height)

    def glInit(self):
        pass

    def glCreateWindow(self, width, height):
        self.bmp = Bitmap(width, height)
        self.width = width
        self.height = height

    def glViewPort(self, x, y, width, height):
        self.view['x'] = x
        self.view['y'] = y
        self.view['width'] = width - 1
        self.view['height'] = height - 1

    def glClear(self):
        self.bmp.clear()

    def glClearColor(self, r, g, b):
        for i in range(self.height):
            for j in range(self.width):
                self.bmp.point(i, j, color(trunc(r * 255), trunc(g * 255), trunc(b * 255)))

    def glVertex(self, x, y):
        self.x = ceil(self.view['x'] + (self.view['width'] / 2) * (x + 1))
        self.y = ceil(self.view['y'] + (self.view['height'] / 2) * (y + 1))

        self.glVertexC(self.x, self.y)

    def glVertexC(self, x, y):
        self.bmp.point(y, x, self.color)

    def glColor(self, r, g, b):
        self.color = color(floor(r * 255), floor(g * 255), floor(b * 255))

    def glFinish(self, name = 'out'):
        self.bmp.write(name+'.bmp')

    def glLine(self, x0p, y0p, x1p, y1p):
        x0 = round(self.view['x'] + (self.view['width'] / 2) * (x0p + 1))
        y0 = round(self.view['y'] + (self.view['height'] / 2) * (y0p + 1))
        x1 = round(self.view['x'] + (self.view['width'] / 2) * (x1p + 1))
        y1 = round(self.view['y'] + (self.view['height'] / 2) * (y1p + 1))

        self.glLineC(x0, y0, x1, y1)

    def glLineC(self, x0, y0, x1, y1):
        # print(x0)
        # print(y0)
        # print(x1)
        # print(y1)

        dx = abs(x1 - x0)
        dy = abs(y1 - y0)

        if x1 < x0:
            x0, x1 = x1, x0
            y0, y1 = y1, y0

        px = 2 * dy - dx
        py = 2 * dx - dy

        if dx >= dy:
            y = y0
            for x in range(x0, x1 + 1):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if px < 0:
                    px += 2 * dy
                else:
                    y += 1 if y0 < y1 else -1
                    px += 2 * (dy - dx)

        else:
            x = x0
            step = 1 if y0 < y1 else -1
            for y in range(y0, y1, step):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if py < 0:
                    py += 2 * dx
                else:
                    x += 1 if x0 < x1 else -1
                    py += 2 * (dx - dy)


    def display(self, name = 'out'):
        self.glFinish(name)

        try:
            from wand.image import Image
            from wand.display import display

            with Image(filename = name + '.bmp') as image:
                display(image)
        except Exception as e:
            print(e)
            pass  # do nothing if no wand is installed

    def fillPolygon(self, points, r, g, b):
        self.glColor(r / 255, g / 255, b / 255)

        for i in range(-1,len(points)-1):
            self.glLineC(points[i][0], points[i][1], points[i+1][0], points[i+1][1])

        edges = self.createPolygonEdges(points)

        y_min = min([points[i][1] for i in range(len(points))])
        y_max = max([points[i][1] for i in range(len(points))])
        x_min = min([points[i][0] for i in range(len(points))])
        x_max = max([points[i][0] for i in range(len(points))])


        for i in range(y_min, y_max+1):
            activeEdges = [edges[n] for n in range(len(edges)) if edges[n]['yMin'] <= i <= edges[n]['yMax']]
            activeEdges = sorted(activeEdges, key=lambda item: item['x'])

            count = 0
            intercepts = []
            for j in range(len(activeEdges)):
                if activeEdges[j]['m'] == 0:
                    adjEdges = []
                    for k in range(len(activeEdges)):
                        if j != k:
                            if (activeEdges[j]['v0'] == activeEdges[k]['v0'] or activeEdges[j]['v0'] == activeEdges[k]['v1']):
                                adjEdges.append(activeEdges[k])
                            if (activeEdges[j]['v1'] == activeEdges[k]['v0'] or activeEdges[j]['v1'] == activeEdges[k]['v1']):
                                adjEdges.append(activeEdges[k])
                            if len(adjEdges) == 2:
                                break
                    if not (adjEdges[0]['yMax'] == adjEdges[1]['yMax'] or adjEdges[0]['yMin'] == adjEdges[1]['yMin']):
                        intercepts.append(activeEdges[j]['x'])
                elif j < len(activeEdges)-1:
                    if not ((
                        (i == activeEdges[j]['v0'][1] and (
                            activeEdges[j]['v0'] == activeEdges[j+1]['v0'] or
                            activeEdges[j]['v0'] == activeEdges[j+1]['v1']
                        )) or
                        (i == activeEdges[j]['v1'][1] and (
                            activeEdges[j]['v1'] == activeEdges[j+1]['v0'] or
                            activeEdges[j]['v1'] == activeEdges[j+1]['v1']
                        ))
                    ) and ((activeEdges[j]['yMin'] != activeEdges[j+1]['yMin']) and (activeEdges[j]['yMax'] != activeEdges[j+1]['yMax']))):
                        if activeEdges[j]['m'] == 0:
                            intercepts.append(activeEdges[j]['x'])
                        else:
                            intercepts.append(round(
                                activeEdges[j]['x0'] - ((activeEdges[j]['y0'] - i) / activeEdges[j]['m'])
                            ))
                else:
                    if activeEdges[j]['m'] == 0:
                        intercepts.append(activeEdges[j]['x'])
                    else:
                        intercepts.append(round(
                            activeEdges[j]['x0'] - ((activeEdges[j]['y0'] - i) / activeEdges[j]['m'])
                        ))

            # if i == 214:
            #     print('INTERCEPTS')
            #     print('')
            #     print(intercepts)
            #     print('')
            #     break
            for j in range(x_min, x_max + 1):
                count = 0
                for k in range(len(intercepts)):
                    if intercepts[k] < j:
                        count += 1

                if count % 2 == 1:
                    self.glVertexC(j, i)

    def createPolygonEdges(self, ver):
        edges = []
        for i in range(-1, len(ver)-1):
            edge = {}
            # if ver[i][1] - ver[i+1][1] != 0:
            edge['yMax'] = max([ver[i][1], ver[i+1][1]])
            edge['yMin'] = min([ver[i][1], ver[i+1][1]])
            edge['x'] = min([ver[i][0], ver[i+1][0]])
            edge['x0'] = ver[i][0]
            edge['y0'] = ver[i][1]
            edge['v0'] = [ver[i][0], ver[i][1]]
            edge['v1'] = [ver[i+1][0], ver[i+1][1]]
            if ver[i][0] - ver[i+1][0] == 0:
                edge['m'] = 999999999
            else:
                edge['m'] = ((ver[i][1]-ver[i+1][1])/(ver[i][0]-ver[i+1][0]))

            edges.append(edge)

        return edges
Пример #9
0
class Render(object):
    def __init__(self, width=None, height=None):
        self.x = 0
        self.y = 0
        self.view = {}
        self.color = color(255, 255, 255)

        if (width == None and height == None):
            self.bmp = None
            self.width = width
            self.height = height
        else:
            self.glCreateWindow(width, height)

    def glInit(self):
        pass

    def glCreateWindow(self, width, height):
        self.bmp = Bitmap(width, height)
        self.width = width
        self.height = height

    def glViewPort(self, x, y, width, height):
        self.view['x'] = x
        self.view['y'] = y
        self.view['width'] = width - 1
        self.view['height'] = height - 1

    def glClear(self):
        self.bmp.clear()

    def glClearColor(self, r, g, b):
        for i in range(self.height):
            for j in range(self.width):
                self.bmp.point(
                    i, j, color(trunc(r * 255), trunc(g * 255),
                                trunc(b * 255)))

    def glVertex(self, x, y):
        self.x = ceil(self.view['x'] + (self.view['width'] / 2) * (x + 1))
        self.y = ceil(self.view['y'] + (self.view['height'] / 2) * (y + 1))

        self.glVertexC(self.x, self.y)

    def glVertexC(self, x, y):
        self.bmp.point(y, x, self.color)

    def glColor(self, r, g, b):
        self.color = color(floor(r * 255), floor(g * 255), floor(b * 255))

    def glFinish(self, name='out'):
        self.bmp.write(name + '.bmp')

    def glLine(self, x0p, y0p, x1p, y1p):
        x0 = round(self.view['x'] + (self.view['width'] / 2) * (x0p + 1))
        y0 = round(self.view['y'] + (self.view['height'] / 2) * (y0p + 1))
        x1 = round(self.view['x'] + (self.view['width'] / 2) * (x1p + 1))
        y1 = round(self.view['y'] + (self.view['height'] / 2) * (y1p + 1))

        self.glLineC(x0, y0, x1, y1)

    def glLineC(self, x0, y0, x1, y1):
        # print(x0)
        # print(y0)
        # print(x1)
        # print(y1)

        dx = abs(x1 - x0)
        dy = abs(y1 - y0)

        if x1 < x0:
            x0, x1 = x1, x0
            y0, y1 = y1, y0

        px = 2 * dy - dx
        py = 2 * dx - dy

        if dx >= dy:
            y = y0
            for x in range(x0, x1 + 1):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if px < 0:
                    px += 2 * dy
                else:
                    y += 1 if y0 < y1 else -1
                    px += 2 * (dy - dx)

        else:
            x = x0
            step = 1 if y0 < y1 else -1
            for y in range(y0, y1, step):
                # print(x)
                # print(y)
                self.glVertexC(x, y)

                if py < 0:
                    py += 2 * dx
                else:
                    x += 1 if x0 < x1 else -1
                    py += 2 * (dx - dy)

    def display(self, name='out'):
        self.glFinish(name)

        try:
            from wand.image import Image
            from wand.display import display

            with Image(filename=name + '.bmp') as image:
                display(image)
        except Exception as e:
            print(e)
            pass  # do nothing if no wand is installed