/* * Copyright (C) 2012 Dr. John Lindsay <jlindsay@uoguelph.ca> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package whitebox.geospatialfiles; import java.io.File; import java.nio.ByteOrder; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.Arrays; import java.util.ArrayList; import whitebox.utilities.Unsigned; import whitebox.utilities.BitOps; import whitebox.structures.BoundingBox; /** * This class is used to provide reading and writing capabilities with LAS LiDAR * files. * * @author Dr. John Lindsay <jlindsay@uoguelph.ca> */ public class LASReader { // Fields private String fileName = ""; private short versionMajor = 1; private short versionMinor = 3; private int fileSourceID = 0; private byte GPSTimeType = 0; private byte waveDataPacketsInternal = 0; private byte waveDataPacketsExternal = 0; private byte retNumsSynthGenerated = 0; private long projectID1 = 0; private int projectID2 = 0; private int projectID3 = 0; private short[] projectID4 = new short[8]; private String systemIdentifer = ""; private String generatingSoftware = ""; private int fileCreationDay = 0; private int fileCreationYear = 0; private int headerSize = 0; private long offsetToPointData = 0; private long numVLR = 0; private short pointDataFormatID = 0; private int pointDataRecLength = 0; private long numPointRecords = 0; private long[] numPointsByReturn = new long[5]; private double xScale, yScale, zScale; private double xOffset, yOffset, zOffset; private double maxX, minX, maxY, minY, maxZ, minZ; private ArrayList<VariableLengthRecord> vlrArray = new ArrayList<>(); private int bufferSize = 1000; private int startingPoint = -1; private int endingPoint = -1; private PointRecord[] pointRecs; private PointRecColours[] pointColours; private boolean coloursNeedReading = true; private boolean pointsNeedReading = true; //private PointWavePacket[] pointWavePagetData; // Constructors public LASReader() { } public LASReader(String fileName) { setFileName(fileName); } // Properties public String getFileName() { return fileName; } public final void setFileName(String fileName) { this.fileName = fileName; readHeaderData(); readVariableLengthRecords(); } public int getFileSourceID() { return fileSourceID; } public short getVersionMajor() { return versionMajor; } public short getVersionMinor() { return versionMinor; } public ArrayList<VariableLengthRecord> getVariableLengthRecords() { return vlrArray; } public byte getGPSTimeType() { return GPSTimeType; } public byte getWaveDataPacketsInternal() { return waveDataPacketsInternal; } public byte getWaveDataPacketsExternal() { return waveDataPacketsExternal; } public byte getRetNumsSynthGenerated() { return retNumsSynthGenerated; } public long getProjectID1() { return projectID1; } public int getProjectID2() { return projectID2; } public int getProjectID3() { return projectID3; } public short[] getProjectID4() { return projectID4; } public String getSystemIdentifer() { return systemIdentifer; } public String getGeneratingSoftware() { return generatingSoftware; } public int getFileCreationDay() { return fileCreationDay; } public int getFileCreationYear() { return fileCreationYear; } public int getHeaderSize() { return headerSize; } public long getOffsetToPointData() { return offsetToPointData; } public long getNumVLR() { return numVLR; } public short getPointDataFormatID() { return pointDataFormatID; } public int getPointDataRecLength() { return pointDataRecLength; } public long getNumPointRecords() { return numPointRecords; } public long[] getNumPointsByReturn() { return numPointsByReturn; } public double getXScale() { return xScale; } public double getYScale() { return yScale; } public double getZScale() { return zScale; } public double getXOffset() { return xOffset; } public double getYOffset() { return yOffset; } public double getZOffset() { return zOffset; } public double getMaxX() { return maxX; } public double getMinX() { return minX; } public double getMaxY() { return maxY; } public double getMinY() { return minY; } public double getMaxZ() { return maxZ; } public double getMinZ() { return minZ; } // Methods public ArrayList<PointRecord> getPointRecordsInBoundingBox(BoundingBox bb) { double minXbb = bb.getMinX(); double minYbb = bb.getMinY(); double maxXbb = bb.getMaxX(); double maxYbb = bb.getMaxY(); double x, y; ArrayList<PointRecord> ret = new ArrayList<>(); PointRecord rec; try { for (int i = 0; i < numPointRecords; i++) { rec = getPointRecord(i); if (rec != null) { x = rec.getX(); y = rec.getY(); if (maxYbb < y || maxXbb < x || minYbb > y || minXbb > x) { // do nothing it's outside the bounds } else { ret.add(rec); } } } } catch (Exception e) { System.out.println(e.getMessage()); } return ret; } // Methods public ArrayList<Integer> getPointRecordIndicesInBoundingBox(BoundingBox bb) { double minXbb = bb.getMinX(); double minYbb = bb.getMinY(); double maxXbb = bb.getMaxX(); double maxYbb = bb.getMaxY(); double x, y; ArrayList<Integer> ret = new ArrayList<>(); PointRecord rec; for (int i = 0; i < numPointRecords; i++) { rec = getPointRecord(i); x = rec.getX(); y = rec.getY(); if (maxYbb < y || maxXbb < x || minYbb > y || minXbb > x) { // do nothing it's outside the bounds } else { ret.add(i); } } return ret; } public PointRecord getPointRecord(int i) { try { if (i < 0 || i > numPointRecords) { return null; } if (i < startingPoint || i > endingPoint || pointsNeedReading) { if (startingPoint != i) { startingPoint = i; coloursNeedReading = true; } if (endingPoint != (i + bufferSize - 1)) { endingPoint = i + bufferSize - 1; coloursNeedReading = true; } //read the points in readPointRecords(); pointsNeedReading = false; } int n = i - startingPoint; return pointRecs[n]; } catch (Exception e) { System.err.println(e); return null; } } public PointRecColours getPointRecordColours(int i) { try { if (i < 0 || i > numPointRecords) { return null; } if (i < startingPoint || i > endingPoint || coloursNeedReading) { if (startingPoint != i) { startingPoint = i; pointsNeedReading = true; } if (endingPoint != (i + bufferSize - 1)) { endingPoint = i + bufferSize - 1; pointsNeedReading = true; } //read the colour data in readPointRecColours(); coloursNeedReading = false; } int n = i - startingPoint; return pointColours[n]; } catch (Exception e) { System.err.println(e); return null; } } private void readPointRecords() { long pos = offsetToPointData + (long)startingPoint * (long)pointDataRecLength; int pos2 = 0; byte returnNumberByte = 0; byte classificationByte = 0; byte b = 0; pointRecs = new PointRecord[bufferSize]; int x, y, z; RandomAccessFile rIn = null; ByteBuffer buf = null; try { buf = ByteBuffer.allocate(bufferSize * pointDataRecLength); rIn = new RandomAccessFile(fileName, "r"); FileChannel inChannel = rIn.getChannel(); inChannel.position(pos); inChannel.read(buf); buf.order(ByteOrder.LITTLE_ENDIAN); buf.rewind(); for (int i = 0; i < bufferSize; i++) { pointRecs[i] = new PointRecord(); x = buf.getInt(pos2); pointRecs[i].setX((x * xScale) + xOffset); y = buf.getInt(pos2 + 4); pointRecs[i].setY((y * yScale) + yOffset); z = buf.getInt(pos2 + 8); pointRecs[i].setZ((z * zScale) + zOffset); pointRecs[i].setIntensity(Unsigned.getUnsignedShort(buf, pos2 + 12)); // get the record number byte returnNumberByte = buf.get(pos2 + 14); b = 0; for (int a = 0; a < 3; a++) { if (BitOps.checkBit(returnNumberByte, a)) { b = BitOps.setBit(b, (byte) a); } } pointRecs[i].setReturnNumber(b); b = 0; for (int a = 0; a < 3; a++) { if (BitOps.checkBit(returnNumberByte, a + 3)) { b = BitOps.setBit(b, (byte) a); } } pointRecs[i].setNumberOfReturns(b); pointRecs[i].setScanDirectionFlag(BitOps.checkBit(returnNumberByte, 6)); pointRecs[i].setEdgeOfFlightLine(BitOps.checkBit(returnNumberByte, 7)); // get the classification data classificationByte = buf.get(pos2 + 15); b = 0; for (int a = 0; a < 5; a++) { if (BitOps.checkBit(classificationByte, a)) { b = BitOps.setBit(b, (byte) a); } } pointRecs[i].setClassification(b); pointRecs[i].setSynthetic(BitOps.checkBit(classificationByte, 5)); pointRecs[i].setKeyPoint(BitOps.checkBit(classificationByte, 6)); pointRecs[i].setPointWithheld(BitOps.checkBit(classificationByte, 7)); pointRecs[i].setScanAngle(buf.get(pos2 + 16)); pointRecs[i].setUserData(Unsigned.getUnsignedByte(buf, pos2 + 17)); pointRecs[i].setPointSourceID(Unsigned.getUnsignedShort(buf, pos2 + 18)); if (pointDataFormatID == 1 || pointDataFormatID == 3 || pointDataFormatID == 4 || pointDataFormatID == 5) { pointRecs[i].setGPSTime(buf.getDouble(pos2 + 20)); } pos2 += pointDataRecLength; } } catch (Exception e) { System.err.println(e); } finally { if (rIn != null) { try { rIn.close(); } catch (Exception e) { } } } } private void readPointRecColours() { if (pointDataFormatID == 2 || pointDataFormatID == 3 || pointDataFormatID == 5) { long pos = offsetToPointData + (long)startingPoint * (long)pointDataRecLength; int pos2 = 0; int offsetToColourData = 0; if (pointDataFormatID == 2) { offsetToColourData = 20; } else if (pointDataFormatID == 3 || pointDataFormatID == 5) { offsetToColourData = 28; } byte b = 0; pointColours = new PointRecColours[bufferSize]; int x, y, z; RandomAccessFile rIn = null; ByteBuffer buf = null; try { buf = ByteBuffer.allocate(bufferSize * pointDataRecLength); rIn = new RandomAccessFile(fileName, "r"); FileChannel inChannel = rIn.getChannel(); inChannel.position(pos); inChannel.read(buf); buf.order(ByteOrder.LITTLE_ENDIAN); buf.rewind(); for (int i = 0; i < bufferSize; i++) { pointColours[i] = new PointRecColours(); pointColours[i].setRed(Unsigned.getUnsignedShort(buf, pos2 + offsetToColourData)); pointColours[i].setGreen(Unsigned.getUnsignedShort(buf, pos2 + offsetToColourData + 2)); pointColours[i].setBlue(Unsigned.getUnsignedShort(buf, pos2 + offsetToColourData + 4)); pos2 += pointDataRecLength; } } catch (Exception e) { System.err.println(e); } finally { if (rIn != null) { try { rIn.close(); } catch (Exception e) { } } } } } public void setBufferSize(int i) { bufferSize = i; startingPoint = -1; endingPoint = -1; // reinitialize the point record arrays. pointRecs = new PointRecord[0]; pointColours = new PointRecColours[0]; } private boolean readHeaderData() { int pos; RandomAccessFile rIn = null; ByteBuffer buf = null; try { // See if the data file exists. File file = new File(fileName); if (!file.exists()) { return false; } buf = ByteBuffer.allocate(300); rIn = new RandomAccessFile(fileName, "r"); FileChannel inChannel = rIn.getChannel(); inChannel.position(0); inChannel.read(buf); buf.order(ByteOrder.LITTLE_ENDIAN); buf.rewind(); // the first four bytes should be the file signature "LASF" short[] sig = new short[4]; sig[0] = Unsigned.getUnsignedByte(buf); sig[1] = Unsigned.getUnsignedByte(buf); sig[2] = Unsigned.getUnsignedByte(buf); sig[3] = Unsigned.getUnsignedByte(buf); short[] testSig = new short[]{76, 65, 83, 70}; if (!Arrays.equals(sig, testSig)) { return false; } fileSourceID = Unsigned.getUnsignedShort(buf); int globalEncoding = Unsigned.getUnsignedShort(buf, 6); if (BitOps.checkBit(globalEncoding, 0)) { GPSTimeType = 1; } if (BitOps.checkBit(globalEncoding, 1)) { waveDataPacketsInternal = 1; } if (BitOps.checkBit(globalEncoding, 2)) { waveDataPacketsExternal = 1; } if (BitOps.checkBit(globalEncoding, 3)) { retNumsSynthGenerated = 1; } projectID1 = Unsigned.getUnsignedInt(buf, 8); projectID2 = Unsigned.getUnsignedShort(buf, 12); projectID3 = Unsigned.getUnsignedShort(buf, 14); pos = 16; for (int a = 0; a < 8; a++) { projectID4[a] = Unsigned.getUnsignedByte(buf, pos); pos += 1; } short[] tmp1 = new short[32]; pos = 26; for (int a = 0; a < tmp1.length; a++) { tmp1[a] = Unsigned.getUnsignedByte(buf, pos); pos += 1; } systemIdentifer = convertShortArrayToAscii(tmp1); tmp1 = new short[32]; pos = 58; for (int a = 0; a < tmp1.length; a++) { tmp1[a] = Unsigned.getUnsignedByte(buf, pos); pos += 1; } generatingSoftware = convertShortArrayToAscii(tmp1); versionMajor = Unsigned.getUnsignedByte(buf, 24); versionMinor = Unsigned.getUnsignedByte(buf, 25); fileCreationDay = Unsigned.getUnsignedShort(buf, 90); fileCreationYear = Unsigned.getUnsignedShort(buf, 92); headerSize = Unsigned.getUnsignedShort(buf, 94); offsetToPointData = Unsigned.getUnsignedInt(buf, 96); numVLR = Unsigned.getUnsignedInt(buf, 100); pointDataFormatID = Unsigned.getUnsignedByte(buf, 104); pointDataRecLength = Unsigned.getUnsignedShort(buf, 105); numPointRecords = Unsigned.getUnsignedInt(buf, 107); pos = 111; for (int a = 0; a < 5; a++) { numPointsByReturn[a] = Unsigned.getUnsignedInt(buf, pos); pos += 4; } xScale = buf.getDouble(131); yScale = buf.getDouble(139); zScale = buf.getDouble(147); xOffset = buf.getDouble(155); yOffset = buf.getDouble(163); zOffset = buf.getDouble(171); maxX = buf.getDouble(179); minX = buf.getDouble(187); maxY = buf.getDouble(195); minY = buf.getDouble(203); maxZ = buf.getDouble(211); minZ = buf.getDouble(219); return true; } catch (Exception e) { return false; } finally { if (rIn != null) { try { rIn.close(); } catch (Exception e) { } } } } private boolean readVariableLengthRecords() { int pos = headerSize; short[] tmp1; RandomAccessFile rIn = null; ByteBuffer buf = null; try { // See if the data file exists. File file = new File(fileName); if (!file.exists()) { return false; } buf = ByteBuffer.allocate((int) offsetToPointData); rIn = new RandomAccessFile(fileName, "r"); FileChannel inChannel = rIn.getChannel(); inChannel.position(0); inChannel.read(buf); buf.order(ByteOrder.LITTLE_ENDIAN); buf.rewind(); for (int a = 0; a < numVLR; a++) { VariableLengthRecord vlr = new VariableLengthRecord(); /* Nothing is done with this reserved byt at the moment, but it * may be useful in future versions of the specification */ int reservedByte = Unsigned.getUnsignedShort(buf, pos); // UserID--16 byte ASCII field tmp1 = new short[16]; int m = 2; // starts at pos + 2 for (int j = 0; j < tmp1.length; j++) { tmp1[j] = Unsigned.getUnsignedByte(buf, pos + m); m++; } String userID = convertShortArrayToAscii(tmp1); vlr.setUserID(userID); // RecordID--starts at pos + 18 //int i = Unsigned.getUnsignedShort(buf, pos + 18); vlr.setRecordID(Unsigned.getUnsignedShort(buf, pos + 18)); // RecordLengthAfterHeader--starts at pos + 20 //int k = Unsigned.getUnsignedShort(buf, pos + 20); vlr.setRecordLengthAfterHeader(Unsigned.getUnsignedShort(buf, pos + 20)); // Description--32 byte ASCII field starting at pos + 22 tmp1 = new short[32]; m = 22; for (int j = 0; j < tmp1.length; j++) { tmp1[j] = Unsigned.getUnsignedByte(buf, pos + m); m++; } String description = convertShortArrayToAscii(tmp1); vlr.setDescription(description); // Read the raw data contained in the vlr byte[] rawData = new byte[vlr.getRecordLengthAfterHeader()]; buf.position(pos + 54); buf.get(rawData); vlr.setRawData(rawData); tmp1 = new short[rawData.length]; for (int j = 0; j < tmp1.length; j++) { tmp1[j] = Unsigned.getUnsignedByte(rawData[j]); } String data = convertShortArrayToAscii(tmp1); String decoded = new String(rawData, "ASCII"); vlr.setFormatedData(data); vlrArray.add(vlr); pos += 54 + vlr.getRecordLengthAfterHeader(); } return true; } catch (Exception e) { return false; } finally { if (rIn != null) { try { rIn.close(); } catch (Exception e) { } } } } private String convertShortArrayToAscii(short[] array) { String str = ""; char[] charArray = new char[array.length]; for (int a = 0; a < array.length; a++) { switch (array[a]) { case 0: charArray[a] = " ".charAt(0); break; case 32: charArray[a] = " ".charAt(0); break; case 33: charArray[a] = "!".charAt(0); break; case 34: charArray[a] = "\"".charAt(0); break; case 35: charArray[a] = "#".charAt(0); break; case 36: charArray[a] = "$".charAt(0); break; case 37: charArray[a] = "%".charAt(0); break; case 38: charArray[a] = "&".charAt(0); break; case 39: charArray[a] = "\'".charAt(0); break; case 40: charArray[a] = "(".charAt(0); break; case 41: charArray[a] = ")".charAt(0); break; case 42: charArray[a] = "*".charAt(0); break; case 43: charArray[a] = "+".charAt(0); break; case 44: charArray[a] = ",".charAt(0); break; case 45: charArray[a] = "-".charAt(0); break; case 46: charArray[a] = ".".charAt(0); break; case 47: charArray[a] = "/".charAt(0); break; case 48: charArray[a] = "0".charAt(0); break; case 49: charArray[a] = "1".charAt(0); break; case 50: charArray[a] = "2".charAt(0); break; case 51: charArray[a] = "3".charAt(0); break; case 52: charArray[a] = "4".charAt(0); break; case 53: charArray[a] = "5".charAt(0); break; case 54: charArray[a] = "6".charAt(0); break; case 55: charArray[a] = "7".charAt(0); break; case 56: charArray[a] = "8".charAt(0); break; case 57: charArray[a] = "9".charAt(0); break; case 58: charArray[a] = ":".charAt(0); break; case 59: charArray[a] = ";".charAt(0); break; case 60: charArray[a] = "<".charAt(0); break; case 61: charArray[a] = "=".charAt(0); break; case 62: charArray[a] = ">".charAt(0); break; case 63: charArray[a] = "?".charAt(0); break; case 64: charArray[a] = "@".charAt(0); break; case 65: charArray[a] = "A".charAt(0); break; case 66: charArray[a] = "B".charAt(0); break; case 67: charArray[a] = "C".charAt(0); break; case 68: charArray[a] = "D".charAt(0); break; case 69: charArray[a] = "E".charAt(0); break; case 70: charArray[a] = "F".charAt(0); break; case 71: charArray[a] = "G".charAt(0); break; case 72: charArray[a] = "H".charAt(0); break; case 73: charArray[a] = "I".charAt(0); break; case 74: charArray[a] = "J".charAt(0); break; case 75: charArray[a] = "K".charAt(0); break; case 76: charArray[a] = "L".charAt(0); break; case 77: charArray[a] = "M".charAt(0); break; case 78: charArray[a] = "N".charAt(0); break; case 79: charArray[a] = "O".charAt(0); break; case 80: charArray[a] = "P".charAt(0); break; case 81: charArray[a] = "Q".charAt(0); break; case 82: charArray[a] = "R".charAt(0); break; case 83: charArray[a] = "S".charAt(0); break; case 84: charArray[a] = "T".charAt(0); break; case 85: charArray[a] = "U".charAt(0); break; case 86: charArray[a] = "V".charAt(0); break; case 87: charArray[a] = "W".charAt(0); break; case 88: charArray[a] = "X".charAt(0); break; case 89: charArray[a] = "Y".charAt(0); break; case 90: charArray[a] = "Z".charAt(0); break; case 91: charArray[a] = "[".charAt(0); break; case 92: charArray[a] = "\\".charAt(0); break; case 93: charArray[a] = "]".charAt(0); break; case 94: charArray[a] = "^".charAt(0); break; case 95: charArray[a] = "_".charAt(0); break; case 96: charArray[a] = "`".charAt(0); break; case 97: charArray[a] = "a".charAt(0); break; case 98: charArray[a] = "b".charAt(0); break; case 99: charArray[a] = "c".charAt(0); break; case 100: charArray[a] = "d".charAt(0); break; case 101: charArray[a] = "e".charAt(0); break; case 102: charArray[a] = "f".charAt(0); break; case 103: charArray[a] = "g".charAt(0); break; case 104: charArray[a] = "h".charAt(0); break; case 105: charArray[a] = "i".charAt(0); break; case 106: charArray[a] = "j".charAt(0); break; case 107: charArray[a] = "k".charAt(0); break; case 108: charArray[a] = "l".charAt(0); break; case 109: charArray[a] = "m".charAt(0); break; case 110: charArray[a] = "n".charAt(0); break; case 111: charArray[a] = "o".charAt(0); break; case 112: charArray[a] = "p".charAt(0); break; case 113: charArray[a] = "q".charAt(0); break; case 114: charArray[a] = "r".charAt(0); break; case 115: charArray[a] = "s".charAt(0); break; case 116: charArray[a] = "t".charAt(0); break; case 117: charArray[a] = "u".charAt(0); break; case 118: charArray[a] = "v".charAt(0); break; case 119: charArray[a] = "w".charAt(0); break; case 120: charArray[a] = "x".charAt(0); break; case 121: charArray[a] = "y".charAt(0); break; case 122: charArray[a] = "z".charAt(0); break; case 123: charArray[a] = "{".charAt(0); break; case 124: charArray[a] = "|".charAt(0); break; case 125: charArray[a] = "}".charAt(0); break; case 126: charArray[a] = "~".charAt(0); break; default: charArray[a] = " ".charAt(0); break; } } str = String.valueOf(charArray); return str; } // related classes public class VariableLengthRecord { // fields String userID; int recordID; int recordLengthAfterHeader; String description; String data; byte[] rawData; // property getters and setters public String getUserID() { return userID; } public void setUserID(String userID) { this.userID = userID; } public int getRecordID() { return recordID; } public void setRecordID(int recordID) { this.recordID = recordID; } public int getRecordLengthAfterHeader() { return recordLengthAfterHeader; } public void setRecordLengthAfterHeader(int recordLengthAfterHeader) { this.recordLengthAfterHeader = recordLengthAfterHeader; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public byte[] getRawData() { return rawData; } public void setRawData(byte[] rawData) { this.rawData = rawData; } public void setFormatedData(String data) { this.data = data; } public String getFormatedData() { return this.data; } } public class PointRecord { private double x; //8 bytes private double y; //8 bytes private double z; //8 bytes private int intensity; //4 bytes private byte classification; //1 bytes private byte returnNumber; //1 byte private byte numberOfReturns; //1 byte private boolean scanDirectionFlag; //1 byte private boolean edgeOfFlightLine; //1 byte private boolean synthetic; //1 byte private boolean keyPoint; //1 byte private boolean pointWithheld; //1 byte private byte scanAngle; //1 byte private short userData; //2 bytes private int pointSourceID; //4 bytes private double GPSTime = -1; //8 bytes public double getX() { return x; } public void setX(double x) { this.x = x; } public double getY() { return y; } public void setY(double y) { this.y = y; } public double getZ() { return z; } public void setZ(double z) { this.z = z; } public int getIntensity() { return intensity; } public void setIntensity(int i) { this.intensity = i; } public byte getClassification() { return classification; } public void setClassification(byte i) { this.classification = i; } public byte getReturnNumber() { return returnNumber; } public void setReturnNumber(byte n) { this.returnNumber = n; } public byte getNumberOfReturns() { return numberOfReturns; } public void setNumberOfReturns(byte n) { numberOfReturns = n; } public boolean getScanDirectionFlag() { return scanDirectionFlag; } public void setScanDirectionFlag(boolean val) { scanDirectionFlag = val; } public boolean isEdgeOfFlightLine() { return edgeOfFlightLine; } public void setEdgeOfFlightLine(boolean val) { edgeOfFlightLine = val; } public boolean isSynthetic() { return synthetic; } public void setSynthetic(boolean val) { synthetic = val; } public boolean isKeyPoint() { return keyPoint; } public void setKeyPoint(boolean val) { keyPoint = val; } public boolean isPointWithheld() { return pointWithheld; } public void setPointWithheld(boolean val) { pointWithheld = val; } public byte getScanAngle() { return scanAngle; } public void setScanAngle(byte a) { scanAngle = a; } public short getUserData() { return userData; } public void setUserData(short d) { userData = d; } public int getPointSourceID() { return pointSourceID; } public void setPointSourceID(int id) { pointSourceID = id; } public double getGPSTime() { return GPSTime; } public void setGPSTime(double t) { GPSTime = t; } } public class PointRecColours { private int red = -1; //2 bytes private int green = -1; //2 bytes private int blue = -1; //2 bytes public int getRed() { return red; } public void setRed(int r) { red = r; } public int getGreen() { return green; } public void setGreen(int g) { green = g; } public int getBlue() { return blue; } public void setBlue(int b) { blue = b; } } // public class PointRecord { // private double x; //8 bytes // private double y; //8 bytes // private double z; //8 bytes // private int intensity; //4 bytes // private byte returnNumber; //1 byte // private byte numberOfReturns; //1 byte // private byte scanDirectionFlag; //1 byte // private byte edgeOfFlightLine; //1 byte // private byte classification; //1 bytes // private short scanAngleRank; //2 bytes // private byte userData; //1 bytes // private int pointSourceID; //4 bytes // private double GPSTime; //8 bytes // private int red; //2 bytes // private int green; //2 bytes // private int blue; //2 bytes // private byte pointWithheld; //1 byte // private byte isSynthetic; //1 byte // private byte isKeyPoint; //1 byte // // public double getX() { // return x; // } // // public void setX(double x) { // this.x = x; // } // } // // This is used for debugging. // public static void main(String[] args) { // int i = 0; // String lasFile = "/Users/johnlindsay/Documents/Data/u_5565073175.las"; // if (!(new File(lasFile)).exists()) { // System.out.println("File not found"); // } else { // LASReader las = new LASReader(lasFile); // for (int a = 0; a < las.getNumPointRecords(); a++) { // //PointRecord pr = las.getPointRecord(a); // //System.out.println(pr.getZ() + " " + pr.getIntensity() + " " + pr.getClassification() + " " + pr.getReturnNumber() + " " + pr.getNumberOfReturns()); // i++; // } // } // System.out.println(i); // } }