use of com.ardor3d.scenegraph.Mesh 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 com.ardor3d.scenegraph.Mesh in project energy3d by concord-consortium.
the class Window method init.
@Override
protected void init() {
label1 = Annotation.makeNewLabel(1);
super.init();
if (Util.isZero(uValue)) {
uValue = 2;
}
if (Util.isZero(solarHeatGainCoefficient)) {
solarHeatGainCoefficient = 0.5;
} else if (solarHeatGainCoefficient > 1) {
solarHeatGainCoefficient *= 0.01;
}
if (Util.isZero(volumetricHeatCapacity)) {
volumetricHeatCapacity = 0.5;
}
if (Util.isZero(shutterLength)) {
shutterLength = 0.5;
}
if (glassColor == null) {
setColor(new ColorRGBA(0.3f, 0.3f, 0.5f, 0.5f));
}
if (shutterColor == null) {
shutterColor = ColorRGBA.DARK_GRAY;
}
mesh = new Mesh("Window");
mesh.getMeshData().setVertexBuffer(BufferUtils.createVector3Buffer(6));
mesh.getMeshData().setNormalBuffer(BufferUtils.createVector3Buffer(6));
mesh.setModelBound(new BoundingBox());
mesh.getSceneHints().setAllPickingHints(false);
if (glassColor == null) {
glassColor = new ColorRGBA(0.3f, 0.3f, 0.5f, 0.5f);
}
mesh.setDefaultColor(glassColor);
final BlendState blend = new BlendState();
blend.setBlendEnabled(true);
// blend.setTestEnabled(true);
mesh.setRenderState(blend);
mesh.getSceneHints().setRenderBucketType(RenderBucketType.Transparent);
final MaterialState ms = new MaterialState();
ms.setColorMaterial(ColorMaterial.Diffuse);
mesh.setRenderState(ms);
root.attachChild(mesh);
collisionMesh = new Mesh("Window Collision");
collisionMesh.getMeshData().setVertexBuffer(BufferUtils.createVector3Buffer(6));
collisionMesh.setVisible(false);
collisionMesh.setUserData(new UserData(this));
collisionMesh.setModelBound(new BoundingBox());
root.attachChild(collisionMesh);
label1.setAlign(Align.SouthWest);
root.attachChild(label1);
bars = new Line("Window (bars)");
bars.setLineWidth(3);
bars.setModelBound(new BoundingBox());
Util.disablePickShadowLight(bars);
bars.getMeshData().setVertexBuffer(BufferUtils.createVector3Buffer(8));
root.attachChild(bars);
leftShutter = new Mesh("Left Shutter");
leftShutter.getMeshData().setIndexMode(IndexMode.Quads);
leftShutter.getMeshData().setVertexBuffer(BufferUtils.createVector3Buffer(4));
leftShutter.getMeshData().setNormalBuffer(BufferUtils.createVector3Buffer(4));
leftShutter.setRenderState(ms);
leftShutter.setModelBound(new BoundingBox());
root.attachChild(leftShutter);
rightShutter = new Mesh("Right Shutter");
rightShutter.getMeshData().setIndexMode(IndexMode.Quads);
rightShutter.getMeshData().setVertexBuffer(BufferUtils.createVector3Buffer(4));
rightShutter.getMeshData().setNormalBuffer(BufferUtils.createVector3Buffer(4));
rightShutter.setRenderState(ms);
rightShutter.setModelBound(new BoundingBox());
root.attachChild(rightShutter);
leftShutterOutline = new Line("Left Shutter (Outline)");
leftShutterOutline.getMeshData().setVertexBuffer(BufferUtils.createVector3Buffer(12));
leftShutterOutline.setDefaultColor(ColorRGBA.BLACK);
leftShutterOutline.setModelBound(new BoundingBox());
root.attachChild(leftShutterOutline);
rightShutterOutline = new Line("Right Shutter (Outline)");
rightShutterOutline.getMeshData().setVertexBuffer(BufferUtils.createVector3Buffer(12));
rightShutterOutline.setDefaultColor(ColorRGBA.BLACK);
rightShutterOutline.setModelBound(new BoundingBox());
root.attachChild(rightShutterOutline);
}
use of com.ardor3d.scenegraph.Mesh in project energy3d by concord-consortium.
the class PrintController method computePrintCenters.
private void computePrintCenters(final ArrayList<ArrayList<Spatial>> pages) {
for (final HousePart printPart : printParts) {
if (printPart.isPrintable()) {
printPart.getRoot().updateWorldTransform(true);
printPart.getRoot().updateWorldBound(true);
if (printPart instanceof Roof) {
final Roof roof = (Roof) printPart;
for (final Spatial roofPart : roof.getRoofPartsRoot().getChildren()) {
if (roofPart.getSceneHints().getCullHint() != CullHint.Always) {
final Mesh mesh = (Mesh) ((Node) roofPart).getChild(0);
roof.setPrintVertical(roofPart, decideVertical(mesh));
computePrintCenterOf(mesh, pages);
}
}
} else {
final Mesh mesh = printPart.getMesh();
printPart.setPrintVertical(decideVertical(mesh));
computePrintCenterOf(mesh, pages);
}
}
}
}
use of com.ardor3d.scenegraph.Mesh in project energy3d by concord-consortium.
the class HeatLoad method computeEnergyToday.
public void computeEnergyToday(final Calendar today) {
today.set(Calendar.SECOND, 0);
today.set(Calendar.MINUTE, 0);
today.set(Calendar.HOUR_OF_DAY, 0);
if (EnergyPanel.getInstance().getCityComboBox().getSelectedItem().equals("")) {
return;
}
final int timeStep = Scene.getInstance().getTimeStep();
final double[] outsideTemperatureRange = Weather.computeOutsideTemperature(today, (String) EnergyPanel.getInstance().getCityComboBox().getSelectedItem());
// System.out.println(today.get(Calendar.DAY_OF_YEAR) + ", " + outsideTemperatureRange[0] + ", " + outsideTemperatureRange[1]);
int iMinute = 0;
for (int minute = 0; minute < SolarRadiation.MINUTES_OF_DAY; minute += timeStep) {
iMinute = minute / timeStep;
final double outsideTemperature = Weather.getInstance().getOutsideTemperatureAtMinute(outsideTemperatureRange[1], outsideTemperatureRange[0], minute);
final double groundTemperature = Scene.getInstance().getGround().getTemperatureMinuteOfDay(today.get(Calendar.DAY_OF_YEAR), minute, 0.5 * (outsideTemperatureRange[1] - outsideTemperatureRange[0]));
for (final HousePart part : Scene.getInstance().getParts()) {
if (part instanceof Human || part instanceof Tree || part instanceof Floor || (part instanceof SolarCollector && !(part instanceof Sensor))) {
continue;
}
final double insideTemperature = (part instanceof Foundation ? (Foundation) part : part.getTopContainer()).getThermostat().getTemperature(today.get(Calendar.MONTH), today.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY, minute / 60);
final float absorption = part instanceof Window ? 0 : 1 - part.getAlbedo();
if (part instanceof Roof) {
// need to compute piece by piece for a roof because sun affects outside temperature of roof part
final Roof roof = (Roof) part;
for (final Spatial child : roof.getRoofPartsRoot().getChildren()) {
if (child.getSceneHints().getCullHint() != CullHint.Always) {
final Mesh mesh = (Mesh) ((Node) child).getChild(6);
final double[] solarPotential = SolarRadiation.getInstance().getSolarPotential(mesh);
final double solarHeat = solarPotential != null ? solarPotential[iMinute] * absorption / roof.getVolumetricHeatCapacity() : 0;
final double deltaT = insideTemperature - (outsideTemperature + solarHeat);
if (part.isDrawCompleted()) {
final double uValue = getUValue(part);
if (Util.isZero(uValue)) {
continue;
}
double heatloss = roof.getAreaWithoutOverhang(mesh) * uValue * deltaT / 1000.0 / 60 * timeStep;
// if the lowest outside temperature is high enough, there is no need to turn on the heater hence no heat loss
if (heatloss > 0 && outsideTemperatureRange[0] >= LOWEST_TEMPERATURE_OF_WARM_DAY) {
heatloss = 0;
}
roof.getHeatLoss()[iMinute] += heatloss;
final double[] heatLossArray = SolarRadiation.getInstance().getHeatLoss(mesh);
if (heatLossArray != null) {
heatLossArray[iMinute] += heatloss;
}
}
}
}
} else if (part instanceof Foundation) {
final Foundation foundation = (Foundation) part;
final double deltaT = insideTemperature - groundTemperature;
if (foundation.isDrawCompleted()) {
final double uValue = getUValue(part);
if (Util.isZero(uValue)) {
continue;
}
final Building building = new Building(foundation);
double area;
if (building.isWallComplete()) {
building.calculate();
area = building.getArea();
} else {
area = foundation.getArea();
}
final double heatloss = area * uValue * deltaT / 1000.0 / 60 * timeStep;
// if (iMinute % 4 == 0) System.out.println((int) (iMinute / 4) + "=" + outsideTemperature + ", " + groundTemperature + ", " + deltaT + ", " + heatloss);
foundation.getHeatLoss()[iMinute] += heatloss;
}
} else {
double deltaT = insideTemperature - outsideTemperature;
if (part instanceof Thermal) {
// direct solar heating raises the outside temperature
deltaT -= part.getSolarPotential()[iMinute] * absorption / ((Thermal) part).getVolumetricHeatCapacity();
}
if (part.isDrawCompleted()) {
final double uValue = getUValue(part);
if (Util.isZero(uValue)) {
continue;
}
double heatloss = part.getArea() * uValue * deltaT / 1000.0 / 60 * timeStep;
// if outside is warm enough, there is no need to turn on the heater hence no heat loss
if (heatloss > 0 && outsideTemperatureRange[0] >= LOWEST_TEMPERATURE_OF_WARM_DAY) {
heatloss = 0;
}
part.getHeatLoss()[iMinute] += heatloss;
}
}
}
}
}
use of com.ardor3d.scenegraph.Mesh in project energy3d by concord-consortium.
the class SelectUtil method getPickResult.
private static PickedHousePart getPickResult(final Ray3 pickRay) {
PickedHousePart pickedHousePart = null;
double polyDist = Double.MAX_VALUE;
double pointDist = Double.MAX_VALUE;
int objCounter = 0;
HousePart prevHousePart = null;
final long pickLayer = SelectUtil.pickLayer == -1 ? -1 : SelectUtil.pickLayer % Math.max(1, pickResults.getNumber());
for (int i = 0; i < pickResults.getNumber(); i++) {
final PickData pick = pickResults.getPickData(i);
if (pick.getIntersectionRecord().getNumberOfIntersections() == 0) {
continue;
}
final Object obj = ((Mesh) pick.getTarget()).getUserData();
UserData userData = null;
if (obj instanceof UserData) {
// FIXME: Note that userData can be null if the pick is the land
userData = (UserData) obj;
if (userData.getHousePart() != prevHousePart) {
objCounter++;
prevHousePart = userData.getHousePart();
}
} else if (pickLayer != -1) {
continue;
}
if (pickLayer != -1 && objCounter - 1 != pickLayer) {
continue;
}
final Vector3 intersectionPoint = pick.getIntersectionRecord().getIntersectionPoint(0);
final PickedHousePart picked_i = new PickedHousePart(userData, intersectionPoint, pick.getIntersectionRecord().getIntersectionNormal(0));
double polyDist_i = pick.getIntersectionRecord().getClosestDistance();
if (userData != null && userData.getHousePart() instanceof Window) {
// give more priority to window (especially skylight)
polyDist_i -= 0.2;
}
double pointDist_i = Double.MAX_VALUE;
if (userData != null && polyDist_i - polyDist < 0.1) {
for (int j = 0; j < userData.getHousePart().getPoints().size(); j++) {
final Vector3 p = userData.getHousePart().getAbsPoint(j);
pointDist_i = p.distance(intersectionPoint);
double adjust = 0;
if (userData.getHousePart().isFirstPointInserted()) {
// to avoid IndexOutOfBoundsException: Index: 2, Size: 2
if (userData.getHousePart().getNormal() != null) {
adjust -= Math.abs(userData.getHousePart().getNormal().negate(null).dot(pickRay.getDirection()) / 10.0);
}
}
if (userData.getHousePart() == SceneManager.getInstance().getSelectedPart()) {
// give more priority because the object is selected
adjust -= 0.1;
}
if (userData.isEditPoint()) {
// give more priority because this is an edit point
adjust -= 0.1;
}
if (userData.isEditPoint() && userData.getHousePart() instanceof Foundation && ((Foundation) userData.getHousePart()).isResizeHouseMode()) {
adjust -= 0.1;
}
pointDist_i += adjust;
if (pointDist_i < pointDist && (userData.getEditPointIndex() != -1 || pickedHousePart == null || pickedHousePart.getUserData() == null || pickedHousePart.getUserData().getEditPointIndex() == -1)) {
pickedHousePart = picked_i;
polyDist = polyDist_i;
pointDist = pointDist_i;
}
}
}
if (pickedHousePart == null || polyDist_i < polyDist) {
pickedHousePart = picked_i;
polyDist = polyDist_i;
pointDist = pointDist_i;
}
}
return pickedHousePart;
}
Aggregations