Reading .shp Files

To write a program to open shape editor (.shp) files, you need to be able to read a binary file, process the information and render the vector graphics.

For users of Visual Basic and FreeBASIC, a simple source file with these capabilities is provided.

VB6 Version: modMinimalShapeAPI.bas (19.7 KB)

VB.NET Version: modMinimalShapeAPI.vb (16.4 KB)

FreeBASIC Version: fbMinimalShapeAPI.bas (19.1 KB)

For C programmers using GCC, it may be possable to build the FreeBASIC version as a static library, and use it in a C program.
http://www.freebasic.net/wiki/wikka.php?wakka=TutUsingLibrariesWithGCC

For example the following code samples will create a program that attempts to open a Shape Editor file named 'ShpFile.shp' from the project folder and draw it on a window.

VB6
Create a 'Standard .EXE' project in VB6, add 'modMinimalShapeAPI.bas' to the project and copy the following code to the form:
Dim SD As BShapeData, SH As BShapeHeader, GDIArray() As GDIShape

Private Sub Form_Load()
    LoadShapeFile SD, SH, App.Path & "\ShpFile.shp"
    ComputeGDIShapes SD, SH, GDIArray
End Sub

Private Sub Form_Paint()
    Dim I As Long
    For I = 1 To UBound(GDIArray)
        HdcDrawGDIShape Me.hdc, GDIArray(I)
    Next I
End Sub

VB.NET
Create a new 'Windows Application' project in VB.NET, add 'modMinimalShapeAPI.vb' to the project and copy the following code to the form class after the designer generated code:
Dim SD As BShapeData, SH As BShapeHeader, GDIArray() As GDIShape

Private Sub Form1_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load
    LoadShapeFile(SD, SH, "ShpFile.shp")
    ComputeGDIShapes(SD, SH, GDIArray)
End Sub

Private Sub Form1_Paint(ByVal eventSender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
    Dim I As Integer
    For I = 1 To UBound(GDIArray)
        GraphicsDrawGDIShape(e.Graphics, GDIArray(I))
    Next I
End Sub

FreeBASIC
Create a .bas file containing the following code, place fbMinimalShapeAPI.bas in the same folder and make sure you have the runtime files for the cairo vector graphics library.
#Include Once "cairo/cairo.bi"
#Include Once "fbMinimalShapeAPI.bas"

Dim SD As BShapeData, SH As BShapeHeader, DrawArray() As DrawShape
Dim ErrStr As String, cairo_surface As cairo_surface_t Ptr, cr As cairo_t Ptr

'Load a shape file and obtain a drawable representation of it
ErrStr = LoadShapeFile(SD, SH, "ShpFile.shp")
ComputeDrawShapes(SD, SH, DrawArray())

'Obtain a blank white cairo surface on which to draw
ScreenRes SH.ScreenWidth, SH.ScreenHeight, 32
ScreenLock
cairo_surface = cairo_image_surface_create_for_data(ScreenPtr, _
                CAIRO_FORMAT_ARGB32, SH.ScreenWidth, _
                SH.ScreenHeight, SH.ScreenWidth*Len(Integer))
cr = cairo_create(cairo_surface)
cairo_set_source_rgba(cr, 1, 1, 1, 1)
cairo_paint(cr)

'Draw all the objects in the Shape Editor file
Dim I As Integer
For I = 1 To UBound(DrawArray)
    CairoDrawShape(cr, DrawArray(I))
Next I

'Free resources and pause the program
cairo_destroy(cr)
ScreenUnLock

Sleep

Internal Representation of Shapes

As can be seen inside the ShapeAPI file, the basic representation in Shape Editor is Shapes (BShape) composed of Curves (CurvePoints) composed of Points (DoublePoint). In every shape file their is an array for each of these, as seen in the BShapeData structure. These 3 arrays do not use the element at index 0, thus they are defined empty when when their upper bound index (UBound) is 0.
Public Type DoublePoint
    X As Double
    Y As Double
End Type

Public Type CurvePoints
    InplPt() As Long 'lpPoint
    NextTanContCurve As Long 'lpCurve
    PrevTanContCurve As Long 'lpCurve
End Type

Public Type BShape
    Seg() As Long 'lpCurve
    Color As Long
    CurveThickness As Long
    LineColor As Long
    
    Closed As Boolean
    ShadeShape As Long 'lpShape
End Type

Public Type BShapeData
    PointArray() As DoublePoint
    CurveArray() As CurvePoints
    ShapeArray() As BShape
End Type
Every Shape in the ShapeArray has an array of indices into the CurveArray, specifying which curves belong to that Shape. Every Shape must have at least one Curve. Every Curve has an array of indicies into the PointArray specifying which points compose that particular curve. Every Curve must have at least 2 points, additionally Curves store indices to adjacent curves with which they are tangent continuous. The convention for adjacent curve indicies is that they are positive if they are in conventional order, ie Curve->Next->Prev = Curve. However, if they are in reversed order, then the indices are negative the correct value to indicate this, ex: Curve->Next->Next = Curve.

Shape Edit Main