/*
* ObserverCameraController.java 09 mars 2012
*
* Sweet Home 3D, Copyright (c) 2012 Emmanuel PUYBARET / eTeks <info@eteks.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.eteks.sweethome3d.viewcontroller;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.List;
import com.eteks.sweethome3d.model.Home;
import com.eteks.sweethome3d.model.HomeEnvironment;
import com.eteks.sweethome3d.model.Level;
import com.eteks.sweethome3d.model.ObserverCamera;
import com.eteks.sweethome3d.model.UserPreferences;
/**
* A MVC controller for observer camera attributes view.
* @author Emmanuel Puybaret
*/
public class ObserverCameraController implements Controller {
/**
* The properties that may be edited by the view associated to this controller.
*/
public enum Property {X, Y, ELEVATION, MINIMUM_ELEVATION,
YAW_IN_DEGREES, PITCH_IN_DEGREES, FIELD_OF_VIEW_IN_DEGREES,
OBSERVER_CAMERA_ELEVATION_ADJUSTED}
private final Home home;
private final UserPreferences preferences;
private final ViewFactory viewFactory;
private final PropertyChangeSupport propertyChangeSupport;
private DialogView observerCameraView;
private float x;
private float y;
private float elevation;
private float minimumElevation;
private int yawInDegrees;
private int pitchInDegrees;
private int fieldOfViewInDegrees;
private boolean elevationAdjusted;
/**
* Creates the controller of 3D view with undo support.
*/
public ObserverCameraController(Home home,
UserPreferences preferences,
ViewFactory viewFactory) {
this.home = home;
this.preferences = preferences;
this.viewFactory = viewFactory;
this.propertyChangeSupport = new PropertyChangeSupport(this);
updateProperties();
}
/**
* Returns the view associated with this controller.
*/
public DialogView getView() {
// Create view lazily only once it's needed
if (this.observerCameraView == null) {
this.observerCameraView = this.viewFactory.createObserverCameraView(this.preferences, this);
}
return this.observerCameraView;
}
/**
* Displays the view controlled by this controller.
*/
public void displayView(View parentView) {
getView().displayView(parentView);
}
/**
* Adds the property change <code>listener</code> in parameter to this controller.
*/
public void addPropertyChangeListener(Property property, PropertyChangeListener listener) {
this.propertyChangeSupport.addPropertyChangeListener(property.name(), listener);
}
/**
* Removes the property change <code>listener</code> in parameter from this controller.
*/
public void removePropertyChangeListener(Property property, PropertyChangeListener listener) {
this.propertyChangeSupport.removePropertyChangeListener(property.name(), listener);
}
/**
* Updates edited properties from the 3D attributes of the home edited by this controller.
*/
protected void updateProperties() {
ObserverCamera observerCamera = this.home.getObserverCamera();
setX(observerCamera.getX());
setY(observerCamera.getY());
List<Level> levels = this.home.getLevels();
setMinimumElevation(levels.size() == 0
? 10
: 10 + levels.get(0).getElevation());
setElevation(observerCamera.getZ());
setYawInDegrees((int)(Math.round(Math.toDegrees(observerCamera.getYaw()))));
setPitchInDegrees((int)(Math.round(Math.toDegrees(
observerCamera.getPitch())) + 360) % 360);
setFieldOfViewInDegrees((int)(Math.round(Math.toDegrees(
observerCamera.getFieldOfView())) + 360) % 360);
HomeEnvironment homeEnvironment = this.home.getEnvironment();
setElevationAdjusted(homeEnvironment.isObserverCameraElevationAdjusted());
}
/**
* Sets the edited abscissa.
*/
public void setX(float x) {
if (x != this.x) {
float oldX = this.x;
this.x = x;
this.propertyChangeSupport.firePropertyChange(Property.X.name(), oldX, x);
}
}
/**
* Returns the edited abscissa.
*/
public float getX() {
return this.x;
}
/**
* Sets the edited ordinate.
*/
public void setY(float y) {
if (y != this.y) {
float oldY = this.y;
this.y = y;
this.propertyChangeSupport.firePropertyChange(Property.Y.name(), oldY, y);
}
}
/**
* Returns the edited ordinate.
*/
public float getY() {
return this.y;
}
/**
* Sets the edited camera elevation.
*/
public void setElevation(float elevation) {
if (elevation != this.elevation) {
float oldObserverCameraElevation = this.elevation;
this.elevation = elevation;
this.propertyChangeSupport.firePropertyChange(Property.ELEVATION.name(), oldObserverCameraElevation, elevation);
}
}
/**
* Returns the edited camera elevation.
*/
public float getElevation() {
return this.elevation;
}
/**
* Sets the minimum elevation.
*/
private void setMinimumElevation(float minimumElevation) {
if (minimumElevation != this.minimumElevation) {
float oldMinimumElevation = this.minimumElevation;
this.minimumElevation = minimumElevation;
this.propertyChangeSupport.firePropertyChange(Property.MINIMUM_ELEVATION.name(), oldMinimumElevation, minimumElevation);
}
}
/**
* Returns the minimum elevation.
*/
public float getMinimumElevation() {
return this.minimumElevation;
}
/**
* Returns <code>true</code> if the observer elevation should be adjusted according
* to the elevation of the selected level.
*/
public boolean isElevationAdjusted() {
return this.elevationAdjusted;
}
/**
* Sets whether the observer elevation should be adjusted according
* to the elevation of the selected level.
*/
public void setElevationAdjusted(boolean observerCameraElevationAdjusted) {
if (this.elevationAdjusted != observerCameraElevationAdjusted) {
this.elevationAdjusted = observerCameraElevationAdjusted;
this.propertyChangeSupport.firePropertyChange(Property.OBSERVER_CAMERA_ELEVATION_ADJUSTED.name(),
!observerCameraElevationAdjusted, observerCameraElevationAdjusted);
Level selectedLevel = this.home.getSelectedLevel();
if (selectedLevel != null) {
if (observerCameraElevationAdjusted) {
setElevation(getElevation() - selectedLevel.getElevation());
} else {
setElevation(getElevation() + selectedLevel.getElevation());
}
}
}
}
/**
* Returns <code>true</code> if the adjustment of the observer camera according to the current level is modifiable.
*/
public boolean isObserverCameraElevationAdjustedEditable() {
return this.home.getLevels().size() > 1;
}
/**
* Sets the edited yaw in degrees.
*/
public void setYawInDegrees(int yawInDegrees) {
if (yawInDegrees != this.yawInDegrees) {
int oldYawInDegrees = this.yawInDegrees;
this.yawInDegrees = yawInDegrees;
this.propertyChangeSupport.firePropertyChange(Property.YAW_IN_DEGREES.name(), oldYawInDegrees, yawInDegrees);
}
}
/**
* Returns the edited yaw in degrees.
*/
public int getYawInDegrees() {
return this.yawInDegrees;
}
/**
* Sets the edited pitch in degrees.
*/
public void setPitchInDegrees(int pitchInDegrees) {
if (pitchInDegrees != this.pitchInDegrees) {
int oldPitchInDegrees = this.pitchInDegrees;
this.pitchInDegrees = pitchInDegrees;
this.propertyChangeSupport.firePropertyChange(Property.PITCH_IN_DEGREES.name(), oldPitchInDegrees, pitchInDegrees);
}
}
/**
* Returns the edited pitch in degrees.
*/
public int getPitchInDegrees() {
return this.pitchInDegrees;
}
/**
* Sets the edited observer field of view in degrees.
*/
public void setFieldOfViewInDegrees(int observerFieldOfViewInDegrees) {
if (observerFieldOfViewInDegrees != this.fieldOfViewInDegrees) {
int oldObserverFieldOfViewInDegrees = this.fieldOfViewInDegrees;
this.fieldOfViewInDegrees = observerFieldOfViewInDegrees;
this.propertyChangeSupport.firePropertyChange(Property.FIELD_OF_VIEW_IN_DEGREES.name(),
oldObserverFieldOfViewInDegrees, observerFieldOfViewInDegrees);
}
}
/**
* Returns the edited observer field of view in degrees.
*/
public int getFieldOfViewInDegrees() {
return this.fieldOfViewInDegrees;
}
/**
* Controls the modification of the observer camera of the edited home.
*/
public void modifyObserverCamera() {
float x = getX();
float y = getY();
float z = getElevation();
boolean observerCameraElevationAdjusted = isElevationAdjusted();
Level selectedLevel = this.home.getSelectedLevel();
if (observerCameraElevationAdjusted && selectedLevel != null) {
z += selectedLevel.getElevation();
List<Level> levels = this.home.getLevels();
z = Math.max(z, levels.size() == 0 ? 10 : 10 + levels.get(0).getElevation());
}
float yaw = (float)Math.toRadians(getYawInDegrees());
float pitch = (float)Math.toRadians(getPitchInDegrees());
float fieldOfView = (float)Math.toRadians(getFieldOfViewInDegrees());
// Apply modification with no undo
ObserverCamera observerCamera = this.home.getObserverCamera();
observerCamera.setX(x);
observerCamera.setY(y);
observerCamera.setZ(z);
observerCamera.setYaw(yaw);
observerCamera.setPitch(pitch);
observerCamera.setFieldOfView(fieldOfView);
HomeEnvironment homeEnvironment = this.home.getEnvironment();
homeEnvironment.setObserverCameraElevationAdjusted(observerCameraElevationAdjusted);
}
}