gvsig-projects-pool / org.gvsig.lidar.prov / org.gvsig.lidar.prov.jgrass / src / main / java / org / gvsig / lidar / prov / jgrasstools / JGrassLASWriter.java @ 281
History | View | Annotate | Download (10.5 KB)
1 |
package org.gvsig.lidar.prov.jgrasstools; |
---|---|
2 |
|
3 |
import java.io.File; |
4 |
import java.util.Date; |
5 |
|
6 |
import org.apache.commons.io.FileUtils; |
7 |
import org.cresques.cts.ICRSFactory; |
8 |
import org.cresques.cts.IProjection; |
9 |
import org.gvsig.fmap.dal.exception.CloseException; |
10 |
import org.gvsig.fmap.dal.exception.DataException; |
11 |
import org.gvsig.fmap.dal.exception.OpenException; |
12 |
import org.gvsig.fmap.dal.exception.WriteException; |
13 |
import org.gvsig.fmap.dal.feature.Feature; |
14 |
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor; |
15 |
import org.gvsig.fmap.dal.feature.FeatureSet; |
16 |
import org.gvsig.fmap.dal.feature.FeatureType; |
17 |
import org.gvsig.fmap.geom.Geometry.TYPES; |
18 |
import org.gvsig.fmap.geom.primitive.Envelope; |
19 |
import org.gvsig.fmap.geom.primitive.Point; |
20 |
import org.gvsig.lidar.prov.ConversionUtils; |
21 |
import org.gvsig.lidar.prov.LASDataStoreParameters; |
22 |
import org.gvsig.lidar.prov.LASDataStoreProvider; |
23 |
import org.gvsig.tools.dispose.DisposableIterator; |
24 |
import org.gvsig.tools.dispose.DisposeUtils; |
25 |
import org.jgrasstools.gears.io.las.core.ALasWriter; |
26 |
import org.jgrasstools.gears.io.las.core.LasRecord; |
27 |
import org.jgrasstools.gears.io.las.core.liblas.LiblasWriter; |
28 |
import org.jgrasstools.gears.io.las.core.v_1_0.LasWriter; |
29 |
import org.slf4j.Logger; |
30 |
import org.slf4j.LoggerFactory; |
31 |
|
32 |
public class JGrassLASWriter { |
33 |
protected LASDataStoreParameters params;
|
34 |
protected Envelope outEnvelope;
|
35 |
protected FeatureType fType;
|
36 |
private int geomIndex, colorIdx, classificationIdx, weektimeIdx, gpstimeIdx, intensityIdx, returnNumIdx, numberOfReturnsIdx; |
37 |
protected ALasWriter writer = null; |
38 |
protected LasRecord record = null; |
39 |
double[] scale = null; |
40 |
double[] offset = null; |
41 |
int pointFormat = -1; |
42 |
|
43 |
private static final Logger LOG = LoggerFactory.getLogger(JGrassLASWriter.class); |
44 |
|
45 |
public JGrassLASWriter(LASDataStoreParameters outParams, FeatureType featType, Envelope outEnvelope) throws DataException { |
46 |
this.params = outParams;
|
47 |
this.outEnvelope = outEnvelope;
|
48 |
this.fType = featType;
|
49 |
} |
50 |
|
51 |
protected ALasWriter getWriter() throws CantCreateWriterException { |
52 |
if (writer==null) { |
53 |
|
54 |
try{
|
55 |
if (ALasWriter.supportsNative()) {
|
56 |
writer = new LiblasWriter(this.params.getFile(), null); |
57 |
} |
58 |
else {
|
59 |
writer = new LasWriter(this.params.getFile(), null); |
60 |
} |
61 |
} catch (Exception exc) { |
62 |
throw new CantCreateWriterException("Can't create LAS writer", exc, "Can't create LAS writer", -1); |
63 |
} |
64 |
} |
65 |
return writer;
|
66 |
} |
67 |
|
68 |
protected int getPointFormat() { |
69 |
if (this.pointFormat!=-1) { |
70 |
return this.pointFormat; |
71 |
} |
72 |
|
73 |
boolean color = this.fType.getAttributeDescriptor(LASDataStoreProvider.COLOR_FIELD)!=null?true:false; |
74 |
boolean weekTime = this.fType.getAttributeDescriptor(LASDataStoreProvider.WEEKTIME_FIELD)!=null?true:false; |
75 |
boolean time = this.fType.getAttributeDescriptor(LASDataStoreProvider.TIME_FIELD)!=null?true:false; |
76 |
int pointFormat;
|
77 |
if ( (time||weekTime) && color ) {
|
78 |
pointFormat = 3;
|
79 |
} |
80 |
else if (color) { |
81 |
pointFormat = 2;
|
82 |
} |
83 |
else if (time||weekTime) { |
84 |
pointFormat = 1;
|
85 |
} |
86 |
else {
|
87 |
pointFormat = 0;
|
88 |
} |
89 |
return pointFormat;
|
90 |
} |
91 |
|
92 |
class CantCreateWriterException extends DataException { |
93 |
public CantCreateWriterException(String messageFormat, |
94 |
Throwable cause, String messageKey, long code) { |
95 |
super(messageFormat, cause, messageKey, code);
|
96 |
} |
97 |
} |
98 |
|
99 |
public boolean open() throws DataException { |
100 |
record = new LasRecord();
|
101 |
record.returnNumber = 1; //set record defaults |
102 |
record.numberOfReturns = 1;
|
103 |
ALasWriter writer = getWriter(); |
104 |
final FeatureAttributeDescriptor geomAttrib = fType.getDefaultGeometryAttribute();
|
105 |
geomIndex = geomAttrib.getIndex(); |
106 |
if (geomAttrib.getGeomType().getType()!=TYPES.POINT) {
|
107 |
new CantCreateWriterException("LAS files can only store points", null, "LAS files can only store points", -1); |
108 |
} |
109 |
if (fType.getAttributeDescriptor(LASDataStoreProvider.COLOR_FIELD)!=null) { |
110 |
colorIdx = fType.getAttributeDescriptor(LASDataStoreProvider.COLOR_FIELD).getIndex(); |
111 |
} |
112 |
else {
|
113 |
colorIdx = -1;
|
114 |
} |
115 |
if (fType.getAttributeDescriptor(LASDataStoreProvider.CLASS_FIELD)!=null) { |
116 |
classificationIdx = fType.getAttributeDescriptor(LASDataStoreProvider.CLASS_FIELD).getIndex(); |
117 |
} |
118 |
else {
|
119 |
classificationIdx = -1;
|
120 |
} |
121 |
if (fType.getAttributeDescriptor(LASDataStoreProvider.WEEKTIME_FIELD)!=null) { |
122 |
weektimeIdx = fType.getAttributeDescriptor(LASDataStoreProvider.WEEKTIME_FIELD).getIndex(); |
123 |
} |
124 |
else {
|
125 |
weektimeIdx = -1;
|
126 |
} |
127 |
if (fType.getAttributeDescriptor(LASDataStoreProvider.TIME_FIELD)!=null) { |
128 |
writer.setGpsTimeType(1);
|
129 |
gpstimeIdx = fType.getAttributeDescriptor(LASDataStoreProvider.TIME_FIELD).getIndex(); |
130 |
} |
131 |
else {
|
132 |
gpstimeIdx = -1;
|
133 |
} |
134 |
if (fType.getAttributeDescriptor(LASDataStoreProvider.INTENSITY_FIELD)!=null) { |
135 |
intensityIdx = fType.getAttributeDescriptor(LASDataStoreProvider.INTENSITY_FIELD).getIndex(); |
136 |
} |
137 |
else {
|
138 |
intensityIdx = -1;
|
139 |
} |
140 |
if (fType.getAttributeDescriptor(LASDataStoreProvider.RETURNNUM_FIELD)!=null) { |
141 |
returnNumIdx = fType.getAttributeDescriptor(LASDataStoreProvider.RETURNNUM_FIELD).getIndex(); |
142 |
} |
143 |
else {
|
144 |
returnNumIdx = -1;
|
145 |
} |
146 |
if (fType.getAttributeDescriptor(LASDataStoreProvider.NUMRETURNS_FIELD)!=null) { |
147 |
numberOfReturnsIdx = fType.getAttributeDescriptor(LASDataStoreProvider.NUMRETURNS_FIELD).getIndex(); |
148 |
} |
149 |
else {
|
150 |
numberOfReturnsIdx = -1;
|
151 |
} |
152 |
writer.setPointFormat(getPointFormat()); |
153 |
if (outEnvelope!=null) { |
154 |
writer.setBounds(this.outEnvelope.getMinimum(0), this.outEnvelope.getMaximum(0), this.outEnvelope.getMinimum(1), this.outEnvelope.getMaximum(1), this.outEnvelope.getMinimum(2), this.outEnvelope.getMaximum(2)); |
155 |
} |
156 |
|
157 |
if (offset==null) { |
158 |
offset = new double[3]; |
159 |
offset[0] = (this.outEnvelope.getMinimum(0) + this.outEnvelope.getMaximum(0))/2; |
160 |
offset[1] = (this.outEnvelope.getMinimum(1) + this.outEnvelope.getMaximum(1))/2; |
161 |
offset[2] = (this.outEnvelope.getMinimum(2) + this.outEnvelope.getMaximum(2))/2; |
162 |
} |
163 |
writer.setOffset(offset[0], offset[1], offset[2]); |
164 |
|
165 |
if (scale==null) { |
166 |
scale = new double[3]; |
167 |
// scaleX
|
168 |
scale[0] = calculateScale(this.outEnvelope.getMinimum(0), this.outEnvelope.getMaximum(0), offset[0]); |
169 |
// scaleY
|
170 |
scale[1] = calculateScale(this.outEnvelope.getMinimum(1), this.outEnvelope.getMaximum(1), offset[1]); |
171 |
// scaleZ
|
172 |
scale[2] = calculateScale(this.outEnvelope.getMinimum(2), this.outEnvelope.getMaximum(2), offset[2]); |
173 |
} |
174 |
writer.setScales(scale[0], scale[1], scale[2]); |
175 |
|
176 |
try {
|
177 |
writer.open(); |
178 |
} catch (Exception e) { |
179 |
throw new OpenException(null, e); |
180 |
} |
181 |
return true; |
182 |
} |
183 |
|
184 |
public void setOffset(double offsetX, double offsetY, double offsetZ) { |
185 |
if (offset==null) { |
186 |
offset = new double[3]; |
187 |
} |
188 |
offset[0] = offsetX;
|
189 |
offset[1] = offsetY;
|
190 |
offset[2] = offsetZ;
|
191 |
} |
192 |
|
193 |
public void setScale(double scaleX, double scaleY, double scaleZ) { |
194 |
if (scale==null) { |
195 |
scale = new double[3]; |
196 |
} |
197 |
scale[0] = scaleX;
|
198 |
scale[1] = scaleY;
|
199 |
scale[2] = scaleZ;
|
200 |
} |
201 |
|
202 |
/**
|
203 |
* Calculates a reasonable scale for the provided min, max and offset
|
204 |
* values
|
205 |
*
|
206 |
* @param min minimum value in the range to store
|
207 |
* @param max maximum value in the range to store
|
208 |
* @param offset
|
209 |
*
|
210 |
* @return
|
211 |
*/
|
212 |
private double calculateScale(double min, double max, double offset) { |
213 |
double offsettedMin = min - offset;
|
214 |
double offsettedMax = max - offset;
|
215 |
|
216 |
int absMax = (int) Math.max(Math.abs(offsettedMin), Math.abs(offsettedMax)); |
217 |
int numDigits = Integer.toString(absMax).length(); |
218 |
int maxDigits = 9; // Java ints can safely store 9 digits |
219 |
int decimalDigits = (maxDigits - numDigits);
|
220 |
if (decimalDigits < 0) { |
221 |
decimalDigits = 0;
|
222 |
} |
223 |
return Math.pow(10, -decimalDigits); |
224 |
} |
225 |
|
226 |
public void close() throws CloseException { |
227 |
try {
|
228 |
getWriter().close(); |
229 |
IProjection crs = this.params.getCRS();
|
230 |
File projFile = this.params.getPrj(); |
231 |
if (crs!=null && projFile!=null) { |
232 |
savePrjFile(projFile, crs); |
233 |
} |
234 |
} catch (Exception e) { |
235 |
throw new CloseException(null, e); |
236 |
} |
237 |
} |
238 |
|
239 |
protected void savePrjFile(File prjFile, IProjection proj){ |
240 |
try {
|
241 |
String export = proj.export(ICRSFactory.FORMAT_WKT); |
242 |
if(export!=null){ |
243 |
FileUtils.writeStringToFile(prjFile, export);
|
244 |
} |
245 |
} catch (Exception e) { |
246 |
LOG.info("Can't write prj file '" + prjFile.getAbsolutePath() + "'."); |
247 |
} |
248 |
} |
249 |
|
250 |
public void write(Feature feature) throws WriteException { |
251 |
try {
|
252 |
Point point = (Point) feature.getGeometry(geomIndex); |
253 |
record.x = point.getCoordinateAt(0);
|
254 |
record.y = point.getCoordinateAt(1);
|
255 |
record.z = point.getCoordinateAt(2);
|
256 |
if (colorIdx!=-1) { |
257 |
int[] rgbArray = ConversionUtils.intToRgb(feature.getInt(colorIdx)); |
258 |
record.color[0] = (short) rgbArray[0]; |
259 |
record.color[1] = (short) rgbArray[1]; |
260 |
record.color[2] = (short) rgbArray[2]; |
261 |
|
262 |
} |
263 |
if (classificationIdx!=-1) { |
264 |
record.classification = feature.getByte(classificationIdx); |
265 |
} |
266 |
if (weektimeIdx!=-1) { |
267 |
record.gpsTime = (double) feature.getLong(weektimeIdx);
|
268 |
} |
269 |
else if (gpstimeIdx!=-1) { |
270 |
Date d = feature.getDate(gpstimeIdx);
|
271 |
if (d!=null) { |
272 |
long unixTime = d.getTime();
|
273 |
long las_time = unixTime - ConversionUtils.LAS_TIME_TO_UNIX_TIME;
|
274 |
record.gpsTime = (double) las_time;
|
275 |
} |
276 |
else {
|
277 |
record.gpsTime = 0.0d;
|
278 |
} |
279 |
} |
280 |
if (intensityIdx!=-1) { |
281 |
record.intensity = (short) feature.getInt(intensityIdx);
|
282 |
} |
283 |
if (returnNumIdx!=-1) { |
284 |
record.returnNumber = (short) feature.getByte(returnNumIdx);
|
285 |
} |
286 |
if (numberOfReturnsIdx!=-1) { |
287 |
record.numberOfReturns = (short) feature.getByte(numberOfReturnsIdx);
|
288 |
} |
289 |
|
290 |
writer.addPoint(record); |
291 |
} catch (NullPointerException e) { |
292 |
throw new WriteException("The writer must be open() before starting writing", e); |
293 |
} catch (Exception e) { |
294 |
throw new WriteException(e.getMessage(), e); |
295 |
} |
296 |
} |
297 |
|
298 |
public void write(FeatureSet set) throws DataException { |
299 |
DisposableIterator iter = null;
|
300 |
try {
|
301 |
iter = set.fastIterator(); |
302 |
while (iter.hasNext()) {
|
303 |
Feature feature = (Feature) iter.next(); |
304 |
write(feature); |
305 |
} |
306 |
} finally {
|
307 |
DisposeUtils.disposeQuietly(iter); |
308 |
} |
309 |
} |
310 |
|
311 |
public void setPointFormat(int pointFormat) { |
312 |
this.pointFormat = pointFormat;
|
313 |
} |
314 |
} |