Example #1
0
class Model:
    """Immutable"""
    def __init__( self, size, observer, position = None, has_grid = False ):
        self.font_colour = ( 0, 0, 0 )
        self.width, self.height = size
        if None == position:
            self.position = Point( 0, 0, 0 )
        else:
            self.position = position
        self.observer = observer
        self.grid = self.make_squares( 10, ( 0, 0 ), ( self.width, self.width ), 10 )
        self.font = pygame.font.SysFont( "monospace", 12 )
        self.has_grid = has_grid
        if self.has_grid:
            self.front_grid = self.make_grid( ( self.width, self.width ), 50 )
        self.highlight_colour = ( 255, 255, 0 )
        self.highlight_radius = 5

    def make_grid( self, size, sep ):
        width, height = size
        grid = []
        for i in range( sep, width, sep ):
            grid.append( Polygon( ( 255, 255, 255 ) ).add( Point( i, 0, 0 ) ).add( Point( i, height, 0 ) ) )
        for i in range( sep, height, sep ):
            grid.append( Polygon( ( 255, 255, 255 ) ).add( Point( 0, i, 0 ) ).add( Point( width, i, 0 ) ) )
        return grid

    def set_grid( self, has_grid ):
        return Model( ( self.width, self.height ), self.observer, self.position, has_grid )

    def move( self, new_position ):
        return Model( ( self.width, self.height ), self.observer, new_position, self.has_grid )

    def move_up( self, n ):
        return self.move( self.position.move_up( n ) )

    def move_right( self, n ):
        return self.move( self.position.move_right( n ) )

    def move_down( self, n ):
        return self.move( self.position.move_down( n ) )

    def move_left( self, n ):
        return self.move( self.position.move_left( n ) )

    def move_forward( self, n ):
        return self.move( self.position.move_forward( n ) )

    def move_back( self, n ):
        return self.move( self.position.move_back( n ) )

    def update_position( self, position ):
        return Model( ( self.width, self.height ), self.observer, position, self.has_grid )

    def update_observer( self, observer ):
        return Model( ( self.width, self.height ), observer, self.position, self.has_grid )

    def snap( self, pos ):
        a = 50
        b = 10
        p = pos % a
        if p < b:
            return pos - p
        elif p > a - b:
            return pos + ( a - p )
        else:
            return pos

    def output( self, screen, mode, polygons ):
        screen.fill( 0 )
        self.output_polygons( screen, self.grid, 1 )
        self.output_polygons( screen, polygons, 0 )
        if len( polygons ) > 0 and polygons[ -1 ].num_points() > 0:
            last = polygons[ -1 ]
            p = last.get_points()[ -1 ]
            if p.z - self.position.z < self.observer.z:
                x, y = Point( p.x - self.position.x, p.y - self.position.y, p.z - self.position.z ).rel_to( self.observer )
                colour = ( 255, 0, 0 ) if last.is_open() else ( 0, 255, 0 )
                pygame.draw.line( screen, colour, ( x - 2, y - 2 ), ( x + 2, y + 2 ), 1 )
                pygame.draw.line( screen, colour, ( x + 2, y - 2 ), ( x - 2, y + 2 ), 1 )
        x, y = pygame.mouse.get_pos()
        if self.has_grid:
            self.op( screen, self.front_grid, 1 )
            x, y = self.snap( x ), self.snap( y )
        if Mode.INSERT == mode:
            colour = ( 0, 0, 255 )
            pygame.draw.line( screen, colour, ( x - 2, y - 2 ), ( x + 2, y + 2 ), 1 )
            pygame.draw.line( screen, colour, ( x + 2, y - 2 ), ( x - 2, y + 2 ), 1 )
        self.highlight( screen, polygons )
        self.select( screen, polygons )
        self.output_toolbar( screen, mode )
        pygame.display.flip()

    def highlight( self, screen, polygons ):
        for polygon in polygons:
            all_points = polygon.get_points()
            highlights = []
            for i in range( 0, len( all_points ) ):
                p = all_points[ i ]
                z = p.z - self.position.z
                if z < self.observer.z and p.z == self.position.z:
                    this = Point( p.x - self.position.x, p.y - self.position.y, z )
                    highlights.append( [ this.rel_to( self.observer ) ] )
                    prev = all_points[ i - 1 ]
                    if prev.z == self.position.z:
                        last = Point( prev.x - self.position.x, prev.y - self.position.y, z )
                        highlights.append( [ last.rel_to( self.observer ), this.rel_to( self.observer ) ] )
            for highlight in highlights:
                if len( highlight ) == 1:
                    pygame.draw.circle( screen, self.highlight_colour, highlight[ 0 ], self.highlight_radius, 1 )
                elif len( highlight ) == 2:
                    pygame.draw.line( screen, self.highlight_colour, highlight[ 0 ], highlight[ 1 ], 1 )

    def select( self, screen, polygons ):
        for polygon in polygons:
            all_points = polygon.get_points()
            highlights = []
            for i in range( 0, len( all_points ) ):
                p = all_points[ i ]
                z = p.z - self.position.z
                if polygon.is_selected() and z < self.observer.z and p.z == self.position.z:
                    this = Point( p.x - self.position.x, p.y - self.position.y, z )
                    prev = all_points[ i - 1 ]
                    last = Point( prev.x - self.position.x, prev.y - self.position.y, z )
                    highlights.append( [ last.rel_to( self.observer ), this.rel_to( self.observer ) ] )
            for highlight in highlights:
                pygame.draw.line( screen, ( 255, 0, 0 ), highlight[ 0 ], highlight[ 1 ], 1 )

    def op( self, screen, polygons, w ):
        for polygon in polygons:
            points = [ ]
            for p in polygon.get_points():
                points.append( ( p.x, p.y ) )
            if len( points ) == 1:
                screen.set_at( points[ 0 ], polygon.get_colour() )
            elif len( points ) == 2:
                pygame.draw.line( screen, polygon.get_colour(), points[ 0 ], points[ 1 ], 1 )
            else:
                pygame.draw.polygon( screen, polygon.get_colour(), points, polygon.get_width() )

    def output_polygons( self, screen, polygons, w ):
        for polygon in polygons:
            all_points = polygon.get_points()
            points = []
            for i in range( 0, len( all_points ) ):
                p = all_points[ i ]
                z = p.z - self.position.z
                if z < self.observer.z:
                    points.append( Point( p.x - self.position.x, p.y - self.position.y, z ).rel_to( self.observer ) )
                else:
                    points = [ ]
                    break
            if len( points ) == 1:
                screen.set_at( points[ 0 ], polygon.get_colour() )
            elif len( points ) == 2:
                pygame.draw.line( screen, polygon.get_colour(), points[ 0 ], points[ 1 ], 1 )
            elif len( points ) > 2:
                pygame.draw.polygon( screen, polygon.get_colour(), points, polygon.get_width() )

    def get_it_from( self, a, b ):
        return ( self.get_it( a.x, a.z, b.x, b.z ), self.get_it( a.y, a.z, b.x, b.z ) )

    def get_it( self, x1, y1, x2, y2 ):
        m = self.slope( x1, y1, x2, y2 )
        return ( m * x1 - y1 ) / 0.1 if m == 0 else m

    def slope( self, x1, y1, x2, y2 ):
        under = ( x2 - x1 )
        return ( y2 - y1 ) / 0.1 if under == 0 else under

    def make_square( self, top_left, bottom_right, z ):
        colour = 255 - z % 100
        a, b = top_left
        c, d = bottom_right
        square = Polygon( ( colour, colour, colour ) ).add( Point( a, b, z ) ) \
            .add( Point( b, c, z ) ).add( Point( c, d, z ) ) \
            .add( Point( d, a, z ) )
        square.set_width( 1 )
        return square

    def make_squares( self, n, top_left, bottom_right, separation ):
        squares = []
        for i in range( 0, n ):
            squares.append( self.make_square( top_left, bottom_right, self.position.z - i * separation ) )
        return squares

    def output_toolbar( self, screen, mode ):
        status = ""
        if Mode.INSERT    == mode: status = "-- INSERT --"
        elif Mode.OBSERVE == mode: status = "-- OBSERVE --"
        elif Mode.VISUAL  == mode: status = "-- VISUAL --"
        pygame.draw.rect( screen, ( 205, 205, 205 ), ( ( 0, 400 ), ( 400, 440 ) ), 0 )
        text = self.font.render( status, True, self.font_colour )
        screen.blit( text, ( 5, 405 ) )
        text = self.font.render( str( self.observer ), True, self.font_colour )
        screen.blit( text, ( 5, 425 ) )
        text = self.font.render( str( self.position ), True, self.font_colour )
        screen.blit( text, ( 125, 425 ) )
        x, y = pygame.mouse.get_pos()
        if self.has_grid:
            x, y = self.snap( x ), self.snap( y )
        text = self.font.render( str( ( x, y ) ), True, self.font_colour )
        screen.blit( text, ( 245, 425 ) )
Example #2
0
                 snapgrid = True
                 model = model.set_grid( True )
             elif 'nosg' == option:
                 snapgrid = False
         elif Command.WRITE == command[ 0 ]:
             filename = command[ 1 ][ 0 ]
             if not filename.endswith( '.3d' ):
                 filename += '.3d'
             write_objects( filename, objects )
             print "Wrote '" + filename + "'"
         elif Command.QUIT == command[ 0 ]:
             running = False
     if Mode.OBSERVE == mode:
         if K_UP      == event.key: observer = observer.move_up( 10 )
         elif K_RIGHT == event.key: observer = observer.move_right( 10 )
         elif K_DOWN  == event.key: observer = observer.move_down( 10 )
         elif K_LEFT  == event.key: observer = observer.move_left( 10 )
         elif K_j     == event.key: observer = observer.move_forward( 10 )
         elif K_k     == event.key and observer.z > model.position.z: observer = observer.move_back( 10 )
         model = model.update_observer( observer )
     else:
         if K_UP      == event.key: model = model.move_up( 10 )
         elif K_RIGHT == event.key: model = model.move_right( 10 )
         elif K_DOWN  == event.key: model = model.move_down( 10 )
         elif K_LEFT  == event.key: model = model.move_left( 10 )
         elif K_j     == event.key and model.position.z < observer.z: model = model.move_forward( 10 )
         elif K_k     == event.key: model = model.move_back( 10 )
 elif MOUSEBUTTONUP == event.type:
     if Mode.INSERT == mode:
         x, y = pygame.mouse.get_pos()
         if snapgrid: