/*******************************************************************************
* 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 java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import au.gov.ga.earthsci.worldwind.common.render.fastshape.FastShape;
/**
* Factory for creating {@link Object}s from GOCAD files.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class GocadFactory
{
private static final String COMMENT_REGEX = "\\s*#.*";
public static boolean isGocadFileSuffix(String suffix)
{
return suffix.equalsIgnoreCase("ts") || suffix.equalsIgnoreCase("gp") || suffix.equalsIgnoreCase("vo")
|| suffix.equalsIgnoreCase("pl") || suffix.equalsIgnoreCase("grs") || suffix.equalsIgnoreCase("sg");
}
/**
* Enumeration of different GOCAD file types.
*/
public enum GocadType
{
PLine(GocadPLineReader.HEADER_REGEX, GocadPLineReader.END_REGEX, GocadPLineReader.class),
Voxet(GocadVoxetReader.HEADER_REGEX, GocadVoxetReader.END_REGEX, GocadVoxetReader.class),
TSurf(GocadTSurfReader.HEADER_REGEX, GocadTSurfReader.END_REGEX, GocadTSurfReader.class),
SGrid(GocadSGridReader.HEADER_REGEX, GocadSGridReader.END_REGEX, GocadSGridReader.class),
GSurf(GocadGSurfReader.HEADER_REGEX, GocadGSurfReader.END_REGEX, GocadGSurfReader.class),
Group(GocadGroupReader.HEADER_REGEX, GocadGroupReader.END_REGEX, GocadGroupReader.class),
VSet(GocadVSetReader.HEADER_REGEX, GocadVSetReader.END_REGEX, GocadVSetReader.class);
/**
* Regular expression used for matching the first line of the GOCAD object to this type.
*/
public final String headerRegex;
/**
* Regular expression used for matching the end of the GOCAD object of this type.
*/
public final String endRegex;
/**
* {@link GocadReader} implementation used for reading this type.
*/
public final Class<? extends GocadReader<?>> readerClass;
private GocadType(String headerRegex, String endRegex, Class<? extends GocadReader<?>> readerClass)
{
this.headerRegex = headerRegex;
this.endRegex = endRegex;
this.readerClass = readerClass;
}
/**
* @return An instance of a {@link GocadReader} for reading a file of
* this type.
*/
public GocadReader<?> instanciateReader()
{
try
{
return readerClass.newInstance();
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
}
}
public static List<FastShape> read(File file, GocadReaderParameters parameters)
{
try
{
return read(new FileReader(file), file.toURI().toURL(), parameters);
}
catch (MalformedURLException e)
{
//won't ever happen
return null;
}
catch (FileNotFoundException e)
{
e.printStackTrace();
return null;
}
}
public static List<FastShape> read(InputStream is, URL context, GocadReaderParameters parameters)
{
return read(new InputStreamReader(is), context, parameters);
}
/**
* Read a GOCAD source to a {@link Object}.
*
* @param reader
* Reader to read from
* @return A list of {@link Object}s containing the geometry from the
* GOCAD file
*/
public static List<FastShape> read(Reader reader, URL context, GocadReaderParameters parameters)
{
List<FastShape> shapes = new ArrayList<FastShape>();
try
{
BufferedReader br = new BufferedReader(reader);
while (true)
{
String line = br.readLine();
if (line == null)
{
if (shapes.size() == 0)
{
throw new IllegalArgumentException("No GOCAD objects found");
}
//file is finished, so break out of loop
break;
}
//check if the line matches any of the GOCAD object header regexes
GocadType type = determineGocadType(line);
if (type == null)
{
//if this line doesn't, try the next line
continue;
}
Object object = readFromGocadObject(type, parameters, br, context);
if (object instanceof FastShape)
{
shapes.add((FastShape) object);
}
else if (object instanceof GocadReaderParameters)
{
parameters = (GocadReaderParameters) object;
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
return shapes;
}
/**
* Determine the {@link GocadType} from the header line in the file.
*
* @param line
* First line in the GOCAD file
* @return {@link GocadType} matched for the header, or null if none found.
*/
protected static GocadType determineGocadType(String line)
{
for (GocadType type : GocadType.values())
{
if (line.matches(type.headerRegex))
{
return type;
}
}
return null;
}
/**
* Reads a GOCAD object of the defined type from the buffered reader provided.
* <p/>
* The provided buffered reader will be advanced to the last line of the GOCAD object
* on successful return from this method.
*
* @param type The type of GOCAD object to read
* @param parameters Global reader parameters to use
* @param br The buffered reader to read the GOCAD object from
* @param context The URL of the file being read
*
* @return A {@link Object} that represents the read GOCAD object
*
* @throws IOException
*/
private static Object readFromGocadObject(GocadType type, GocadReaderParameters parameters, BufferedReader br, URL context) throws IOException
{
GocadReader<?> gocadReader = type.instanciateReader();
gocadReader.begin(parameters);
while (true)
{
String line = br.readLine();
if (line == null)
{
throw new IllegalArgumentException("GOCAD file ended unexpectedly");
}
if (line.matches(COMMENT_REGEX))
{
//don't pass comment lines to the reader
continue;
}
if (line.matches(type.endRegex))
{
//object has ended, break out of the loop to parse the next object (if any)
break;
}
gocadReader.addLine(line);
}
return gocadReader.end(context);
}
}