Search in sources :

Example 11 with Floor

use of org.concord.energy3d.model.Floor 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;
                }
            }
        }
    }
}
Also used : Human(org.concord.energy3d.model.Human) Window(org.concord.energy3d.model.Window) Building(org.concord.energy3d.model.Building) Floor(org.concord.energy3d.model.Floor) Mesh(com.ardor3d.scenegraph.Mesh) CullHint(com.ardor3d.scenegraph.hint.CullHint) Roof(org.concord.energy3d.model.Roof) Spatial(com.ardor3d.scenegraph.Spatial) SolarCollector(org.concord.energy3d.model.SolarCollector) Tree(org.concord.energy3d.model.Tree) Foundation(org.concord.energy3d.model.Foundation) HousePart(org.concord.energy3d.model.HousePart) Sensor(org.concord.energy3d.model.Sensor) Thermal(org.concord.energy3d.model.Thermal)

Example 12 with Floor

use of org.concord.energy3d.model.Floor in project energy3d by concord-consortium.

the class BuildingCost method showPieChart.

@Override
void showPieChart() {
    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
    final Foundation selectedBuilding;
    if (selectedPart == null || selectedPart instanceof Tree || selectedPart instanceof Human) {
        selectedBuilding = null;
    } else if (selectedPart instanceof Foundation) {
        selectedBuilding = (Foundation) selectedPart;
    } else {
        selectedBuilding = selectedPart.getTopContainer();
        selectedPart.setEditPointsVisible(false);
        SceneManager.getInstance().setSelectedPart(selectedBuilding);
    }
    String details = "";
    int count = 0;
    for (final HousePart p : Scene.getInstance().getParts()) {
        if (p instanceof Foundation) {
            count++;
            if (selectedBuilding == null) {
                final Foundation foundation = (Foundation) p;
                details += "$" + (int) getCostByFoundation(foundation) + " (" + foundation.getId() + ") | ";
            }
        }
    }
    if (selectedBuilding == null) {
        if (count > 0) {
            details = details.substring(0, details.length() - 2);
        }
    }
    double wallSum = 0;
    double floorSum = 0;
    double windowSum = 0;
    double roofSum = 0;
    double foundationSum = 0;
    double doorSum = 0;
    double solarPanelSum = 0;
    double treeSum = 0;
    String info;
    if (selectedBuilding != null) {
        info = "Building #" + selectedBuilding.getId();
        foundationSum = getPartCost(selectedBuilding);
        for (final HousePart p : Scene.getInstance().getParts()) {
            if (p.getTopContainer() == selectedBuilding) {
                if (p instanceof Wall) {
                    wallSum += getPartCost(p);
                } else if (p instanceof Floor) {
                    floorSum += getPartCost(p);
                } else if (p instanceof Window) {
                    windowSum += getPartCost(p);
                } else if (p instanceof Roof) {
                    roofSum += getPartCost(p);
                } else if (p instanceof Door) {
                    doorSum += getPartCost(p);
                } else if (p instanceof SolarPanel || p instanceof Rack) {
                    solarPanelSum += getPartCost(p);
                }
            }
            if (count <= 1) {
                if (p instanceof Tree && !p.getLockEdit()) {
                    treeSum += getPartCost(p);
                }
            }
        }
    } else {
        info = count + " buildings";
        for (final HousePart p : Scene.getInstance().getParts()) {
            if (p instanceof Wall) {
                wallSum += getPartCost(p);
            } else if (p instanceof Floor) {
                floorSum += getPartCost(p);
            } else if (p instanceof Window) {
                windowSum += getPartCost(p);
            } else if (p instanceof Roof) {
                roofSum += getPartCost(p);
            } else if (p instanceof Foundation) {
                foundationSum += getPartCost(p);
            } else if (p instanceof Door) {
                doorSum += getPartCost(p);
            } else if (p instanceof SolarPanel || p instanceof Rack) {
                solarPanelSum += getPartCost(p);
            } else if (p instanceof Tree && !p.getLockEdit()) {
                treeSum += getPartCost(p);
            }
        }
    }
    final double[] data = new double[] { wallSum, windowSum, roofSum, foundationSum, floorSum, doorSum, solarPanelSum, treeSum };
    // show them in a popup window
    final PieChart pie = new PieChart(data, BuildingCostGraph.colors, BuildingCostGraph.legends, "$", info, count > 1 ? details : null, true);
    pie.setBackground(Color.WHITE);
    pie.setBorder(BorderFactory.createEtchedBorder());
    final JDialog dialog = new JDialog(MainFrame.getInstance(), "Project Costs by Category", true);
    dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    dialog.getContentPane().add(pie, BorderLayout.CENTER);
    final JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
    final JButton buttonItemize = new JButton("Itemize");
    buttonItemize.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(final ActionEvent e) {
            showItemizedCost();
        }
    });
    buttonPanel.add(buttonItemize);
    final JButton buttonClose = new JButton("Close");
    buttonClose.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(final ActionEvent e) {
            dialog.dispose();
        }
    });
    buttonPanel.add(buttonClose);
    dialog.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
    dialog.pack();
    dialog.setLocationRelativeTo(MainFrame.getInstance());
    dialog.setVisible(true);
}
Also used : Human(org.concord.energy3d.model.Human) Window(org.concord.energy3d.model.Window) Floor(org.concord.energy3d.model.Floor) JPanel(javax.swing.JPanel) Wall(org.concord.energy3d.model.Wall) FlowLayout(java.awt.FlowLayout) ActionEvent(java.awt.event.ActionEvent) JButton(javax.swing.JButton) Door(org.concord.energy3d.model.Door) Rack(org.concord.energy3d.model.Rack) Roof(org.concord.energy3d.model.Roof) ActionListener(java.awt.event.ActionListener) SolarPanel(org.concord.energy3d.model.SolarPanel) Tree(org.concord.energy3d.model.Tree) Foundation(org.concord.energy3d.model.Foundation) HousePart(org.concord.energy3d.model.HousePart) JDialog(javax.swing.JDialog)

Example 13 with Floor

use of org.concord.energy3d.model.Floor in project energy3d by concord-consortium.

the class PopupMenuForFloor method getPopupMenu.

static JPopupMenu getPopupMenu(final MouseEvent e) {
    if (e.isShiftDown()) {
        SceneManager.getTaskManager().update(new Callable<Object>() {

            @Override
            public Object call() throws Exception {
                Scene.getInstance().pasteToPickedLocationOnFloor();
                Scene.getInstance().setEdited(true);
                return null;
            }
        });
        return null;
    }
    if (popupMenuForFloor == null) {
        final JMenuItem miInfo = new JMenuItem("Floor");
        miInfo.setEnabled(false);
        miInfo.setOpaque(true);
        miInfo.setBackground(Config.isMac() ? Color.BLACK : Color.GRAY);
        miInfo.setForeground(Color.WHITE);
        final JMenuItem miPaste = new JMenuItem("Paste");
        miPaste.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, Config.isMac() ? KeyEvent.META_MASK : InputEvent.CTRL_MASK));
        miPaste.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                SceneManager.getTaskManager().update(new Callable<Object>() {

                    @Override
                    public Object call() throws Exception {
                        Scene.getInstance().pasteToPickedLocationOnFloor();
                        Scene.getInstance().setEdited(true);
                        return null;
                    }
                });
            }
        });
        final JMenuItem miClear = new JMenuItem("Clear");
        miClear.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(final ActionEvent e) {
                SceneManager.getTaskManager().update(new Callable<Object>() {

                    @Override
                    public Object call() throws Exception {
                        Scene.getInstance().removeAllChildren(SceneManager.getInstance().getSelectedPart());
                        Scene.getInstance().setEdited(true);
                        return null;
                    }
                });
            }
        });
        final JMenu typeMenu = new JMenu("Type");
        final ButtonGroup typeGroup = new ButtonGroup();
        final JRadioButtonMenuItem rbmiSolid = new JRadioButtonMenuItem("Solid");
        rbmiSolid.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Floor) {
                        final Floor floor = (Floor) selectedPart;
                        // final ChangeRoofTypeCommand c = new ChangeRoofTypeCommand(roof);
                        floor.setType(Floor.SOLID);
                        floor.draw();
                        SceneManager.getInstance().refresh();
                        Scene.getInstance().setEdited(true);
                    // SceneManager.getInstance().getUndoManager().addEdit(c);
                    }
                }
            }
        });
        typeMenu.add(rbmiSolid);
        typeGroup.add(rbmiSolid);
        final JRadioButtonMenuItem rbmiTransparent = new JRadioButtonMenuItem("Transparent");
        rbmiTransparent.addItemListener(new ItemListener() {

            @Override
            public void itemStateChanged(final ItemEvent e) {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                    if (selectedPart instanceof Floor) {
                        final Floor floor = (Floor) selectedPart;
                        // final ChangeRoofTypeCommand c = new ChangeRoofTypeCommand(roof);
                        floor.setType(Floor.TRANSPARENT);
                        floor.draw();
                        SceneManager.getInstance().refresh();
                        Scene.getInstance().setEdited(true);
                    // SceneManager.getInstance().getUndoManager().addEdit(c);
                    }
                }
            }
        });
        typeMenu.add(rbmiTransparent);
        typeGroup.add(rbmiTransparent);
        typeMenu.addMenuListener(new MenuListener() {

            @Override
            public void menuSelected(final MenuEvent e) {
                final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
                if (selectedPart instanceof Floor) {
                    final Floor floor = (Floor) selectedPart;
                    switch(floor.getType()) {
                        case Floor.SOLID:
                            Util.selectSilently(rbmiSolid, true);
                            break;
                        case Floor.TRANSPARENT:
                            Util.selectSilently(rbmiTransparent, true);
                            break;
                    }
                }
            }

            @Override
            public void menuDeselected(final MenuEvent e) {
                typeMenu.setEnabled(true);
            }

            @Override
            public void menuCanceled(final MenuEvent e) {
                typeMenu.setEnabled(true);
            }
        });
        popupMenuForFloor = createPopupMenu(false, false, new Runnable() {

            @Override
            public void run() {
                final HousePart copyBuffer = Scene.getInstance().getCopyBuffer();
                miPaste.setEnabled(copyBuffer instanceof SolarPanel || copyBuffer instanceof Rack);
            }
        });
        popupMenuForFloor.add(miPaste);
        popupMenuForFloor.add(miClear);
        popupMenuForFloor.addSeparator();
        popupMenuForFloor.add(typeMenu);
        popupMenuForFloor.add(colorAction);
    }
    return popupMenuForFloor;
}
Also used : Floor(org.concord.energy3d.model.Floor) ItemEvent(java.awt.event.ItemEvent) ActionEvent(java.awt.event.ActionEvent) MenuListener(javax.swing.event.MenuListener) JRadioButtonMenuItem(javax.swing.JRadioButtonMenuItem) Callable(java.util.concurrent.Callable) Rack(org.concord.energy3d.model.Rack) ActionListener(java.awt.event.ActionListener) ButtonGroup(javax.swing.ButtonGroup) SolarPanel(org.concord.energy3d.model.SolarPanel) ItemListener(java.awt.event.ItemListener) JMenuItem(javax.swing.JMenuItem) JMenu(javax.swing.JMenu) HousePart(org.concord.energy3d.model.HousePart) MenuEvent(javax.swing.event.MenuEvent)

Example 14 with Floor

use of org.concord.energy3d.model.Floor in project energy3d by concord-consortium.

the class EnergyPanel method updateProperties.

// As this method may be called from a non-Event-Queue thread, updating GUI must be done through invokeLater.
public void updateProperties() {
    // update part properties
    final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
    final boolean energyViewShown = MainPanel.getInstance().getEnergyButton().isSelected();
    final double meterToFoot;
    final String lengthUnit;
    switch(Scene.getInstance().getUnit()) {
        case USCustomaryUnits:
            meterToFoot = 3.28084;
            lengthUnit = "ft";
            break;
        default:
            meterToFoot = 1;
            lengthUnit = "m";
    }
    final double scale = Scene.getInstance().getAnnotationScale() * meterToFoot;
    final TitledBorder partPanelBorder = (TitledBorder) partPanel.getBorder();
    if (selectedPart != null) {
        final ReadOnlyVector3 v = selectedPart.getAbsPoint(0);
        if (selectedPart instanceof Tree) {
            final Tree tree = (Tree) selectedPart;
            if (tree.isDrawable()) {
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Tree (" + tree.getId() + "): " + tree.getTreeName());
                        partProperty1Label.setText("  Spread & Height:");
                        partProperty2Label.setText("  Type:");
                        partProperty3Label.setText("  Position:");
                        final double l = v.length();
                        double a = 90 + Math.toDegrees(Math.asin(-v.getY() / l));
                        if (v.getX() < 0) {
                            a = 360 - a;
                        }
                        if (Util.isZero(a - 360)) {
                            a = 0;
                        }
                        partProperty1TextField.setText(ONE_DECIMAL.format(tree.getWidth() * scale) + lengthUnit + ", " + ONE_DECIMAL.format(tree.getHeight() * scale) + lengthUnit);
                        partProperty2TextField.setText(tree.getTreeName() + " (" + (tree.getTreeType() == Tree.PINE ? "Evergreen" : "Deciduous") + ")");
                        partProperty3TextField.setText("(" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ")" + lengthUnit + " or (" + ONE_DECIMAL.format(l * scale) + lengthUnit + ", " + ONE_DECIMAL.format(a) + "\u00B0)");
                        partProperty1TextField.putClientProperty("tooltip", "The spread and height of the tree");
                        partProperty2TextField.putClientProperty("tooltip", "The type of the tree");
                        partProperty3TextField.putClientProperty("tooltip", "The (x, y) or polar coordinates on the land");
                    }
                });
            }
        } else if (selectedPart instanceof Human) {
            final Human human = (Human) selectedPart;
            if (human.isDrawable()) {
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Human (" + human.getId() + "): " + human.getHumanName());
                        partProperty1Label.setText("  X:");
                        partProperty2Label.setText("  Y:");
                        partProperty3Label.setText("  Z:");
                        partProperty1TextField.setText(ONE_DECIMAL.format(v.getX() * scale) + lengthUnit);
                        partProperty2TextField.setText(ONE_DECIMAL.format(v.getY() * scale) + lengthUnit);
                        partProperty3TextField.setText(ONE_DECIMAL.format(v.getZ() * scale) + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "X coordinate");
                        partProperty2TextField.putClientProperty("tooltip", "Y coordinate");
                        partProperty3TextField.putClientProperty("tooltip", "Z coordinate");
                    }
                });
            }
        } else if (selectedPart instanceof SolarPanel) {
            final SolarPanel sp = (SolarPanel) selectedPart;
            if (sp.isDrawable()) {
                final Foundation f = sp.getTopContainer();
                if (f != null) {
                    double a = sp.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double az = a;
                    final boolean flat = (sp.getContainer() instanceof Roof && Util.isZero(sp.getContainer().getHeight())) || (sp.getContainer() instanceof Foundation);
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            String title = "Solar Panel (" + sp.getId() + "), " + (sp.getModelName() == null ? "" : "Model: " + sp.getModelName());
                            final String trackerName = sp.getTrackerName();
                            if (trackerName != null) {
                                title += ", Tracker: " + trackerName;
                            }
                            partPanelBorder.setTitle(title);
                            partProperty1Label.setText("  Size & Position:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(sp.getPanelWidth() * meterToFoot) + "\u00d7" + TWO_DECIMALS.format(sp.getPanelHeight() * meterToFoot) + lengthUnit + ", (" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit);
                            partProperty1TextField.putClientProperty("tooltip", "The length, width, and center coordinates of the solar panel");
                            partProperty2Label.setText("  Angles:");
                            partProperty2TextField.setText(flat ? "tilt: " + ONE_DECIMAL.format(Util.isZero(sp.getTiltAngle()) ? Math.toDegrees(Math.asin(sp.getNormal().getY())) : sp.getTiltAngle()) + "\u00B0, azimuth: " + ONE_DECIMAL.format(az) + "\u00B0" : " --- ");
                            partProperty2TextField.putClientProperty("tooltip", "The angles of the solar panel");
                            final String eff = ONE_DECIMAL.format(sp.getCellEfficiency() * 100) + "%";
                            if (energyViewShown) {
                                partProperty3Label.setText("  Efficiency & Yield:");
                                partProperty3TextField.setText(eff + ", " + TWO_DECIMALS.format(sp.getSolarPotentialToday()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The solar cell efficiency and daily yield of the solar panel");
                            } else {
                                partProperty3Label.setText("  Efficiency:");
                                partProperty3TextField.setText(eff);
                                partProperty3TextField.putClientProperty("tooltip", "The solar cell efficiency of the solar panel");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof Rack) {
            final Rack rack = (Rack) selectedPart;
            if (rack.isDrawable()) {
                final Foundation f = rack.getTopContainer();
                if (f != null) {
                    double a = rack.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double az = a;
                    final int n = rack.isMonolithic() ? rack.getNumberOfSolarPanels() : rack.getChildren().size();
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            String title = "Rack (" + rack.getId() + ")";
                            final SolarPanel s = rack.getSolarPanel();
                            if (s.getModelName() != null) {
                                title += ", Model: " + s.getModelName();
                            }
                            final String trackerName = rack.getTrackerName();
                            if (trackerName != null) {
                                title += ", Tracker: " + trackerName;
                            }
                            partPanelBorder.setTitle(title);
                            partProperty1Label.setText("  Size & Center:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(rack.getRackWidth() * meterToFoot) + "\u00d7" + TWO_DECIMALS.format(rack.getRackHeight() * meterToFoot) + lengthUnit + ", (" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit);
                            partProperty1TextField.putClientProperty("tooltip", "The length, width, and center coordinates of the rack");
                            partProperty2Label.setText("  Angles:");
                            partProperty2TextField.setText("tilt: " + ONE_DECIMAL.format(Util.isZero(rack.getTiltAngle()) ? Math.toDegrees(Math.asin(rack.getNormal().getY())) : rack.getTiltAngle()) + "\u00B0, azimuth: " + ONE_DECIMAL.format(az) + "\u00B0");
                            partProperty2TextField.putClientProperty("tooltip", "The angles of the rack");
                            partProperty3Label.setText("  Solar Panels:");
                            final SolarPanel sp = rack.getSolarPanel();
                            final String eff = ONE_DECIMAL.format(sp.getCellEfficiency() * 100) + "%";
                            if (energyViewShown) {
                                partProperty3Label.setText("  Efficiency & Yield:");
                                partProperty3TextField.setText(eff + ", " + TWO_DECIMALS.format(rack.getSolarPotentialToday()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The solar cell efficiency and daily yield of the solar panel array on the rack");
                            } else {
                                if (rack.isMonolithic()) {
                                    final int[] rnc = rack.getSolarPanelRowAndColumnNumbers();
                                    partProperty3TextField.setText("" + n + " (" + rnc[0] + "\u00D7" + rnc[1] + "), " + s.getPanelWidth() + "\u00D7" + s.getPanelHeight() + lengthUnit + ", " + eff);
                                } else {
                                    partProperty3TextField.setText("" + n);
                                }
                                partProperty3TextField.putClientProperty("tooltip", "Number and type of solar panels on this rack");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof Mirror) {
            final Mirror m = (Mirror) selectedPart;
            if (m.isDrawable()) {
                final Foundation f = m.getTopContainer();
                if (f != null) {
                    double a = m.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double az = a;
                    final boolean flat = m.getContainer() instanceof Foundation;
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            partPanelBorder.setTitle("Heliostat (" + m.getId() + ")");
                            partProperty1Label.setText("  Size & Center:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(m.getMirrorWidth() * meterToFoot) + "\u00d7" + TWO_DECIMALS.format(m.getMirrorHeight() * meterToFoot) + lengthUnit + ", (" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit);
                            partProperty1TextField.putClientProperty("tooltip", "The length, width, and center coordinates of the heliostat");
                            partProperty2Label.setText("  Angles:");
                            partProperty2TextField.setText(flat ? "tilt: " + ONE_DECIMAL.format(m.getTiltAngle()) + "\u00B0, azimuth: " + ONE_DECIMAL.format(az) + "\u00B0" : " --- ");
                            partProperty2TextField.putClientProperty("tooltip", "The angles of the heliostat");
                            final Foundation receiver = m.getReceiver();
                            final String s = "R=" + ONE_DECIMAL.format(m.getReflectance() * 100) + "%" + (receiver == null ? "" : ", \u03B7=" + ONE_DECIMAL.format(receiver.getSolarReceiverEfficiency() * 100) + "%");
                            if (energyViewShown) {
                                partProperty3Label.setText("  Properties & Yield:");
                                partProperty3TextField.setText(s + ", " + ONE_DECIMAL.format(m.getSolarPotentialToday() * m.getSystemEfficiency()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The physical properties and electric yield of this heliostat");
                            } else {
                                partProperty3Label.setText("  Properties:");
                                partProperty3TextField.setText(s);
                                partProperty3TextField.putClientProperty("tooltip", "The physical properties of this heliostat");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof ParabolicTrough) {
            final ParabolicTrough t = (ParabolicTrough) selectedPart;
            if (t.isDrawable()) {
                final Foundation f = t.getTopContainer();
                if (f != null) {
                    double a = t.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double az = a;
                    // http://www.powerfromthesun.net/Book/chapter08/chapter08.html
                    final double focalLength = t.getSemilatusRectum() * 0.5;
                    final double d = t.getApertureWidth();
                    final double h = d * d / (16 * focalLength);
                    final double rimAngle = Math.toDegrees(Math.atan(1.0 / (d / (8 * h) - (2 * h) / d)));
                    final double b = 4 * h / d;
                    final double c = Math.sqrt(b * b + 1);
                    final double s = 0.5 * d * c + 2 * focalLength * Math.log(b + c);
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            partPanelBorder.setTitle("Parabolic Trough (" + t.getId() + ")");
                            partProperty1Label.setText("  Length & Center:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(t.getTroughLength() * meterToFoot) + lengthUnit + ", module:" + TWO_DECIMALS.format(t.getModuleLength() * meterToFoot) + lengthUnit + ", (" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit + ", azimuth:" + ONE_DECIMAL.format(az) + "\u00B0");
                            partProperty1TextField.putClientProperty("tooltip", "Assembly length, module length, center coordinates, and azimith of the parabolic trough");
                            partProperty2Label.setText("  Parabola Shape:");
                            partProperty2TextField.setText("f=" + ONE_DECIMAL.format(focalLength * meterToFoot) + lengthUnit + ", d=" + ONE_DECIMAL.format(t.getApertureWidth() * meterToFoot) + lengthUnit + ", h=" + ONE_DECIMAL.format(h * meterToFoot) + lengthUnit + ", \u03C6=" + ONE_DECIMAL.format(rimAngle >= 0 ? rimAngle : 180 + rimAngle) + "\u00B0");
                            partProperty2TextField.putClientProperty("tooltip", "Parameters of the parabolic shape");
                            final String str = "R=" + ONE_DECIMAL.format(t.getReflectance() * 100) + "%, s=" + ONE_DECIMAL.format(s * t.getTroughLength() * meterToFoot * meterToFoot) + lengthUnit + "\u00B2, a=" + ONE_DECIMAL.format(d * t.getTroughLength() * meterToFoot * meterToFoot) + lengthUnit + "\u00B2, \u03B1=" + ONE_DECIMAL.format(t.getAbsorptance() * 100) + "%";
                            if (energyViewShown) {
                                partProperty3Label.setText("  Properties & Yield:");
                                partProperty3TextField.setText(str + ", " + ONE_DECIMAL.format(t.getSolarPotentialToday() * t.getSystemEfficiency()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The properties and yield of this parabolic trough");
                            } else {
                                partProperty3Label.setText("  Properties:");
                                partProperty3TextField.setText(str);
                                partProperty3TextField.putClientProperty("tooltip", "The properties of this parabolic trough");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof ParabolicDish) {
            final ParabolicDish d = (ParabolicDish) selectedPart;
            if (d.isDrawable()) {
                final Foundation f = d.getTopContainer();
                if (f != null) {
                    double a = d.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double focalLength = d.getFocalLength();
                    final double rimRadius = d.getRimRadius();
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            partPanelBorder.setTitle("Parabolic Dish (" + d.getId() + ")");
                            partProperty1Label.setText("  Size & Center:");
                            partProperty1TextField.setText("Rim radius=" + TWO_DECIMALS.format(rimRadius * meterToFoot) + lengthUnit + ", (" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit);
                            partProperty1TextField.putClientProperty("tooltip", "Rim radius and center coordinates of the parabolic dish");
                            partProperty2Label.setText("  Parabola Shape:");
                            partProperty2TextField.setText("Focal length=" + ONE_DECIMAL.format(focalLength * meterToFoot) + lengthUnit);
                            partProperty2TextField.putClientProperty("tooltip", "Parameters of the parabolic shape");
                            final String str = "R=" + ONE_DECIMAL.format(d.getReflectance() * 100) + "%, \u03B1=" + ONE_DECIMAL.format(d.getAbsorptance() * 100) + "%";
                            if (energyViewShown) {
                                partProperty3Label.setText("  Properties & Yield:");
                                partProperty3TextField.setText(str + ", " + ONE_DECIMAL.format(d.getSolarPotentialToday() * d.getSystemEfficiency()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The properties and yield of this parabolic dish");
                            } else {
                                partProperty3Label.setText("  Properties:");
                                partProperty3TextField.setText(str);
                                partProperty3TextField.putClientProperty("tooltip", "The properties of this parabolic dish");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof FresnelReflector) {
            final FresnelReflector r = (FresnelReflector) selectedPart;
            if (r.isDrawable()) {
                final Foundation f = r.getTopContainer();
                if (f != null) {
                    double a = r.getRelativeAzimuth() + f.getAzimuth();
                    if (a >= 360) {
                        a -= 360;
                    }
                    final double az = a;
                    EventQueue.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            partPanelBorder.setTitle("Fresnel Reflector (" + r.getId() + ")");
                            partProperty1Label.setText("  Center & Azimuth:");
                            partProperty1TextField.setText("(" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit + ", azimuth:" + ONE_DECIMAL.format(az) + "\u00B0");
                            partProperty1TextField.putClientProperty("tooltip", "Center coordinates and azimuth of the Fresnel reflector");
                            partProperty2Label.setText("  Length & Width:");
                            partProperty2TextField.setText(TWO_DECIMALS.format(r.getLength() * meterToFoot) + lengthUnit + ", module:" + TWO_DECIMALS.format(r.getModuleLength() * meterToFoot) + lengthUnit + ", " + ONE_DECIMAL.format(r.getModuleWidth() * meterToFoot) + lengthUnit);
                            partProperty2TextField.putClientProperty("tooltip", "Assembly length, module length, and width of the Fresnel reflector");
                            final Foundation receiver = r.getReceiver();
                            final String str = "R=" + ONE_DECIMAL.format(r.getReflectance() * 100) + "%, a=" + ONE_DECIMAL.format(r.getModuleWidth() * r.getLength() * meterToFoot * meterToFoot) + lengthUnit + "\u00B2" + (receiver == null ? "" : ", \u03B7=" + ONE_DECIMAL.format(receiver.getSolarReceiverEfficiency() * 100) + "%");
                            if (energyViewShown) {
                                partProperty3Label.setText("  Properties & Yield:");
                                partProperty3TextField.setText(str + ", " + ONE_DECIMAL.format(r.getSolarPotentialToday() * r.getSystemEfficiency()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The properties and yield of this Fresnel reflector");
                            } else {
                                partProperty3Label.setText("  Properties:");
                                partProperty3TextField.setText(str);
                                partProperty3TextField.putClientProperty("tooltip", "The properties of this Fresnel reflector");
                            }
                        }
                    });
                }
            }
        } else if (selectedPart instanceof Sensor) {
            final Sensor sensor = (Sensor) selectedPart;
            if (sensor.isDrawable()) {
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Sensor (" + sensor.getId() + ")");
                        partProperty1Label.setText("  Position:");
                        partProperty2Label.setText("  Thermal:");
                        partProperty3Label.setText("  Light:");
                        partProperty1TextField.setText("(" + ONE_DECIMAL.format(v.getX() * scale) + ", " + ONE_DECIMAL.format(v.getY() * scale) + ", " + ONE_DECIMAL.format(v.getZ() * scale) + ")" + lengthUnit);
                        partProperty2TextField.setText(TWO_DECIMALS.format(-sensor.getTotalHeatLoss() / sensor.getArea()) + " kWh/day/m\u00B2");
                        partProperty3TextField.setText(TWO_DECIMALS.format(sensor.getSolarPotentialToday() / sensor.getArea()) + " kWh/day/m\u00B2");
                        partProperty1TextField.putClientProperty("tooltip", "The (x, y, z) coordinates of the sensor");
                        partProperty2TextField.putClientProperty("tooltip", "The heat flux measured by the sensor");
                        partProperty3TextField.putClientProperty("tooltip", "The light intensity measured by the sensor");
                    }
                });
            }
        } else if (selectedPart instanceof Foundation) {
            final Foundation foundation = (Foundation) selectedPart;
            if (foundation.isDrawable()) {
                final Vector3 v1 = foundation.getAbsPoint(1);
                final Vector3 v2 = foundation.getAbsPoint(2);
                final Vector3 v3 = foundation.getAbsPoint(3);
                final double cx = 0.25 * (v.getX() + v1.getX() + v2.getX() + v3.getX());
                final double cy = 0.25 * (v.getY() + v1.getY() + v2.getY() + v3.getY());
                final double lx = v.distance(v2);
                final double ly = v.distance(v1);
                final double lz = foundation.getHeight();
                final double az = foundation.getAzimuth();
                final String landArea;
                final FoundationPolygon polygon = foundation.getPolygon();
                if (polygon != null && polygon.isVisible()) {
                    landArea = " (inset:" + ONE_DECIMAL.format(polygon.getArea()) + ")";
                } else {
                    landArea = "";
                }
                final Mesh selectedMesh;
                final Node selectedNode;
                final OrientedBoundingBox nodeBox, meshBox;
                final List<Node> nodes = foundation.getImportedNodes();
                if (nodes != null) {
                    selectedMesh = foundation.getSelectedMesh();
                    if (selectedMesh != null) {
                        selectedNode = selectedMesh.getParent();
                        nodeBox = Util.getOrientedBoundingBox(selectedNode);
                        meshBox = Util.getOrientedBoundingBox(selectedMesh);
                    } else {
                        selectedNode = null;
                        nodeBox = null;
                        meshBox = null;
                    }
                } else {
                    selectedMesh = null;
                    selectedNode = null;
                    nodeBox = null;
                    meshBox = null;
                }
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        if (selectedNode != null) {
                            final double xNodeBox = 2 * nodeBox.getExtent().getX() * scale;
                            final double yNodeBox = 2 * nodeBox.getExtent().getY() * scale;
                            final double zNodeBox = 2 * nodeBox.getExtent().getZ() * scale;
                            final double xMeshBox = 2 * meshBox.getExtent().getX() * scale;
                            final double yMeshBox = 2 * meshBox.getExtent().getY() * scale;
                            final double zMeshBox = 2 * meshBox.getExtent().getZ() * scale;
                            final ReadOnlyVector3 meshBoxCenter = meshBox.getCenter();
                            final NodeState ns = foundation.getNodeState(selectedNode);
                            final Vector3 position = ns.getRelativePosition().add(foundation.getAbsCenter(), null);
                            Vector3 meshNormal = null;
                            int meshIndex = -1;
                            if (selectedMesh.getUserData() instanceof UserData) {
                                final UserData ud = (UserData) selectedMesh.getUserData();
                                meshIndex = ud.getMeshIndex();
                                meshNormal = (Vector3) ud.getNormal();
                                if (!Util.isZero(az)) {
                                    selectedNode.getRotation().applyPost(meshNormal, meshNormal);
                                }
                            }
                            // System.out.println(">>>" + Util.computeFirstNormal(selectedMesh) + ", " + Util.getFirstNormalFromBuffer(selectedMesh));
                            final String meshBoxString = TWO_DECIMALS.format(xMeshBox) + "\u00d7" + (TWO_DECIMALS.format(yMeshBox)) + "\u00d7" + (TWO_DECIMALS.format(zMeshBox)) + lengthUnit;
                            final String meshCenterString = "(" + ONE_DECIMAL.format(meshBoxCenter.getX() * scale) + ", " + ONE_DECIMAL.format(meshBoxCenter.getY() * scale) + ", " + ONE_DECIMAL.format(meshBoxCenter.getZ() * scale) + ")" + lengthUnit;
                            final String meshNormalString = meshNormal != null ? "(" + TWO_DECIMALS.format(meshNormal.getX()) + ", " + TWO_DECIMALS.format(meshNormal.getY()) + ", " + TWO_DECIMALS.format(meshNormal.getZ()) + ")" : "";
                            partPanelBorder.setTitle("Node #" + foundation.getImportedNodes().indexOf(selectedNode) + " (" + Util.getFileName(ns.getSourceURL().getPath()).replace("%20", " ") + "), Mesh #" + meshIndex + ", Base #" + foundation.getId());
                            partProperty1Label.setText("  Node:");
                            partProperty2Label.setText("  Mesh:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(xNodeBox) + "\u00d7" + (TWO_DECIMALS.format(yNodeBox)) + "\u00d7" + (TWO_DECIMALS.format(zNodeBox)) + lengthUnit + ", (" + TWO_DECIMALS.format(position.getX() * scale) + ", " + TWO_DECIMALS.format(position.getY() * scale) + ")" + lengthUnit);
                            partProperty2TextField.setText(meshBoxString + ", " + meshCenterString);
                            partProperty1TextField.putClientProperty("tooltip", "Dimension and location of the bounding box of the selected node<br>File:" + ns.getSourceURL().getFile());
                            partProperty2TextField.putClientProperty("tooltip", "Dimension and location of the bounding box of the selected mesh");
                            if (energyViewShown) {
                                double dailyMeshSolarPotential = 0;
                                final double[] meshSolarPotential = SolarRadiation.getInstance().getSolarPotential(selectedMesh);
                                for (final double x : meshSolarPotential) {
                                    dailyMeshSolarPotential += x;
                                }
                                partProperty3Label.setText("  Solar:");
                                partProperty3TextField.setText("\u2191" + meshNormalString + ", " + TWO_DECIMALS.format(dailyMeshSolarPotential) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "Normal vector and solar potential of the selected mesh");
                            } else {
                                partProperty3Label.setText("  Normal:");
                                partProperty3TextField.setText("\u2191" + meshNormalString + ", " + selectedMesh.getMeshData().getVertexCount() + " vertices");
                                partProperty3TextField.putClientProperty("tooltip", "Normal vector and vertex count of the selected mesh");
                            }
                        } else {
                            partPanelBorder.setTitle("Foundation (" + foundation.getId() + ")");
                            partProperty1Label.setText("  Size:");
                            partProperty1TextField.setText(TWO_DECIMALS.format(lx * scale) + "\u00d7" + (TWO_DECIMALS.format(ly * scale)) + "\u00d7" + (TWO_DECIMALS.format(lz * scale)) + lengthUnit + ", Area\u2248" + ONE_DECIMAL.format(lx * ly * scale * scale) + landArea + lengthUnit + "\u00B2");
                            partProperty1TextField.putClientProperty("tooltip", "The length and width of the foundation");
                            partProperty2Label.setText("  Position:");
                            partProperty2TextField.setText("(" + TWO_DECIMALS.format(cx * scale) + ", " + TWO_DECIMALS.format(cy * scale) + ")" + lengthUnit);
                            partProperty2TextField.putClientProperty("tooltip", "The (x, y) coordinate of the center of the foundation");
                            partProperty3Label.setText("  Azimuth:");
                            partProperty3TextField.setText(TWO_DECIMALS.format(az) + "\u00B0");
                            partProperty3TextField.putClientProperty("tooltip", "The azimuth of the reference edge");
                        }
                    }
                });
            }
        } else if (selectedPart instanceof Roof) {
            final Roof roof = (Roof) selectedPart;
            if (roof.isDrawable()) {
                final double area = roof.getArea();
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Roof (" + roof.getId() + ")");
                        partProperty1Label.setText("  Area & Rise:");
                        partProperty1TextField.setText("Area = " + TWO_DECIMALS.format(area) + lengthUnit + "\u00B2, Rise = " + TWO_DECIMALS.format(roof.getHeight() * scale) + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "The total area and the rise of the roof<br>(The rise is the highest point of the roof to the top of the walls.)");
                        partProperty2Label.setText("  Thermal:");
                        partProperty3Label.setText("  Solar:");
                        final String rval = ONE_DECIMAL.format(Util.toUsRValue(roof.getUValue()));
                        final boolean isBuildingProject = Scene.getInstance().getProjectType() == Foundation.TYPE_BUILDING;
                        final float absorptance = 1 - roof.getAlbedo();
                        if (energyViewShown) {
                            partProperty2TextField.setText("R-value = " + rval + ", Gain = " + TWO_DECIMALS.format(-roof.getTotalHeatLoss()) + " kWh");
                            partProperty2TextField.putClientProperty("tooltip", "The R-value and daily thermal gain of the roof");
                            if (isBuildingProject) {
                                partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance) + ", Absorption = " + TWO_DECIMALS.format(roof.getSolarPotentialToday() * absorptance) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The absorptance and daily solar heat gain of the roof surface");
                            } else {
                                partProperty3TextField.setText("Radiation energy = " + TWO_DECIMALS.format(roof.getSolarPotentialToday()) + " kWh");
                                partProperty3TextField.putClientProperty("tooltip", "The solar radiation energy onto this roof surface");
                            }
                        } else {
                            partProperty2TextField.setText("R-value = " + rval + " (US system)");
                            partProperty2TextField.putClientProperty("tooltip", "The R-value of the roof");
                            partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance));
                            partProperty3TextField.putClientProperty("tooltip", "The absorptance of the roof surface");
                        }
                    }
                });
            }
        } else if (selectedPart instanceof Window) {
            final Window window = (Window) selectedPart;
            if (window.isDrawable()) {
                final double lx = window.getWindowWidth();
                final double ly = window.getWindowHeight();
                final Vector3 v1 = window.getAbsPoint(1);
                final Vector3 v2 = window.getAbsPoint(2);
                final Vector3 v3 = window.getAbsPoint(3);
                final double cx = 0.25 * (v.getX() + v1.getX() + v2.getX() + v3.getX());
                final double cy = 0.25 * (v.getY() + v1.getY() + v2.getY() + v3.getY());
                final double cz = 0.25 * (v.getZ() + v1.getZ() + v2.getZ() + v3.getZ());
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Window (" + window.getId() + ")");
                        partProperty1Label.setText("  Size & Center:");
                        partProperty1TextField.setText(TWO_DECIMALS.format(lx) + "\u00d7" + (TWO_DECIMALS.format(ly)) + lengthUnit + " \u2248 " + TWO_DECIMALS.format(lx * ly) + lengthUnit + "\u00B2, (" + TWO_DECIMALS.format(cx * scale) + ", " + TWO_DECIMALS.format(cy * scale) + ", " + TWO_DECIMALS.format(cz * scale) + ")" + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "The width, height, and center of the window");
                        partProperty2Label.setText("  Thermal:");
                        partProperty3Label.setText("  Solar:");
                        final String shgc = TWO_DECIMALS.format(window.getSolarHeatGainCoefficient());
                        if (energyViewShown) {
                            partProperty2TextField.setText("U-Value = " + TWO_DECIMALS.format(Util.toUsUValue(window.getUValue())) + ", Gain = " + TWO_DECIMALS.format(-window.getTotalHeatLoss()) + " kWh");
                            partProperty2TextField.putClientProperty("tooltip", "The U-value and daily thermal gain of the window");
                            partProperty3TextField.setText("SHGC = " + shgc + ", Gain = " + TWO_DECIMALS.format(window.getSolarPotentialToday() * window.getSolarHeatGainCoefficient()) + " kWh");
                            partProperty3TextField.putClientProperty("tooltip", "The SHGC value and daily solar gain of the window");
                        } else {
                            partProperty2TextField.setText("U-Value = " + TWO_DECIMALS.format(Util.toUsUValue(window.getUValue())) + " (US system)");
                            partProperty2TextField.putClientProperty("tooltip", "The U-value of the window");
                            partProperty3TextField.setText("SHGC = " + shgc);
                            partProperty3TextField.putClientProperty("tooltip", "The solar heat gain coefficient (SHGC) of the window");
                        }
                    }
                });
            }
        } else if (selectedPart instanceof Wall) {
            final Wall wall = (Wall) selectedPart;
            if (wall.isDrawable()) {
                final Vector3 v1 = wall.getAbsPoint(1);
                final Vector3 v2 = wall.getAbsPoint(2);
                final Vector3 v3 = wall.getAbsPoint(3);
                final double cx = 0.25 * (v.getX() + v1.getX() + v2.getX() + v3.getX());
                final double cy = 0.25 * (v.getY() + v1.getY() + v2.getY() + v3.getY());
                final double cz = 0.25 * (v.getZ() + v1.getZ() + v2.getZ() + v3.getZ());
                final double lx = v.distance(v2);
                final double ly = v.distance(v1);
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Wall (" + wall.getId() + ")");
                        partProperty1Label.setText("  Size & Center:");
                        partProperty1TextField.setText(TWO_DECIMALS.format(lx * scale) + "\u00d7" + (TWO_DECIMALS.format(ly * scale)) + lengthUnit + " \u2248 " + TWO_DECIMALS.format(lx * ly * scale * scale) + lengthUnit + " \u00B2, " + "(" + TWO_DECIMALS.format(cx * scale) + ", " + TWO_DECIMALS.format(cy * scale) + ", " + TWO_DECIMALS.format(cz * scale) + ")" + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "The width, height, and center of the wall");
                        partProperty2Label.setText("  Thermal:");
                        partProperty3Label.setText("  Solar:");
                        final String rval = ONE_DECIMAL.format(Util.toUsRValue(wall.getUValue()));
                        final float absorptance = 1 - wall.getAlbedo();
                        if (energyViewShown) {
                            partProperty2TextField.setText("R-Value = " + rval + ", Gain = " + TWO_DECIMALS.format(-wall.getTotalHeatLoss()) + " kWh");
                            partProperty2TextField.putClientProperty("tooltip", "The R-value and daily thermal gain of the wall");
                            partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance) + ", Absorption = " + TWO_DECIMALS.format(wall.getSolarPotentialToday() * absorptance) + " kWh");
                            partProperty3TextField.putClientProperty("tooltip", "The absorptance and daily solar heat gain of the wall surface");
                        } else {
                            partProperty2TextField.setText("R-Value = " + rval + " (US system)");
                            partProperty2TextField.putClientProperty("tooltip", "The R-value of the wall");
                            partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance));
                            partProperty3TextField.putClientProperty("tooltip", "The absorptance of the wall surface");
                        }
                    }
                });
            }
        } else if (selectedPart instanceof Door) {
            final Door door = (Door) selectedPart;
            if (door.isDrawable()) {
                final Vector3 v1 = door.getAbsPoint(1);
                final Vector3 v2 = door.getAbsPoint(2);
                final Vector3 v3 = door.getAbsPoint(3);
                final double cx = 0.25 * (v.getX() + v1.getX() + v2.getX() + v3.getX());
                final double cy = 0.25 * (v.getY() + v1.getY() + v2.getY() + v3.getY());
                final double cz = 0.25 * (v.getZ() + v1.getZ() + v2.getZ() + v3.getZ());
                final double lx = v.distance(v2);
                final double ly = v.distance(v1);
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Door (" + door.getId() + ")");
                        partProperty1Label.setText("  Size & Center:");
                        partProperty1TextField.setText(TWO_DECIMALS.format(lx * scale) + "\u00d7" + (TWO_DECIMALS.format(ly * scale)) + lengthUnit + " \u2248 " + TWO_DECIMALS.format(lx * ly * scale * scale) + lengthUnit + "\u00B2, (" + TWO_DECIMALS.format(cx * scale) + ", " + TWO_DECIMALS.format(cy * scale) + ", " + TWO_DECIMALS.format(cz * scale) + ")" + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "The width, height, and center of the door");
                        partProperty2Label.setText("  Thermal:");
                        partProperty3Label.setText("  Solar:");
                        final String uval = TWO_DECIMALS.format(Util.toUsUValue(door.getUValue()));
                        final float absorptance = 1 - door.getAlbedo();
                        if (energyViewShown) {
                            partProperty2TextField.setText("U-Value = " + uval + ", Gain = " + TWO_DECIMALS.format(-door.getTotalHeatLoss()) + " kWh");
                            partProperty2TextField.putClientProperty("tooltip", "The R-value and daily thermal gain of the door");
                            partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance) + ", Absorption = " + TWO_DECIMALS.format(door.getSolarPotentialToday() * absorptance) + " kWh");
                            partProperty3TextField.putClientProperty("tooltip", "The absorptance and daily solar heat gain of the door surface");
                        } else {
                            partProperty2TextField.setText("U-Value = " + uval + " (US system)");
                            partProperty2TextField.putClientProperty("tooltip", "The U-value of the door");
                            partProperty3TextField.setText("Absorptance = " + TWO_DECIMALS.format(absorptance));
                            partProperty3TextField.putClientProperty("tooltip", "The absorptance of the door surface");
                        }
                    }
                });
            }
        } else if (selectedPart instanceof Floor) {
            final Floor floor = (Floor) selectedPart;
            if (floor.isDrawable()) {
                final double cx, cy;
                final double cz = v.getZ();
                if (floor.getPoints().size() > 1) {
                    final Vector3 v1 = floor.getAbsPoint(1);
                    final Vector3 v2 = floor.getAbsPoint(2);
                    final Vector3 v3 = floor.getAbsPoint(3);
                    cx = 0.25 * (v.getX() + v1.getX() + v2.getX() + v3.getX());
                    cy = 0.25 * (v.getY() + v1.getY() + v2.getY() + v3.getY());
                } else {
                    cx = v.getX();
                    cy = v.getY();
                }
                EventQueue.invokeLater(new Runnable() {

                    @Override
                    public void run() {
                        partPanelBorder.setTitle("Floor (" + floor.getId() + ")");
                        partProperty1Label.setText("  Area & Center");
                        partProperty1TextField.setText(ONE_DECIMAL.format(floor.getArea()) + lengthUnit + "\u00B2, (" + ONE_DECIMAL.format(cx * scale) + ", " + ONE_DECIMAL.format(cy * scale) + ", " + ONE_DECIMAL.format(cz * scale) + ")" + lengthUnit);
                        partProperty1TextField.putClientProperty("tooltip", "The area and center of the floor");
                        partProperty2Label.setText("  Thermal:");
                        partProperty2TextField.setText("N.A.");
                        partProperty2TextField.putClientProperty("tooltip", "Not applicable to thermal analysis");
                        partProperty3Label.setText("  Solar:");
                        partProperty3TextField.setText("N.A.");
                        partProperty3TextField.putClientProperty("tooltip", "Not applicable to solar analysis");
                    }
                });
            }
        }
    } else {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                final int numberOfSolarPanels = Scene.getInstance().countSolarPanels();
                if (numberOfSolarPanels > 0) {
                    partPanelBorder.setTitle("Solar Panels");
                    partProperty1Label.setText("  Total Number:");
                    partProperty1TextField.setText("" + numberOfSolarPanels);
                    partProperty1TextField.putClientProperty("tooltip", "Total number of solar panels");
                    partProperty2Label.setText("  Total Cost:");
                    partProperty2TextField.setText("$" + TWO_DECIMALS.format(PvProjectCost.getInstance().getTotalCost()));
                    partProperty2TextField.putClientProperty("tooltip", "Total cost of solar panels");
                    partProperty3Label.setText("  -");
                    partProperty3TextField.setText("");
                    partProperty3TextField.putClientProperty("tooltip", null);
                } else {
                    final int numberOfHeliostats = Scene.getInstance().countParts(Mirror.class);
                    if (numberOfHeliostats > 0) {
                        partPanelBorder.setTitle("Heliostats");
                        partProperty1Label.setText("  Total Number:");
                        partProperty1TextField.setText("" + numberOfHeliostats);
                        partProperty1TextField.putClientProperty("tooltip", "Total number of heliostats");
                        partProperty2Label.setText("  Total Cost:");
                        partProperty2TextField.setText("$" + TWO_DECIMALS.format(CspProjectCost.getInstance().getTotalCost()));
                        partProperty2TextField.putClientProperty("tooltip", "Total cost of heliostats");
                        partProperty3Label.setText("  -");
                        partProperty3TextField.setText("");
                        partProperty3TextField.putClientProperty("tooltip", null);
                    } else {
                        final int numberOfParabolicTroughs = Scene.getInstance().countParts(ParabolicTrough.class);
                        if (numberOfParabolicTroughs > 0) {
                            partPanelBorder.setTitle("Parabolic Troughs");
                            partProperty1Label.setText("  Total Number:");
                            partProperty1TextField.setText("" + numberOfParabolicTroughs);
                            partProperty1TextField.putClientProperty("tooltip", "Total number of parabolic troughs");
                            partProperty2Label.setText("  Total Cost:");
                            partProperty2TextField.setText("$" + TWO_DECIMALS.format(CspProjectCost.getInstance().getTotalCost()));
                            partProperty2TextField.putClientProperty("tooltip", "Total cost of parabolic troughs");
                            partProperty3Label.setText("  -");
                            partProperty3TextField.setText("");
                            partProperty3TextField.putClientProperty("tooltip", null);
                        } else {
                            final int numberOfParabolicDishes = Scene.getInstance().countParts(ParabolicDish.class);
                            if (numberOfParabolicDishes > 0) {
                                partPanelBorder.setTitle("Parabolic Dishes");
                                partProperty1Label.setText("  Total Number:");
                                partProperty1TextField.setText("" + numberOfParabolicDishes);
                                partProperty1TextField.putClientProperty("tooltip", "Total number of parabolic dishes");
                                partProperty2Label.setText("  Total Cost:");
                                partProperty2TextField.setText("$" + TWO_DECIMALS.format(CspProjectCost.getInstance().getTotalCost()));
                                partProperty2TextField.putClientProperty("tooltip", "Total cost of parabolic dishes");
                                partProperty3Label.setText("  -");
                                partProperty3TextField.setText("");
                                partProperty3TextField.putClientProperty("tooltip", null);
                            } else {
                                final int numberOfFresnelReflectors = Scene.getInstance().countParts(FresnelReflector.class);
                                if (numberOfFresnelReflectors > 0) {
                                    partPanelBorder.setTitle("Fresnel Reflectors");
                                    partProperty1Label.setText("  Total Number:");
                                    partProperty1TextField.setText("" + numberOfFresnelReflectors);
                                    partProperty1TextField.putClientProperty("tooltip", "Total number of Fresnel reflectors");
                                    partProperty2Label.setText("  Total Cost:");
                                    partProperty2TextField.setText("$" + TWO_DECIMALS.format(CspProjectCost.getInstance().getTotalCost()));
                                    partProperty2TextField.putClientProperty("tooltip", "Total cost of Fresnel reflectors");
                                    partProperty3Label.setText("  -");
                                    partProperty3TextField.setText("");
                                    partProperty3TextField.putClientProperty("tooltip", null);
                                } else {
                                    final int numberOfNodes = Scene.getInstance().countNodes();
                                    if (numberOfNodes > 0) {
                                        partPanelBorder.setTitle("Structures");
                                        partProperty1Label.setText("  Total Nodes:");
                                        partProperty1TextField.setText("" + numberOfNodes);
                                        partProperty1TextField.putClientProperty("tooltip", "Total number of structure nodes");
                                        partProperty2Label.setText("  Total Meshes:");
                                        partProperty2TextField.setText("" + Scene.getInstance().countMeshes());
                                        partProperty2TextField.putClientProperty("tooltip", "Total number of structure meshes");
                                        partProperty3Label.setText("  -");
                                        partProperty3TextField.setText("");
                                        partProperty3TextField.putClientProperty("tooltip", null);
                                    } else {
                                        partPanelBorder.setTitle(" -");
                                        partProperty1Label.setText("  -");
                                        partProperty1TextField.setText("");
                                        partProperty1TextField.putClientProperty("tooltip", null);
                                        partProperty2Label.setText("  -");
                                        partProperty2TextField.setText("");
                                        partProperty2TextField.putClientProperty("tooltip", null);
                                        partProperty3Label.setText("  -");
                                        partProperty3TextField.setText("");
                                        partProperty3TextField.putClientProperty("tooltip", null);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        });
    }
    partPanel.repaint();
    // update building properties
    final Foundation selectedFoundation;
    if (selectedPart == null) {
        selectedFoundation = null;
    } else if (selectedPart instanceof Foundation) {
        selectedFoundation = (Foundation) selectedPart;
    } else {
        selectedFoundation = selectedPart.getTopContainer();
    }
    EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            if (selectedFoundation != null) {
                switch(selectedFoundation.getProjectType()) {
                    case Foundation.TYPE_BUILDING:
                        dataPanel.remove(instructionPanel);
                        dataPanel.remove(pvProjectPanel);
                        dataPanel.remove(cspProjectPanel);
                        dataPanel.add(buildingPanel, 2);
                        final Calendar c = Heliodon.getInstance().getCalendar();
                        final int temp = selectedFoundation.getThermostat().getTemperature(c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY, c.get(Calendar.HOUR_OF_DAY));
                        switch(Scene.getInstance().getUnit()) {
                            case InternationalSystemOfUnits:
                                thermostatTemperatureField.setText(temp + " \u00B0C");
                                break;
                            case USCustomaryUnits:
                                thermostatTemperatureField.setText(Math.round(32.0 + 9.0 * temp / 5.0) + " \u00B0F");
                                break;
                        }
                        thermostatPanel.add(adjustThermostatButton, BorderLayout.EAST);
                        String s2 = selectedFoundation.toString();
                        s2 = s2.substring(0, s2.indexOf(')') + 1);
                        final int i1 = s2.indexOf('(');
                        final int i2 = s2.indexOf(')');
                        ((TitledBorder) buildingPanel.getBorder()).setTitle("Building #" + s2.substring(i1 + 1, i2));
                        buildingInfoPanel.update(selectedFoundation);
                        break;
                    case Foundation.TYPE_PV_PROJECT:
                        dataPanel.remove(instructionPanel);
                        dataPanel.remove(buildingPanel);
                        dataPanel.remove(cspProjectPanel);
                        dataPanel.add(pvProjectPanel, 2);
                        pvProjectInfoPanel.update(selectedFoundation);
                        break;
                    case Foundation.TYPE_CSP_PROJECT:
                        dataPanel.remove(instructionPanel);
                        dataPanel.remove(buildingPanel);
                        dataPanel.remove(pvProjectPanel);
                        dataPanel.add(cspProjectPanel, 2);
                        cspProjectInfoPanel.update(selectedFoundation);
                        break;
                    case -1:
                        dataPanel.remove(instructionPanel);
                        dataPanel.remove(buildingPanel);
                        dataPanel.remove(pvProjectPanel);
                        dataPanel.remove(cspProjectPanel);
                        break;
                }
            } else {
                dataPanel.remove(buildingPanel);
                dataPanel.remove(pvProjectPanel);
                dataPanel.remove(cspProjectPanel);
                dataPanel.add(instructionPanel, 2);
                for (int i = 0; i < instructionSheets.length; i++) {
                    final String contentType = Scene.getInstance().getInstructionSheetTextType(i);
                    instructionSheets[i].setContentType(contentType == null ? "text/plain" : contentType);
                    if (!instructionSheets[i].getText().equals(Scene.getInstance().getInstructionSheetText(i))) {
                        instructionSheets[i].setText(Scene.getInstance().getInstructionSheetText(i));
                    }
                }
            }
            dataPanel.validate();
            dataPanel.repaint();
        }
    });
}
Also used : ParabolicTrough(org.concord.energy3d.model.ParabolicTrough) NodeState(org.concord.energy3d.model.NodeState) Wall(org.concord.energy3d.model.Wall) UserData(org.concord.energy3d.model.UserData) Node(com.ardor3d.scenegraph.Node) TitledBorder(javax.swing.border.TitledBorder) Rack(org.concord.energy3d.model.Rack) Roof(org.concord.energy3d.model.Roof) Tree(org.concord.energy3d.model.Tree) Foundation(org.concord.energy3d.model.Foundation) List(java.util.List) HousePart(org.concord.energy3d.model.HousePart) FoundationPolygon(org.concord.energy3d.model.FoundationPolygon) Human(org.concord.energy3d.model.Human) Window(org.concord.energy3d.model.Window) Floor(org.concord.energy3d.model.Floor) FresnelReflector(org.concord.energy3d.model.FresnelReflector) GregorianCalendar(java.util.GregorianCalendar) Calendar(java.util.Calendar) Mesh(com.ardor3d.scenegraph.Mesh) ReadOnlyVector3(com.ardor3d.math.type.ReadOnlyVector3) Vector3(com.ardor3d.math.Vector3) Door(org.concord.energy3d.model.Door) ParabolicDish(org.concord.energy3d.model.ParabolicDish) ReadOnlyVector3(com.ardor3d.math.type.ReadOnlyVector3) OrientedBoundingBox(com.ardor3d.bounding.OrientedBoundingBox) SolarPanel(org.concord.energy3d.model.SolarPanel) Mirror(org.concord.energy3d.model.Mirror) Sensor(org.concord.energy3d.model.Sensor)

Example 15 with Floor

use of org.concord.energy3d.model.Floor in project energy3d by concord-consortium.

the class BuildingCostGraph method calculateCost.

private void calculateCost() {
    int countBuildings = 0;
    for (final HousePart p : Scene.getInstance().getParts()) {
        if (p instanceof Foundation) {
            countBuildings++;
        }
    }
    wallSum = 0;
    floorSum = 0;
    windowSum = 0;
    roofSum = 0;
    doorSum = 0;
    solarPanelSum = 0;
    treeSum = 0;
    foundationSum = BuildingCost.getPartCost(foundation);
    for (final HousePart p : Scene.getInstance().getParts()) {
        if (p.getTopContainer() == foundation) {
            if (p instanceof Wall) {
                wallSum += BuildingCost.getPartCost(p);
            } else if (p instanceof Floor) {
                floorSum += BuildingCost.getPartCost(p);
            } else if (p instanceof Window) {
                windowSum += BuildingCost.getPartCost(p);
            } else if (p instanceof Roof) {
                roofSum += BuildingCost.getPartCost(p);
            } else if (p instanceof Door) {
                doorSum += BuildingCost.getPartCost(p);
            } else if (p instanceof SolarPanel) {
                solarPanelSum += BuildingCost.getPartCost(p);
            } else if (p instanceof Rack) {
                solarPanelSum += BuildingCost.getPartCost(p);
            }
        }
        if (countBuildings <= 1) {
            if (p instanceof Tree && !p.getLockEdit()) {
                treeSum += BuildingCost.getPartCost(p);
            }
        }
    }
    totalCost = wallSum + windowSum + roofSum + doorSum + solarPanelSum + treeSum + foundationSum + floorSum;
}
Also used : Window(org.concord.energy3d.model.Window) Floor(org.concord.energy3d.model.Floor) Rack(org.concord.energy3d.model.Rack) Roof(org.concord.energy3d.model.Roof) Wall(org.concord.energy3d.model.Wall) SolarPanel(org.concord.energy3d.model.SolarPanel) Tree(org.concord.energy3d.model.Tree) Foundation(org.concord.energy3d.model.Foundation) HousePart(org.concord.energy3d.model.HousePart) Door(org.concord.energy3d.model.Door)

Aggregations

Floor (org.concord.energy3d.model.Floor)16 HousePart (org.concord.energy3d.model.HousePart)15 Foundation (org.concord.energy3d.model.Foundation)12 Door (org.concord.energy3d.model.Door)11 Roof (org.concord.energy3d.model.Roof)11 Wall (org.concord.energy3d.model.Wall)11 Window (org.concord.energy3d.model.Window)10 Rack (org.concord.energy3d.model.Rack)9 SolarPanel (org.concord.energy3d.model.SolarPanel)8 Tree (org.concord.energy3d.model.Tree)7 ArrayList (java.util.ArrayList)6 List (java.util.List)5 Mesh (com.ardor3d.scenegraph.Mesh)4 Node (com.ardor3d.scenegraph.Node)4 Spatial (com.ardor3d.scenegraph.Spatial)4 Human (org.concord.energy3d.model.Human)4 Sensor (org.concord.energy3d.model.Sensor)4 SolarCollector (org.concord.energy3d.model.SolarCollector)4 ReadOnlyVector3 (com.ardor3d.math.type.ReadOnlyVector3)3 CullHint (com.ardor3d.scenegraph.hint.CullHint)3