4
\$\begingroup\$

I want to implement a wavefront-reader in Java. Therefore I've created some classes to extract a Vector3f and Vector2f (I use JOML for these model classes) or a Triangle (my own model class) from a certain line of a wavefront (.obj) file.

I only want to read a special wavefront file (not all types) and only some certain lines.

I want to read:

  • 3-dimensional geometric Vertices defined as v v1 v2 v3
  • 2-dimensional TextureCoordinates defined as vt vt1 vt2
  • 3-dimensional Vertex Normals defined as vn vn1 vn2 vn3
  • The corresponding Faces defined as f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3

I use:

  • Spring for dependency-injection
  • AutoValue classes
  • Guava for collections, functions and preconditions
  • Java 8 for lambda expressions

The Spring Configuration File

@Configuration
@ComponentScan("de.sorted.chaos.wavefront.reader")
@EnableAutoConfiguration
public class ApplicationConfiguration {
}

Model

Point

@AutoValue
public abstract class Point {
  public static Point of(final Integer... indices) {
    checkArgument(indices.length == 3, "invalid number of of indices for a Point");
    final List<Integer> indexList = Arrays.asList(indices);
    return new AutoValue_Point(indexList);
  }

  Point() {}

  public abstract List<Integer> indices();

  public int vertexIndex() {
    return indices().get(0);
  }

  public int textureIndex() {
    return indices().get(1);
  }

  public int normalIndex() {
    return indices().get(2);
  }
}

Triangle

@AutoValue
public abstract class Triangle {
  public static Triangle of(final Point... points) {
    checkArgument(points.length == 3, "invalid number of Points for a Triangle");
    final List<Point> pointList = Arrays.asList(points);
    return new AutoValue_Triangle(pointList);
  }

  Triangle() {}

  public abstract List<Point> points();

  public Point point1() {
    return points().get(0);
  }

  public Point point2() {
    return points().get(1);
  }

  public Point point3() {
    return points().get(2);
  }
}

Helpers to get the Elements of a file line

RemoveToken

@Component
public class RemoveToken {
  public List<String> from(final List<String> lineElements) {
    final int size = lineElements.size();
    return lineElements.subList(1, size);
  }
}

ExtractLineElements

@Component
public class ExtractLineElements {
  private static final String DELIMITER = " ";

  @Autowired
  private RemoveToken removeToken;

  public List<String> from(final String line) {
    final List<String> lineElements = Arrays.asList(line.split(DELIMITER));
    return removeToken.from(lineElements);
  }
}

ExtractIndices

@Component
public class ExtractIndices {
  private static final String DELIMITER = "/";

  public List<String> from(final String pointIndices) {
    return Arrays.asList(pointIndices.split(DELIMITER));
  }
}

Helpers for transforming the data

ToFloat

@Component
public class ToFloat {
  public float from(final String text) {
    return Float.parseFloat(text);
  }
}

ToInt

@Component
public class ToInt {
  public int from(final String text) {
    return Integer.parseInt(text);
  }
}

ToPoint

@Component
public class ToPoint {
  @Autowired
  private ExtractIndices extract;
  @Autowired
  private ToInt toInt;

  public Point from(final String pointIndices) {
    final List<String> indices = extract.from(pointIndices);
    return toPoint().apply(indices);
  }

  private Function<List<String>, Point> toPoint() {
    return input -> {
      checkArgument(input.size() == 3, "invalid number of arguments for a Point");
      final int vertexIndex = toInt.from(input.get(0));
      final int textureIndex = toInt.from(input.get(1));
      final int normalIndex = toInt.from(input.get(2));
      return Point.of(vertexIndex, textureIndex, normalIndex);
    };
  }
}

The Transformers

CreateVector3f

@Component
public class CreateVector3f {
  @Autowired
  private ExtractLineElements extract;
  @Autowired
  private ToFloat toFloat;

  public Vector3f from(final String line) {
    final List<String> lineElements = extract.from(line);
    return toVector3f().apply(lineElements);
  }

  private Function<List<String>, Vector3f> toVector3f() {
    return input -> {
      checkArgument(input.size() == 3, "invalid number of arguments for Vector3f");
      final float x = toFloat.from(input.get(0));
      final float y = toFloat.from(input.get(1));
      final float z = toFloat.from(input.get(2));
      return new Vector3f(x, y, z);
    };
  }
}

CreateVector2f

@Component
public class CreateVector2f {
  @Autowired
  private ExtractLineElements extract;
  @Autowired
  private ToFloat toFloat;

  public Vector2f from(final String line) {
    final List<String> lineElements = extract.from(line);
    return toVector2f().apply(lineElements);
  }

  private Function<List<String>, Vector2f> toVector2f() {
    return input -> {
      checkArgument(input.size() == 2, "invalid number of arguments for Vector2f");
      final float x = toFloat.from(input.get(0));
      final float y = toFloat.from(input.get(1));
      return new Vector2f(x, y);
    };
  }
}

CreateTriangle

@Component
public class CreateTriangle {
  @Autowired
  private ExtractLineElements extract;
  @Autowired
  private ToPoint toPoint;

  public Triangle from(final String line) {
    final List<String> lineElements = extract.from(line);
    return toTriangle().apply(lineElements);
  }

  private Function<List<String>, Triangle> toTriangle() {
    return input -> {
      checkArgument(input.size() == 3, "invalid number of arguments for a Triangle");
      final Point point1 = toPoint.from(input.get(0));
      final Point point2 = toPoint.from(input.get(1));
      final Point point3 = toPoint.from(input.get(2));
      return Triangle.of(point1, point2, point3);
    };
  }
}

Has someone some hints for me to write better code? Perhaps something with generics because the CreateStuff classes look nearly the same (but I have no access to Vector2f and Vector3f classes) - same for the Extractor classes to get the lines of the file. They look nearly the same too.

If you are interested in part II - look here.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.