unit shapefiles;
interface
uses
Classes, SysUtils;
type
TSHPFileHeader =
packed record
// Big Endian
FileCode : LongInt;
Unused1,
Unused2,
Unused3,
Unused4,
Unused5 : LongInt;
FileLen : LongInt;
// Little Endian
Version : LongInt;
ShapeType: LongInt;
Xmin : Double;
Ymin : Double;
Xmax : Double;
Ymax : Double;
Zmin : Double;
Zmax : Double;
Mmin : Double;
Mmax : Double;
end;
TRecordHeader =
packed record
Nummer: LongInt;
// Big Endian
Laenge: LongInt;
// Big Endian
end;
TBox =
Array[0..3]
of Double;
TPunkt =
packed record
ID : LongInt;
X : Double;
Y : Double;
end;
TPunktXY =
record
X, Y : Double;
end;
TPolyLine =
record
ShapeType : LongInt;
Box : TBox;
NumParts : LongInt;
NumPoints : LongInt;
Parts :
Array Of LongInt;
Points :
Array Of TPunktXY;
end;
TPolyHeader =
packed record
Shapetype : LongInt;
Box : TBox;
NumParts : LongInt;
NumPoints : LongInt;
end;
TPolyContent =
packed record
Parts :
Array of LongInt;
Points :
Array of TPunktXY;
end;
TShapefile =
class
protected
FErrMsg:
string;
FError : Boolean;
procedure ReadFromStream(Stream : TFileStream);
public
FileHeader : TSHPFileHeader;
PLHead : TPolyHeader;
PLContent : TPolyContent;
Punkte :
array Of TPunkt;
PolyLinien :
array of TPolyLine;
procedure AddPoint (ID : LongInt; X, Y : Double);
procedure AddPLPart (ID : LongInt; zahl : LongInt);
procedure LoadSHP(
const AFilename :
string);
property ErrMsg:
string read FErrMsg;
property Error: Boolean
read FError;
end;
const
shpNullShape = 0;
shpPoint = 1;
shpPolyLine = 3;
shpPolygon = 5;
shpMultiPoint = 8;
shpPointZ = 11;
shpPolyLineZ = 13;
shpPolygonZ = 15;
shpMultiPointZ = 18;
shpPointM = 21;
shpPolyLineM = 23;
shpPolygonM = 25;
shpMultiPointM = 28;
shpMultiPatch = 31;
sizeHeader = 100;
implementation
function ChangeEndian32(AValue: LongWord): LongWord;
register;
asm
bswap EAX
// konvertiert Reienfolge der Byte
end;
procedure TShapeFile.AddPoint(ID: LongInt; X, Y: Double);
begin
SetLength(Punkte,Length(Punkte)+1);
Punkte[High(Punkte)].ID := ID;
Punkte[High(Punkte)].X := X;
Punkte[High(Punkte)].Y := Y;
end;
procedure TShapeFile.AddPLPart (ID : LongInt; zahl : LongInt);
begin
//if (High(PolyLinien)<ID) then SetLength(PolyLinien,ID+1);
//
end;
procedure TShapefile.ReadFromStream(Stream : TFileStream);
var
In_Punkt : TPunkt;
index : integer;
RecordHeader : TRecordHeader;
begin
FError := False;
FErrmsg := '
';
// Lies den Header des Shapefiles ein
try
Stream.ReadBuffer(FileHeader,SizeOf(FileHeader));
except
FError := True;
FErrmsg := '
Kein gültiges ESRI-Shapefile!';
Exit;
end;
// Big Endian in Little Endian umwandeln
FileHeader.FileCode := ChangeEndian32(FileHeader.FileCode);
FileHeader.FileLen := ChangeEndian32(FileHeader.FileLen);
// Records einlesen
Index := 0;
try
repeat
index:=index+1;
Stream.ReadBuffer(RecordHeader, SizeOf(RecordHeader));
// Big Endian
RecordHeader.Nummer := ChangeEndian32(RecordHeader.Nummer);
RecordHeader.Laenge := ChangeEndian32(RecordHeader.Laenge);
case FileHeader.ShapeType
of
1:
// Punkt - Shapefile
begin
Stream.
Read(In_Punkt, SizeOf(In_Punkt));
AddPoint(RecordHeader.Nummer, In_Punkt.X, In_Punkt.Y);
end;
3:
// PolyLine - Shapefile
begin
SetLength(PolyLinien,
index);
Stream.ReadBuffer(PLHead, SizeOf(PLHead));
SetLength(PLContent.Parts, PLHead.NumParts);
SetLength(PLContent.Points, PLHead.NumPoints);
Stream.ReadBuffer(PLContent.Parts[0],
SizeOf(PLContent.Parts[0]) * PLHead.NumParts);
Stream.ReadBuffer(PLContent.Points[0],
SizeOf(PLContent.Points[0]) * PLHead.NumPoints);
end;
end;
until (Stream.Position >= (FileHeader.FileLen * 2));
// da Filesize in Word =
// 16-Bit = 2 Bytes angegeben wird
except
FError := True;
FErrmsg := '
Fehler beim Einlesen der einzelnen Elemente bei ID : ' + IntToStr(RecordHeader.Nummer);
Exit;
end;
end;
procedure TShapefile.LoadSHP(
const AFilename :
string);
var
Stream : TFileStream;
begin
Stream := TFileStream.Create(AFilename, fmOpenRead);
try
ReadFromStream(Stream);
finally
Stream.Free;
end;
end;
end.