View Javadoc

1   package nl.tudelft.goal.ut2004.visualizer.timeline.map;
2   
3   import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
4   import cz.cuni.amis.pogamut.unreal.communication.worldview.map.Box;
5   import java.util.HashSet;
6   import java.util.Set;
7   import javax.vecmath.Matrix4d;
8   import javax.vecmath.Vector3d;
9   
10  /**
11   * Representation of where is observer in map and where does he look, what is
12   * its POV angle ect.
13   * 
14   * @author Honza
15   */
16  public class MapViewpoint {
17  
18  	private Location center;
19  	private Location eye;
20  	private Vector3d up;
21  
22  	public MapViewpoint() {
23  		this(0, 0, 0);
24  
25  	}
26  
27  	public MapViewpoint(double x, double y, double z) {
28  		center = new Location(x, y, z);
29  		eye = Location.ZERO;
30  		up = new Vector3d(1, 0, 0);
31  	}
32  
33  	public void moveEye(Location delta) {
34  		eye = eye.add(delta);
35  		emitChangedViewport();
36  	}
37  
38  	public Location getLocation() {
39  		return center;
40  	}
41  
42  	public Location getEye() {
43  		return eye;
44  	}
45  
46  	public Vector3d getUp() {
47  		return new Vector3d(up);
48  	}
49  
50  	public Location getEye2Center() {
51  		return Location.sub(center, eye);
52  	}
53  
54  	/**
55  	 * Get distance from eye point to center point.
56  	 * 
57  	 * @return distance from eye to center.
58  	 */
59  	public double getCenter2EyeDistance() {
60  		return Location.getDistance(eye, center);
61  	}
62  
63  	public Location getRightVector() {
64  		Location moveUpVec = new Location(up.x, up.y, up.z);
65  		Location center2eye = Location.sub(getEye(), getLocation());
66  		Location moveRightVec = center2eye.cross(moveUpVec).getNormalized();
67  
68  		return moveRightVec;
69  	}
70  
71  	public void setLocation(Location location) {
72  		this.center = location;
73  
74  		emitChangedViewport();
75  	}
76  
77  	public void setFromViewedBox(Box box) {
78  		center = new Location(box.getCenterX(), box.getCenterY(), box.getCenterZ());
79  
80  		double max = Math.max(box.getDeltaX(), box.getDeltaY());
81  
82  		eye = new Location(box.getCenterX(), box.getCenterY(), box.getCenterZ() - max);
83  
84  		this.up.x = 0;
85  		this.up.y = 1;
86  		this.up.z = 0;
87  	}
88  
89  	/**
90  	 * Rotate eye and up vectors around axis with origin in center by angle
91  	 * angle.
92  	 * 
93  	 * @param axis
94  	 *            angle how much rotate, in degress, by right hand, thumb
95  	 *            direction of axis, plam in direction of angle
96  	 * @param angle
97  	 */
98  	public void rotateEye(Location axis, double angle) {
99  		// get vector from center to eye
100 		Location eyeVector = Location.sub(eye, center);
101 
102 		Location newEyeVector = rotateVectorAroundAxis(eyeVector, axis, angle);
103 		Location newUpVector = rotateVectorAroundAxis(new Location(up.x, up.y, up.z), axis, angle);
104 
105 		eye = Location.add(center, newEyeVector);
106 		up = new Vector3d(newUpVector.x, newUpVector.y, newUpVector.z);
107 
108 		emitChangedViewport();
109 	}
110 
111 	public void rotateCenter(Location axis, double angle) {
112 		// /System.out.println("RotateCenter " + angle);
113 		Location eyeVector = Location.sub(center, eye);
114 
115 		Location newEye2Center = rotateVectorAroundAxis(eyeVector, axis, angle);
116 		Location newUpVector = rotateVectorAroundAxis(new Location(up.x, up.y, up.z), axis, angle);
117 
118 		center = Location.add(eye, newEye2Center);
119 		up = new Vector3d(newUpVector.x, newUpVector.y, newUpVector.z);
120 
121 		// System.out.println("RotateCenter axis: " + axis + " angle " +angle +
122 		// " " + getRightVector());
123 		// System.out.println("RotateCenter center: " + center + " up " + up);
124 		emitChangedViewport();
125 
126 	}
127 
128 	/**
129 	 * Rotate by angle around vector axis. Thumb of right hand in same direction
130 	 * as axis vector and closing palm shows direction of rotation.
131 	 * 
132 	 * @param vector
133 	 * @param axis
134 	 * @param angle
135 	 *            angle in degrees
136 	 */
137 	public static Location rotateVectorAroundAxis(Location vector, Location axis, double angle) {
138 		// move eye stuff back
139 		double x = axis.x;
140 		double y = axis.y;
141 		double z = axis.z;
142 
143 		double radianAngle = angle * Math.PI / 180;
144 		double c = Math.cos(radianAngle);
145 		double s = Math.sin(radianAngle);
146 
147 		/*
148 		 * ( xx(1-c)+c xy(1-c)-zs xz(1-c)+ys 0 ) | yx(1-c)+zs yy(1-c)+c
149 		 * yz(1-c)-xs 0 | | xz(1-c)-ys yz(1-c)+xs zz(1-c)+c 0 | ( 0 0 0 1 )
150 		 */
151 
152 		Matrix4d rotateMatrix = new Matrix4d(x * x * (1 - c) + c, x * y * (1 - c) - z * s, x * z * (1 - c) + y * s, 0,
153 				y * x * (1 - c) + z * s, y * y * (1 - c) + c, y * z * (1 - c) - x * s, 0, x * z * (1 - c) - y * s, y
154 						* z * (1 - c) + x * s, z * z * (1 - c) + c, 0, 0, 0, 0, 1);
155 
156 		Vector3d vec = new Vector3d(vector.x, vector.y, vector.z);
157 
158 		rotateMatrix.transform(vec);
159 
160 		return new Location(vec.x, vec.y, vec.z);
161 	}
162 
163 	private Set<ViewpointListener> listeners = new HashSet<ViewpointListener>();
164 
165 	// perpendicular to x axis
166 	public void setFrontView(Box box) {
167 		center = new Location(box.getCenterX(), box.getCenterY(), box.getCenterZ());
168 
169 		double maxDelta = Math.max(box.getDeltaX(), box.getDeltaZ());
170 
171 		double halfAngleRad = Math.PI * ((getViewAngle() / 2) / 180);
172 		double distance = (maxDelta / 2) / (Math.tan(halfAngleRad));
173 
174 		eye = new Location(box.getCenterX(), (box.getCenterY() - (box.getDeltaY() / 2)) - distance, box.getCenterZ());
175 
176 		this.up.x = 0;
177 		this.up.y = 0;
178 		this.up.z = 1;
179 
180 		emitChangedViewport();
181 	}
182 
183 	public void setSideView(Box box) {
184 		center = new Location(box.getCenterX(), box.getCenterY(), box.getCenterZ());
185 
186 		double maxDelta = Math.max(box.getDeltaZ(), box.getDeltaY());
187 
188 		double halfAngleRad = Math.PI * ((getViewAngle() / 2) / 180);
189 		double distance = (maxDelta / 2) / (Math.tan(halfAngleRad));
190 
191 		eye = new Location(box.getCenterX() + box.getDeltaX() / 2 + distance, box.getCenterY(), box.getCenterZ());
192 
193 		this.up.x = 0;
194 		this.up.y = 0;
195 		this.up.z = 1;
196 
197 		emitChangedViewport();
198 	}
199 
200 	public void setTopView(Box box) {
201 		center = new Location(box.getCenterX(),box.getCenterY(),box.getCenterZ());
202 
203 		double maxDelta = Math.max(box.getDeltaX(), box.getDeltaY());
204 
205 		double halfAngleRad = Math.PI * ((getViewAngle() / 2) / 180);
206 		double distance = (maxDelta / 2) / (Math.tan(halfAngleRad));
207 
208 		eye = new Location(box.getCenterX(), box.getCenterY(), box.getCenterZ() + box.getDeltaZ() / 2 + distance);
209 
210 		this.up.x = 0;
211 		this.up.y = 1;
212 		this.up.z = 0;
213 
214 		emitChangedViewport();
215 	}
216 
217 	public double getViewAngle() {
218 		return 45.0;
219 	}
220 
221 	/**
222 	 * Move center and eye in worldspace by the vector.
223 	 * 
224 	 * @param moveVec
225 	 *            how much and in which direction should eye and center move
226 	 */
227 	public void move(Location moveVec) {
228 		center = this.center.add(moveVec);
229 		eye = this.eye.add(moveVec);
230 
231 		emitChangedViewport();
232 	}
233 
234 	/**
235 	 * Move center and eye by deltaX,Y,Z in worldspace.
236 	 * 
237 	 * @param deltaX
238 	 *            how much should eye and center move along world x axis
239 	 * @param deltaY
240 	 *            how much should eye and center move along world y axis
241 	 * @param deltaZ
242 	 *            how much should eye and center move along world z axis
243 	 */
244 	public void move(double deltaX, double deltaY, double deltaZ) {
245 		move(new Location(deltaX, deltaY, deltaZ));
246 	}
247 
248 	/**
249 	 * Zoom in or out. Basically move the eye according to factor. If factor if
250 	 * e.g. 1.1, distance of eye from center will be 10% greater than is now.
251 	 * 
252 	 * @param factor
253 	 *            percentage of new distance from center to eye compared to
254 	 *            current state
255 	 */
256 	void zoom(double factor, double minDist) {
257 		Location center2eye = Location.sub(eye, center);
258 
259 		eye = Location.add(center, center2eye.scale(factor));
260 
261 		emitChangedViewport();
262 	}
263 
264 	private void emitChangedViewport() {
265 		ViewpointListener[] listenersArray = listeners.toArray(new ViewpointListener[] {});
266 
267 		for (ViewpointListener listener : listenersArray) {
268 			listener.onChangedViewpoint(this);
269 		}
270 	}
271 
272 	public void addViewpointListener(ViewpointListener listener) {
273 		listeners.add(listener);
274 	}
275 
276 	public boolean isViewpointListener(ViewpointListener listener) {
277 		return listeners.contains(listener);
278 	}
279 
280 	public void removeViewpointListener(ViewpointListener listener) {
281 		listeners.remove(listener);
282 	}
283 
284 	/**
285 	 * Set the viewpoint so it looks at specified location. Set new center and
286 	 * update up angle.
287 	 * 
288 	 * @param location
289 	 *            location that should be in the middle of screen
290 	 * @param axis
291 	 *            x = 0, y = 1, z = 2, which axis is up direction?
292 	 * @param upFlag
293 	 *            is up at positive infinity of the axis (true) or negative
294 	 *            infinity (false);
295 	 */
296 	public void lookAt(Location location, int axis, boolean upFlag) {
297 		System.out.println("Look at target: " + location);
298 
299 		Vector3d newEye2Center = new Vector3d();
300 		newEye2Center.x = location.x - eye.x;
301 		newEye2Center.y = location.y - eye.y;
302 		newEye2Center.z = location.z - eye.z;
303 
304 		Vector3d currentEye2Center = new Vector3d(getEye2Center().x, getEye2Center().y, getEye2Center().z);
305 
306 		double angle = currentEye2Center.angle(newEye2Center);
307 		System.out.println("Angle " + angle + " " + angle * 180 / Math.PI);
308 
309 		/*
310 		 * Vector3d upVec; double upDir = upFlag ? 1: -1; center = new
311 		 * Location(location);
312 		 * 
313 		 * switch (axis) { case 0: upVec = new Vector3d(upDir, 0, 0); break;
314 		 * case 1: upVec = new Vector3d(0, upDir, 0); break; case 2: upVec = new
315 		 * Vector3d(0, 0, upDir); break; default: throw new
316 		 * IllegalArgumentException("Invalid axis: " + axis); }
317 		 * 
318 		 * Location eye2CenterLoc = getEye2Center(); Vector3d eye2Center = new
319 		 * Vector3d(); eye2Center.x = eye2CenterLoc.x; eye2Center.y =
320 		 * eye2CenterLoc.y; eye2Center.z = eye2CenterLoc.z;
321 		 * 
322 		 * eye2Center.normalize(); // from look direction and up vector compute
323 		 * "right" vector Vector3d right = new Vector3d();
324 		 * right.cross(eye2Center, upVec);
325 		 * 
326 		 * up.cross(right, eye2Center);
327 		 * 
328 		 * emitChangedViewport();
329 		 */
330 	}
331 
332 	public interface ViewpointListener {
333 
334 		public void onChangedViewpoint(MapViewpoint viewpoint);
335 	}
336 }