From c1528bbfe1af905475afeaae1ae79690e63f7e8c Mon Sep 17 00:00:00 2001
From: Vellu Sorvari <70940730+Kuoste@users.noreply.github.com>
Date: Tue, 10 Mar 2026 14:34:58 +0200
Subject: [PATCH 1/2] Migrate WritePoint to unsafe native pointer and split
LasPoint.cs
- Extract LasZipPointNative to its own file with new WriteFromLasPoint method
- Extract LasZipPointStruct to its own file, marked [Obsolete]
- Rewrite WritePoint to use LasZipPointNative* instead of Marshal.StructureToPtr
- Remove legacy ConvertPoint(LasZipPointStruct) overload from LasPoint
- Fix bug where old WritePoint mutated caller's point coordinates
Closes #11
---
LasZipNetStandard/LasPoint.cs | 176 +++----------------------
LasZipNetStandard/LasZip.cs | 81 +++++++++---
LasZipNetStandard/LasZipPointNative.cs | 155 ++++++++++++++++++++++
LasZipNetStandard/LasZipPointStruct.cs | 140 ++++++++++++++++++++
4 files changed, 378 insertions(+), 174 deletions(-)
create mode 100644 LasZipNetStandard/LasZipPointNative.cs
create mode 100644 LasZipNetStandard/LasZipPointStruct.cs
diff --git a/LasZipNetStandard/LasPoint.cs b/LasZipNetStandard/LasPoint.cs
index 1c46419..933b74a 100644
--- a/LasZipNetStandard/LasPoint.cs
+++ b/LasZipNetStandard/LasPoint.cs
@@ -1,9 +1,8 @@
-using System;
-using System.Runtime.InteropServices;
+using System;
+using System.Runtime.CompilerServices;
namespace Kuoste.LasZipNetStandard
{
-
public class LasPoint
{
public double X { get; set; }
@@ -23,24 +22,25 @@ public class LasPoint
public ushort Green { get; set; }
public ushort Blue { get; set; }
- internal static void ConvertPoint(LasZipPointStruct pointStruct, ref LasPoint lasPoint)
- {
- lasPoint.X = pointStruct.X;
- lasPoint.Y = pointStruct.Y;
- lasPoint.Z = pointStruct.Z;
- lasPoint.Intensity = pointStruct.Intensity;
- lasPoint.ReturnNumber = pointStruct.ReturnNumber;
- lasPoint.NumberOfReturns = pointStruct.NumberOfReturns;
- lasPoint.ScanDirectionFlag = pointStruct.ScanDirectionFlag;
- lasPoint.EdgeOfFlightLine = pointStruct.EdgeOfFlightLine;
- lasPoint.Classification = pointStruct.Classification;
- lasPoint.ScanAngleRank = pointStruct.ScanAngleRank;
- lasPoint.UserData = pointStruct.UserData;
- lasPoint.PointSourceId = pointStruct.PointSourceID;
- lasPoint.GpsTime = pointStruct.GpsTime;
- lasPoint.Red = pointStruct.Rgb[0];
- lasPoint.Green = pointStruct.Rgb[1];
- lasPoint.Blue = pointStruct.Rgb[2];
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe void ConvertPoint(LasZipPointNative* pointStruct, ref LasPoint lasPoint, double scaleFactorX, double scaleFactorY, double scaleFactorZ, double offsetX, double offsetY, double offsetZ)
+ {
+ lasPoint.X = pointStruct->X * scaleFactorX + offsetX;
+ lasPoint.Y = pointStruct->Y * scaleFactorY + offsetY;
+ lasPoint.Z = pointStruct->Z * scaleFactorZ + offsetZ;
+ lasPoint.Intensity = pointStruct->Intensity;
+ lasPoint.ReturnNumber = pointStruct->ReturnNumber;
+ lasPoint.NumberOfReturns = pointStruct->NumberOfReturns;
+ lasPoint.ScanDirectionFlag = pointStruct->ScanDirectionFlag;
+ lasPoint.EdgeOfFlightLine = pointStruct->EdgeOfFlightLine;
+ lasPoint.Classification = pointStruct->Classification;
+ lasPoint.ScanAngleRank = pointStruct->ScanAngleRank;
+ lasPoint.UserData = pointStruct->UserData;
+ lasPoint.PointSourceId = pointStruct->PointSourceID;
+ lasPoint.GpsTime = pointStruct->GpsTime;
+ lasPoint.Red = pointStruct->Rgb[0];
+ lasPoint.Green = pointStruct->Rgb[1];
+ lasPoint.Blue = pointStruct->Rgb[2];
}
public override bool Equals(object obj)
@@ -74,138 +74,4 @@ public override int GetHashCode()
return HashCode.Combine(GpsTime, Z);
}
}
-
- [StructLayout(LayoutKind.Sequential)]
- public struct LasZipPointStruct
- {
- public int X;
- public int Y;
- public int Z;
- public ushort Intensity;
- private byte bitField1; // ReturnNumber : 3, NumberOfReturns : 3, ScanDirectionFlag : 1, EdgeOfFlightLine : 1
- private byte bitField2; // Classification : 5, SyntheticFlag : 1, KeypointFlag : 1, WithheldFlag : 1
- public sbyte ScanAngleRank;
- public byte UserData;
- public ushort PointSourceID;
-
- // LAS 1.4 only
- public short ExtendedScanAngle;
- private byte bitField3; // ExtendedPointType : 2, ExtendedScannerChannel : 2, ExtendedClassificationFlags : 4
- public byte ExtendedClassification;
- private byte bitField4; // ExtendedReturnNumber : 4, ExtendedNumberOfReturns : 4
-
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
- public byte[] Dummy;
-
- public double GpsTime;
-
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
- public ushort[] Rgb;
-
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = 29)]
- public byte[] WavePacket;
-
- public int NumExtraBytes;
-
- public IntPtr ExtraBytes; // Use IntPtr instead of byte* for safe pointer handling
-
- public byte ReturnNumber
- {
- get => (byte)(bitField1 & 0b00000111);
- set => bitField1 = (byte)((bitField1 & 0b11111000) | (value & 0b00000111));
- }
-
- public byte NumberOfReturns
- {
- get => (byte)((bitField1 >> 3) & 0b00000111);
- set => bitField1 = (byte)((bitField1 & 0b11000111) | ((value & 0b00000111) << 3));
- }
-
- public byte ScanDirectionFlag
- {
- get => (byte)((bitField1 >> 6) & 0b00000001);
- set => bitField1 = (byte)((bitField1 & 0b10111111) | ((value & 0b00000001) << 6));
- }
-
- public byte EdgeOfFlightLine
- {
- get => (byte)((bitField1 >> 7) & 0b00000001);
- set => bitField1 = (byte)((bitField1 & 0b01111111) | ((value & 0b00000001) << 7));
- }
-
- public byte Classification
- {
- get => (byte)(bitField2 & 0b00011111);
- set => bitField2 = (byte)((bitField2 & 0b11100000) | (value & 0b00011111));
- }
-
- public byte SyntheticFlag
- {
- get => (byte)((bitField2 >> 5) & 0b00000001);
- set => bitField2 = (byte)((bitField2 & 0b11011111) | ((value & 0b00000001) << 5));
- }
-
- public byte KeypointFlag
- {
- get => (byte)((bitField2 >> 6) & 0b00000001);
- set => bitField2 = (byte)((bitField2 & 0b10111111) | ((value & 0b00000001) << 6));
- }
-
- public byte WithheldFlag
- {
- get => (byte)((bitField2 >> 7) & 0b00000001);
- set => bitField2 = (byte)((bitField2 & 0b01111111) | ((value & 0b00000001) << 7));
- }
-
- public byte ExtendedPointType
- {
- get => (byte)(bitField3 & 0b00000011);
- set => bitField3 = (byte)((bitField3 & 0b11111100) | (value & 0b00000011));
- }
-
- public byte ExtendedScannerChannel
- {
- get => (byte)((bitField3 >> 2) & 0b00000011);
- set => bitField3 = (byte)((bitField3 & 0b11110011) | ((value & 0b00000011) << 2));
- }
-
- public byte ExtendedClassificationFlags
- {
- get => (byte)((bitField3 >> 4) & 0b00001111);
- set => bitField3 = (byte)((bitField3 & 0b00001111) | ((value & 0b00001111) << 4));
- }
-
- public byte ExtendedReturnNumber
- {
- get => (byte)(bitField4 & 0b00001111);
- set => bitField4 = (byte)((bitField4 & 0b11110000) | (value & 0b00001111));
- }
-
- public byte ExtendedNumberOfReturns
- {
- get => (byte)((bitField4 >> 4) & 0b00001111);
- set => bitField4 = (byte)((bitField4 & 0b00001111) | ((value & 0b00001111) << 4));
- }
-
- internal static LasZipPointStruct ConvertPoint(LasPoint lasPoint)
- {
- return new LasZipPointStruct()
- {
- X = (int)(lasPoint.X + 0.5),
- Y = (int)(lasPoint.Y + 0.5),
- Z = (int)(lasPoint.Z + 0.5),
- Intensity = lasPoint.Intensity,
- ReturnNumber = lasPoint.ReturnNumber,
- NumberOfReturns = lasPoint.NumberOfReturns,
- ScanDirectionFlag = lasPoint.ScanDirectionFlag,
- EdgeOfFlightLine = lasPoint.EdgeOfFlightLine,
- Classification = lasPoint.Classification,
- ScanAngleRank = lasPoint.ScanAngleRank,
- UserData = lasPoint.UserData,
- PointSourceID = lasPoint.PointSourceId,
- GpsTime = lasPoint.GpsTime,
- Rgb = new ushort[] { lasPoint.Red, lasPoint.Green, lasPoint.Blue, 0 }
- };
- }
- }
}
diff --git a/LasZipNetStandard/LasZip.cs b/LasZipNetStandard/LasZip.cs
index 1c51bde..9655847 100644
--- a/LasZipNetStandard/LasZip.cs
+++ b/LasZipNetStandard/LasZip.cs
@@ -1,10 +1,12 @@
-using System;
+using System;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Kuoste.LasZipNetStandard
{
- public class LasZip
+ public class LasZip : IDisposable
{
+ private bool _disposed = false;
private const string _lasZipDll = "laszip64";
private IntPtr _pLasZipReader;
@@ -135,7 +137,8 @@ public void SetWriterHeader(LaszipHeaderStruct header)
///
/// Point data is read to this reference.
/// Reading failed.
- public void ReadPoint(ref LasPoint point)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public unsafe void ReadPoint(ref LasPoint point)
{
// Get the memory location for the point in LasZip library
if (_pPointReader == IntPtr.Zero)
@@ -152,22 +155,18 @@ public void ReadPoint(ref LasPoint point)
throw new Exception("Failed to read LasZip point");
}
- // Copy point data from C++ struct to C# class
- LasPoint.ConvertPoint(Marshal.PtrToStructure(_pPointReader), ref point);
-
- // Scale the coordinates and add offsets. Not using the laszip_get_coordinates in order to make things faster.
- point.X = point.X * _headerReader.ScaleFactorX + _headerReader.OffsetX;
- point.Y = point.Y * _headerReader.ScaleFactorY + _headerReader.OffsetY;
- point.Z = point.Z * _headerReader.ScaleFactorZ + _headerReader.OffsetZ;
+ LasPoint.ConvertPoint((LasZipPointNative*)_pPointReader, ref point,
+ _headerReader.ScaleFactorX, _headerReader.ScaleFactorY, _headerReader.ScaleFactorZ,
+ _headerReader.OffsetX, _headerReader.OffsetY, _headerReader.OffsetZ);
}
///
/// Writes the point given as reference.
///
- /// LasPoint to write. Note that the method changes the coordinates
- /// of the point by applying the Offsets and ScaleFactors.
+ /// LasPoint to write. The coordinates are scaled and offset
+ /// using the header values before writing.
/// Writing failed.
- public void WritePoint(ref LasPoint point)
+ public unsafe void WritePoint(ref LasPoint point)
{
// Get the memory location for the point in LasZip library
if (_pPointWriter == IntPtr.Zero)
@@ -178,12 +177,9 @@ public void WritePoint(ref LasPoint point)
}
}
- // Scale the coordinates and add offsets. Not using the laszip_set_coordinates in order to make things faster.
- point.X = (point.X - _headerWriter.OffsetX) / _headerWriter.ScaleFactorX;
- point.Y = (point.Y - _headerWriter.OffsetY) / _headerWriter.ScaleFactorY;
- point.Z = (point.Z - _headerWriter.OffsetZ) / _headerWriter.ScaleFactorZ;
-
- Marshal.StructureToPtr(LasZipPointStruct.ConvertPoint(point), _pPointWriter, false);
+ LasZipPointNative.WriteFromLasPoint((LasZipPointNative*)_pPointWriter, point,
+ _headerWriter.ScaleFactorX, _headerWriter.ScaleFactorY, _headerWriter.ScaleFactorZ,
+ _headerWriter.OffsetX, _headerWriter.OffsetY, _headerWriter.OffsetZ);
// Write point
if (laszip_write_point(_pLasZipWriter) != 0)
@@ -232,5 +228,52 @@ public void DestroyWriter()
_pLasZipWriter = IntPtr.Zero;
}
+
+ ///
+ /// Releases all resources used by the LasZip instance.
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ /// Releases the unmanaged resources and optionally releases the managed resources.
+ ///
+ /// True to release both managed and unmanaged resources; false to release only unmanaged resources.
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed)
+ return;
+
+ // Clean up unmanaged resources
+ if (_pLasZipReader != IntPtr.Zero)
+ {
+ laszip_close_reader(_pLasZipReader);
+ laszip_destroy(_pLasZipReader);
+ _pLasZipReader = IntPtr.Zero;
+ _pPointReader = IntPtr.Zero;
+ }
+
+ if (_pLasZipWriter != IntPtr.Zero)
+ {
+ laszip_close_writer(_pLasZipWriter);
+ laszip_destroy(_pLasZipWriter);
+ _pLasZipWriter = IntPtr.Zero;
+ _pPointWriter = IntPtr.Zero;
+ _pHeaderWriter = IntPtr.Zero;
+ }
+
+ _disposed = true;
+ }
+
+ ///
+ /// Finalizer to ensure unmanaged resources are released.
+ ///
+ ~LasZip()
+ {
+ Dispose(false);
+ }
}
}
diff --git a/LasZipNetStandard/LasZipPointNative.cs b/LasZipNetStandard/LasZipPointNative.cs
new file mode 100644
index 0000000..8c22302
--- /dev/null
+++ b/LasZipNetStandard/LasZipPointNative.cs
@@ -0,0 +1,155 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace Kuoste.LasZipNetStandard
+{
+ [StructLayout(LayoutKind.Sequential)]
+ internal unsafe struct LasZipPointNative
+ {
+ public int X;
+ public int Y;
+ public int Z;
+ public ushort Intensity;
+ private byte bitField1;
+ private byte bitField2;
+ public sbyte ScanAngleRank;
+ public byte UserData;
+ public ushort PointSourceID;
+ public short ExtendedScanAngle;
+ private byte bitField3;
+ public byte ExtendedClassification;
+ private byte bitField4;
+ public fixed byte Dummy[7];
+ public double GpsTime;
+ public fixed ushort Rgb[4];
+ public fixed byte WavePacket[29];
+ public int NumExtraBytes;
+ public IntPtr ExtraBytes;
+
+ public byte ReturnNumber
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)(bitField1 & 0b00000111);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField1 = (byte)((bitField1 & 0b11111000) | (value & 0b00000111));
+ }
+
+ public byte NumberOfReturns
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)((bitField1 >> 3) & 0b00000111);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField1 = (byte)((bitField1 & 0b11000111) | ((value & 0b00000111) << 3));
+ }
+
+ public byte ScanDirectionFlag
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)((bitField1 >> 6) & 0b00000001);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField1 = (byte)((bitField1 & 0b10111111) | ((value & 0b00000001) << 6));
+ }
+
+ public byte EdgeOfFlightLine
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)((bitField1 >> 7) & 0b00000001);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField1 = (byte)((bitField1 & 0b01111111) | ((value & 0b00000001) << 7));
+ }
+
+ public byte Classification
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)(bitField2 & 0b00011111);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField2 = (byte)((bitField2 & 0b11100000) | (value & 0b00011111));
+ }
+
+ public byte SyntheticFlag
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)((bitField2 >> 5) & 0b00000001);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField2 = (byte)((bitField2 & 0b11011111) | ((value & 0b00000001) << 5));
+ }
+
+ public byte KeypointFlag
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)((bitField2 >> 6) & 0b00000001);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField2 = (byte)((bitField2 & 0b10111111) | ((value & 0b00000001) << 6));
+ }
+
+ public byte WithheldFlag
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)((bitField2 >> 7) & 0b00000001);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField2 = (byte)((bitField2 & 0b01111111) | ((value & 0b00000001) << 7));
+ }
+
+ public byte ExtendedPointType
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)(bitField3 & 0b00000011);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField3 = (byte)((bitField3 & 0b11111100) | (value & 0b00000011));
+ }
+
+ public byte ExtendedScannerChannel
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)((bitField3 >> 2) & 0b00000011);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField3 = (byte)((bitField3 & 0b11110011) | ((value & 0b00000011) << 2));
+ }
+
+ public byte ExtendedClassificationFlags
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)((bitField3 >> 4) & 0b00001111);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField3 = (byte)((bitField3 & 0b00001111) | ((value & 0b00001111) << 4));
+ }
+
+ public byte ExtendedReturnNumber
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)(bitField4 & 0b00001111);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField4 = (byte)((bitField4 & 0b11110000) | (value & 0b00001111));
+ }
+
+ public byte ExtendedNumberOfReturns
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get => (byte)((bitField4 >> 4) & 0b00001111);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set => bitField4 = (byte)((bitField4 & 0b00001111) | ((value & 0b00001111) << 4));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe void WriteFromLasPoint(LasZipPointNative* native, LasPoint point, double scaleFactorX, double scaleFactorY, double scaleFactorZ, double offsetX, double offsetY, double offsetZ)
+ {
+ native->X = (int)((point.X - offsetX) / scaleFactorX + 0.5);
+ native->Y = (int)((point.Y - offsetY) / scaleFactorY + 0.5);
+ native->Z = (int)((point.Z - offsetZ) / scaleFactorZ + 0.5);
+ native->Intensity = point.Intensity;
+ native->ReturnNumber = point.ReturnNumber;
+ native->NumberOfReturns = point.NumberOfReturns;
+ native->ScanDirectionFlag = point.ScanDirectionFlag;
+ native->EdgeOfFlightLine = point.EdgeOfFlightLine;
+ native->Classification = point.Classification;
+ native->ScanAngleRank = point.ScanAngleRank;
+ native->UserData = point.UserData;
+ native->PointSourceID = point.PointSourceId;
+ native->GpsTime = point.GpsTime;
+ native->Rgb[0] = point.Red;
+ native->Rgb[1] = point.Green;
+ native->Rgb[2] = point.Blue;
+ }
+ }
+}
diff --git a/LasZipNetStandard/LasZipPointStruct.cs b/LasZipNetStandard/LasZipPointStruct.cs
new file mode 100644
index 0000000..d5ab047
--- /dev/null
+++ b/LasZipNetStandard/LasZipPointStruct.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Kuoste.LasZipNetStandard
+{
+ [Obsolete("Use LasZipPointNative for new code. This type will be removed in a future release.")]
+ [StructLayout(LayoutKind.Sequential)]
+ public struct LasZipPointStruct
+ {
+ public int X;
+ public int Y;
+ public int Z;
+ public ushort Intensity;
+ private byte bitField1; // ReturnNumber : 3, NumberOfReturns : 3, ScanDirectionFlag : 1, EdgeOfFlightLine : 1
+ private byte bitField2; // Classification : 5, SyntheticFlag : 1, KeypointFlag : 1, WithheldFlag : 1
+ public sbyte ScanAngleRank;
+ public byte UserData;
+ public ushort PointSourceID;
+
+ // LAS 1.4 only
+ public short ExtendedScanAngle;
+ private byte bitField3; // ExtendedPointType : 2, ExtendedScannerChannel : 2, ExtendedClassificationFlags : 4
+ public byte ExtendedClassification;
+ private byte bitField4; // ExtendedReturnNumber : 4, ExtendedNumberOfReturns : 4
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 7)]
+ public byte[] Dummy;
+
+ public double GpsTime;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
+ public ushort[] Rgb;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 29)]
+ public byte[] WavePacket;
+
+ public int NumExtraBytes;
+
+ public IntPtr ExtraBytes; // Use IntPtr instead of byte* for safe pointer handling
+
+ public byte ReturnNumber
+ {
+ get => (byte)(bitField1 & 0b00000111);
+ set => bitField1 = (byte)((bitField1 & 0b11111000) | (value & 0b00000111));
+ }
+
+ public byte NumberOfReturns
+ {
+ get => (byte)((bitField1 >> 3) & 0b00000111);
+ set => bitField1 = (byte)((bitField1 & 0b11000111) | ((value & 0b00000111) << 3));
+ }
+
+ public byte ScanDirectionFlag
+ {
+ get => (byte)((bitField1 >> 6) & 0b00000001);
+ set => bitField1 = (byte)((bitField1 & 0b10111111) | ((value & 0b00000001) << 6));
+ }
+
+ public byte EdgeOfFlightLine
+ {
+ get => (byte)((bitField1 >> 7) & 0b00000001);
+ set => bitField1 = (byte)((bitField1 & 0b01111111) | ((value & 0b00000001) << 7));
+ }
+
+ public byte Classification
+ {
+ get => (byte)(bitField2 & 0b00011111);
+ set => bitField2 = (byte)((bitField2 & 0b11100000) | (value & 0b00011111));
+ }
+
+ public byte SyntheticFlag
+ {
+ get => (byte)((bitField2 >> 5) & 0b00000001);
+ set => bitField2 = (byte)((bitField2 & 0b11011111) | ((value & 0b00000001) << 5));
+ }
+
+ public byte KeypointFlag
+ {
+ get => (byte)((bitField2 >> 6) & 0b00000001);
+ set => bitField2 = (byte)((bitField2 & 0b10111111) | ((value & 0b00000001) << 6));
+ }
+
+ public byte WithheldFlag
+ {
+ get => (byte)((bitField2 >> 7) & 0b00000001);
+ set => bitField2 = (byte)((bitField2 & 0b01111111) | ((value & 0b00000001) << 7));
+ }
+
+ public byte ExtendedPointType
+ {
+ get => (byte)(bitField3 & 0b00000011);
+ set => bitField3 = (byte)((bitField3 & 0b11111100) | (value & 0b00000011));
+ }
+
+ public byte ExtendedScannerChannel
+ {
+ get => (byte)((bitField3 >> 2) & 0b00000011);
+ set => bitField3 = (byte)((bitField3 & 0b11110011) | ((value & 0b00000011) << 2));
+ }
+
+ public byte ExtendedClassificationFlags
+ {
+ get => (byte)((bitField3 >> 4) & 0b00001111);
+ set => bitField3 = (byte)((bitField3 & 0b00001111) | ((value & 0b00001111) << 4));
+ }
+
+ public byte ExtendedReturnNumber
+ {
+ get => (byte)(bitField4 & 0b00001111);
+ set => bitField4 = (byte)((bitField4 & 0b11110000) | (value & 0b00001111));
+ }
+
+ public byte ExtendedNumberOfReturns
+ {
+ get => (byte)((bitField4 >> 4) & 0b00001111);
+ set => bitField4 = (byte)((bitField4 & 0b00001111) | ((value & 0b00001111) << 4));
+ }
+
+ internal static LasZipPointStruct ConvertPoint(LasPoint lasPoint)
+ {
+ return new LasZipPointStruct()
+ {
+ X = (int)(lasPoint.X + 0.5),
+ Y = (int)(lasPoint.Y + 0.5),
+ Z = (int)(lasPoint.Z + 0.5),
+ Intensity = lasPoint.Intensity,
+ ReturnNumber = lasPoint.ReturnNumber,
+ NumberOfReturns = lasPoint.NumberOfReturns,
+ ScanDirectionFlag = lasPoint.ScanDirectionFlag,
+ EdgeOfFlightLine = lasPoint.EdgeOfFlightLine,
+ Classification = lasPoint.Classification,
+ ScanAngleRank = lasPoint.ScanAngleRank,
+ UserData = lasPoint.UserData,
+ PointSourceID = lasPoint.PointSourceId,
+ GpsTime = lasPoint.GpsTime,
+ Rgb = new ushort[] { lasPoint.Red, lasPoint.Green, lasPoint.Blue, 0 }
+ };
+ }
+ }
+}
From f3fe1f02e6f11883b61dd99bd066d206f20ebcbf Mon Sep 17 00:00:00 2001
From: git
Date: Wed, 11 Mar 2026 13:57:32 +0200
Subject: [PATCH 2/2] adding missing change to csproj
---
LasZipNetStandard/LasZipNetStandard.csproj | 1 +
1 file changed, 1 insertion(+)
diff --git a/LasZipNetStandard/LasZipNetStandard.csproj b/LasZipNetStandard/LasZipNetStandard.csproj
index 3886e9c..84590e0 100644
--- a/LasZipNetStandard/LasZipNetStandard.csproj
+++ b/LasZipNetStandard/LasZipNetStandard.csproj
@@ -12,6 +12,7 @@
README.md
Apache-2.0
Kuoste.LasZipNetStandard
+ true