use of com.ardor3d.math.Vector3 in project energy3d by concord-consortium.
the class Rack method setNormal.
// ensure that a rack in special cases (on a flat roof or at a tilt angle) will have correct orientation. here angle = 90 - tilt (the angle to the z axis)
private void setNormal(final double angle, final double azimuth) {
final Foundation foundation = getTopContainer();
Vector3 v = foundation.getAbsPoint(0);
// (1, 0) x direction
final Vector3 vx = foundation.getAbsPoint(2).subtractLocal(v);
// (2, 0) y direction
final Vector3 vy = foundation.getAbsPoint(1).subtractLocal(v);
if (Util.isZero(azimuth)) {
v = new Matrix3().fromAngleAxis(angle, vx).applyPost(vy, null);
} else {
final Matrix3 m = new Matrix3().applyRotationZ(azimuth);
final Vector3 v1 = m.applyPost(vx, null);
final Vector3 v2 = m.applyPost(vy, null);
v = new Matrix3().fromAngleAxis(angle, v1).applyPost(v2, null);
}
if (v.getZ() < 0) {
v.negateLocal();
}
normal = v.normalizeLocal();
}
use of com.ardor3d.math.Vector3 in project energy3d by concord-consortium.
the class Rack method isPositionLegal.
private boolean isPositionLegal(final Rack rack, final Foundation foundation) {
final Vector3 p0 = foundation.getAbsPoint(0);
final Vector3 p1 = foundation.getAbsPoint(1);
final Vector3 p2 = foundation.getAbsPoint(2);
final double a = -Math.toRadians(relativeAzimuth) * Math.signum(p2.subtract(p0, null).getX() * p1.subtract(p0, null).getY());
final Vector3 v = new Vector3(Math.cos(Math.PI / 2 + a), Math.sin(Math.PI / 2 + a), 0);
double length;
double s;
boolean inHeight = true;
final Rack nearest = foundation.getNearestRack(this);
if (nearest != null) {
// use the nearest rack as the reference to infer next position
final Vector3 d = getAbsCenter().subtractLocal(nearest.getAbsCenter());
length = d.length();
if (rackHeight > length * Scene.getInstance().getAnnotationScale()) {
inHeight = false;
}
if (length > Math.min(rackWidth, rackHeight) * 5 / Scene.getInstance().getAnnotationScale()) {
length = (1 + copyLayoutGap) * rackHeight / Scene.getInstance().getAnnotationScale();
s = Math.signum(foundation.getAbsCenter().subtractLocal(Scene.getInstance().getOriginalCopy().getAbsCenter()).dot(v));
} else {
final double vx = v.getX();
final double vy = v.getY();
if (Math.abs(d.getX()) > Math.abs(d.getY())) {
if (Math.abs(vx) < Math.abs(vy)) {
v.setX(vy);
v.setY(vx);
}
} else {
if (Math.abs(vx) > Math.abs(vy)) {
v.setX(vy);
v.setY(vx);
}
}
s = Math.signum(d.dot(v));
}
} else {
length = (1 + copyLayoutGap) * rackHeight / Scene.getInstance().getAnnotationScale();
s = Math.signum(foundation.getAbsCenter().subtractLocal(Scene.getInstance().getOriginalCopy().getAbsCenter()).dot(v));
}
final double tx = length / p0.distance(p2);
final double ty = length / p0.distance(p1);
final double lx = s * v.getX() * tx;
final double ly = s * v.getY() * ty;
final double newX = points.get(0).getX() + lx;
if (newX > 1 - tx || newX < tx) {
return false;
}
final double newY = points.get(0).getY() + ly;
if (newY > 1 - ty || newY < ty) {
return false;
}
rack.points.get(0).setX(newX);
rack.points.get(0).setY(newY);
final double o = rack.checkCopyOverlap(inHeight);
if (o >= 0) {
JOptionPane.showMessageDialog(MainFrame.getInstance(), "Sorry, your new rack is too close to an existing one (" + o + ").", "Error", JOptionPane.ERROR_MESSAGE);
return false;
}
return true;
}
use of com.ardor3d.math.Vector3 in project energy3d by concord-consortium.
the class Rack method move.
@Override
public void move(final Vector3 v, final double steplength) {
if (lockEdit) {
return;
}
v.normalizeLocal().multiplyLocal(steplength);
final Vector3 v_rel = toRelativeVector(v);
points.get(0).addLocal(v_rel);
moveSolarPanels(v_rel);
draw();
if (outOfBound()) {
if (oldRackCenter != null) {
points.get(0).set(oldRackCenter);
}
} else {
oldRackCenter = points.get(0).clone();
}
}
use of com.ardor3d.math.Vector3 in project energy3d by concord-consortium.
the class Rack method drawMesh.
@Override
protected void drawMesh() {
if (container == null) {
return;
}
final double az = Math.toRadians(relativeAzimuth);
final double currentTilt = monthlyTiltAngles[Heliodon.getInstance().getCalendar().get(Calendar.MONTH)];
boolean onFlatSurface = onFlatSurface();
getEditPointShape(0).setDefaultColor(ColorRGBA.ORANGE);
// if this rack rests on an imported mesh or not?
final Mesh host = meshLocator == null ? null : meshLocator.find();
if (host == null) {
normal = pickedNormal != null ? pickedNormal : computeNormalAndKeepOnSurface();
} else {
final UserData ud = (UserData) host.getUserData();
normal = ud.getRotatedNormal() == null ? ud.getNormal() : ud.getRotatedNormal();
onFlatSurface = Util.isEqual(normal, Vector3.UNIT_Z);
}
final double dotE = 0.9999;
switch(trackerType) {
case ALTAZIMUTH_DUAL_AXIS_TRACKER:
normal = Heliodon.getInstance().computeSunLocation(Heliodon.getInstance().getCalendar()).normalizeLocal();
break;
case HORIZONTAL_SINGLE_AXIS_TRACKER:
final Vector3 sunDirection = Heliodon.getInstance().computeSunLocation(Heliodon.getInstance().getCalendar()).normalizeLocal();
// by default, the rotation axis is in the east-west direction, so az = 0 maps to (1, 0, 0)
final Vector3 rotationAxis = Util.isZero(az) ? new Vector3(1, 0, 0) : new Vector3(MathUtils.cos(az), MathUtils.sin(az), 0);
final double axisSunDot = sunDirection.dot(rotationAxis);
// avoid singularity when the direction of the sun is perpendicular to the rotation axis
rotationAxis.multiplyLocal(Util.isZero(axisSunDot) ? 0.001 : axisSunDot);
normal = sunDirection.subtractLocal(rotationAxis).normalizeLocal();
break;
case VERTICAL_SINGLE_AXIS_TRACKER:
final Vector3 a = Heliodon.getInstance().computeSunLocation(Heliodon.getInstance().getCalendar()).multiplyLocal(1, 1, 0).normalizeLocal();
final Vector3 b = Vector3.UNIT_Z.cross(a, null);
Matrix3 m = new Matrix3().applyRotation(Math.toRadians(90 - currentTilt), b.getX(), b.getY(), b.getZ());
normal = m.applyPost(a, null);
if (normal.getZ() < 0) {
normal = normal.negate(null);
}
break;
case // TODO: The following does not work
TILTED_SINGLE_AXIS_TRACKER:
final double sunAngleX = Heliodon.getInstance().computeSunLocation(Heliodon.getInstance().getCalendar()).normalizeLocal().dot(Vector3.UNIT_X);
System.out.println("*** sun cosx = " + sunAngleX + ", " + Math.toDegrees(Math.asin(sunAngleX)));
// rotate the normal according to the tilt angle, at this point, the axis is still north-south
// exactly 90 degrees will cause the solar panel to disappear
setNormal(Util.isZero(currentTilt) ? Math.PI / 2 * dotE : Math.toRadians(90 - currentTilt), az);
System.out.println("*** tilt normal = " + normal);
// the following vector should be the rack axis
final Vector3 rackAxis = Vector3.UNIT_X.cross(normal, null);
System.out.println("*** rack axis = " + rackAxis);
m = new Matrix3().fromAngleNormalAxis(Math.asin(sunAngleX), rackAxis);
normal = m.applyPost(normal, null);
System.out.println("*** final normal = " + normal);
if (normal.getZ() < 0) {
normal = normal.negate(null);
}
break;
default:
if (onFlatSurface) {
// exactly 90 degrees will cause the solar panel to disappear
setNormal(Util.isZero(currentTilt) ? Math.PI / 2 * dotE : Math.toRadians(90 - currentTilt), az);
}
}
if (Util.isEqual(normal, Vector3.UNIT_Z)) {
normal = new Vector3(-0.001, 0, 1).normalizeLocal();
}
if (previousNormal == null) {
previousNormal = normal;
}
if (previousNormal != null && normal.dot(previousNormal) < dotE) {
// azimuth rotation
Matrix3 matrix = null;
if (allowAzimuthLargeRotation && Util.isEqual(normal.multiply(1, 1, 0, null).normalizeLocal(), previousNormal.multiply(1, 1, 0, null).negateLocal().normalizeLocal())) {
matrix = new Matrix3().fromAngleAxis(Math.PI, Vector3.UNIT_Z);
} else if (normal.multiply(1, 1, 0, null).normalizeLocal().dot(previousNormal.multiply(1, 1, 0, null).normalizeLocal()) > -dotE) {
matrix = findRotationMatrix(previousNormal.multiply(1, 1, 0, null).normalizeLocal(), normal.multiply(1, 1, 0, null).normalizeLocal());
}
if (matrix != null) {
rotateSolarPanels(matrix);
previousNormal = matrix.applyPost(previousNormal, null);
}
// tilt rotation
rotateSolarPanels(findRotationMatrix(previousNormal, normal));
initSolarPanelsForMove();
previousNormal = normal;
}
allowAzimuthLargeRotation = false;
if (container instanceof Foundation) {
if (host != null && Util.isEqualFaster(normal, Vector3.UNIT_Z, 0.001)) {
// compute the height of the underlying mesh
final FloatBuffer buff = host.getMeshData().getVertexBuffer();
Vector3 v0 = new Vector3(buff.get(0), buff.get(1), buff.get(2));
v0 = host.getWorldTransform().applyForward(v0, null);
baseZ = v0.getZ();
} else {
baseZ = container.getHeight();
}
} else {
baseZ = container.getPoints().get(0).getZ();
}
// if (onFlatSurface && Util.isEqual(points.get(0).getZ(), baseZ)) {
if (onFlatSurface && host == null) {
points.get(0).setZ(baseZ + baseHeight);
}
final double annotationScale = Scene.getInstance().getAnnotationScale();
surround.setData(new Vector3(0, 0, 0), 0.5 * rackWidth / annotationScale, 0.5 * rackHeight / annotationScale, 0.15);
surround.updateModelBound();
final boolean heatMap = SceneManager.getInstance().getSolarHeatMap();
final FloatBuffer boxVertexBuffer = surround.getMeshData().getVertexBuffer();
final FloatBuffer vertexBuffer = mesh.getMeshData().getVertexBuffer();
final FloatBuffer textureBuffer = mesh.getMeshData().getTextureBuffer(0);
final FloatBuffer outlineBuffer = outlineMesh.getMeshData().getVertexBuffer();
vertexBuffer.rewind();
outlineBuffer.rewind();
textureBuffer.rewind();
// when the heat map is on, use a single texture from the radiation calculation, don't repeat
final double sampleSolarPanelX = sampleSolarPanel.isRotated() ? sampleSolarPanel.getPanelHeight() : sampleSolarPanel.getPanelWidth();
final double sampleSolarPanelY = sampleSolarPanel.isRotated() ? sampleSolarPanel.getPanelWidth() : sampleSolarPanel.getPanelHeight();
final float spw = heatMap ? 1 : (monolithic ? (float) (rackWidth / sampleSolarPanelX) : 1);
final float sph = heatMap ? 1 : (monolithic ? (float) (rackHeight / sampleSolarPanelY) : 1);
int i = 8 * 3;
vertexBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
textureBuffer.put(spw).put(0);
outlineBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
i += 3;
vertexBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
textureBuffer.put(0).put(0);
outlineBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
outlineBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
i += 3;
vertexBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
vertexBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
textureBuffer.put(0).put(sph);
textureBuffer.put(0).put(sph);
outlineBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
outlineBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
i += 3;
vertexBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
textureBuffer.put(spw).put(sph);
outlineBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
outlineBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
i = 8 * 3;
vertexBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
textureBuffer.put(spw).put(0);
outlineBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
mesh.updateModelBound();
outlineMesh.updateModelBound();
mesh.setRotation(new Matrix3().lookAt(normal, normal.getX() > 0 ? Vector3.UNIT_Z : Vector3.NEG_UNIT_Z));
mesh.setTranslation(onFlatSurface && host != null ? getAbsPoint(0).addLocal(0, 0, baseHeight) : getAbsPoint(0));
surround.setTranslation(mesh.getTranslation());
surround.setRotation(mesh.getRotation());
outlineMesh.setTranslation(mesh.getTranslation());
outlineMesh.setRotation(mesh.getRotation());
polesRoot.detachAllChildren();
if (!poleInvisible) {
final Vector3 center = getAbsPoint(0);
final double halfRackWidth = rackWidth * 0.5;
switch(trackerType) {
case Trackable.NO_TRACKER:
HousePart container = getContainerRelative();
final Vector3 uDir = container.getPoints().get(2).subtract(container.getPoints().get(0), null).normalizeLocal();
final Vector3 vDir = container.getPoints().get(1).subtract(container.getPoints().get(0), null).normalizeLocal();
final Matrix3 matrix = new Matrix3().fromAngles(0, 0, az);
matrix.applyPost(uDir, uDir);
matrix.applyPost(vDir, vDir);
if (vDir.dot(normal) < 0) {
vDir.negateLocal();
}
final double tanTiltAngle = Math.abs(Math.tan(Math.toRadians(currentTilt)));
if (tanTiltAngle < 100) {
final double cosTiltAngle = Math.cos(Math.toRadians(currentTilt));
// project to the horizontal direction
final double poleDistanceYHorizontal = poleDistanceY * cosTiltAngle;
final double rackHeightHorizontal = rackHeight * cosTiltAngle;
final double halfRackHeightHorizontal = 0.5 * rackHeightHorizontal;
for (double u = halfRackWidth; u < rackWidth; u += poleDistanceX) {
for (double v = halfRackHeightHorizontal; v < rackHeightHorizontal; v += poleDistanceYHorizontal) {
final double vFactor = (v - halfRackHeightHorizontal) / annotationScale;
final Vector3 position = uDir.multiply((u - halfRackWidth) / annotationScale, null).addLocal(vDir.multiply(vFactor, null)).addLocal(center);
final double dz = tanTiltAngle * vFactor;
if (baseHeight > dz) {
addPole(position, baseHeight - dz, baseZ);
}
}
for (double v = halfRackHeightHorizontal - poleDistanceYHorizontal; v > 0; v -= poleDistanceYHorizontal) {
final double vFactor = (v - halfRackHeightHorizontal) / annotationScale;
final Vector3 position = uDir.multiply((u - halfRackWidth) / annotationScale, null).addLocal(vDir.multiply(vFactor, null)).addLocal(center);
final double dz = tanTiltAngle * vFactor;
if (baseHeight > dz) {
addPole(position, baseHeight - dz, baseZ);
}
}
}
for (double u = halfRackWidth - poleDistanceX; u > 0; u -= poleDistanceX) {
for (double v = halfRackHeightHorizontal; v < rackHeightHorizontal; v += poleDistanceYHorizontal) {
final double vFactor = (v - halfRackHeightHorizontal) / annotationScale;
final Vector3 position = uDir.multiply((u - halfRackWidth) / annotationScale, null).addLocal(vDir.multiply(vFactor, null)).addLocal(center);
final double dz = tanTiltAngle * vFactor;
if (baseHeight > dz) {
addPole(position, baseHeight - dz, baseZ);
}
}
for (double v = halfRackHeightHorizontal - poleDistanceYHorizontal; v > 0; v -= poleDistanceYHorizontal) {
final double vFactor = (v - halfRackHeightHorizontal) / annotationScale;
final Vector3 position = uDir.multiply((u - halfRackWidth) / annotationScale, null).addLocal(vDir.multiply(vFactor, null)).addLocal(center);
final double dz = tanTiltAngle * vFactor;
if (baseHeight > dz) {
addPole(position, baseHeight - dz, baseZ);
}
}
}
}
break;
case Trackable.HORIZONTAL_SINGLE_AXIS_TRACKER:
polesRoot.detachAllChildren();
container = getContainerRelative();
// (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(0), vertexBuffer.get(1), vertexBuffer.get(2));
final Vector3 pd = p0.subtract(p1, null).normalizeLocal();
final int nPoles = Math.max(1, (int) (rackWidth / poleDistanceX));
if (nPoles > 1) {
final double halfLength = rackWidth * 0.5;
final Vector3 qd = new Matrix3().applyRotationZ(az).applyPost(pd, null);
for (double u = halfLength; u < rackWidth; u += poleDistanceX) {
addPole(qd.multiply((u - halfLength) / annotationScale, null).addLocal(center), baseHeight, baseZ);
}
for (double u = halfLength - poleDistanceX; u > 0; u -= poleDistanceX) {
addPole(qd.multiply((u - halfLength) / annotationScale, null).addLocal(center), baseHeight, baseZ);
}
} else {
addPole(center, baseHeight, baseZ);
}
polesRoot.getSceneHints().setCullHint(CullHint.Inherit);
break;
case Trackable.ALTAZIMUTH_DUAL_AXIS_TRACKER:
case Trackable.VERTICAL_SINGLE_AXIS_TRACKER:
addPole(getAbsPoint(0), baseHeight, baseZ);
break;
}
}
polesRoot.getSceneHints().setCullHint(onFlatSurface ? CullHint.Inherit : CullHint.Always);
if (drawSunBeam) {
drawSunBeam();
}
drawFloatingLabel(onFlatSurface);
if (heatMap && (rackWidth > sampleSolarPanelX || rackHeight > sampleSolarPanelY)) {
drawSolarPanelOutlines();
} else {
solarPanelOutlines.setVisible(false);
}
CollisionTreeManager.INSTANCE.removeCollisionTree(mesh);
CollisionTreeManager.INSTANCE.removeCollisionTree(surround);
root.updateGeometricState(0);
drawChildren();
}
use of com.ardor3d.math.Vector3 in project energy3d by concord-consortium.
the class Rack method setPreviewPoint.
@Override
public void setPreviewPoint(final int x, final int y) {
if (lockEdit) {
return;
}
if (moveStartPoint == null) {
initSolarPanelsForMove();
}
if (editPointIndex <= 0) {
// isBaseZ = true;
final PickedHousePart picked = pickContainer(x, y, new Class<?>[] { Foundation.class, Roof.class, Wall.class, Floor.class });
if (picked != null && picked.getUserData() != null) {
// when the user data is null, it picks the land
final Vector3 p = picked.getPoint().clone();
// isBaseZ = Util.isEqual(p.getZ(), baseZ);
final UserData ud = picked.getUserData();
if (ud.getHousePart() instanceof Foundation && ud.isImported() && ud.getNodeIndex() >= 0 && ud.getMeshIndex() >= 0) {
// if this rack rests on an imported mesh, store its info and don't snap to grid (as imported meshes do not sit on grid)
meshLocator = new MeshLocator((Foundation) ud.getHousePart(), ud.getNodeIndex(), ud.getMeshIndex());
} else {
snapToGrid(p, getAbsPoint(0), getGridSize(), container instanceof Wall);
meshLocator = null;
}
points.get(0).set(toRelative(p));
pickedNormal = ud.getRotatedNormal() == null ? ud.getNormal() : ud.getRotatedNormal();
} else {
pickedNormal = null;
}
if (outOfBound()) {
if (oldRackCenter != null && !oldRackCenter.equals(new Vector3())) {
// TODO: Need to find a better way to do this
points.get(0).set(oldRackCenter);
}
} else {
oldRackCenter = points.get(0).clone();
}
if (container != null) {
moveSolarPanels(getPoints().get(0).clone().subtractLocal(moveStartPoint), solarOrgPoints);
}
} else {
final ReadOnlyVector3 pEdit = getEditPointShape(editPointIndex).getTranslation();
final Vector3 p;
if (editPointIndex % 2 == 0) {
final ReadOnlyVector3 p1 = getEditPointShape(editPointIndex == 2 ? 4 : 2).getTranslation();
p = Util.closestPoint(pEdit, pEdit.subtract(p1, null).normalizeLocal(), x, y);
if (p != null) {
final double rw = p.distance(p1) * Scene.getInstance().getAnnotationScale();
final double pw = sampleSolarPanel.isRotated() ? sampleSolarPanel.getPanelHeight() : sampleSolarPanel.getPanelWidth();
if (rw > pw) {
final Vector3 delta = toRelativeVector(p.subtract(pEdit, null)).multiplyLocal(0.5);
points.get(0).addLocal(delta);
getEditPointShape(editPointIndex).setTranslation(p);
setRackWidth(rw);
if (outOfBound()) {
if (oldRackCenter != null) {
points.get(0).set(oldRackCenter);
}
setRackWidth(oldRackWidth);
} else {
oldRackCenter = points.get(0).clone();
oldRackWidth = rackWidth;
}
}
}
} else {
final ReadOnlyVector3 p1 = getEditPointShape(editPointIndex == 1 ? 3 : 1).getTranslation();
p = Util.closestPoint(pEdit, pEdit.subtract(p1, null).normalizeLocal(), x, y);
if (p != null) {
final double rh = p.distance(p1) * Scene.getInstance().getAnnotationScale();
final double ph = sampleSolarPanel.isRotated() ? sampleSolarPanel.getPanelWidth() : sampleSolarPanel.getPanelHeight();
if (rh > ph) {
final Vector3 delta = toRelativeVector(p.subtract(pEdit, null)).multiplyLocal(0.5);
points.get(0).addLocal(delta);
getEditPointShape(editPointIndex).setTranslation(p);
setRackHeight(rh);
if (outOfBound()) {
if (oldRackCenter != null) {
points.get(0).set(oldRackCenter);
}
setRackHeight(oldRackHeight);
} else {
oldRackCenter = points.get(0).clone();
oldRackHeight = rackHeight;
}
}
}
}
}
if (container != null) {
draw();
drawChildren();
setEditPointsVisible(true);
setHighlight(!isDrawable());
}
}
Aggregations