forked from cmangos/mangos-tbc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCylinder.cpp
176 lines (129 loc) · 3.94 KB
/
Cylinder.cpp
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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
/**
@file Cylinder.cpp
@maintainer Morgan McGuire, http://graphics.cs.williams.edu
@created 2003-02-07
@edited 2006-02-18
Copyright 2000-2006, Morgan McGuire.
All rights reserved.
*/
#include "G3D/platform.h"
#include "G3D/Cylinder.h"
#include "G3D/BinaryInput.h"
#include "G3D/BinaryOutput.h"
#include "G3D/LineSegment.h"
#include "G3D/CoordinateFrame.h"
#include "G3D/Line.h"
#include "G3D/AABox.h"
namespace G3D {
Cylinder::Cylinder(class BinaryInput& b) {
deserialize(b);
}
Cylinder::Cylinder() {
}
Cylinder::Cylinder(const Vector3& _p1, const Vector3& _p2, float _r)
: p1(_p1), p2(_p2), mRadius(_r) {
}
void Cylinder::serialize(class BinaryOutput& b) const {
p1.serialize(b);
p2.serialize(b);
b.writeFloat64(mRadius);
}
void Cylinder::deserialize(class BinaryInput& b) {
p1.deserialize(b);
p2.deserialize(b);
mRadius = b.readFloat64();
}
Line Cylinder::axis() const {
return Line::fromTwoPoints(p1, p2);
}
float Cylinder::radius() const {
return mRadius;
}
float Cylinder::volume() const {
return
(float)pi() * square(mRadius) * (p1 - p2).magnitude();
}
float Cylinder::area() const {
return
// Sides
(twoPi() * mRadius) * height() +
// Caps
twoPi() * square(mRadius);
}
void Cylinder::getBounds(AABox& out) const {
Vector3 min = p1.min(p2) - (Vector3(1, 1, 1) * mRadius);
Vector3 max = p1.max(p2) + (Vector3(1, 1, 1) * mRadius);
out = AABox(min, max);
}
bool Cylinder::contains(const Vector3& p) const {
return LineSegment::fromTwoPoints(p1, p2).distanceSquared(p) <= square(mRadius);
}
void Cylinder::getReferenceFrame(CoordinateFrame& cframe) const {
cframe.translation = center();
Vector3 Y = (p1 - p2).direction();
Vector3 X = (abs(Y.dot(Vector3::unitX())) > 0.9) ? Vector3::unitY() : Vector3::unitX();
Vector3 Z = X.cross(Y).direction();
X = Y.cross(Z);
cframe.rotation.setColumn(0, X);
cframe.rotation.setColumn(1, Y);
cframe.rotation.setColumn(2, Z);
}
void Cylinder::getRandomSurfacePoint(Vector3& p, Vector3& N) const {
float h = height();
float r = radius();
// Create a random point on a standard cylinder and then rotate to the global frame.
// Relative areas (factor of 2PI already taken out)
float capRelArea = square(r) / 2.0f;
float sideRelArea = r * h;
float r1 = uniformRandom(0, capRelArea * 2 + sideRelArea);
if (r1 < capRelArea * 2) {
// Select a point uniformly at random on a disk
// @cite http://mathworld.wolfram.com/DiskPointPicking.html
float a = uniformRandom(0, (float)twoPi());
float r2 = sqrt(uniformRandom(0, 1)) * r;
p.x = cos(a) * r2;
p.z = sin(a) * r2;
N.x = 0;
N.z = 0;
if (r1 < capRelArea) {
// Top
p.y = h / 2.0f;
N.y = 1;
} else {
// Bottom
p.y = -h / 2.0f;
N.y = -1;
}
} else {
// Side
float a = uniformRandom(0, (float)twoPi());
N.x = cos(a);
N.y = 0;
N.z = sin(a);
p.x = N.x * r;
p.z = N.y * r;
p.y = uniformRandom(-h / 2.0f, h / 2.0f);
}
// Transform to world space
CoordinateFrame cframe;
getReferenceFrame(cframe);
p = cframe.pointToWorldSpace(p);
N = cframe.normalToWorldSpace(N);
}
Vector3 Cylinder::randomInteriorPoint() const {
float h = height();
float r = radius();
// Create a random point in a standard cylinder and then rotate to the global frame.
// Select a point uniformly at random on a disk
// @cite http://mathworld.wolfram.com/DiskPointPicking.html
float a = uniformRandom(0, (float)twoPi());
float r2 = sqrt(uniformRandom(0, 1)) * r;
Vector3 p( cos(a) * r2,
uniformRandom(-h / 2.0f, h / 2.0f),
sin(a) * r2);
// Transform to world space
CoordinateFrame cframe;
getReferenceFrame(cframe);
return cframe.pointToWorldSpace(p);
}
} // namespace