use of com.ardor3d.scenegraph.Node in project energy3d by concord-consortium.
the class Tree method init.
@Override
protected void init() {
super.init();
switch(treeType) {
case COTTONWOOD:
treeWidth = 80;
treeHeight = 100;
break;
case LINDEN:
treeWidth = 90;
treeHeight = 120;
break;
case OAK:
treeWidth = 70;
treeHeight = 80;
break;
case ELM:
treeWidth = 60;
treeHeight = 75;
break;
case MAPLE:
treeWidth = 30;
treeHeight = 60;
break;
case PINE:
treeWidth = 30;
treeHeight = 80;
break;
default:
treeWidth = 30;
treeHeight = 40;
}
mesh = new Quad("Tree Quad", treeWidth, treeHeight);
mesh.setModelBound(new BoundingBox());
mesh.updateModelBound();
mesh.setRotation(new Matrix3().fromAngles(Math.PI / 2, 0, 0));
mesh.setTranslation(0, 0, treeHeight / 2.0);
mesh.getSceneHints().setPickingHint(PickingHint.Pickable, false);
final BlendState bs = new BlendState();
bs.setEnabled(true);
bs.setBlendEnabled(false);
bs.setTestEnabled(true);
bs.setTestFunction(TestFunction.GreaterThan);
bs.setReference(0.7f);
mesh.setRenderState(bs);
mesh.getSceneHints().setRenderBucketType(RenderBucketType.Transparent);
billboard = new BillboardNode("Billboard");
billboard.setAlignment(BillboardAlignment.AxialZ);
billboard.attachChild(mesh);
root.attachChild(billboard);
switch(treeType) {
case PINE:
// axis samples, radial samples, radius, height, closed
crown = new Cone("Tree Crown", 2, 6, 18, 20, false);
break;
default:
// z samples, radial samples, radius
crown = new Sphere("Tree Crown", 4, 8, 14);
}
crown.setModelBound(new BoundingSphere());
crown.updateModelBound();
final Cylinder trunk = new Cylinder("Tree Trunk", 10, 10, 1, 20);
trunk.setModelBound(new BoundingBox());
trunk.updateModelBound();
switch(treeType) {
case COTTONWOOD:
crown.setScale(3, 3, 3.5);
crown.setTranslation(0, 0, 55);
trunk.setScale(8, 8, 2);
trunk.setTranslation(0, 0, 20);
break;
case LINDEN:
crown.setScale(3.5, 3.5, 4);
crown.setTranslation(0, 0, 65);
trunk.setScale(5, 5, 2);
trunk.setTranslation(0, 0, 20);
break;
case OAK:
crown.setScale(2.5, 2.5, 3);
crown.setTranslation(0, 0, 45);
trunk.setScale(5, 5, 2);
trunk.setTranslation(0, 0, 20);
break;
case ELM:
crown.setScale(2, 2, 2.5);
crown.setTranslation(0, 0, 40);
trunk.setScale(2, 2, 2);
trunk.setTranslation(0, 0, 20);
break;
case MAPLE:
crown.setScale(1, 1, 2.1);
crown.setTranslation(0, 0, 32);
trunk.setTranslation(0, 0, 10);
break;
case PINE:
crown.setScale(1, 1, -4.0);
crown.setTranslation(0, 0, 45);
trunk.setTranslation(0, 0, 10);
break;
default:
crown.setScale(1, 1, 1.2);
crown.setTranslation(0, 0, 24);
trunk.setTranslation(0, 0, 10);
break;
}
collisionRoot = new Node("Tree Collision Root");
collisionRoot.attachChild(crown);
collisionRoot.attachChild(trunk);
if (points.size() > 0) {
collisionRoot.setTranslation(getAbsPoint(0));
}
collisionRoot.updateWorldTransform(true);
collisionRoot.updateWorldBound(true);
collisionRoot.getSceneHints().setCullHint(showPolygons ? CullHint.Never : CullHint.Always);
root.attachChild(collisionRoot);
crown.setUserData(new UserData(this));
trunk.setUserData(new UserData(this));
updateTextureAndColor();
}
use of com.ardor3d.scenegraph.Node in project energy3d by concord-consortium.
the class SolarRadiation method computeOnMirror.
// unlike PV solar panels, no indirect (ambient or diffuse) radiation should be included in reflection calculation
private void computeOnMirror(final int minute, final ReadOnlyVector3 directionTowardSun, final Mirror mirror) {
final int nx = Scene.getInstance().getMirrorNx();
final int ny = Scene.getInstance().getMirrorNy();
final Foundation target = mirror.getReceiver();
if (target != null) {
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);
mirror.draw();
}
// nx*ny*60: nx*ny is to get the unit cell area of the nx*ny grid; 60 is to convert the unit of timeStep from minute to kWh
final double a = mirror.getMirrorWidth() * mirror.getMirrorHeight() * Scene.getInstance().getTimeStep() / (nx * ny * 60.0);
final ReadOnlyVector3 normal = mirror.getNormal();
if (normal == null) {
throw new RuntimeException("Normal is null");
}
final Mesh mesh = mirror.getRadiationMesh();
MeshDataStore data = onMesh.get(mesh);
if (data == null) {
data = initMeshTextureDataOnRectangle(mesh, 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 FloatBuffer vertexBuffer = mesh.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));
// final Vector3 q0 = drawMesh.localToWorld(p0, null);
// final Vector3 q1 = drawMesh.localToWorld(p1, null);
// final Vector3 q2 = drawMesh.localToWorld(p2, null);
// System.out.println("***" + q0.distance(q1) * Scene.getInstance().getAnnotationScale() + "," + q0.distance(q2) * Scene.getInstance().getAnnotationScale());
// this is the longer side (supposed to be y)
final Vector3 u = p1.subtract(p0, null).normalizeLocal();
// this is the shorter side (supposed to be x)
final Vector3 v = p2.subtract(p0, null).normalizeLocal();
// 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)
final double xSpacing = p1.distance(p0) / nx;
final double ySpacing = p2.distance(p0) / ny;
final Vector3 receiver = target != null ? target.getSolarReceiverCenter() : null;
List<Mesh> towerCollisionMeshes = null;
if (target != null) {
towerCollisionMeshes = new ArrayList<Mesh>();
for (final HousePart child : target.getChildren()) {
towerCollisionMeshes.add((Mesh) child.getRadiationCollisionSpatial());
}
final List<Roof> roofs = target.getRoofs();
if (!roofs.isEmpty()) {
for (final Roof r : roofs) {
for (final Spatial roofPart : r.getRoofPartsRoot().getChildren()) {
towerCollisionMeshes.add((Mesh) ((Node) roofPart).getChild(6));
}
}
}
}
final int iMinute = minute / Scene.getInstance().getTimeStep();
final boolean reflectionMapOnly = Scene.getInstance().getOnlyReflectedEnergyInMirrorSolarMap();
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 = mesh.getWorldTransform().applyForward(p0.add(v2, null).addLocal(u2)).addLocal(offset);
final Ray3 pickRay = new Ray3(p, directionTowardSun);
if (dot > 0) {
final PickResults pickResults = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != mesh) {
PickingUtil.findPick(spatial, pickRay, pickResults, false);
if (pickResults.getNumber() != 0) {
break;
}
}
}
if (pickResults.getNumber() == 0) {
// for heat map generation
if (!reflectionMapOnly) {
data.dailySolarIntensity[x][y] += directRadiation;
}
if (receiver != null) {
// for concentrated energy calculation
final Vector3 toReceiver = receiver.subtract(p, null);
final Ray3 rayToReceiver = new Ray3(p, toReceiver.normalize(null));
final PickResults pickResultsToReceiver = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != mesh) {
if (towerCollisionMeshes == null || (towerCollisionMeshes != null && !towerCollisionMeshes.contains(spatial))) {
PickingUtil.findPick(spatial, rayToReceiver, pickResultsToReceiver, false);
if (pickResultsToReceiver.getNumber() != 0) {
break;
}
}
}
}
if (pickResultsToReceiver.getNumber() == 0) {
final double r = directRadiation * Atmosphere.getTransmittance(toReceiver.length() * Scene.getInstance().getAnnotationScale() * 0.001, false);
mirror.getSolarPotential()[iMinute] += r * a;
if (reflectionMapOnly) {
data.dailySolarIntensity[x][y] += r;
}
}
}
}
}
}
}
}
use of com.ardor3d.scenegraph.Node in project energy3d by concord-consortium.
the class SolarRadiation method initCollidables.
private void initCollidables() {
collidables.clear();
collidablesToParts.clear();
for (final HousePart part : Scene.getInstance().getParts()) {
if (part instanceof SolarCollector || part instanceof Tree || part instanceof Window) {
if (part instanceof Rack) {
final Rack rack = (Rack) part;
if (rack.isMonolithic()) {
final Spatial s = part.getRadiationCollisionSpatial();
collidables.add(s);
collidablesToParts.put(s, rack);
}
} else {
final Spatial s = part.getRadiationCollisionSpatial();
collidables.add(s);
collidablesToParts.put(s, part);
}
} else if (part instanceof Foundation) {
final Foundation foundation = (Foundation) part;
for (int i = 0; i < 4; i++) {
final Spatial s = foundation.getRadiationCollisionSpatial(i);
collidables.add(s);
collidablesToParts.put(s, foundation);
}
final List<Node> importedNodes = foundation.getImportedNodes();
if (importedNodes != null) {
for (final Node node : importedNodes) {
for (final Spatial s : node.getChildren()) {
collidables.add(s);
collidablesToParts.put(s, foundation);
}
}
}
} else if (part instanceof Wall) {
final Wall wall = (Wall) part;
if (wall.getType() == Wall.SOLID_WALL) {
final Spatial s = part.getRadiationCollisionSpatial();
collidables.add(s);
collidablesToParts.put(s, wall);
}
} else if (part instanceof Door) {
final Door door = (Door) part;
final Spatial s = door.getRadiationCollisionSpatial();
collidables.add(s);
collidablesToParts.put(s, door);
} else if (part instanceof Floor) {
final Floor floor = (Floor) part;
final Spatial s = floor.getRadiationCollisionSpatial();
collidables.add(s);
collidablesToParts.put(s, floor);
} else if (part instanceof Roof) {
final Roof roof = (Roof) part;
for (final Spatial roofPart : roof.getRoofPartsRoot().getChildren()) {
if (roofPart.getSceneHints().getCullHint() != CullHint.Always) {
final Spatial s = ((Node) roofPart).getChild(6);
collidables.add(s);
collidablesToParts.put(s, roof);
}
}
}
}
}
use of com.ardor3d.scenegraph.Node in project energy3d by concord-consortium.
the class SolarRadiation method computeOnFresnelReflector.
// unlike PV solar panels, no indirect (ambient or diffuse) radiation should be included in reflection calculation
private void computeOnFresnelReflector(final int minute, final ReadOnlyVector3 directionTowardSun, final FresnelReflector reflector) {
final int nx = reflector.getNSectionLength();
final int ny = reflector.getNSectionWidth();
final Foundation target = reflector.getReceiver();
if (target != null) {
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);
reflector.draw();
}
// nx*ny*60: nx*ny is to get the unit cell area of the nx*ny grid; 60 is to convert the unit of timeStep from minute to kWh
final double a = reflector.getModuleWidth() * reflector.getLength() * Scene.getInstance().getTimeStep() / (nx * ny * 60.0);
final ReadOnlyVector3 normal = reflector.getNormal();
if (normal == null) {
throw new RuntimeException("Normal is null");
}
final Mesh mesh = reflector.getRadiationMesh();
MeshDataStore data = onMesh.get(mesh);
if (data == null) {
data = initMeshTextureDataOnRectangle(mesh, 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 FloatBuffer vertexBuffer = mesh.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));
// final Vector3 q0 = mesh.localToWorld(p0, null);
// final Vector3 q1 = mesh.localToWorld(p1, null);
// final Vector3 q2 = mesh.localToWorld(p2, null);
// System.out.println("***" + q0.distance(q1) * Scene.getInstance().getAnnotationScale() + "," + q0.distance(q2) * Scene.getInstance().getAnnotationScale());
// this is the longer side (supposed to be y)
final Vector3 u = p1.subtract(p0, null).normalizeLocal();
// this is the shorter side (supposed to be x)
final Vector3 v = p2.subtract(p0, null).normalizeLocal();
// 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)
final double xSpacing = p1.distance(p0) / nx;
final double ySpacing = p2.distance(p0) / ny;
final Vector3 absorber = target != null ? target.getSolarReceiverCenter() : null;
List<Mesh> absorberCollisionMeshes = null;
if (target != null) {
absorberCollisionMeshes = new ArrayList<Mesh>();
for (final HousePart child : target.getChildren()) {
absorberCollisionMeshes.add((Mesh) child.getRadiationCollisionSpatial());
}
final List<Roof> roofs = target.getRoofs();
if (!roofs.isEmpty()) {
for (final Roof r : roofs) {
for (final Spatial roofPart : r.getRoofPartsRoot().getChildren()) {
absorberCollisionMeshes.add((Mesh) ((Node) roofPart).getChild(6));
}
}
}
}
final int iMinute = minute / Scene.getInstance().getTimeStep();
final boolean reflectionMapOnly = Scene.getInstance().getOnlyReflectedEnergyInMirrorSolarMap();
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 = mesh.getWorldTransform().applyForward(p0.add(v2, null).addLocal(u2)).addLocal(offset);
final Ray3 pickRay = new Ray3(p, directionTowardSun);
if (dot > 0) {
final PickResults pickResults = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != mesh) {
PickingUtil.findPick(spatial, pickRay, pickResults, false);
if (pickResults.getNumber() != 0) {
break;
}
}
}
if (pickResults.getNumber() == 0) {
// for heat map generation
if (!reflectionMapOnly) {
data.dailySolarIntensity[x][y] += directRadiation;
}
// TODO: Edge losses are not considered yet
if (absorber != null) {
// TODO: This calculation is not exactly accurate as the collision detection assumes that the ray emits from a grid point on the reflector to
// the parallel position on the absorber tube -- without considering the actual direction of the reflected light
final Vector3 toAbsorber = absorber.subtract(p, null);
toAbsorber.setY(0);
final Ray3 rayToAbsorber = new Ray3(p, toAbsorber.normalize(null));
final PickResults pickResultsToAbsorber = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != mesh) {
if (absorberCollisionMeshes == null || (absorberCollisionMeshes != null && !absorberCollisionMeshes.contains(spatial))) {
PickingUtil.findPick(spatial, rayToAbsorber, pickResultsToAbsorber, false);
if (pickResultsToAbsorber.getNumber() != 0) {
// FIXME: how to stop the ray when it hits the absorber?
break;
}
}
}
}
if (pickResultsToAbsorber.getNumber() == 0) {
final double r = directRadiation * Atmosphere.getTransmittance(toAbsorber.length() * Scene.getInstance().getAnnotationScale() * 0.001, false);
reflector.getSolarPotential()[iMinute] += r * a;
if (reflectionMapOnly) {
data.dailySolarIntensity[x][y] += r;
}
}
}
}
}
}
}
}
use of com.ardor3d.scenegraph.Node in project energy3d by concord-consortium.
the class SolarRadiation method setupImportedMeshes.
private void setupImportedMeshes() {
for (final HousePart part : Scene.getInstance().getParts()) {
if (part instanceof Foundation) {
final Foundation foundation = (Foundation) part;
final boolean nonZeroAz = !Util.isZero(foundation.getAzimuth());
final List<Node> importedNodes = foundation.getImportedNodes();
if (importedNodes != null) {
for (final Node node : importedNodes) {
for (final Spatial s : node.getChildren()) {
final Mesh m = (Mesh) s;
final UserData ud = (UserData) m.getUserData();
ReadOnlyVector3 normal = ud.getNormal();
if (nonZeroAz) {
// if the foundation is rotated, rotate the imported meshes, too, but this doesn't alter their original normals
// this must be recalculated in case the foundation has been rotated after loading
ud.setRotatedNormal(node.getRotation().applyPost(normal, null));
normal = ud.getRotatedNormal();
}
MeshDataStore data = onMesh.get(m);
if (data == null) {
// initialize mesh solar data and texture
data = initMeshTextureData(m, m, normal, true);
data.solarPotential = new double[MINUTES_OF_DAY / Scene.getInstance().getTimeStep()];
}
}
}
}
}
}
}
Aggregations