public SQuantizedExtent3D Convert(Extent3D extent) { var e = new Extent3D( (extent.GetMinPoint3D() - Offset) / ScaleFactor, (extent.GetMaxPoint3D() - Offset) / ScaleFactor ); return new SQuantizedExtent3D(e); }
public SQuantizedExtent3D Convert(Extent3D extent) { var e = new Extent3D( (extent.GetMinPoint3D() - Offset) / ScaleFactor, (extent.GetMaxPoint3D() - Offset) / ScaleFactor ); return(new SQuantizedExtent3D(e)); }
public PointCloudBinarySource(FileHandlerBase file, long count, Extent3D extent, SQuantization3D quantization, long dataOffset, short pointSizeBytes) : base(file) { m_count = count; m_extent = extent; m_quantization = quantization; m_pointDataOffset = dataOffset; m_pointSizeBytes = pointSizeBytes; m_quantizedExtent = quantization.Convert(m_extent); }
public PointCloudBinarySourceComposite(FileHandlerBase file, Extent3D extent, IPointCloudBinarySource[] sources) : base(file) { m_sources = sources; // verify that they are compatible m_count = m_sources.Sum(s => s.Count); m_extent = extent; m_quantization = m_sources[0].Quantization; m_pointSizeBytes = m_sources[0].PointSizeBytes; m_quantizedExtent = m_quantization.Convert(m_extent); }
public static void CopyToUnquantized(this Grid<int> target, Grid<float> output, Quantization3D quantization, Extent3D extent) { var data0 = target.Data; var data1 = output.Data; var scaleFactorZ = (float)quantization.ScaleFactorZ; var adjustedOffset = (float)(extent != null ? quantization.OffsetZ - extent.MinZ : quantization.OffsetZ); // ">" zero is not quite what I want here // it could lose some min values (not important for now) for (int y = 0; y < target.SizeY; y++) for (int x = 0; x < target.SizeX; x++) if (data0[y, x] != target.FillVal) data1[y, x] = data0[y, x] * scaleFactorZ + adjustedOffset; }
public LASFile(string path, LASHeader header, LASVLR[] vlrs, LASEVLR[] evlrs) : base(path) { m_header = header; m_vlrs = vlrs; m_evlrs = evlrs; using (var stream = File.Create(FilePath)) { using (var writer = new FlexibleBinaryWriter(stream)) { header.Serialize(writer); } //header.WriteVLRs(stream, vlrs); } m_extent = m_header.Extent; }
public static Extent3D CreateOffsetExtent(Extent3D extent) { double offsetX = Math.Floor(extent.MinX); double offsetY = Math.Floor(extent.MinY); double offsetZ = Math.Floor(extent.MinZ); // degrees don't like Floor if (extent.MinX - offsetX > extent.RangeX) { offsetX = extent.MinX; } if (extent.MinY - offsetY > extent.RangeY) { offsetY = extent.MinY; } if (extent.MinZ - offsetZ > extent.RangeZ) { offsetZ = extent.MinZ; } return(new Extent3D(offsetX, offsetY, offsetZ, extent.MaxX, extent.MaxY, extent.MaxZ)); }
public LASFile(string path) : base(path) { if (Exists) { try { using (var stream = StreamManager.OpenReadStream(FilePath)) { using (var reader = new FlexibleBinaryReader(stream)) { m_header = reader.ReadLASHeader(); } m_vlrs = m_header.ReadVLRs(stream); m_evlrs = m_header.ReadEVLRs(stream); } m_extent = m_header.Extent; } catch { } } }
public void Initialize(Extent3D extent, int numPointsToProcess) { double SQRT3 = Math.Sqrt(3); //create one big Triangle_t aka. supertriangle //Make the bounding box slightly bigger, //actually no need for this if coming from streaming delaunay side m_extent = extent; // compute the supertriangle vertices, clockwise order, check the math m_superA = new DelaunayPoint(extent.MinX - extent.RangeY * SQRT3 / 3.0f, extent.MinY, extent.MinZ, numPointsToProcess); m_superB = new DelaunayPoint(extent.MidpointX, extent.MaxY + extent.RangeX * SQRT3 * 0.5f, extent.MinZ, numPointsToProcess + 1); m_superC = new DelaunayPoint(extent.MaxX + extent.RangeY * SQRT3 / 3.0f, extent.MinY, extent.MinZ, numPointsToProcess + 2); //create the super Triangle_t m_delaunayGraph = new Triangle(m_superA, m_superB, m_superC); //keep track of the current Triangle_t m_currentTriangle = m_delaunayGraph; m_newTriangles = new List<Triangle>(); m_outputTriangles = new List<int>(); }
public static SQuantization3D Create(Extent3D extent) { Extent3D qOffsetExtent = CreateOffsetExtent(extent); // midpoint doubles the signed range, // but I don't really care var qOffsetX = qOffsetExtent.MinX; var qOffsetY = qOffsetExtent.MinY; var qOffsetZ = qOffsetExtent.MinZ; // Use only the non-negative int range double range = Math.Pow(2, 31); const double logBase = 10; // this value effects debugging and compressibility var precisionMaxX = (int)Math.Floor(Math.Log(range / (qOffsetExtent.RangeX), logBase)); var precisionMaxY = (int)Math.Floor(Math.Log(range / (qOffsetExtent.RangeY), logBase)); var precisionMaxZ = (int)Math.Floor(Math.Log(range / (qOffsetExtent.RangeZ), logBase)); var qScaleFactorX = Math.Pow(logBase, -precisionMaxX); var qScaleFactorY = Math.Pow(logBase, -precisionMaxY); var qScaleFactorZ = Math.Pow(logBase, -precisionMaxZ); return(new SQuantization3D(qScaleFactorX, qScaleFactorY, qScaleFactorZ, qOffsetX, qOffsetY, qOffsetZ)); }
public LASHeader(BinaryReader reader) { long length = reader.BaseStream.Length; if (length < c_minHeaderSize[LASVersion.LAS_1_0]) throw new OpenFailedException("Invalid format: header too short"); if (Encoding.ASCII.GetString(reader.ReadBytes(FILE_SIGNATURE.Length)) != FILE_SIGNATURE) throw new OpenFailedException("Invalid format: signature does not match"); m_fileSourceID = reader.ReadUInt16(); m_globalEncoding = reader.ReadLASGlobalEncoding(); m_projectID = reader.ReadLASProjectID(); m_version = reader.ReadLASVersionInfo(); m_systemIdentifier = reader.ReadBytes(32).ToAsciiString(); m_generatingSoftware = reader.ReadBytes(32).ToAsciiString(); m_fileCreationDayOfYear = reader.ReadUInt16(); m_fileCreationYear = reader.ReadUInt16(); m_headerSize = reader.ReadUInt16(); m_offsetToPointData = reader.ReadUInt32(); ushort minHeaderSize = c_minHeaderSize[m_version.Version]; if (length < minHeaderSize) throw new OpenFailedException("Invalid format: header too short for version"); if(minHeaderSize > m_headerSize) throw new OpenFailedException("Invalid format: header size incorrect"); m_numberOfVariableLengthRecords = reader.ReadUInt32(); m_pointDataRecordFormat = reader.ReadByte(); m_pointDataRecordLength = reader.ReadUInt16(); m_legacyNumberOfPointRecords = reader.ReadUInt32(); m_legacyNumberOfPointsByReturn = reader.ReadUInt32Array(5); m_quantization = reader.ReadSQuantization3D(); m_extent = reader.ReadExtent3D(); if (m_version.Version >= LASVersion.LAS_1_3) { m_startOfWaveformDataPacketRecord = reader.ReadUInt64(); } if (m_version.Version >= LASVersion.LAS_1_4) { m_startOfFirstExtendedVariableLengthRecord = reader.ReadUInt64(); m_numberOfExtendedVariableLengthRecords = reader.ReadUInt32(); m_numberOfPointRecords = reader.ReadUInt64(); m_numberOfPointsByReturn = reader.ReadUInt64Array(15); } else { m_numberOfPointRecords = m_legacyNumberOfPointRecords; m_numberOfPointsByReturn = new ulong[15]; for (int i = 0; i < m_legacyNumberOfPointsByReturn.Length; i++) m_numberOfPointsByReturn[i] = m_legacyNumberOfPointsByReturn[i]; } // This doesn't apply to LAZ files //ulong pointDataRegionLength = (ulong)length - m_offsetToPointData; //if (pointDataRegionLength < m_pointDataRecordLength * PointCount) // throw new Exception("Invalid format: point data region is not the expected size"); }
/// <summary> /// This will only work if point format, point length, offset, and scale are identical. /// </summary> public LASHeader(LASHeader[] headers, LASVLR[] vlrs, LASEVLR[] evlrs) { var header = headers[0]; var extent = headers.Select(h => h.m_extent).Union3D(); var points = (ulong)headers.Sum(h => (long)h.m_numberOfPointRecords); var pointsByReturn = new ulong[15]; for (var i = 0; i < pointsByReturn.Length; i++) { pointsByReturn[i] = (ulong)headers.Sum(h => (long)h.m_numberOfPointsByReturn[i]); } uint legacyPoints = 0; uint[] legacyPointsByReturn; if (points > uint.MaxValue) { legacyPoints = 0; legacyPointsByReturn = new uint[5]; } else { legacyPoints = (uint)points; legacyPointsByReturn = pointsByReturn.Take(5).Select(c => (uint)c).ToArray(); } m_fileSourceID = header.m_fileSourceID; m_globalEncoding = header.m_globalEncoding; m_projectID = header.m_projectID; m_version = LASVersionInfo.Create(LASVersion.LAS_1_4); m_systemIdentifier = header.m_systemIdentifier; m_generatingSoftware = header.m_generatingSoftware; m_fileCreationDayOfYear = header.m_fileCreationDayOfYear; m_fileCreationYear = header.m_fileCreationYear; m_headerSize = c_minHeaderSize[LASVersion.LAS_1_4]; m_offsetToPointData = m_headerSize + (uint)vlrs.Sum(vlr => vlr.Length); m_numberOfVariableLengthRecords = (uint)vlrs.Length; m_pointDataRecordFormat = header.m_pointDataRecordFormat; m_pointDataRecordLength = header.m_pointDataRecordLength; if (points > uint.MaxValue) { m_legacyNumberOfPointRecords = 0; m_legacyNumberOfPointsByReturn = new uint[5]; } else { m_legacyNumberOfPointRecords = legacyPoints; m_legacyNumberOfPointsByReturn = legacyPointsByReturn; } m_quantization = header.m_quantization; m_extent = extent; m_startOfWaveformDataPacketRecord = 0; m_startOfFirstExtendedVariableLengthRecord = m_offsetToPointData + (points * m_pointDataRecordLength); m_numberOfExtendedVariableLengthRecords = (uint)evlrs.Length; m_numberOfPointRecords = points; m_numberOfPointsByReturn = pointsByReturn; }
public static System.Windows.Media.Media3D.MeshGeometry3D GenerateMesh(this PointCloudTileSource source, Grid<float> grid, Extent3D distributionExtent, bool showBackFaces) { // subtract midpoint to center around (0,0,0) Extent3D centeringExtent = source.Extent; Point3D centerOfMass = source.CenterOfMass; double centerOfMassMinusMin = centerOfMass.Z - centeringExtent.MinZ; var positions = new System.Windows.Media.Media3D.Point3DCollection(grid.CellCount); var indices = new System.Windows.Media.Int32Collection(2 * (grid.SizeX - 1) * (grid.SizeY - 1)); float fillVal = grid.FillVal; for (int x = 0; x < grid.SizeX; x++) { for (int y = 0; y < grid.SizeY; y++) { double value = grid.Data[x, y] - centerOfMassMinusMin; double xCoord = ((double)x / grid.SizeX) * distributionExtent.RangeX + distributionExtent.MinX - distributionExtent.MidpointX; double yCoord = ((double)y / grid.SizeY) * distributionExtent.RangeY + distributionExtent.MinY - distributionExtent.MidpointY; xCoord += (distributionExtent.MidpointX - centeringExtent.MidpointX); yCoord += (distributionExtent.MidpointY - centeringExtent.MidpointY); var point = new System.Windows.Media.Media3D.Point3D(xCoord, yCoord, value); positions.Add(point); if (x > 0 && y > 0) { // add two triangles int currentPosition = x * grid.SizeY + y; int topPosition = currentPosition - 1; int leftPosition = currentPosition - grid.SizeY; int topleftPosition = leftPosition - 1; if (grid.Data[x - 1, y] != fillVal && grid.Data[x, y - 1] != fillVal) { if (grid.Data[x, y] != fillVal) { indices.Add(leftPosition); indices.Add(topPosition); indices.Add(currentPosition); if (showBackFaces) { indices.Add(leftPosition); indices.Add(currentPosition); indices.Add(topPosition); } } if (grid.Data[x - 1, y - 1] != fillVal) { indices.Add(topleftPosition); indices.Add(topPosition); indices.Add(leftPosition); if (showBackFaces) { indices.Add(topleftPosition); indices.Add(leftPosition); indices.Add(topPosition); } } } } } } var normals = new System.Windows.Media.Media3D.Vector3DCollection(positions.Count); for (int i = 0; i < positions.Count; i++) normals.Add(new System.Windows.Media.Media3D.Vector3D(0, 0, 0)); for (int i = 0; i < indices.Count; i += 3) { int index1 = indices[i]; int index2 = indices[i + 1]; int index3 = indices[i + 2]; System.Windows.Media.Media3D.Vector3D side1 = positions[index1] - positions[index3]; System.Windows.Media.Media3D.Vector3D side2 = positions[index1] - positions[index2]; System.Windows.Media.Media3D.Vector3D normal = System.Windows.Media.Media3D.Vector3D.CrossProduct(side1, side2); normals[index1] += normal; normals[index2] += normal; normals[index3] += normal; } for (int i = 0; i < normals.Count; i++) { if (normals[i].Length > 0) { var normal = normals[i]; normal.Normalize(); // the fact that this is necessary means I am doing something wrong if (normal.Z < 0) normal.Negate(); normals[i] = normal; } } var geometry = new System.Windows.Media.Media3D.MeshGeometry3D { Positions = positions, TriangleIndices = indices, Normals = normals }; return geometry; }
public LAZBinarySource(FileHandlerBase file, long count, Extent3D extent, SQuantization3D quantization, long dataOffset, short pointSizeBytes) : base(file, count, extent, quantization, dataOffset, pointSizeBytes) { m_handler = (LAZFile)file; }
public unsafe void ComputeExtent(ProgressManager progressManager) { using (var process = progressManager.StartProcess("CalculateLASExtent")) { short pointSizeBytes = PointSizeBytes; int minX = 0, minY = 0, minZ = 0; int maxX = 0, maxY = 0, maxZ = 0; foreach (var chunk in GetBlockEnumerator(process)) { if (minX == 0 && maxX == 0) { var p = (SQuantizedPoint3D*)chunk.PointDataPtr; minX = maxX = (*p).X; minY = maxY = (*p).Y; minZ = maxZ = (*p).Z; } byte* pb = chunk.PointDataPtr; while (pb < chunk.PointDataEndPtr) { var p = (SQuantizedPoint3D*)pb; if ((*p).X < minX) minX = (*p).X; else if ((*p).X > maxX) maxX = (*p).X; if ((*p).Y < minY) minY = (*p).Y; else if ((*p).Y > maxY) maxY = (*p).Y; if ((*p).Z < minZ) minZ = (*p).Z; else if ((*p).Z > maxZ) maxZ = (*p).Z; pb += pointSizeBytes; } if (!process.Update(chunk)) break; } var quantizedExtent = new SQuantizedExtent3D(minX, minY, minZ, maxX, maxY, maxZ); m_extent = m_header.Quantization.Convert(quantizedExtent); process.LogTime("Traversed {0:0,0} points", Count); } }
public SQuantizedExtent3D(Extent3D extent) { m_min = new SQuantizedPoint3D((int)extent.MinX, (int)extent.MinY, (int)extent.MinZ); m_max = new SQuantizedPoint3D((int)extent.MaxX, (int)extent.MaxY, (int)extent.MaxZ); }
public unsafe PointCloudBinarySource ConvertTextToBinary(string binaryPath, ProgressManager progressManager) { short pointSizeBytes = 3 * sizeof(double); double minX = 0, minY = 0, minZ = 0; double maxX = 0, maxY = 0, maxZ = 0; int pointCount = 0; using (var process = progressManager.StartProcess("ConvertTextToBinary")) { BufferInstance inputBuffer = process.AcquireBuffer(true); BufferInstance outputBuffer = process.AcquireBuffer(true); int pointsPerBuffer = outputBuffer.Length / pointSizeBytes; int usableBytesPerBuffer = pointsPerBuffer * pointSizeBytes; byte* inputBufferPtr = inputBuffer.DataPtr; byte* outputBufferPtr = outputBuffer.DataPtr; int bufferIndex = 0; int skipped = 0; using (var inputStream = StreamManager.OpenReadStream(FilePath)) { long inputLength = inputStream.Length; long estimatedOutputLength = inputLength; using (var outputStream = StreamManager.OpenWriteStream(binaryPath, estimatedOutputLength, 0, true)) { int bytesRead; int readStart = 0; while ((bytesRead = inputStream.Read(inputBuffer.Data, readStart, inputBuffer.Length - readStart)) > 0) { bytesRead += readStart; readStart = 0; int i = 0; while (i < bytesRead) { // identify line start while (i < bytesRead && (inputBufferPtr[i] == '\r' || inputBufferPtr[i] == '\n')) { ++i; } int lineStart = i; // identify line end while (i < bytesRead && inputBufferPtr[i] != '\r' && inputBufferPtr[i] != '\n') { ++i; } // handle buffer overlap if (i == bytesRead) { Array.Copy(inputBuffer.Data, lineStart, inputBuffer.Data, 0, i - lineStart); readStart = i - lineStart; break; } // this may get overwritten if this is not a valid parse double* p = (double*)(outputBufferPtr + bufferIndex); if (!ParseXYZFromLine(inputBufferPtr, lineStart, i, p)) { ++skipped; continue; } if (pointCount == 0) { minX = maxX = p[0]; minY = maxY = p[1]; minZ = maxZ = p[2]; } else { if (p[0] < minX) minX = p[0]; else if (p[0] > maxX) maxX = p[0]; if (p[1] < minY) minY = p[1]; else if (p[1] > maxY) maxY = p[1]; if (p[2] < minZ) minZ = p[2]; else if (p[2] > maxZ) maxZ = p[2]; } bufferIndex += pointSizeBytes; ++pointCount; // write usable buffer chunk if (usableBytesPerBuffer == bufferIndex) { outputStream.Write(outputBuffer.Data, 0, bufferIndex); bufferIndex = 0; } } if (!process.Update((float)inputStream.Position / inputLength)) break; } // write remaining buffer if (bufferIndex > 0) outputStream.Write(outputBuffer.Data, 0, bufferIndex); } } process.Log("Skipped {0} lines", skipped); process.LogTime("Copied {0:0,0} points", pointCount); } var extent = new Extent3D(minX, minY, minZ, maxX, maxY, maxZ); var source = new PointCloudBinarySource(this, pointCount, extent, null, 0, pointSizeBytes); return source; }
public static System.Windows.Media.Media3D.MeshGeometry3D GenerateMesh(this PointCloudTileSource source, Grid<float> grid, Extent3D distributionExtent) { return GenerateMesh(source, grid, distributionExtent, false); }