use of org.poly2tri.geometry.primitives.Point in project energy3d by concord-consortium.
the class SolarRadiation method initMeshTextureData.
private MeshDataStore initMeshTextureData(final Mesh drawMesh, final Mesh collisionMesh, final ReadOnlyVector3 normal, final boolean updateTexture) {
final MeshDataStore data = new MeshDataStore();
if (normal != null) {
final AnyToXYTransform toXY = new AnyToXYTransform(normal.getX(), normal.getY(), normal.getZ());
final XYToAnyTransform fromXY = new XYToAnyTransform(normal.getX(), normal.getY(), normal.getZ());
final FloatBuffer vertexBuffer = collisionMesh.getMeshData().getVertexBuffer();
vertexBuffer.rewind();
double minX, minY, maxX, maxY;
minX = minY = Double.POSITIVE_INFINITY;
maxX = maxY = Double.NEGATIVE_INFINITY;
double z = Double.NaN;
final List<ReadOnlyVector2> points = new ArrayList<ReadOnlyVector2>(vertexBuffer.limit() / 3);
while (vertexBuffer.hasRemaining()) {
final Vector3 pWorld = drawMesh.localToWorld(new Vector3(vertexBuffer.get(), vertexBuffer.get(), vertexBuffer.get()), null);
final Point p = new TPoint(pWorld.getX(), pWorld.getY(), pWorld.getZ());
toXY.transform(p);
if (p.getX() < minX) {
minX = p.getX();
}
if (p.getX() > maxX) {
maxX = p.getX();
}
if (p.getY() < minY) {
minY = p.getY();
}
if (p.getY() > maxY) {
maxY = p.getY();
}
if (Double.isNaN(z)) {
z = p.getZ();
}
points.add(new Vector2(p.getX(), p.getY()));
}
final Point tmp = new TPoint(minX, minY, z);
fromXY.transform(tmp);
data.p0 = new Vector3(tmp.getX(), tmp.getY(), tmp.getZ());
tmp.set(minX, maxY, z);
fromXY.transform(tmp);
data.p1 = new Vector3(tmp.getX(), tmp.getY(), tmp.getZ());
tmp.set(maxX, minY, z);
fromXY.transform(tmp);
data.p2 = new Vector3(tmp.getX(), tmp.getY(), tmp.getZ());
final double solarStep = Scene.getInstance().getSolarStep();
data.rows = Math.max(1, (int) Math.ceil(data.p1.subtract(data.p0, null).length() / solarStep));
data.cols = Math.max(1, (int) Math.ceil(data.p2.subtract(data.p0, null).length() / solarStep));
data.dailySolarIntensity = new double[Util.roundToPowerOfTwo(data.rows)][Util.roundToPowerOfTwo(data.cols)];
final ReadOnlyVector2 originXY = new Vector2(minX, minY);
final ReadOnlyVector2 uXY = new Vector2(maxX - minX, 0).normalizeLocal();
final ReadOnlyVector2 vXY = new Vector2(0, maxY - minY).normalizeLocal();
final int nrow = data.dailySolarIntensity.length;
final int ncol = data.dailySolarIntensity[0].length;
for (int row = 0; row < nrow; row++) {
for (int col = 0; col < ncol; col++) {
if (row >= data.rows || col >= data.cols) {
// overshot cells
data.dailySolarIntensity[row][col] = -1;
} else {
final ReadOnlyVector2 p = originXY.add(uXY.multiply(col * solarStep, null), null).add(vXY.multiply(row * solarStep, null), null);
boolean isInside = false;
final int numberOfPoints = points.size();
if (numberOfPoints >= 3) {
// FIXME: sometimes we can end up with less than three points
for (int i = 0; i < numberOfPoints; i += 3) {
if (i + 2 < points.size()) {
if (Util.isPointInsideTriangle(p, points.get(i), points.get(i + 1), points.get(i + 2))) {
isInside = true;
break;
}
}
}
}
if (!isInside && col > 0 && row > 0) {
// must at least include one column or row
data.dailySolarIntensity[row][col] = -1;
}
}
}
}
data.u = data.p2.subtract(data.p0, null).normalizeLocal();
data.v = data.p1.subtract(data.p0, null).normalizeLocal();
onMesh.put(drawMesh, data);
if (updateTexture) {
updateTextureCoords(drawMesh);
}
}
return data;
}
use of org.poly2tri.geometry.primitives.Point in project energy3d by concord-consortium.
the class SolarRadiation method computeOnMesh.
// Formula from http://en.wikipedia.org/wiki/Air_mass_(solar_energy)#Solar_intensity
private void computeOnMesh(final int minute, final ReadOnlyVector3 directionTowardSun, final HousePart housePart, final Mesh drawMesh, final Mesh collisionMesh, final ReadOnlyVector3 normal) {
if (normal == null) {
// FIXME: normal can be null sometimes, fix it
return;
}
if (Scene.getInstance().getOnlySolarComponentsInSolarMap()) {
return;
}
MeshDataStore data = onMesh.get(drawMesh);
if (data == null) {
data = initMeshTextureData(drawMesh, collisionMesh, normal, !(housePart instanceof Window));
}
/* needed in order to prevent picking collision with neighboring wall at wall edge (seem 0.1 is too small, 0.5 is about right) */
final ReadOnlyVector3 offset = directionTowardSun.multiply(0.5, null);
final double dot = normal.dot(directionTowardSun);
final double directRadiation = dot > 0 ? calculateDirectRadiation(directionTowardSun, normal) : 0;
final double indirectRadiation = calculateDiffuseAndReflectedRadiation(directionTowardSun, normal);
final int timeStep = Scene.getInstance().getTimeStep();
final double solarStep = Scene.getInstance().getSolarStep();
final double annotationScale = Scene.getInstance().getAnnotationScale();
final double scaleFactor = annotationScale * annotationScale / 60 * timeStep;
// a window itself doesn't really absorb solar energy, but it passes the energy into the house to be absorbed
final float absorption = housePart instanceof Window ? 1 : 1 - housePart.getAlbedo();
if (housePart instanceof Roof) {
// for now, only store this for roofs that have different meshes
if (data.solarPotential == null) {
data.solarPotential = new double[MINUTES_OF_DAY / timeStep];
}
if (data.heatLoss == null) {
data.heatLoss = new double[MINUTES_OF_DAY / timeStep];
}
}
for (int col = 0; col < data.cols; col++) {
final double w = col == data.cols - 1 ? data.p2.distance(data.u.multiply(col * solarStep, null).addLocal(data.p0)) : solarStep;
final ReadOnlyVector3 pU = data.u.multiply(col * solarStep + 0.5 * w, null).addLocal(data.p0);
for (int row = 0; row < data.rows; row++) {
if (EnergyPanel.getInstance().isCancelled()) {
throw new CancellationException();
}
if (data.dailySolarIntensity[row][col] == -1) {
continue;
}
final double h = row == data.rows - 1 ? data.p1.distance(data.p0) - row * solarStep : solarStep;
final ReadOnlyVector3 p = data.v.multiply(row * solarStep + 0.5 * h, null).addLocal(pU).add(offset, null);
final Ray3 pickRay = new Ray3(p, directionTowardSun);
final PickResults pickResults = new PrimitivePickResults();
// assuming that indirect (ambient or diffuse) radiation can always reach a grid point
double radiation = indirectRadiation;
final double scaledArea = w * h * scaleFactor;
if (dot > 0) {
for (final Spatial spatial : collidables) {
if (EnergyPanel.getInstance().isCancelled()) {
throw new CancellationException();
}
if (spatial != collisionMesh) {
PickingUtil.findPick(spatial, pickRay, pickResults, false);
if (pickResults.getNumber() != 0) {
if (housePart instanceof Foundation) {
// at this point, we only show radiation heat map on the first floor
final HousePart collidableOwner = collidablesToParts.get(spatial);
if (collidableOwner instanceof Window) {
radiation += directRadiation * ((Window) collidableOwner).getSolarHeatGainCoefficient();
}
}
break;
}
}
}
if (pickResults.getNumber() == 0) {
radiation += directRadiation;
}
}
data.dailySolarIntensity[row][col] += Scene.getInstance().getOnlyAbsorptionInSolarMap() ? absorption * radiation : radiation;
if (data.solarPotential != null) {
data.solarPotential[minute / timeStep] += radiation * scaledArea;
}
if (!(housePart instanceof Foundation)) {
// exclude radiation on foundation
housePart.getSolarPotential()[minute / timeStep] += radiation * scaledArea;
}
}
}
}
use of org.poly2tri.geometry.primitives.Point in project energy3d by concord-consortium.
the class SolarRadiation method computeOnRack.
// TODO: we probably should handle the radiation heat map visualization on the rack using a coarse grid and the energy calculation using a fine grid
private void computeOnRack(final int minute, final ReadOnlyVector3 directionTowardSun, final Rack rack) {
if (rack.getTracker() != SolarPanel.NO_TRACKER) {
final Calendar calendar = Heliodon.getInstance().getCalendar();
calendar.set(Calendar.HOUR_OF_DAY, (int) ((double) minute / (double) SolarRadiation.MINUTES_OF_DAY * 24.0));
calendar.set(Calendar.MINUTE, minute % 60);
rack.draw();
}
if (!rack.isMonolithic()) {
return;
}
final ReadOnlyVector3 normal = rack.getNormal();
if (normal == null) {
throw new RuntimeException("Normal is null");
}
int nx = Scene.getInstance().getRackNx();
int ny = Scene.getInstance().getRackNy();
final Mesh drawMesh = rack.getRadiationMesh();
final Mesh collisionMesh = (Mesh) rack.getRadiationCollisionSpatial();
MeshDataStore data = onMesh.get(drawMesh);
if (data == null) {
data = initMeshTextureDataOnRectangle(drawMesh, nx, ny);
}
final ReadOnlyVector3 offset = directionTowardSun.multiply(1, null);
final double dot = normal.dot(directionTowardSun);
double directRadiation = 0;
if (dot > 0) {
directRadiation += calculateDirectRadiation(directionTowardSun, normal);
}
final double indirectRadiation = calculateDiffuseAndReflectedRadiation(directionTowardSun, normal);
final FloatBuffer vertexBuffer = drawMesh.getMeshData().getVertexBuffer();
// (0, 0)
final Vector3 p0 = new Vector3(vertexBuffer.get(3), vertexBuffer.get(4), vertexBuffer.get(5));
// (1, 0)
final Vector3 p1 = new Vector3(vertexBuffer.get(6), vertexBuffer.get(7), vertexBuffer.get(8));
// (0, 1)
final Vector3 p2 = new Vector3(vertexBuffer.get(0), vertexBuffer.get(1), vertexBuffer.get(2));
// this is the longer side (supposed to be y)
final double d10 = p1.distance(p0);
// this is the shorter side (supposed to be x)
final double d20 = p2.distance(p0);
final Vector3 p10 = p1.subtract(p0, null).normalizeLocal();
final Vector3 p20 = p2.subtract(p0, null).normalizeLocal();
// generate the heat map first. this doesn't affect the energy calculation, it just shows the distribution of solar radiation on the rack.
// x and y must be swapped to have correct heat map texture, because nx represents rows and ny columns as we call initMeshTextureDataOnRectangle(mesh, nx, ny)
double xSpacing = d10 / nx;
double ySpacing = d20 / ny;
Vector3 u = p10;
Vector3 v = p20;
final int iMinute = minute / Scene.getInstance().getTimeStep();
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
if (EnergyPanel.getInstance().isCancelled()) {
throw new CancellationException();
}
final Vector3 u2 = u.multiply(xSpacing * (x + 0.5), null);
final Vector3 v2 = v.multiply(ySpacing * (y + 0.5), null);
final ReadOnlyVector3 p = drawMesh.getWorldTransform().applyForward(p0.add(v2, null).addLocal(u2)).addLocal(offset);
final Ray3 pickRay = new Ray3(p, directionTowardSun);
// assuming that indirect (ambient or diffuse) radiation can always reach a grid point
double radiation = indirectRadiation;
if (dot > 0) {
final PickResults pickResults = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != collisionMesh) {
PickingUtil.findPick(spatial, pickRay, pickResults, false);
if (pickResults.getNumber() != 0) {
break;
}
}
}
if (pickResults.getNumber() == 0) {
radiation += directRadiation;
}
}
data.dailySolarIntensity[x][y] += radiation;
}
}
// now do the calculation to get the total energy generated by the cells
final double airTemperature = Weather.getInstance().getOutsideTemperatureAtMinute(dailyAirTemperatures[1], dailyAirTemperatures[0], minute);
// system efficiency
double syseff;
// output at a cell center
double output;
// cell temperature
double tcell;
final SolarPanel panel = rack.getSolarPanel();
if (Scene.getInstance().isRackModelExact()) {
// exactly model each solar cell on each solar panel
final int[] rc = rack.getSolarPanelRowAndColumnNumbers();
// numbers of solar panels in x and y directions
final int nxPanels = rc[0];
final int nyPanels = rc[1];
// numbers of solar cells on each panel in x and y directions
int nxCells, nyCells;
if (panel.isRotated()) {
nxCells = panel.getNumberOfCellsInY();
nyCells = panel.getNumberOfCellsInX();
} else {
nxCells = panel.getNumberOfCellsInX();
nyCells = panel.getNumberOfCellsInY();
}
nx = nxCells * rc[0];
ny = nyCells * rc[1];
// get the area of a solar cell. 60 converts the unit of timeStep from minute to kWh
final double a = panel.getPanelWidth() * panel.getPanelHeight() * Scene.getInstance().getTimeStep() / (panel.getNumberOfCellsInX() * panel.getNumberOfCellsInY() * 60.0);
// swap the x and y back to correct order
xSpacing = d20 / nx;
ySpacing = d10 / ny;
u = p20;
v = p10;
if (cellOutputs == null || cellOutputs.length != nx || cellOutputs[0].length != ny) {
cellOutputs = new double[nx][ny];
}
// calculate the solar radiation first without worrying about the underlying cell wiring and distributed efficiency
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
if (EnergyPanel.getInstance().isCancelled()) {
throw new CancellationException();
}
final Vector3 u2 = u.multiply(xSpacing * (x + 0.5), null);
final Vector3 v2 = v.multiply(ySpacing * (y + 0.5), null);
final ReadOnlyVector3 p = drawMesh.getWorldTransform().applyForward(p0.add(v2, null).addLocal(u2)).addLocal(offset);
final Ray3 pickRay = new Ray3(p, directionTowardSun);
// assuming that indirect (ambient or diffuse) radiation can always reach a grid point
double radiation = indirectRadiation;
if (dot > 0) {
final PickResults pickResults = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != collisionMesh) {
PickingUtil.findPick(spatial, pickRay, pickResults, false);
if (pickResults.getNumber() != 0) {
break;
}
}
}
if (pickResults.getNumber() == 0) {
radiation += directRadiation;
}
}
cellOutputs[x][y] = radiation * a;
}
}
// Tcell = Tair + (NOCT - 20) / 80 * R, where the unit of R is mW/cm^2
final double noctFactor = (panel.getNominalOperatingCellTemperature() - 20.0) * 100.0 / (a * 80.0);
// now consider cell wiring and distributed efficiency. TODO: This is very inaccurate. The output depends on both cell wiring and panel wiring.
switch(// the ideal case that probably doesn't exist in reality
panel.getShadeTolerance()) {
case SolarPanel.HIGH_SHADE_TOLERANCE:
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
output = cellOutputs[x][y];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
rack.getSolarPotential()[iMinute] += output * syseff;
}
}
break;
case // assuming that all the cells on a panel are connected in series and all panels are connected in parallel
SolarPanel.NO_SHADE_TOLERANCE:
double min = Double.MAX_VALUE;
for (int ix = 0; ix < nxPanels; ix++) {
// panel by panel
for (int iy = 0; iy < nyPanels; iy++) {
min = Double.MAX_VALUE;
for (int jx = 0; jx < nxCells; jx++) {
// cell by cell on each panel
for (int jy = 0; jy < nyCells; jy++) {
output = cellOutputs[ix * nxCells + jx][iy * nyCells + jy];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
output *= syseff;
if (output < min) {
min = output;
}
}
}
rack.getSolarPotential()[iMinute] += min * nxCells * nyCells;
}
}
break;
case // assuming each panel uses a diode bypass to connect two columns of cells
SolarPanel.PARTIAL_SHADE_TOLERANCE:
for (int ix = 0; ix < nxPanels; ix++) {
// panel by panel
for (int iy = 0; iy < nyPanels; iy++) {
min = Double.MAX_VALUE;
if (panel.isRotated()) {
// landscape: nxCells = 10, nyCells = 6
for (int jy = 0; jy < nyCells; jy++) {
// cell by cell on each panel
if (jy % 2 == 0) {
// reset min every two columns of cells
min = Double.MAX_VALUE;
}
for (int jx = 0; jx < nxCells; jx++) {
output = cellOutputs[ix * nxCells + jx][iy * nyCells + jy];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
output *= syseff;
if (output < min) {
min = output;
}
}
if (jy % 2 == 1) {
rack.getSolarPotential()[iMinute] += min * 2 * nxCells;
}
}
} else {
// portrait: nxCells = 6, nyCells = 10
for (int jx = 0; jx < nxCells; jx++) {
// cell by cell on each panel
if (jx % 2 == 0) {
// reset min every two columns of cells
min = Double.MAX_VALUE;
}
for (int jy = 0; jy < nyCells; jy++) {
output = cellOutputs[ix * nxCells + jx][iy * nyCells + jy];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
output *= syseff;
if (output < min) {
min = output;
}
}
if (jx % 2 == 1) {
rack.getSolarPotential()[iMinute] += min * 2 * nyCells;
}
}
}
}
}
break;
}
} else {
// for simulation speed, approximate rack model doesn't compute panel by panel and cell by cell
ySpacing = xSpacing = Scene.getInstance().getRackCellSize() / Scene.getInstance().getAnnotationScale();
// swap the x and y back to correct order
nx = Math.max(2, (int) (d20 / xSpacing));
ny = Math.max(2, (int) (d10 / ySpacing));
// nx*ny*60: dividing the total rack area by nx*ny gets the unit cell area of the nx*ny grid; 60 converts the unit of timeStep from minute to kWh
final double a = rack.getRackWidth() * rack.getRackHeight() * Scene.getInstance().getTimeStep() / (nx * ny * 60.0);
u = p20;
v = p10;
if (cellOutputs == null || cellOutputs.length != nx || cellOutputs[0].length != ny) {
cellOutputs = new double[nx][ny];
}
// calculate the solar radiation first without worrying about the underlying cell wiring and distributed efficiency
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
if (EnergyPanel.getInstance().isCancelled()) {
throw new CancellationException();
}
final Vector3 u2 = u.multiply(xSpacing * (x + 0.5), null);
final Vector3 v2 = v.multiply(ySpacing * (y + 0.5), null);
final ReadOnlyVector3 p = drawMesh.getWorldTransform().applyForward(p0.add(v2, null).addLocal(u2)).addLocal(offset);
final Ray3 pickRay = new Ray3(p, directionTowardSun);
// assuming that indirect (ambient or diffuse) radiation can always reach a grid point
double radiation = indirectRadiation;
if (dot > 0) {
final PickResults pickResults = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != collisionMesh) {
PickingUtil.findPick(spatial, pickRay, pickResults, false);
if (pickResults.getNumber() != 0) {
break;
}
}
}
if (pickResults.getNumber() == 0) {
radiation += directRadiation;
}
}
cellOutputs[x][y] = radiation * a;
}
}
// Tcell = Tair + (NOCT - 20) / 80 * R, where the unit of R is mW/cm^2
final double noctFactor = (panel.getNominalOperatingCellTemperature() - 20.0) * 100.0 / (a * 80.0);
// now consider cell wiring and distributed efficiency. TODO: This is very inaccurate. The output depends on both cell wiring and panel wiring.
switch(panel.getShadeTolerance()) {
case // the ideal case that probably doesn't exist in reality
SolarPanel.HIGH_SHADE_TOLERANCE:
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
output = cellOutputs[x][y];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
rack.getSolarPotential()[iMinute] += output * syseff;
}
}
break;
case SolarPanel.NO_SHADE_TOLERANCE:
double min = Double.MAX_VALUE;
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
output = cellOutputs[x][y];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
output *= syseff;
if (output < min) {
min = output;
}
}
}
rack.getSolarPotential()[iMinute] += min * ny * nx;
break;
case SolarPanel.PARTIAL_SHADE_TOLERANCE:
for (int x = 0; x < nx; x++) {
min = Double.MAX_VALUE;
for (int y = 0; y < ny; y++) {
output = cellOutputs[x][y];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
output *= syseff;
if (output < min) {
min = output;
}
}
rack.getSolarPotential()[iMinute] += min * ny;
}
break;
}
}
}
use of org.poly2tri.geometry.primitives.Point in project energy3d by concord-consortium.
the class Util method area3D_Polygon.
// area3D_Polygon(): compute the area of a 3D planar polygon
// Input: int n = the number of vertices in the polygon
// Point* points = an array of n+1 points in a 2D plane with V[n]=V[0]
// Point normal = a normal vector of the polygon's plane
// Return: the (float) area of the polygon
public static double area3D_Polygon(final List<ReadOnlyVector3> points, final ReadOnlyVector3 normal) {
final int n = points.size() - 1;
double area = 0;
// abs value of normal and its coords
double an, ax, ay, az;
// coord to ignore: 1=x, 2=y, 3=z
int coord;
// loop indices
int i, j, k;
if (n < 3) {
// a degenerate polygon
return 0;
}
// select largest abs coordinate to ignore for projection
// abs x-coord
ax = (normal.getX() > 0 ? normal.getX() : -normal.getX());
// abs y-coord
ay = (normal.getY() > 0 ? normal.getY() : -normal.getY());
// abs z-coord
az = (normal.getZ() > 0 ? normal.getZ() : -normal.getZ());
// ignore z-coord
coord = 3;
if (ax > ay) {
if (ax > az) {
// ignore x-coord
coord = 1;
}
} else if (ay > az) {
// ignore y-coord
coord = 2;
}
// compute area of the 2D projection
switch(coord) {
case 1:
for (i = 1, j = 2, k = 0; i < n; i++, j++, k++) {
area += (points.get(i).getY() * (points.get(j).getZ() - points.get(k).getZ()));
}
break;
case 2:
for (i = 1, j = 2, k = 0; i < n; i++, j++, k++) {
area += (points.get(i).getZ() * (points.get(j).getX() - points.get(k).getX()));
}
break;
case 3:
for (i = 1, j = 2, k = 0; i < n; i++, j++, k++) {
area += (points.get(i).getX() * (points.get(j).getY() - points.get(k).getY()));
}
break;
}
switch(// wrap-around term
coord) {
case 1:
area += (points.get(n).getY() * (points.get(1).getZ() - points.get(n - 1).getZ()));
break;
case 2:
area += (points.get(n).getZ() * (points.get(1).getX() - points.get(n - 1).getX()));
break;
case 3:
area += (points.get(n).getX() * (points.get(1).getY() - points.get(n - 1).getY()));
break;
}
// scale to get area before projection
// length of normal vector
an = Math.sqrt(ax * ax + ay * ay + az * az);
switch(coord) {
case 1:
area *= (an / (2 * normal.getX()));
break;
case 2:
area *= (an / (2 * normal.getY()));
break;
case 3:
area *= (an / (2 * normal.getZ()));
}
return Math.abs(area);
}
use of org.poly2tri.geometry.primitives.Point in project energy3d by concord-consortium.
the class Wall method drawOutline.
private void drawOutline(final List<List<Vector3>> wallAndWindowsPoints) {
final List<Vector3> wallPolygonPoints = wallAndWindowsPoints.get(0);
FloatBuffer outlineVertexBuffer = outlineMesh.getMeshData().getVertexBuffer();
final int requiredSize = 2 * (wallPolygonPoints.size() + (wallAndWindowsPoints.size() - 1) * 4);
if (outlineVertexBuffer.capacity() / 3 < requiredSize) {
outlineVertexBuffer = BufferUtils.createVector3Buffer(requiredSize);
outlineMesh.getMeshData().setVertexBuffer(outlineVertexBuffer);
} else {
outlineVertexBuffer.rewind();
outlineVertexBuffer.limit(outlineVertexBuffer.capacity());
}
outlineVertexBuffer.rewind();
ReadOnlyVector3 prev = wallPolygonPoints.get(wallPolygonPoints.size() - 1);
for (final ReadOnlyVector3 point : wallPolygonPoints) {
outlineVertexBuffer.put(prev.getXf()).put(prev.getYf()).put(prev.getZf());
prev = point;
outlineVertexBuffer.put(point.getXf()).put(point.getYf()).put(point.getZf());
}
for (int i = 1; i < wallAndWindowsPoints.size(); i++) {
final List<Vector3> windowHolePoints = wallAndWindowsPoints.get(i);
prev = windowHolePoints.get(3);
for (int j = 0; j < 4; j++) {
final ReadOnlyVector3 point = windowHolePoints.get(j);
outlineVertexBuffer.put(prev.getXf()).put(prev.getYf()).put(prev.getZf());
prev = point;
outlineVertexBuffer.put(point.getXf()).put(point.getYf()).put(point.getZf());
}
}
outlineVertexBuffer.limit(outlineVertexBuffer.position());
outlineMesh.getMeshData().updateVertexCount();
outlineMesh.updateModelBound();
outlineMesh.setTranslation(getNormal().multiply(0.001, null));
}
Aggregations