Coder Social home page Coder Social logo

afourmy / pyearth Goto Github PK

View Code? Open in Web Editor NEW
111.0 10.0 24.0 23.04 MB

:globe_with_meridians: A lightweight 3D visualization of the earth in 150 lines of Qt/OpenGL

License: MIT License

Python 100.00%
geographical-information-system shapefile shapely pyproj gis pyqt5 geographic geographic-data geospatial 3d-graphics

pyearth's Introduction

Introduction

pyEarth is a lightweight 3D visualization of the Earth implemented with pyQt and OpenGL: it is the 3D counterpart of pyGISS.

Users can:

  • import shapefiles to visualize maps in 3D.
  • create objects (nodes or links) using Excel.
  • export a project to Google Earth.

pyEarth demo

pyEarth versions

Standard version (pyEarth.py, < 150 lines)

The standard version implements pyEarth in less than 150 lines of code. Maps can be created by importing shapefiles, and the following bindings are implemented:

  • the scroll wheel for zooming in and out.
  • the left-click button rotates the earth in any direction.
  • the right-click button moves the view in the 3-dimensional space (like a viewfinder).
  • pressing space will start a continuous rotation of the earth.

A few shapefiles are available for testing in the 'pyEarth/shapefiles' folder (world countries, US).

Extended version (extended_pyEarth.py, < 300 lines)

In the extended version, besides the import of shapefiles, nodes and links can be created on the map by importing an Excel file (an example is available in the 'PyGISS/projects' folder). A pyEarth project can then be exported to Google Earth (a KML file is created).

pyEarth demo

How it works

Polygon extraction

As shown below with Italy, a map can be represented as a set of polygons.

pyEarth

To draw the polygons, we need their coordinates. A shapefile (.shp) is a file that describes vector data as a set of shapes. For a map, there are two types of shapes: polygons and multipolygons. Polygons and multipolygons are defined as a set of points (longitude, latitude) on the earth.

pyEarth

To read the shapefile and extract the shapes it contains, we will use the pyshp library. Once this is done, we have a set of shapes, polygons and mutipolygons.

pyEarth

We can only draw polygons with the GUI framework polygon function. A multipolygon is actually composed of multiple polygons. To draw a multipolygon, we will decompose it into the polygons it is made of with the shapely library.

pyEarth

Coordinates conversion

The coordinates of a shapefile are geodetic coordinates: a point on the earth is defined as a longitude and a latitude. Longitude and latitude are angles.

pyEarth

We need to convert a point defined with geodetic coordinates ('Latitude, Longitude, Height', the LLH system) to a point defined with carthesian coordinates ('x, y, z', the ECEF system, "Earth-Centered, Earth-Fixed", also known as ECR, "Earth-Centered Rotational"). To make that conversion, we will use a library called "pyproj".

pyEarth

3D visualization

For the 3D visualization, we use the pyQt programming framework. Qt has a special widget for for rendering OpenGL graphics, QOpenGLWidget. QOpenGLWidget supports rendering of polygons with the GlPolygon primitive.

pyEarth

The tricky part about drawing polygons in OpenGL is that only convex polygons can be filled with a color. As a consequence, non-convex polygons must be broken down into convex subpolygons. pyEarth uses GLU tesselator function to triangulate the polygons, i.e break them down into triangles.

pyEarth

To move through the 3D space, we will implement a basic camera moving forward and backward along the z-axis. We use the GLU function gluLookAt for that purpose.

pyEarth

The resulting algorithm is:

- Use pyshp to read the shapefile
- Extract the shapes of the shapefile
- When a shape is a multipolygon, decompose it into multiple polygons with shapely
- Use pyproj to convert the shape's geodetic coordinates to carthesian coordinates
- Triangulate the polygon with the tesselation function
- Use OpenGL functions to create the polygon in the 3D space

Below is the algorithm implemented with the pyQt framework:

# function to extract the polygons (shapefile library) and convert multipolygons 
# into polygons when necessary (shapely library)
def extract_polygons(self):      
    polygons = shapefile.Reader(self.shapefile).shapes() 
    for polygon in polygons:
        polygon = shapely.geometry.shape(polygon)
        yield from [polygon] if polygon.geom_type == 'Polygon' else polygon
        
# function to convert coordinates from LLH to ECEF with pyproj
def LLH_to_ECEF(self, lat, lon, alt):
    ecef, llh = pyproj.Proj(proj='geocent'), pyproj.Proj(proj='latlong')
    x, y, z = pyproj.transform(llh, ecef, lon, lat, alt, radians=False)
    return x, y, z
      
# function that performs the tesselation process (polygon triangulation): 
# polygons are broken down into triangles
def polygon_tesselator(self, polygon):    
    vertices, tess = [], gluNewTess()
    gluTessCallback(tess, GLU_TESS_EDGE_FLAG_DATA, lambda *args: None)
    gluTessCallback(tess, GLU_TESS_VERTEX, lambda v: vertices.append(v))
    gluTessCallback(tess, GLU_TESS_COMBINE, lambda v, *args: v)
    gluTessCallback(tess, GLU_TESS_END, lambda: None)
    
    gluTessBeginPolygon(tess, 0)
    gluTessBeginContour(tess)
    for lon, lat in polygon.exterior.coords:
        point = self.LLH_to_ECEF(lat, lon, 0)
        gluTessVertex(tess, point, point)
    gluTessEndContour(tess)
    gluTessEndPolygon(tess)
    gluDeleteTess(tess)
    return vertices
    
# finally, we extract the polygons, triangulate them, and use OpenGL functions
# to create the triangles in the 3D space
def create_polygons(self):
    self.polygons = glGenLists(1)
    glNewList(self.polygons, GL_COMPILE)
    for polygon in self.extract_polygons():
        glColor(0, 255, 0)
        glBegin(GL_TRIANGLES)
        for vertex in self.polygon_tesselator(polygon):
            glVertex(*vertex)
        glEnd()
    glEndList()

pyEarth dependencies

pyQt5 is required: it can be download from the Riverband website

PyEarth relies on three Python libraries:

  • pyshp, used for reading shapefiles.
  • shapely, used for converting a multipolygon into a set of polygons
  • pyproj, used for translating geographic coordinates (longitude and latitude) into projected coordinates

Before using pyEarth, you must make sure all these libraries are properly installed:

pip install -r requirements

pyearth's People

Contributors

afourmy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyearth's Issues

solid polygon with tesselations

Only convex polygons can be filled in openGl (i.e neither concave, nor multipolygons).
All polygons must be decomposed into triangles (polygon triangulation) with GLU tesselation.

    def create_polygons(self):
        self.polygons = glGenLists(1)
        glNewList(self.polygons, GL_COMPILE)
        for polygon in self.draw_polygons():
            glColor(0, 255, 0)
            vertices = self.triangulate(polygon)
            glBegin(GL_TRIANGLES)
            for vertex in vertices:
                glVertex(*vertex)
            glEnd()
            # glBegin(GL_POLYGON)
            # for (lon, lat) in polygon:
            #     glVertex3f(*self.LLH_to_ECEF(lat, lon, 1))
            # glEnd()
        glEndList()
        
    def triangulate(self, polygon):
        vertices = []
        
        def edgeFlagCallback(param1, param2): pass
        def beginCallback(param=None):
            vertices = []
        def vertexCallback(vertex, otherData=None):
            vertices.append(vertex)
        def endCallback(data=None): pass
    
        tess = gluNewTess()
        gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD)
        gluTessCallback(tess, GLU_TESS_EDGE_FLAG_DATA, edgeFlagCallback)
        gluTessCallback(tess, GLU_TESS_BEGIN, beginCallback)
        gluTessCallback(tess, GLU_TESS_VERTEX, vertexCallback)
        gluTessCallback(tess, GLU_TESS_END, endCallback)
        
        gluTessBeginPolygon(tess, 0)
        gluTessBeginContour(tess)
        for (lon, lat) in polygon:
            x, y, z = self.LLH_to_ECEF(lat, lon, 1)
            point3d = (x, y, z)
            gluTessVertex(tess, point3d, point3d)
        gluTessEndContour(tess)
        gluTessEndPolygon(tess)
        gluDeleteTess(tess)
        return vertices
        
    def draw_polygons(self):
        sf = shapefile.Reader(self.shapefile)       
        polygons = sf.shapes() 
        for polygon in polygons:
            polygon = shapely.geometry.shape(polygon)
            if polygon.geom_type == 'Polygon':
                polygon = [polygon]
            for land in polygon:
                longitudes, latitudes = land.exterior.coords.xy
                yield zip(longitudes, latitudes)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.