@dimension-mismatch/2dphysics 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/body.ts +6 -4
- package/collision.ts +57 -77
- package/constraints/constraint.ts +1 -2
- package/constraints/springs.ts +1 -1
- package/constraints/wheel.ts +1 -1
- package/geometry.ts +39 -30
- package/package.json +1 -1
package/body.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Rotation, vec2 } from "
|
|
1
|
+
import { Rotation, vec2 } from "@dimension-mismatch/vec2";
|
|
2
2
|
import { Circle, Polygon, Shape, ShapeType } from "./geometry.js";
|
|
3
3
|
let uniqueID: number = 0;
|
|
4
4
|
|
|
@@ -167,9 +167,11 @@ export class PhysicsObject implements GameObject{
|
|
|
167
167
|
private calculateProperties(skipCOM?: boolean){
|
|
168
168
|
let COM = new vec2(0,0);
|
|
169
169
|
let totalArea = 0;
|
|
170
|
+
|
|
170
171
|
for(let i = 0; i < this.colliders.length; i++){
|
|
171
|
-
|
|
172
|
-
|
|
172
|
+
let com = this.colliders[i].computeWeightedCOM();
|
|
173
|
+
totalArea += com.area;
|
|
174
|
+
COM.add(vec2.times(com.COM, com.area));
|
|
173
175
|
}
|
|
174
176
|
COM.divideBy(totalArea);
|
|
175
177
|
this.mass = totalArea * this.material.density;
|
|
@@ -179,7 +181,7 @@ export class PhysicsObject implements GameObject{
|
|
|
179
181
|
let inertia = 0;
|
|
180
182
|
for(let i = 0; i < this.colliders.length; i++){
|
|
181
183
|
this.colliders[i].translate(COM.inverse());
|
|
182
|
-
inertia += this.colliders[i].
|
|
184
|
+
inertia += this.colliders[i].computeInertia();
|
|
183
185
|
}
|
|
184
186
|
this.inertia = inertia * this.material.density;
|
|
185
187
|
|
package/collision.ts
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import { PhysicsObject } from "./body.js";
|
|
2
|
-
import { Rotation, vec2 } from "
|
|
2
|
+
import { Rotation, vec2 } from "@dimension-mismatch/vec2";
|
|
3
3
|
import { Circle, Polygon, Shape, ShapeType, Vertex } from "./geometry.js";
|
|
4
4
|
|
|
5
5
|
export interface Contact{
|
|
6
6
|
depth: number;
|
|
7
7
|
normal: vec2;
|
|
8
|
-
objectA
|
|
9
|
-
objectB
|
|
10
|
-
|
|
11
|
-
shapeA: Shape;
|
|
12
|
-
shapeB: Shape;
|
|
8
|
+
objectA?: PhysicsObject;
|
|
9
|
+
objectB?: PhysicsObject;
|
|
13
10
|
|
|
14
11
|
contactPoints: vec2[];
|
|
15
12
|
}
|
|
16
13
|
|
|
17
|
-
|
|
14
|
+
interface SATresult{
|
|
18
15
|
axis: vec2;
|
|
19
16
|
depth: number;
|
|
20
17
|
Aindex: number;
|
|
@@ -26,21 +23,31 @@ function invert(r: Contact){
|
|
|
26
23
|
let objectB = r.objectB;
|
|
27
24
|
r.objectB = r.objectA;
|
|
28
25
|
r.objectA = objectB;
|
|
29
|
-
|
|
30
|
-
let shapeB = r.shapeB;
|
|
31
|
-
r.shapeB = r.shapeA;
|
|
32
|
-
r.shapeA = shapeB;
|
|
33
26
|
}
|
|
34
|
-
function
|
|
35
|
-
return vec2.worldToLocalSpace(v , vert.position, new Rotation(0, vert.normal.x, vert.normal.y))
|
|
27
|
+
function worldToVertexSpace(v: vec2, vert: Vertex): vec2{
|
|
28
|
+
return vec2.worldToLocalSpace(v , vert.position, new Rotation(0, vert.normal.x, vert.normal.y));
|
|
36
29
|
}
|
|
37
|
-
function
|
|
38
|
-
return
|
|
30
|
+
function vertexToWorldSpace(v: vec2, vert: Vertex): vec2{
|
|
31
|
+
return vec2.localToWorldSpace(v , vert.position, new Rotation(0, vert.normal.x, vert.normal.y));
|
|
39
32
|
}
|
|
40
|
-
function
|
|
41
|
-
|
|
33
|
+
function shapeFromObjectToWorldSpace(shape: Shape, object: PhysicsObject): Shape{
|
|
34
|
+
switch(shape.type){
|
|
35
|
+
case ShapeType.POLYGON:
|
|
36
|
+
const polygon = shape as Polygon;
|
|
37
|
+
return {vertices: polygon.vertices.map((v) =>
|
|
38
|
+
{return {isInternal: v.isInternal,
|
|
39
|
+
position: object.localToWorldSpace(v.position),
|
|
40
|
+
normal: object.localToAASpace(v.normal)
|
|
41
|
+
}}), type: ShapeType.POLYGON} as Polygon;
|
|
42
|
+
case ShapeType.CIRCLE:
|
|
43
|
+
const circle = shape as Circle;
|
|
44
|
+
return {position: object.localToWorldSpace(circle.position),
|
|
45
|
+
radius: circle.radius,
|
|
46
|
+
type: ShapeType.CIRCLE
|
|
47
|
+
} as Circle;
|
|
48
|
+
}
|
|
42
49
|
}
|
|
43
|
-
function SAT(shapeA: Polygon, shapeB: Polygon
|
|
50
|
+
function SAT(shapeA: Polygon, shapeB: Polygon): Contact | false{
|
|
44
51
|
let bestResult: SATresult = {axis: new vec2(0,0), depth: Infinity, Aindex: 0, Bindex: 0}
|
|
45
52
|
|
|
46
53
|
//find which normal of shapeB has the least overlap
|
|
@@ -53,10 +60,8 @@ function SAT(shapeA: Polygon, shapeB: Polygon, objectA: PhysicsObject, objectB:
|
|
|
53
60
|
let BmaxProjection = vec2.dot(shapeB.vertices[axis].position, normal);
|
|
54
61
|
|
|
55
62
|
for(let vertex = 0; vertex < shapeA.vertices.length; vertex++){
|
|
56
|
-
let worldPosition = objectA.localToWorldSpace(shapeA.vertices[vertex].position);
|
|
57
|
-
let localPosition = objectB.worldToLocalSpace(worldPosition);
|
|
58
63
|
|
|
59
|
-
let proj = vec2.dot(
|
|
64
|
+
let proj = vec2.dot(shapeA.vertices[vertex].position, normal);
|
|
60
65
|
if(proj < AminProjection){
|
|
61
66
|
AminProjection = proj;
|
|
62
67
|
mindex = vertex;
|
|
@@ -88,10 +93,6 @@ function SAT(shapeA: Polygon, shapeB: Polygon, objectA: PhysicsObject, objectB:
|
|
|
88
93
|
|
|
89
94
|
let n2 = shapeA.vertices[n1idx].normal;
|
|
90
95
|
|
|
91
|
-
|
|
92
|
-
n1 = vec2.rotatedBy(n1, objectA.angle).rotateBy(Rotation.inverse(objectB.angle));
|
|
93
|
-
n2 = vec2.rotatedBy(n2, objectA.angle).rotateBy(Rotation.inverse(objectB.angle));
|
|
94
|
-
|
|
95
96
|
let contactPoints: vec2[];
|
|
96
97
|
if(vec2.dot(n1, bestResult.axis) < vec2.dot(n2, bestResult.axis)){
|
|
97
98
|
contactPoints = [shapeA.vertices[n0idx].position, shapeA.vertices[n1idx].position];
|
|
@@ -99,8 +100,8 @@ function SAT(shapeA: Polygon, shapeB: Polygon, objectA: PhysicsObject, objectB:
|
|
|
99
100
|
else{
|
|
100
101
|
contactPoints = [shapeA.vertices[n1idx].position, shapeA.vertices[n2idx].position];
|
|
101
102
|
}
|
|
102
|
-
contactPoints = contactPoints.map((v) => (worldToVertexSpace(v,
|
|
103
|
-
let b2 =
|
|
103
|
+
contactPoints = contactPoints.map((v) => (worldToVertexSpace(v, shapeB.vertices[bestResult.Bindex])));
|
|
104
|
+
let b2 = worldToVertexSpace(shapeB.vertices[b1idx].position, shapeB.vertices[bestResult.Bindex]);
|
|
104
105
|
|
|
105
106
|
for(let i = contactPoints.length - 1; i >= 0; i--){
|
|
106
107
|
if(contactPoints[i].x > 0){
|
|
@@ -117,28 +118,19 @@ function SAT(shapeA: Polygon, shapeB: Polygon, objectA: PhysicsObject, objectB:
|
|
|
117
118
|
contactPoints[i].y = b2.y;
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
|
-
contactPoints = contactPoints.map((v) => (vertexToWorldSpace(v,
|
|
121
|
+
contactPoints = contactPoints.map((v) => (vertexToWorldSpace(v, shapeB.vertices[bestResult.Bindex])));
|
|
121
122
|
return {
|
|
122
|
-
|
|
123
|
-
shapeB: shapeB,
|
|
124
|
-
|
|
125
|
-
objectA: objectA,
|
|
126
|
-
objectB: objectB,
|
|
127
|
-
|
|
128
|
-
normal: vec2.rotatedBy(bestResult.axis,objectB.angle),
|
|
123
|
+
normal: bestResult.axis,
|
|
129
124
|
depth: bestResult.depth,
|
|
130
|
-
|
|
131
125
|
contactPoints: contactPoints
|
|
132
|
-
|
|
133
126
|
}
|
|
134
|
-
//return bestResult;
|
|
135
127
|
}
|
|
136
|
-
|
|
137
|
-
let rA = SAT(shapeA, shapeB
|
|
128
|
+
function PolygonCollsion(shapeA: Polygon, shapeB: Polygon): Contact | false{
|
|
129
|
+
let rA = SAT(shapeA, shapeB);
|
|
138
130
|
if(!rA){
|
|
139
131
|
return false;
|
|
140
132
|
}
|
|
141
|
-
let rB = SAT(shapeB, shapeA
|
|
133
|
+
let rB = SAT(shapeB, shapeA);
|
|
142
134
|
if(!rB){
|
|
143
135
|
return false;
|
|
144
136
|
}
|
|
@@ -150,8 +142,7 @@ export function PolygonCollsion(shapeA: Polygon, shapeB: Polygon, objectA: Physi
|
|
|
150
142
|
return rA;
|
|
151
143
|
}
|
|
152
144
|
}
|
|
153
|
-
|
|
154
|
-
let localCenter = objectB.worldToLocalSpace(objectA.localToWorldSpace(shapeA.COM));
|
|
145
|
+
function CirclePolygonCollision(shapeA: Circle, shapeB: Polygon): Contact | false{
|
|
155
146
|
|
|
156
147
|
let bestResult: {distance: number, normal: vec2, contact: vec2};
|
|
157
148
|
bestResult = {distance: Infinity, normal: vec2.zero(), contact: vec2.zero()};
|
|
@@ -160,8 +151,8 @@ export function CirclePolygonCollision(shapeA: Circle, shapeB: Polygon, objectA:
|
|
|
160
151
|
for(let i = 0; i < shapeB.vertices.length; i++){
|
|
161
152
|
let vertex = shapeB.vertices[i];
|
|
162
153
|
|
|
163
|
-
let relativeCenter =
|
|
164
|
-
let relativeLast =
|
|
154
|
+
let relativeCenter = worldToVertexSpace(shapeA.position, vertex);
|
|
155
|
+
let relativeLast = worldToVertexSpace(lastPoint, vertex);
|
|
165
156
|
lastPoint = vertex.position;
|
|
166
157
|
|
|
167
158
|
|
|
@@ -171,8 +162,8 @@ export function CirclePolygonCollision(shapeA: Circle, shapeB: Polygon, objectA:
|
|
|
171
162
|
if(relativeCenter.y > 0){
|
|
172
163
|
currentResult = {
|
|
173
164
|
distance: relativeCenter.mag(),
|
|
174
|
-
contact:
|
|
175
|
-
normal: vec2.asUnitVector(vec2.minus(
|
|
165
|
+
contact: vertex.position,
|
|
166
|
+
normal: vec2.asUnitVector(vec2.minus(shapeA.position, vertex.position))}
|
|
176
167
|
|
|
177
168
|
}
|
|
178
169
|
else{
|
|
@@ -184,7 +175,7 @@ export function CirclePolygonCollision(shapeA: Circle, shapeB: Polygon, objectA:
|
|
|
184
175
|
}
|
|
185
176
|
currentResult = {
|
|
186
177
|
distance: relativeCenter.x,
|
|
187
|
-
contact: new vec2(0, relativeCenter.y),
|
|
178
|
+
contact: vertexToWorldSpace(new vec2(0, relativeCenter.y), vertex),
|
|
188
179
|
normal: vertex.normal}
|
|
189
180
|
}
|
|
190
181
|
|
|
@@ -194,29 +185,21 @@ export function CirclePolygonCollision(shapeA: Circle, shapeB: Polygon, objectA:
|
|
|
194
185
|
|
|
195
186
|
|
|
196
187
|
if(Math.abs(currentResult.distance) < Math.abs(bestResult.distance)){
|
|
197
|
-
bestResult
|
|
198
|
-
bestResult.normal = currentResult.normal;
|
|
199
|
-
bestResult.contact = vertexToWorldSpace(currentResult.contact, objectB, vertex);
|
|
188
|
+
bestResult = currentResult;
|
|
200
189
|
}
|
|
201
190
|
}
|
|
202
191
|
if(bestResult.distance > shapeA.radius){
|
|
203
192
|
return false;
|
|
204
193
|
}
|
|
205
194
|
return {
|
|
206
|
-
|
|
207
|
-
shapeB: shapeB,
|
|
208
|
-
|
|
209
|
-
objectA: objectA,
|
|
210
|
-
objectB: objectB,
|
|
211
|
-
|
|
212
|
-
normal: vec2.rotatedBy(bestResult.normal, objectB.angle),
|
|
195
|
+
normal: bestResult.normal,
|
|
213
196
|
depth: shapeA.radius - bestResult.distance,
|
|
214
197
|
|
|
215
198
|
contactPoints: [bestResult.contact]
|
|
216
199
|
}
|
|
217
200
|
}
|
|
218
|
-
|
|
219
|
-
let ret = CirclePolygonCollision(shapeB, shapeA
|
|
201
|
+
function PolygonCircleCollsion(shapeA: Polygon, shapeB: Circle): Contact | false{
|
|
202
|
+
let ret = CirclePolygonCollision(shapeB, shapeA);
|
|
220
203
|
if(!ret){
|
|
221
204
|
return false;
|
|
222
205
|
}
|
|
@@ -226,9 +209,8 @@ export function PolygonCircleCollsion(shapeA: Polygon, shapeB: Circle, objectA:
|
|
|
226
209
|
}
|
|
227
210
|
}
|
|
228
211
|
|
|
229
|
-
|
|
230
|
-
let
|
|
231
|
-
let between = vec2.minus(Acenter, shapeB.COM);
|
|
212
|
+
function CircleCircleCollision(shapeA: Circle, shapeB: Circle): Contact | false{
|
|
213
|
+
let between = vec2.minus(shapeA.position, shapeB.position);
|
|
232
214
|
let dist = between.mag();
|
|
233
215
|
if(between.x == 0 && between.y == 0){
|
|
234
216
|
between.y = 1;
|
|
@@ -240,33 +222,27 @@ export function CircleCircleCollision(shapeA: Circle, shapeB: Circle, objectA: P
|
|
|
240
222
|
let normal = vec2.dividedBy(between, dist);
|
|
241
223
|
return{
|
|
242
224
|
depth: shapeA.radius + shapeB.radius - dist,
|
|
243
|
-
normal: normal
|
|
244
|
-
|
|
245
|
-
shapeA: shapeA,
|
|
246
|
-
shapeB: shapeB,
|
|
247
|
-
|
|
248
|
-
objectA: objectA,
|
|
249
|
-
objectB: objectB,
|
|
225
|
+
normal: normal,
|
|
250
226
|
|
|
251
|
-
contactPoints: [
|
|
227
|
+
contactPoints: [vec2.plus(shapeB.position, vec2.times(normal, shapeB.radius))]
|
|
252
228
|
}
|
|
253
229
|
}
|
|
254
230
|
}
|
|
255
|
-
export function ShapeCollision(shapeA: Shape, shapeB: Shape
|
|
231
|
+
export function ShapeCollision(shapeA: Shape, shapeB: Shape): Contact | false{
|
|
256
232
|
if(shapeA.type == ShapeType.CIRCLE){
|
|
257
233
|
if(shapeB.type == ShapeType.CIRCLE){
|
|
258
|
-
return CircleCircleCollision(shapeA as Circle, shapeB as Circle
|
|
234
|
+
return CircleCircleCollision(shapeA as Circle, shapeB as Circle);
|
|
259
235
|
}
|
|
260
236
|
else{
|
|
261
|
-
return CirclePolygonCollision(shapeA as Circle, shapeB as Polygon
|
|
237
|
+
return CirclePolygonCollision(shapeA as Circle, shapeB as Polygon);
|
|
262
238
|
}
|
|
263
239
|
}
|
|
264
240
|
else{
|
|
265
241
|
if(shapeB.type == ShapeType.CIRCLE){
|
|
266
|
-
return PolygonCircleCollsion(shapeA as Polygon, shapeB as Circle
|
|
242
|
+
return PolygonCircleCollsion(shapeA as Polygon, shapeB as Circle);
|
|
267
243
|
}
|
|
268
244
|
else{
|
|
269
|
-
return PolygonCollsion(shapeA as Polygon, shapeB as Polygon
|
|
245
|
+
return PolygonCollsion(shapeA as Polygon, shapeB as Polygon);
|
|
270
246
|
}
|
|
271
247
|
}
|
|
272
248
|
}
|
|
@@ -274,8 +250,12 @@ export function Collision(objectA: PhysicsObject, objectB: PhysicsObject): Conta
|
|
|
274
250
|
let results: Contact[] = [];
|
|
275
251
|
for(let i = 0; i < objectA.colliders.length; i++){
|
|
276
252
|
for(let j = 0; j < objectB.colliders.length; j++){
|
|
277
|
-
let
|
|
253
|
+
let transformedA = shapeFromObjectToWorldSpace(objectA.colliders[i], objectA);
|
|
254
|
+
let transformedB = shapeFromObjectToWorldSpace(objectB.colliders[j], objectB);
|
|
255
|
+
let res = ShapeCollision(transformedA, transformedB);
|
|
278
256
|
if(res){
|
|
257
|
+
res.objectA = objectA;
|
|
258
|
+
res.objectB = objectB;
|
|
279
259
|
results.push(res);
|
|
280
260
|
}
|
|
281
261
|
}
|
package/constraints/springs.ts
CHANGED
package/constraints/wheel.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PhysicsObject } from "../body.js";
|
|
2
|
-
import { vec2, Rotation } from "
|
|
2
|
+
import { vec2, Rotation } from "@dimension-mismatch/vec2";
|
|
3
3
|
import { Constraint, ConstraintType } from "./constraint.js";
|
|
4
4
|
export interface MotorDrivable extends Constraint{
|
|
5
5
|
applyMotorTorque(torque: number): void;
|
package/geometry.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Rotation, vec2 } from "
|
|
1
|
+
import { Rotation, vec2 } from "@dimension-mismatch/vec2";
|
|
2
2
|
|
|
3
3
|
export class Vertex{
|
|
4
4
|
position: vec2;
|
|
@@ -14,42 +14,50 @@ export type Shape = Polygon | Circle;
|
|
|
14
14
|
|
|
15
15
|
export class Polygon{
|
|
16
16
|
type = ShapeType.POLYGON;
|
|
17
|
-
area: number;
|
|
18
|
-
inertia: number;
|
|
19
|
-
COM: vec2;
|
|
20
17
|
vertices: Vertex[];
|
|
21
18
|
constructor(points: vec2[], internalEdges?: boolean[]){
|
|
22
|
-
let totalArea = 0;
|
|
23
|
-
this.COM = vec2.zero();
|
|
24
19
|
let lastPoint = points[points.length - 1];
|
|
25
20
|
this.vertices = [];
|
|
26
|
-
this.inertia = 0;
|
|
27
21
|
for(let i = 0; i < points.length; i++){
|
|
28
|
-
let triArea = vec2.cross(lastPoint, points[i]) / 2;
|
|
29
|
-
let triCom = vec2.times(vec2.plus(lastPoint, points[i]), triArea);
|
|
30
|
-
this.inertia += (lastPoint.magSqr() + vec2.dot(lastPoint, points[i]) + points[i].magSqr()) * triArea;
|
|
31
|
-
|
|
32
|
-
totalArea += triArea;
|
|
33
|
-
this.COM.add(triCom);
|
|
34
|
-
|
|
35
22
|
this.vertices.push(
|
|
36
23
|
{position: points[i],
|
|
37
24
|
normal: vec2.minus(points[i], lastPoint).normalize().rotateBy(Rotation.cw90deg()),
|
|
38
25
|
isInternal: internalEdges? internalEdges[i]: false});
|
|
39
26
|
lastPoint = points[i];
|
|
40
27
|
}
|
|
41
|
-
this.COM.divideBy(totalArea * 3);
|
|
42
|
-
this.inertia /= 6;
|
|
43
|
-
this.area = totalArea;
|
|
44
28
|
}
|
|
45
29
|
translate(t: vec2){
|
|
46
30
|
for(let i = 0; i < this.vertices.length; i++){
|
|
47
31
|
this.vertices[i].position.add(t);
|
|
48
32
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
33
|
+
}
|
|
34
|
+
computeWeightedCOM(): {COM: vec2, area: number}{
|
|
35
|
+
let COM : vec2 = vec2.zero();
|
|
36
|
+
let totalArea = 0;
|
|
37
|
+
let lastPoint : vec2 = this.vertices[this.vertices.length - 1].position;
|
|
38
|
+
for(let i = 0; i < this.vertices.length; i++){
|
|
39
|
+
let currentPoint = this.vertices[i].position;
|
|
40
|
+
let triArea = vec2.cross(lastPoint, currentPoint) / 2;
|
|
41
|
+
let triCom = vec2.times(vec2.plus(lastPoint, currentPoint), triArea);
|
|
42
|
+
totalArea += triArea;
|
|
43
|
+
COM.add(triCom);
|
|
44
|
+
lastPoint = currentPoint;
|
|
45
|
+
}
|
|
46
|
+
COM.divideBy(totalArea);
|
|
47
|
+
return {COM: COM, area: totalArea};
|
|
48
|
+
}
|
|
49
|
+
computeInertia() : number{
|
|
50
|
+
let inertia = 0;
|
|
51
|
+
let lastPoint : vec2 = this.vertices[this.vertices.length - 1].position;
|
|
52
|
+
for(let i = 0; i < this.vertices.length; i++){
|
|
53
|
+
let currentPoint = this.vertices[i].position;
|
|
54
|
+
let triArea = vec2.cross(lastPoint, currentPoint) / 2;
|
|
52
55
|
|
|
56
|
+
inertia += (lastPoint.magSqr() + vec2.dot(lastPoint, currentPoint) + currentPoint.magSqr()) * triArea;
|
|
57
|
+
lastPoint = currentPoint;
|
|
58
|
+
}
|
|
59
|
+
inertia /= 6;
|
|
60
|
+
return inertia;
|
|
53
61
|
}
|
|
54
62
|
static rectangle(position: vec2, width: number , height: number){
|
|
55
63
|
let x = position.x;
|
|
@@ -78,21 +86,22 @@ export class Polygon{
|
|
|
78
86
|
}
|
|
79
87
|
export class Circle{
|
|
80
88
|
type = ShapeType.CIRCLE;
|
|
81
|
-
|
|
82
|
-
inertia: number;
|
|
83
|
-
COM: vec2;
|
|
89
|
+
position: vec2;
|
|
84
90
|
radius: number;
|
|
85
91
|
|
|
86
92
|
constructor(position: vec2 , radius: number){
|
|
87
|
-
this.
|
|
88
|
-
this.inertia = this.area * radius * radius + 0.5 * position.magSqr() * this.area;
|
|
89
|
-
this.COM = position;
|
|
93
|
+
this.position = position;
|
|
90
94
|
this.radius = radius;
|
|
91
95
|
}
|
|
92
96
|
translate(t: vec2){
|
|
93
|
-
this.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
+
this.position.add(t);
|
|
98
|
+
}
|
|
99
|
+
computeWeightedCOM(): {COM: vec2, area: number}{
|
|
100
|
+
return {COM: this.position.copy(), area: Math.PI * this.radius * this.radius};
|
|
101
|
+
}
|
|
102
|
+
computeInertia(): number{
|
|
103
|
+
let rSquared = this.radius * this.radius;
|
|
104
|
+
let area = Math.PI * rSquared;
|
|
105
|
+
return area * rSquared + 0.5 * this.position.magSqr() * area;
|
|
97
106
|
}
|
|
98
107
|
}
|