mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-10-31 17:21:34 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			500 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			500 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
| {
 | |
| lasvectorialreader.pas
 | |
| 
 | |
| Reads geospatial data encoded in the ASPRS LASer (LAS) file format version 1.3
 | |
| 
 | |
| LAS file format specification obtained from:
 | |
| 
 | |
| http://www.asprs.org/a/society/committees/standards/lidar_exchange_format.html
 | |
| LAS 1.3 r11
 | |
| 
 | |
| All data is in little-endian format.
 | |
| 
 | |
| AUTHORS: Felipe Monteiro de Carvalho
 | |
| 
 | |
| License: The same modified LGPL as the Free Pascal RTL
 | |
|          See the file COPYING.modifiedLGPL for more details
 | |
| }
 | |
| unit lasvectorialreader;
 | |
| 
 | |
| {$ifdef fpc}
 | |
|   {$mode delphi}
 | |
| {$endif}
 | |
| 
 | |
| {$define FPVECTORIALDEBUG_LAS}
 | |
| 
 | |
| interface
 | |
| 
 | |
| uses
 | |
|   Classes, SysUtils, dateutils,
 | |
|   fpcanvas, fpimage,
 | |
|   //avisozlib,
 | |
|   fpvectorial;
 | |
| 
 | |
| type
 | |
|   // LAS data types introduced in LAS 1.0
 | |
|   laschar = AnsiChar; // or ShortInt
 | |
|   lasuchar = Byte;
 | |
|   lasshort = Smallint;
 | |
|   lasushort = Word;
 | |
|   laslong = Integer;
 | |
|   lasulong = Cardinal;
 | |
|   lasdouble = double;
 | |
|   //
 | |
|   laslonglong = Int64;
 | |
|   lasulonglong = QWord;
 | |
| 
 | |
|   // PUBLIC HEADER BLOCK version 1.0
 | |
|   TLASPublicHeaderBlock_1_0 = packed record
 | |
|     FileSignatureLASF: array[0..3] of laschar;
 | |
|     FileSourceID: lasushort;                    // Reserved in LAS 1.0
 | |
|     GlobalEncoding: lasushort;                  // Reserved in LAS 1.0
 | |
|     ProjectIDGUIDdata1: lasulong;               // Optional
 | |
|     ProjectIDGUIDdata2: lasushort;              // Optional
 | |
|     ProjectIDGUIDdata3: lasushort;              // Optional
 | |
|     ProjectIDGUIDdata4: array[0..7] of lasuchar;// Optional
 | |
|     VersionMajor: lasuchar;
 | |
|     VersionMinor: lasuchar;
 | |
|     SystemIdentifier: array[0..31] of laschar;
 | |
|     GeneratingSoftware: array[0..31] of laschar;
 | |
|     FileCreationDayofYear: lasushort;           // Name in LAS 1.0 -> FlightDateJulian, but same meaning
 | |
|     FileCreationYear: lasushort;                // Name in LAS 1.0 -> Year, but same meaning
 | |
|     HeaderSize: lasushort;                      // Name in LAS 1.0 -> OffsetToData
 | |
|     OffsetToPointData: lasulong;
 | |
|     NumberofVariableLengthRecords: lasulong;
 | |
|     PointDataFormatID: lasuchar; // (0-99 for spec)
 | |
|     PointDataRecordLength: lasushort;
 | |
|     Numberofpointrecords: lasulong;
 | |
|     Numberofpointsbyreturn: array[0..4] of lasulong;
 | |
|     Xscalefactor: lasdouble;
 | |
|     Yscalefactor: lasdouble;
 | |
|     Zscalefactor: lasdouble;
 | |
| 
 | |
|     Xoffset: lasdouble;
 | |
|     Yoffset: lasdouble;
 | |
|     Zoffset: lasdouble;
 | |
|     MaxX: lasdouble;
 | |
|     MinX: lasdouble;
 | |
|     MaxY: lasdouble;
 | |
|     MinY: lasdouble;
 | |
|     MaxZ: lasdouble;
 | |
|     MinZ: lasdouble;
 | |
|   end;
 | |
| 
 | |
|   // PUBLIC HEADER BLOCK Extension in Version 1.3
 | |
|   TLASPublicHeaderBlock_1_3_Extension = packed record
 | |
|     StartofWaveformDataPacket: lasulonglong;
 | |
|   end;
 | |
| 
 | |
|   TLASVariableLengthRecord = packed record
 | |
|     RecordSignatureAABB: lasushort;
 | |
|     UserID: array[0..15] of laschar;
 | |
|     RecordID: lasushort;
 | |
|     RecordLengthAfterHeader: lasushort;
 | |
|     Description: array[0..31] of laschar;
 | |
|   end;
 | |
| 
 | |
|   // Points are split in the following atoms for compression:
 | |
|   // POINT10, GPSTIME10, RGB12, WAVEPACKET13, and BYTE
 | |
|   // for the LAZ format
 | |
| 
 | |
|   // Contains POINT10
 | |
|   TLASPointDataRecordFormat0 = packed record
 | |
|     X: laslong;
 | |
|     Y: laslong;
 | |
|     Z: laslong;
 | |
|     Intensity: lasushort;
 | |
|     Flags: Byte;
 | |
|     Classification: lasuchar;
 | |
|     ScanAngleRank: lasuchar; // (-90 to +90) - is the left side
 | |
|     FileMarker: lasuchar;
 | |
|     UserBitField: lasushort;
 | |
|   end;
 | |
| 
 | |
|   // Contains POINT10 + GPSTIME10
 | |
|   TLASPointDataRecordFormat1 = packed record
 | |
|     X: laslong;
 | |
|     Y: laslong;
 | |
|     Z: laslong;
 | |
|     Intensity: lasushort;
 | |
|     Flags: Byte;
 | |
|     Classification: lasuchar;
 | |
|     ScanAngleRank: lasuchar; // (-90 to +90) - is the left side
 | |
|     FileMarker: lasuchar;
 | |
|     UserBitField: lasushort;
 | |
|     GPSTime: lasdouble;
 | |
|   end;
 | |
| 
 | |
|   { TvLASVectorialReader }
 | |
| 
 | |
|   TvLASVectorialReader = class(TvCustomVectorialReader)
 | |
|   protected
 | |
|     // Stream position information
 | |
|     InitialPos, PositionAfterPublicHeader: Int64;
 | |
|     {$ifdef FPVECTORIALDEBUG_LAS}
 | |
|     procedure DebugOutPublicHeaderBlock();
 | |
|     {$endif}
 | |
|     procedure ReadVariableLengthRecords(AStream: TStream);
 | |
|     procedure DoProgress(AProgress: Byte; AData: TvVectorialDocument);
 | |
|     function ReadLAZPoint0(AStream: TStream): TLASPointDataRecordFormat0;
 | |
|   public
 | |
|     // Public Header
 | |
|     PublicHeaderBlock_1_0: TLASPublicHeaderBlock_1_0;
 | |
|     PublicHeaderBlock_1_3_Extension: TLASPublicHeaderBlock_1_3_Extension;
 | |
|     // Variable Length Records
 | |
|     VariableLengthRecords: array of TLASVariableLengthRecord;
 | |
|     // Point Data
 | |
|     PointsFormat0: array of TLASPointDataRecordFormat0;
 | |
|     PointsFormat1: array of TLASPointDataRecordFormat1;
 | |
|     { General reading methods }
 | |
|     procedure ReadFromStream(AStream: TStream; AData: TvVectorialDocument); override;
 | |
|   end;
 | |
| 
 | |
|   { TvLASVectorialWriter }
 | |
| 
 | |
|   TvLASVectorialWriter = class(TvCustomVectorialWriter)
 | |
|   private
 | |
|     // Stream position information
 | |
|     InitialPos, PositionAfterPublicHeader: Int64;
 | |
|   public
 | |
|     // Public Header
 | |
|     PublicHeaderBlock_1_0: TLASPublicHeaderBlock_1_0;
 | |
|     PublicHeaderBlock_1_3_Extension: TLASPublicHeaderBlock_1_3_Extension;
 | |
|     // Variable Length Records
 | |
|     VariableLengthRecords: array of TLASVariableLengthRecord;
 | |
|     // Point Data
 | |
|     PointsFormat0: array of TLASPointDataRecordFormat0;
 | |
|     PointsFormat1: array of TLASPointDataRecordFormat1;
 | |
|     { General reading methods }
 | |
|     procedure WriteToStream(AStream: TStream; AData: TvVectorialDocument); override;
 | |
|   end;
 | |
| 
 | |
| implementation
 | |
| 
 | |
| { TvLASVectorialWriter }
 | |
| 
 | |
| procedure TvLASVectorialWriter.WriteToStream(AStream: TStream;
 | |
|   AData: TvVectorialDocument);
 | |
| var
 | |
|   lPage: TvVectorialPage;
 | |
|   lRecord0: TLASPointDataRecordFormat0;
 | |
|   lRecord1: TLASPointDataRecordFormat1;
 | |
|   lPoint: TvPoint;
 | |
|   lColor: TFPColor;
 | |
|   lCreationDate: TDateTime;
 | |
|   lEntity: TvEntity;
 | |
|   i: Integer;
 | |
| begin
 | |
|   // Get the first page
 | |
|   lPage := AData.GetPageAsVectorial(0);
 | |
|   lCreationDate := Now;
 | |
| 
 | |
|   // Write our LAS 1.0 header
 | |
|   FillChar(PublicHeaderBlock_1_0, SizeOf(PublicHeaderBlock_1_0), #0);
 | |
|   PublicHeaderBlock_1_0.FileSignatureLASF := 'LASF';
 | |
|   PublicHeaderBlock_1_0.FileSourceID := 0;
 | |
|   PublicHeaderBlock_1_0.GlobalEncoding := 0;
 | |
|   PublicHeaderBlock_1_0.ProjectIDGUIDdata1 := 0;
 | |
|   PublicHeaderBlock_1_0.ProjectIDGUIDdata2 := 0;
 | |
|   PublicHeaderBlock_1_0.ProjectIDGUIDdata3 := 0;
 | |
|   // PublicHeaderBlock_1_0.ProjectIDGUIDdata4 all zero
 | |
|   PublicHeaderBlock_1_0.VersionMajor := 1;
 | |
|   PublicHeaderBlock_1_0.VersionMinor := 0;
 | |
|   PublicHeaderBlock_1_0.SystemIdentifier := '';
 | |
|   PublicHeaderBlock_1_0.GeneratingSoftware := 'FPSpreadsheet';
 | |
|   PublicHeaderBlock_1_0.FileCreationDayofYear := DayOfTheYear(lCreationDate);
 | |
|   PublicHeaderBlock_1_0.FileCreationYear := YearOf(lCreationDate);
 | |
|   PublicHeaderBlock_1_0.HeaderSize := SizeOf(PublicHeaderBlock_1_0);
 | |
|   PublicHeaderBlock_1_0.OffsetToPointData := SizeOf(PublicHeaderBlock_1_0);
 | |
|   PublicHeaderBlock_1_0.NumberofVariableLengthRecords := 0;
 | |
|   PublicHeaderBlock_1_0.PointDataFormatID := 1;
 | |
|   PublicHeaderBlock_1_0.PointDataRecordLength := $1C;
 | |
|   PublicHeaderBlock_1_0.Numberofpointrecords := lPage.GetEntitiesCount;
 | |
|   PublicHeaderBlock_1_0.Numberofpointsbyreturn[0] := 0;
 | |
|   PublicHeaderBlock_1_0.Numberofpointsbyreturn[1] := 0;
 | |
|   PublicHeaderBlock_1_0.Numberofpointsbyreturn[2] := 0;
 | |
|   PublicHeaderBlock_1_0.Numberofpointsbyreturn[3] := 0;
 | |
|   PublicHeaderBlock_1_0.Numberofpointsbyreturn[4] := 0;
 | |
|   PublicHeaderBlock_1_0.Xscalefactor := 1;
 | |
|   PublicHeaderBlock_1_0.Yscalefactor := 1;
 | |
|   PublicHeaderBlock_1_0.Zscalefactor := 1;
 | |
| 
 | |
|   PublicHeaderBlock_1_0.Xoffset := 0;
 | |
|   PublicHeaderBlock_1_0.Yoffset := 0;
 | |
|   PublicHeaderBlock_1_0.Zoffset := 0;
 | |
|   PublicHeaderBlock_1_0.MaxX := lPage.MaxX;
 | |
|   PublicHeaderBlock_1_0.MinX := lPage.MinX;
 | |
|   PublicHeaderBlock_1_0.MaxY := lPage.MaxY;
 | |
|   PublicHeaderBlock_1_0.MinY := lPage.MinY;
 | |
|   PublicHeaderBlock_1_0.MaxZ := lPage.MaxZ;
 | |
|   PublicHeaderBlock_1_0.MinZ := lPage.MinZ;
 | |
|   AStream.Write(PublicHeaderBlock_1_0, SizeOf(TLASPublicHeaderBlock_1_0));
 | |
| 
 | |
|   // Write the variable length records
 | |
|   // none currently
 | |
| 
 | |
|   // Write the point data
 | |
|   for i := 0 to lPage.GetEntitiesCount()-1 do
 | |
|   begin
 | |
|     lEntity := lPage.GetEntity(i);
 | |
|     if not (lEntity is TvPoint) then Continue;
 | |
|     lPoint := lEntity as TvPoint;
 | |
| 
 | |
|     FillChar(lRecord1, SizeOf(TLASPointDataRecordFormat1), #0);
 | |
|     lRecord1.X := Round(lEntity.X);
 | |
|     lRecord1.Y := Round(lEntity.Y);
 | |
|     lRecord1.Z := Round(lEntity.Z);
 | |
| 
 | |
|     // Convert the colors into LIDAR Point Classes
 | |
|     lColor := lPoint.Pen.Color;
 | |
|     // 2 Ground
 | |
|     if lColor = colMaroon then
 | |
|       lRecord1.Classification := 2
 | |
|     // 3 Low Vegetation
 | |
|     else if lColor = colGreen then
 | |
|       lRecord1.Classification := 3
 | |
|     // 4 Medium Vegetation
 | |
|     //4: lColor := colGreen;
 | |
|     // 5 High Vegetation
 | |
|     else if lColor = colDkGreen then
 | |
|       lRecord1.Classification := 5
 | |
|     // 6 Building
 | |
|     else if lColor = colGray then
 | |
|       lRecord1.Classification := 6
 | |
|     // 7 Low Point (noise)
 | |
|     // 8 Model Key-point (mass point)
 | |
|     // 9 Water
 | |
|     else if lColor = colBlue then
 | |
|       lRecord1.Classification := 9;
 | |
| 
 | |
|     AStream.Write(lRecord1, SizeOf(TLASPointDataRecordFormat1));
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| {$ifdef FPVECTORIALDEBUG_LAS}
 | |
| procedure TvLASVectorialReader.DebugOutPublicHeaderBlock;
 | |
| begin
 | |
|   WriteLn(Format('FileSignatureLASF = %s = %x %x %x %x',
 | |
|     [string(PublicHeaderBlock_1_0.FileSignatureLASF),
 | |
|      Ord(PublicHeaderBlock_1_0.FileSignatureLASF[0]),
 | |
|      Ord(PublicHeaderBlock_1_0.FileSignatureLASF[1]),
 | |
|      Ord(PublicHeaderBlock_1_0.FileSignatureLASF[2]),
 | |
|      Ord(PublicHeaderBlock_1_0.FileSignatureLASF[3])]));
 | |
|   WriteLn(Format('FileSourceID = $%x', [PublicHeaderBlock_1_0.FileSourceID]));
 | |
|   WriteLn(Format('GlobalEncoding = $%x', [PublicHeaderBlock_1_0.GlobalEncoding]));
 | |
|   WriteLn(Format('ProjectIDGUIDdata1 = $%x', [PublicHeaderBlock_1_0.ProjectIDGUIDdata1]));
 | |
|   WriteLn(Format('ProjectIDGUIDdata2 = $%x', [PublicHeaderBlock_1_0.ProjectIDGUIDdata2]));
 | |
|   WriteLn(Format('ProjectIDGUIDdata3 = $%x', [PublicHeaderBlock_1_0.ProjectIDGUIDdata3]));
 | |
| //  WriteLn(Format('ProjectIDGUIDdata4 = %x', [ProjectIDGUIDdata2]));
 | |
|   WriteLn(Format('VersionMajor = %d', [PublicHeaderBlock_1_0.VersionMajor]));
 | |
|   WriteLn(Format('VersionMinor = %d', [PublicHeaderBlock_1_0.VersionMinor]));
 | |
|   WriteLn(Format('SystemIdentifier = %s', [PublicHeaderBlock_1_0.SystemIdentifier]));
 | |
|   WriteLn(Format('GeneratingSoftware = %s', [PublicHeaderBlock_1_0.GeneratingSoftware]));
 | |
|   WriteLn(Format('FileCreationDayofYear = %d', [PublicHeaderBlock_1_0.FileCreationDayofYear]));
 | |
|   WriteLn(Format('FileCreationYear = %d', [PublicHeaderBlock_1_0.FileCreationYear]));
 | |
|   WriteLn(Format('HeaderSize = $%x', [PublicHeaderBlock_1_0.HeaderSize]));
 | |
|   WriteLn(Format('OffsetToPointData = $%x', [PublicHeaderBlock_1_0.OffsetToPointData]));
 | |
|   WriteLn(Format('NumberofVariableLengthRecords = $%x', [PublicHeaderBlock_1_0.NumberofVariableLengthRecords]));
 | |
|   WriteLn(Format('PointDataFormatID = $%x', [PublicHeaderBlock_1_0.PointDataFormatID]));
 | |
|   WriteLn(Format('PointDataRecordLength = $%x', [PublicHeaderBlock_1_0.PointDataRecordLength]));
 | |
|   WriteLn(Format('Numberofpointrecords = $%x', [PublicHeaderBlock_1_0.Numberofpointrecords]));
 | |
|   WriteLn(Format('Numberofpointsbyreturn = %x %x %x %x %x',
 | |
|     [PublicHeaderBlock_1_0.Numberofpointsbyreturn[0],
 | |
|      PublicHeaderBlock_1_0.Numberofpointsbyreturn[1],
 | |
|      PublicHeaderBlock_1_0.Numberofpointsbyreturn[2],
 | |
|      PublicHeaderBlock_1_0.Numberofpointsbyreturn[3],
 | |
|      PublicHeaderBlock_1_0.Numberofpointsbyreturn[4]
 | |
|      ]));
 | |
|   WriteLn(Format('Xscalefactor = %f', [PublicHeaderBlock_1_0.Xscalefactor]));
 | |
|   WriteLn(Format('Yscalefactor = %f', [PublicHeaderBlock_1_0.Yscalefactor]));
 | |
|   WriteLn(Format('Zscalefactor = %f', [PublicHeaderBlock_1_0.Zscalefactor]));
 | |
|   WriteLn(Format('Xoffset = %f', [PublicHeaderBlock_1_0.Xoffset]));
 | |
|   WriteLn(Format('Yoffset = %f', [PublicHeaderBlock_1_0.Yoffset]));
 | |
|   WriteLn(Format('Zoffset = %f', [PublicHeaderBlock_1_0.Zoffset]));
 | |
|   WriteLn(Format('MaxX = %f', [PublicHeaderBlock_1_0.MaxX]));
 | |
|   WriteLn(Format('MinX = %f', [PublicHeaderBlock_1_0.MinX]));
 | |
|   WriteLn(Format('MaxY = %f', [PublicHeaderBlock_1_0.MaxY]));
 | |
|   WriteLn(Format('MinY = %f', [PublicHeaderBlock_1_0.MinY]));
 | |
|   WriteLn(Format('MaxZ = %f', [PublicHeaderBlock_1_0.MaxZ]));
 | |
|   WriteLn(Format('MinZ = %f', [PublicHeaderBlock_1_0.MinZ]));
 | |
|   WriteLn('');
 | |
|   WriteLn(Format('LAS 1.0 header size = $%x', [SizeOf(TLASPublicHeaderBlock_1_0)]));
 | |
|   WriteLn('');
 | |
| end;
 | |
| {$endif}
 | |
| 
 | |
| procedure TvLASVectorialReader.ReadVariableLengthRecords(AStream: TStream);
 | |
| var
 | |
|   i: Integer;
 | |
|   NextPosition: Int64;
 | |
| begin
 | |
|   NextPosition := PositionAfterPublicHeader;
 | |
| 
 | |
|   SetLength(VariableLengthRecords, PublicHeaderBlock_1_0.NumberofVariableLengthRecords);
 | |
|   for i := 0 to PublicHeaderBlock_1_0.NumberofVariableLengthRecords - 1 do
 | |
|   begin
 | |
|     AStream.Position := NextPosition;
 | |
|     {$ifdef FPVECTORIALDEBUG_LAS}
 | |
|     WriteLn(Format('Variable Length Record #%d Position = $%x', [i, NextPosition]));
 | |
|     WriteLn('');
 | |
|     {$endif}
 | |
|     AStream.Read(VariableLengthRecords[i], SizeOf(TLASVariableLengthRecord));
 | |
|     NextPosition := AStream.Position+VariableLengthRecords[i].RecordLengthAfterHeader;
 | |
|     {$ifdef FPVECTORIALDEBUG_LAS}
 | |
|     WriteLn(Format('RecordSignatureAABB = $%x', [VariableLengthRecords[i].RecordSignatureAABB]));
 | |
|     WriteLn(Format('UserID = %s', [VariableLengthRecords[i].UserID]));
 | |
|     WriteLn(Format('RecordID = $%x', [VariableLengthRecords[i].RecordID]));
 | |
|     WriteLn(Format('RecordLengthAfterHeader = $%x', [VariableLengthRecords[i].RecordLengthAfterHeader]));
 | |
|     WriteLn(Format('Description = %s', [VariableLengthRecords[i].Description]));
 | |
|     WriteLn('');
 | |
|     {$endif}
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| procedure TvLASVectorialReader.DoProgress(AProgress: Byte; AData: TvVectorialDocument);
 | |
| begin
 | |
|   if @AData.OnProgress <> nil then AData.OnProgress(AProgress);
 | |
| end;
 | |
| 
 | |
| function TvLASVectorialReader.ReadLAZPoint0(AStream: TStream
 | |
|   ): TLASPointDataRecordFormat0;
 | |
| begin
 | |
| 
 | |
| end;
 | |
| 
 | |
| procedure TvLASVectorialReader.ReadFromStream(AStream: TStream;
 | |
|   AData: TvVectorialDocument);
 | |
| var
 | |
|   lPage: TvVectorialPage;
 | |
|   lRecord0: TLASPointDataRecordFormat0;
 | |
|   lRecord1: TLASPointDataRecordFormat1;
 | |
|   lFirstPoint: Boolean = True;
 | |
|   lPoint: TvPoint;
 | |
|   lClassification: Integer = -1;
 | |
|   lColor: TFPColor;
 | |
|   lPointsCounter: Integer = 0;
 | |
| begin
 | |
|   // Clear and add the first page
 | |
|   AData.Clear;
 | |
|   lPage := AData.AddPage();
 | |
| 
 | |
|   // First read the header like if it was for LAS 1.0,
 | |
|   // this will tell us the real version so then we read it again
 | |
|   InitialPos := AStream.Position;
 | |
|   AStream.Read(PublicHeaderBlock_1_0, SizeOf(TLASPublicHeaderBlock_1_0));
 | |
|   {$ifdef FPVECTORIALDEBUG_LAS}
 | |
|   DebugOutPublicHeaderBlock();
 | |
|   {$endif}
 | |
| 
 | |
|   // First check the signature
 | |
|   if PublicHeaderBlock_1_0.FileSignatureLASF <> 'LASF' then
 | |
|     raise Exception.Create('[TvLASVectorialReader.ReadFromStream] Invalid file signoture while reading LAS file');
 | |
| 
 | |
|   lPage.MinX := PublicHeaderBlock_1_0.MinX;
 | |
|   lPage.MinY := PublicHeaderBlock_1_0.MinY;
 | |
|   lPage.MinZ := PublicHeaderBlock_1_0.MinZ;
 | |
|   lPage.MaxX := PublicHeaderBlock_1_0.MaxX;
 | |
|   lPage.MaxY := PublicHeaderBlock_1_0.MaxY;
 | |
|   lPage.MaxZ := PublicHeaderBlock_1_0.MaxZ;
 | |
| 
 | |
|   // In LAS 1.3+ read the header extension
 | |
|   // ToDo
 | |
| 
 | |
|   PositionAfterPublicHeader := AStream.Position;
 | |
| 
 | |
|   // Read the variable length records
 | |
|   ReadVariableLengthRecords(AStream);
 | |
| 
 | |
|   // Read the point data
 | |
|   AStream.Position := InitialPos + PublicHeaderBlock_1_0.OffsetToPointData;
 | |
|   while AStream.Position < AStream.Size do
 | |
|   begin
 | |
|     // Send a progress event every 1k points
 | |
|     Inc(lPointsCounter);
 | |
|     if lPointsCounter mod 1000 = 0 then
 | |
|       DoProgress(Round(AStream.Position * 100 / AStream.Size), AData);
 | |
| 
 | |
|     // hack to cut las files: if lPage.GetEntitiesCount = 100000 then Exit;
 | |
|     case PublicHeaderBlock_1_0.PointDataFormatID of
 | |
|     0:
 | |
|     begin
 | |
|       AStream.ReadBuffer(lRecord0, SizeOf(TLASPointDataRecordFormat0));
 | |
|       lClassification := lRecord0.Classification;
 | |
|       lPoint := lPage.AddPoint(lRecord0.X, lRecord0.Y, lRecord0.Z);
 | |
|     end;
 | |
|     1:
 | |
|     begin
 | |
|       AStream.ReadBuffer(lRecord1, SizeOf(TLASPointDataRecordFormat1));
 | |
|       lClassification := lRecord1.Classification;
 | |
|       lPoint := lPage.AddPoint(lRecord1.X, lRecord1.Y, lRecord1.Z);
 | |
|     end;
 | |
|     130:
 | |
|     begin
 | |
|       lRecord0 := ReadLAZPoint0(AStream);
 | |
|       lClassification := lRecord0.Classification;
 | |
|       lPoint := lPage.AddPoint(lRecord0.X, lRecord0.Y, lRecord0.Z);
 | |
|     end;
 | |
|     else
 | |
|       raise Exception.Create('[TvLASVectorialReader.ReadFromStream] Error reading LAS point: Unknown point type number='
 | |
|        + IntToStr(PublicHeaderBlock_1_0.PointDataFormatID));
 | |
|     end;
 | |
| 
 | |
|     // Correct the min and max
 | |
|     if lFirstPoint then
 | |
|     begin
 | |
|       lPage.MinX := lPoint.X;
 | |
|       lPage.MinY := lPoint.Y;
 | |
|       lPage.MinZ := lPoint.Z;
 | |
|       lPage.MaxX := lPoint.X;
 | |
|       lPage.MaxY := lPoint.Y;
 | |
|       lPage.MaxZ := lPoint.Z;
 | |
| 
 | |
|       lFirstPoint := False;
 | |
|     end
 | |
|     else
 | |
|     begin
 | |
|       if lPage.MinX > lPoint.X then lPage.MinX := lPoint.X;
 | |
|       if lPage.MinY > lPoint.Y then lPage.MinY := lPoint.Y;
 | |
|       if lPage.MinZ > lPoint.Z then lPage.MinZ := lPoint.Z;
 | |
|       if lPage.MaxX < lPoint.X then lPage.MaxX := lPoint.X;
 | |
|       if lPage.MaxY < lPoint.Y then lPage.MaxY := lPoint.Y;
 | |
|       if lPage.MaxZ < lPoint.Z then lPage.MaxZ := lPoint.Z;
 | |
|     end;
 | |
| 
 | |
|     // Set a color if desired
 | |
|     case lClassification of
 | |
|     // Table 4.9 - ASPRS Standard LIDAR Point Classes
 | |
|     // Classification Value
 | |
|     // 0 Created, never classified
 | |
|     // 1 Unclassified1
 | |
|     // 2 Ground
 | |
|     2: lColor := colMaroon;
 | |
|     // 3 Low Vegetation
 | |
|     3: lColor := colGreen;
 | |
|     // 4 Medium Vegetation
 | |
|     4: lColor := colGreen;
 | |
|     // 5 High Vegetation
 | |
|     5: lColor := colDkGreen;
 | |
|     // 6 Building
 | |
|     6: lColor := colGray;
 | |
|     // 7 Low Point (noise)
 | |
|     // 8 Model Key-point (mass point)
 | |
|     // 9 Water
 | |
|     9: lColor := colBlue;
 | |
|     else
 | |
|       lColor := colBlack;
 | |
|     end;
 | |
| 
 | |
|     lPoint.Pen.Color := lColor;
 | |
|   end;
 | |
| end;
 | |
| 
 | |
| initialization
 | |
| 
 | |
|   RegisterVectorialReader(TvLASVectorialReader, vfLAS);
 | |
|   RegisterVectorialWriter(TvLASVectorialWriter, vfLAS);
 | |
|   RegisterVectorialReader(TvLASVectorialReader, vfLAZ);
 | |
| 
 | |
| end.
 | |
| 
 | 
