use of com.ardor3d.math.Matrix3 in project energy3d by concord-consortium.
the class Rack method findRotationMatrix.
private Matrix3 findRotationMatrix(final ReadOnlyVector3 v1, final ReadOnlyVector3 v2) {
final double angle = v1.smallestAngleBetween(v2);
final Vector3 axis = v1.cross(v2, null).normalizeLocal();
final Matrix3 matrix = new Matrix3().fromAngleAxis(angle, axis);
return matrix;
}
use of com.ardor3d.math.Matrix3 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.Matrix3 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.Matrix3 in project energy3d by concord-consortium.
the class Roof method flattenQuadTriangle.
private void flattenQuadTriangle(final Node roofPartNode, final double flattenTime) {
final ReadOnlyVector3 normal = (ReadOnlyVector3) roofPartNode.getUserData();
final double angleZ = Util.angleBetween(new Vector3(normal.getX(), normal.getY(), 0).normalizeLocal(), Vector3.NEG_UNIT_Y, Vector3.UNIT_Z);
final Matrix3 m1 = new Matrix3().fromAngles(0, 0, flattenTime * angleZ);
final ReadOnlyVector3 normal2 = m1.applyPost(normal, null);
final double angleX = Util.angleBetween(normal2, Vector3.NEG_UNIT_Y, Vector3.UNIT_X);
final Matrix3 m2 = new Matrix3().fromAngles(flattenTime * angleX, 0, 0);
final Matrix3 matrix = m2.multiplyLocal(m1);
final Boolean isVertical = roofPartPrintVerticalMap.get(roofPartNode);
if (isVertical != null && isVertical) {
new Matrix3().fromAngles(0, -Math.PI / 2.0 * flattenTime, 0).multiply(matrix, matrix);
}
roofPartNode.setRotation(matrix);
ReadOnlyVector3 orgCenter = orgCenters.get(roofPartNode);
if (orgCenter == null) {
orgCenter = Vector3.ZERO;
}
final Vector3 targetPrintCenter = ((UserData) roofPartNode.getChild(0).getUserData()).getPrintCenter();
if (!targetPrintCenter.equals(Vector3.ZERO)) {
roofPartNode.setTranslation(targetPrintCenter.subtract(orgCenter, null).multiplyLocal(flattenTime));
}
}
use of com.ardor3d.math.Matrix3 in project energy3d by concord-consortium.
the class Sensor method drawMesh.
@Override
protected void drawMesh() {
if (container == null) {
return;
}
if (container instanceof Roof) {
final PickResults pickResults = new PrimitivePickResults();
final Ray3 ray = new Ray3(getAbsPoint(0).addLocal(0, 0, 1000), Vector3.NEG_UNIT_Z);
PickingUtil.findPick(container.getRoot(), ray, pickResults, false);
if (pickResults.getNumber() != 0) {
final PickData pickData = pickResults.getPickData(0);
final Vector3 p = pickData.getIntersectionRecord().getIntersectionPoint(0);
points.get(0).setZ(p.getZ());
final UserData userData = (UserData) ((Spatial) pickData.getTarget()).getUserData();
final int roofPartIndex = userData.getEditPointIndex();
normal = (ReadOnlyVector3) ((Roof) container).getRoofPartsRoot().getChild(roofPartIndex).getUserData();
}
} else {
normal = container.getNormal();
}
updateEditShapes();
final double annotationScale = Scene.getInstance().getAnnotationScale();
// last arg sets close to zero so the sensor doesn't cast shadow
surround.setData(Vector3.ZERO, WIDTH / 2.0 / annotationScale, HEIGHT / 2.0 / annotationScale, 0.02);
surround.updateModelBound();
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();
int i = 8 * 3;
vertexBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
textureBuffer.put(1).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(1);
textureBuffer.put(0).put(1);
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(1).put(1);
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(1).put(0);
outlineBuffer.put(boxVertexBuffer.get(i)).put(boxVertexBuffer.get(i + 1)).put(boxVertexBuffer.get(i + 2));
mesh.updateModelBound();
outlineMesh.updateModelBound();
mesh.setTranslation(getAbsPoint(0));
if (normal != null) {
// FIXME: Sometimes normal is null
if (Util.isEqual(normal, Vector3.UNIT_Z)) {
mesh.setRotation(new Matrix3());
} else {
mesh.setRotation(new Matrix3().lookAt(normal, Vector3.UNIT_Z));
}
}
surround.setTranslation(mesh.getTranslation());
surround.setRotation(mesh.getRotation());
outlineMesh.setTranslation(mesh.getTranslation());
outlineMesh.setRotation(mesh.getRotation());
final ReadOnlyVector3 translation = mesh.getTranslation();
label.setText("" + getId());
if (normal != null) {
final double labelOffset = 1.0;
label.setTranslation(translation.getX() + labelOffset * normal.getX(), translation.getY() + labelOffset * normal.getY(), translation.getZ() + labelOffset * normal.getZ());
}
}
Aggregations