/*******************************************************************************
* Copyright 2012 Geoscience Australia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package au.gov.ga.earthsci.worldwind.common.layers.model.gocad;
import gov.nasa.worldwind.geom.Position;
import java.awt.Color;
import java.net.URL;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.media.opengl.GL2;
import au.gov.ga.earthsci.worldwind.common.render.fastshape.FastShape;
/**
* {@link GocadReader} implementation for reading PLine GOCAD files.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class GocadPLineReader implements GocadReader<FastShape>
{
public final static String HEADER_REGEX = "(?i).*pline.*";
private final static Pattern segmentPattern = Pattern.compile("SEG\\s+(\\d+)\\s+(\\d+).*");
private GocadReaderParameters parameters;
private List<Position> positions;
private List<Integer> segmentIds;
private Color color;
private Map<Integer, Integer> vertexIdMap;
private String name;
private boolean zPositive = true;
private List<Float> values;
private float min, max;
private String paintedVariableName;
private int paintedVariableId = 0;
private float noDataValue = -Float.MAX_VALUE;
@Override
public void begin(GocadReaderParameters parameters)
{
this.parameters = parameters;
positions = new ArrayList<Position>();
values = new ArrayList<Float>();
min = Float.MAX_VALUE;
max = -Float.MAX_VALUE;
segmentIds = new ArrayList<Integer>();
vertexIdMap = new HashMap<Integer, Integer>();
paintedVariableName = parameters.getPaintedVariable();
}
@Override
public void addLine(String line)
{
Matcher matcher;
matcher = vertexPattern.matcher(line);
if (matcher.matches())
{
int id = Integer.parseInt(matcher.group(1));
if (vertexIdMap.containsKey(id))
{
throw new IllegalArgumentException("Duplicate vertex id: " + id);
}
double x = Double.parseDouble(matcher.group(2));
double y = Double.parseDouble(matcher.group(3));
double z = Double.parseDouble(matcher.group(4));
z = zPositive ? z : -z;
if (parameters.getCoordinateTransformation() != null)
{
double[] transformed = new double[3];
parameters.getCoordinateTransformation().TransformPoint(transformed, x, y, z);
x = transformed[0];
y = transformed[1];
z = transformed[2];
}
Position position = Position.fromDegrees(y, x, z);
vertexIdMap.put(id, positions.size());
positions.add(position);
float value = Float.NaN;
if (paintedVariableId <= 0)
{
value = (float) z;
}
else
{
double[] values = GocadTSurfReader.splitStringToDoubles(matcher.group(5));
if (paintedVariableId <= values.length)
{
value = (float) values[paintedVariableId - 1];
}
}
if (!Float.isNaN(value) && value != noDataValue)
{
min = Math.min(min, value);
max = Math.max(max, value);
}
values.add(value);
return;
}
matcher = atomPattern.matcher(line);
if (matcher.matches())
{
int id1 = Integer.parseInt(matcher.group(1));
int id2 = Integer.parseInt(matcher.group(2));
if (vertexIdMap.containsKey(id1))
{
throw new IllegalArgumentException("Duplicate vertex id: " + id1);
}
if (!vertexIdMap.containsKey(id2))
{
throw new IllegalArgumentException("Unknown vertex id: " + id2);
}
Position position = positions.get(vertexIdMap.get(id2));
vertexIdMap.put(id1, positions.size());
positions.add(position);
float value = Float.NaN;
if (paintedVariableId <= 0)
{
value = (float) position.elevation;
}
else
{
double[] values = GocadTSurfReader.splitStringToDoubles(matcher.group(3));
if (paintedVariableId <= values.length)
{
value = (float) values[paintedVariableId - 1];
}
}
if (!Float.isNaN(value) && value != noDataValue)
{
min = Math.min(min, value);
max = Math.max(max, value);
}
values.add(value);
return;
}
matcher = segmentPattern.matcher(line);
if (matcher.matches())
{
int s1 = Integer.parseInt(matcher.group(1));
int s2 = Integer.parseInt(matcher.group(2));
segmentIds.add(s1);
segmentIds.add(s2);
return;
}
matcher = lineColorPattern.matcher(line);
if (matcher.matches())
{
color = GocadColor.gocadLineToColor(line);
return;
}
matcher = namePattern.matcher(line);
if (matcher.matches())
{
name = matcher.group(1);
return;
}
matcher = zpositivePattern.matcher(line);
if (matcher.matches())
{
zPositive = !matcher.group(1).equalsIgnoreCase("depth");
}
matcher = paintedVariablePattern.matcher(line);
if (matcher.matches())
{
if (parameters.getPaintedVariable() == null)
{
paintedVariableName = matcher.group(1);
}
return;
}
matcher = propertiesPattern.matcher(line);
if (matcher.matches())
{
String properties = matcher.group(1).trim();
String[] split = properties.split("\\s+");
for (int i = 0; i < split.length; i++)
{
if (split[i].equalsIgnoreCase(paintedVariableName))
{
paintedVariableId = i + 1;
break;
}
}
return;
}
matcher = nodataValuesPattern.matcher(line);
if (matcher.matches())
{
double[] values = GocadTSurfReader.splitStringToDoubles(matcher.group(1));
if (0 < paintedVariableId && paintedVariableId <= values.length)
{
noDataValue = (float) values[paintedVariableId - 1];
}
return;
}
}
@Override
public FastShape end(URL context)
{
IntBuffer indicesBuffer = IntBuffer.allocate(segmentIds.size());
for (Integer i : segmentIds)
{
if (!vertexIdMap.containsKey(i))
{
throw new IllegalArgumentException("Unknown vertex id: " + i);
}
indicesBuffer.put(vertexIdMap.get(i));
}
if (name == null)
{
name = "PLine";
}
FastShape shape = new FastShape(positions, indicesBuffer.array(), GL2.GL_LINES);
shape.setName(name);
if (parameters.getColorMap() != null)
{
FloatBuffer colorBuffer = FloatBuffer.allocate(positions.size() * 4);
for (float value : values)
{
if (Float.isNaN(value) || value == noDataValue)
{
colorBuffer.put(0).put(0).put(0).put(0);
}
else
{
Color color = parameters.getColorMap().calculateColorNotingIsValuesPercentages(value, min, max);
colorBuffer.put(color.getRed() / 255f).put(color.getGreen() / 255f).put(color.getBlue() / 255f)
.put(color.getAlpha() / 255f);
}
}
shape.setColorBufferElementSize(4);
shape.setColorBuffer(colorBuffer.array());
}
else if (color != null)
{
shape.setColor(color);
}
return shape;
}
}