I created a fairly simple algorithm to answer my question.
I don't think it is very efficient but it works pretty well.
I think the functions that I have added can be bypassed by JPCT functions easier to use.
The class is called ModelComposerImpl.
The main function :
public static Object3D generateFlatModel(final List<Object3D> inPoints,
final float height, final int groundTextureId,
final int roofTextureId) {
final Object3D plan = new Object3D(1000);
final List<Object3D> points = new ArrayList<Object3D>(inPoints);
int i = 0;
// The angle to know if a corner is in or out the shape.
final float innerAngle = ModelComposerImpl.calcInnerAngle(inPoints);
// The vector to lift the plan by the given value.
final SimpleVector liftVector = new SimpleVector(0, 0, -(inPoints
.get(0).getOrigin().z - height));
final float textureRatio = 128;
// While we can make triangles
while (points.size() > 2) {
final int size = points.size();
// Get the angle of the corner
final float angle = ModelComposerImpl.getAngle(points.get(i % size)
.getOrigin(), points.get((i + 1) % size).getOrigin(),
points.get((i + 2) % size).getOrigin());
// If the corner is an obtuse angle
if (angle <= 0 && innerAngle > 0 || angle >= 0 && innerAngle < 0) {
++i;
continue;
}
boolean intersected = false;
// Check if the triangle overlaps another side of the shape
for (int j = 0; j < inPoints.size() && !intersected; ++j) {
intersected = ModelComposerImpl.isLineCrossing(
points.get(i % size).getOrigin(),
points.get((i + 2) % size).getOrigin(),
inPoints.get(j % inPoints.size()).getOrigin(), inPoints
.get((j + 1) % inPoints.size()).getOrigin());
}
// If the triangle does not overlaps another side of the shape,
// create the triangle.
if (!intersected) {
final SimpleVector point1 = points.get((i + 2) % size)
.getOrigin().calcAdd(liftVector);
final SimpleVector point2 = points.get((i + 1) % size)
.getOrigin().calcAdd(liftVector);
final SimpleVector point3 = points.get(i % size).getOrigin()
.calcAdd(liftVector);
// Upper face
plan.addTriangle(point1, point1.x / textureRatio, point1.y
/ textureRatio, point2, point2.x / textureRatio,
point2.y / textureRatio, point3, point3.x
/ textureRatio, point3.y / textureRatio,
innerAngle > 0 ? groundTextureId : roofTextureId);
// Lower face
plan.addTriangle(point3, point3.x / textureRatio, point3.y
/ textureRatio, point2, point2.x / textureRatio,
point2.y / textureRatio, point1, point1.x
/ textureRatio, point1.y / textureRatio,
innerAngle > 0 ? roofTextureId : groundTextureId);
points.remove((i + 1) % size);
} else {
++i;
}
}
return plan;
}
The function to get the an angle between two vectors (it's to bad that I don't found a simple method to get an oriented angle so I do it manualy) :
public static float getAngle(final SimpleVector side1,
final SimpleVector center, final SimpleVector side2) {
final SimpleVector side1Vector = side1.calcSub(center);
final SimpleVector side2Vector = side2.calcSub(center);
float angle = side1.calcSub(center).calcAngle(side2.calcSub(center));
// If the angle is an obtuse angle, subtract PI to the angle
if (side1Vector.x < side2Vector.x && side1Vector.y > side2Vector.y
&& side1Vector.y > 0 && side2Vector.x > 0) {
angle -= Math.PI;
}
if (side1Vector.x < side2Vector.x && side1Vector.y < side2Vector.y
&& side1Vector.x < 0 && side2Vector.y > 0) {
angle -= Math.PI;
}
if (side1Vector.x > side2Vector.x && side1Vector.y < side2Vector.y
&& side1Vector.y < 0 && side2Vector.x < 0) {
angle -= Math.PI;
}
if (side1Vector.x > side2Vector.x && side1Vector.y > side2Vector.y
&& side1Vector.x > 0 && side2Vector.y < 0) {
angle -= Math.PI;
}
return angle;
}
The function to check if two segments are crossing (return false if the segments get a same point)
I think this function can be replaced by a jpct's function but I don't find it.
public static boolean isLineCrossing(final SimpleVector line1Origin,
final SimpleVector line1End, final SimpleVector line2Origin,
final SimpleVector line2End) {
// If the lines have a same point , return false.
if (line1Origin.distance(line2Origin) == 0
|| line1Origin.distance(line2End) == 0
|| line1End.distance(line2Origin) == 0
|| line1End.distance(line2End) == 0) {
return false;
}
double sx;
double sy;
if (line1Origin.x == line1End.x) {
if (line2Origin.x == line2End.x) {
return false;
} else {
final double pCD = (line2Origin.y - line2End.y)
/ (line2Origin.x - line2End.x);
sx = line1Origin.x;
sy = pCD * (line1Origin.x - line2Origin.x) + line2Origin.y;
}
} else {
if (line2Origin.x == line2End.x) {
final double pAB = (line1Origin.y - line1End.y)
/ (line1Origin.x - line1End.x);
sx = line2Origin.x;
sy = pAB * (line2Origin.x - line1Origin.x) + line1Origin.y;
} else {
final double pCD = (line2Origin.y - line2End.y)
/ (line2Origin.x - line2End.x);
final double pAB = (line1Origin.y - line1End.y)
/ (line1Origin.x - line1End.x);
if (pAB == pCD) {
// If the vectors are collinear, we don't need to consider that they colliding.
return false;
}
final double oCD = line2Origin.y - pCD * line2Origin.x;
final double oAB = line1Origin.y - pAB * line1Origin.x;
sx = (oAB - oCD) / (pCD - pAB);
sy = pCD * sx + oCD;
}
}
// if sx and sy are not in the lines, return false.
if ((sx < line1Origin.x && sx < line1End.x)
| (sx > line1Origin.x && sx > line1End.x)
| (sx < line2Origin.x && sx < line2End.x)
| (sx > line2Origin.x && sx > line2End.x)
| (sy < line1Origin.y && sy < line1End.y)
| (sy > line1Origin.y && sy > line1End.y)
| (sy < line2Origin.y && sy < line2End.y)
| (sy > line2Origin.y && sy > line2End.y)) {
return false;
}
return true;
}
The function to get the inner angle of the shape :
public static float calcInnerAngle(final List<Object3D> points) {
float angle = 0;
final int size = points.size();
for (int i = 0; i < points.size(); ++i) {
angle += ModelComposerImpl.getAngle(points.get(i).getOrigin(),
points.get((i + 1) % size).getOrigin(),
points.get((i + 2) % size).getOrigin());
}
return angle / 4;
}
And then :
Thanks EgonOlsen for your reactivity !
Best regards.