-
Notifications
You must be signed in to change notification settings - Fork 1
/
ArcBall.pde
156 lines (131 loc) · 4.18 KB
/
ArcBall.pde
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import processing.core.*;
/**
* ArcBall is an interface for rotate 3D objects. It allows the rotation of a 3D
* object from a 2D input by simulating touching a sphere (arcball) that can be
* spun in any direction.
*
* @author Kelly Egan
*
*/
public class ArcBall implements PConstants{
/**
* Constants for calling specific views when using setViews
*/
public final Quaternion FRONT_VIEW = new Quaternion(1.0f, 0.0f, 0.0f, 0.0f);
public final Quaternion TOP_VIEW = new Quaternion(-PApplet.sqrt(2.0f)/2.0f, PApplet.sqrt(2.0f)/2.0f, 0, 0);
public final Quaternion LEFT_VIEW = new Quaternion(PApplet.sqrt(2.0f)/2.0f, 0, PApplet.sqrt(2.0f)/2.0f, 0);
public final Quaternion RIGHT_VIEW = new Quaternion(-PApplet.sqrt(2.0f) / 2.0f, 0f, PApplet.sqrt(2.0f) / 2.0f, 0f);
public final Quaternion BOTTOM_VIEW = new Quaternion(PApplet.sqrt(2.0f)/2.0f, PApplet.sqrt(2.0f)/2.0f, 0, 0);
public final Quaternion BACK_VIEW = new Quaternion(0.0f, 0.0f, 1.0f, 0.0f);
private PApplet p;
//Center position and radius of ArcBall
private PVector center;
private float radius;
//Start and end point on ArcBall surface of rotation
private PVector startPoint, endPoint;
private boolean dragging;
public Quaternion currentRotation, startRotation, deltaRotation;
public Quaternion quaternion;
/**
* Construct an ArcBall given its center position and radius
*
* @param p parent PApplet
* @param center_x x coordinate of the center of ArcBall
* @param center_y y coordinate of the center of the ArcBall
* @param radius radius of the ArcBall
*/
public ArcBall(PApplet p, float center_x, float center_y, float radius){
this.p = p;
center = new PVector(center_x, center_y);
this.radius = radius;
startPoint = new PVector();
endPoint = new PVector();
quaternion = new Quaternion();
currentRotation = new Quaternion();
startRotation = new Quaternion();
deltaRotation = new Quaternion();
}
/**
* Called when dragging of the ArcBall begins.
* @param x screen position on x axis
* @param y screen position on y axis
*/
public void dragStart(float x, float y){
startPoint = screenToArcball(x, y);
startRotation.set(currentRotation);
deltaRotation.setToIdentity();
dragging = true;
}
/**
* Called during dragging of ArcBall
* @param x
* @param y
*/
public void dragging(float x, float y){
endPoint = screenToArcball(x, y);
quaternion.rotationBetween(startPoint, endPoint, deltaRotation);
}
/**
* Called when draggin ends
*/
public void dragEnd() {
dragging = false;
}
/**
* Update currentRotation with data from dragging
*/
public void update(){
if( dragging ) {
currentRotation = quaternion.mult(deltaRotation, startRotation);
if(frameCount % 3 == 0) {
startRotation.set(currentRotation);
deltaRotation.setToIdentity();
startPoint.set(endPoint);
}
} else {
currentRotation = quaternion.mult(deltaRotation, currentRotation);
deltaRotation = deltaRotation.power(0.999f);
}
applyRotation(currentRotation);
}
/**
* Project screen coordinates onto ArcBall sphere. If coordinate
* is outside of the sphere treat as edge of sphere.
*
* @param x
* @param y
* @return
*/
public PVector screenToArcball(float x, float y){
PVector result = new PVector();
result.x = (x - center.x) / radius;
result.y = (y - center.y) / radius;
float mag = result.magSq();
if (mag > 1.0f){
result.normalize();
} else {
result.z = PApplet.sqrt(1.0f - mag);
}
return result;
}
/**
* Set the view to one of six stand views
*
* @param viewIndex
*/
public void setView( Quaternion view ) {
startRotation.set(view);
deltaRotation.setToIdentity();
currentRotation.set(view);
}
public void applyRotation(Quaternion q){
float[] axisAngle = q.toAngleAxis();
p.rotate(axisAngle[0], axisAngle[1], axisAngle[2], axisAngle[3]);
}
public float[] getRotation() {
return currentRotation.toAngleAxis();
}
public float[] getInverseRotation() {
return currentRotation.inverse().toAngleAxis();
}
}