Skip to content

Commit

Permalink
修复凹多边形分解算法的bug
Browse files Browse the repository at this point in the history
  • Loading branch information
phenomLi committed Oct 25, 2020
1 parent dfd826b commit da577c6
Show file tree
Hide file tree
Showing 21 changed files with 143 additions and 124 deletions.
3 changes: 2 additions & 1 deletion demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ const examples = [
['运动刚体', kineticWorld],
['复合刚体', compositeWorld],
['压力测试', stressWorld],
['真空', vacuumWorld]
['失重', weightlessWorld],
['凹多边形', concaveWorld]
];

let renderer = null,
Expand Down
2 changes: 1 addition & 1 deletion demo/examples/basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ function basicWorld(canvas) {

const canvasWidth = canvas.offsetWidth,
canvasHeight = canvas.offsetHeight,
vector = Torque.math.vector,
vector = Torque.vector,
renderer = new Renderer(canvas, canvasWidth, canvasHeight, {
gravity: vector(0, 9.8),
enableSleeping: true,
Expand Down
6 changes: 3 additions & 3 deletions demo/examples/composite.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ function compositeWorld(canvas) {

const canvasWidth = canvas.offsetWidth,
canvasHeight = canvas.offsetHeight,
vector = Torque.math.vector,
vector = Torque.vector,
renderer = new Renderer(canvas, canvasWidth, canvasHeight, {
gravity: vector(0, 9.8),
enableSleeping: true,
Expand Down Expand Up @@ -33,7 +33,7 @@ function compositeWorld(canvas) {

createWall(canvasWidth, canvasHeight, 30, {...options, static: true});

function createComposite() {
function createComposite(i) {
let rect1 = renderer.createRect(700, 500, 80, 30, {
...options
});
Expand All @@ -48,7 +48,7 @@ function compositeWorld(canvas) {
}

for(let i = 0; i < 20; i++) {
createComposite();
createComposite(i);
}

return renderer;
Expand Down
69 changes: 69 additions & 0 deletions demo/examples/concave.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@

function concaveWorld(canvas) {

const canvasWidth = canvas.offsetWidth,
canvasHeight = canvas.offsetHeight,
vector = Torque.vector,
renderer = new Renderer(canvas, canvasWidth, canvasHeight, {
gravity: vector(0, 9.8),
enableSleeping: true,
enableCache: true,
enableSATBoost: true,
backgroundColor: 0x555555
}),
options = renderer.defaultOptions;

/**
* 创建四面墙
* @param {*} cWidth
* @param {*} cHeight
* @param {*} wallWidth
* @param {*} options
*/
function createWall(cWidth, cHeight, wallWidth, options) {
// 顶墙壁
renderer.createRect(0, 0, cWidth, wallWidth, options);
// 底墙壁
renderer.createRect(0, cHeight - wallWidth, cWidth, wallWidth, options);
// 左墙壁
renderer.createRect(0, 0, wallWidth, cHeight, options);
// 右墙壁
renderer.createRect(cWidth - wallWidth, 0, wallWidth, cHeight, options);
}

createWall(canvasWidth, canvasHeight, 30, {...options, static: true});

function fromPath(path) {
var pathPattern = /L?\s*([\-\d\.e]+)[\s,]*([\-\d\.e]+)*/ig,
points = [];

path.replace(pathPattern, function(match, x, y) {
points.push([parseFloat(x), parseFloat(y)]);
});

return points;
};

const arrowPath = '0 0 40 0 40 20 100 20 100 80 40 80 40 100 0 50',
chevronPath = '100 0 75 50 100 100 25 100 0 50 25 0',
starPath = '50 0 63 38 100 38 69 59 82 100 50 75 18 100 31 59 0 38 37 38',
horseShoePath = '35 7 19 17 14 38 14 58 25 79 45 85 65 84 65 66 46 67 34 59 30 44 33 29 45 23 66 23 66 7 53 7';

for(let i = 0; i < 4; i++) {
renderer.createPolygon(100, i * 100, fromPath(arrowPath), { ...options });
renderer.createPolygon(200, i * 100, fromPath(chevronPath), { ...options });
renderer.createPolygon(300, i * 100, fromPath(starPath), { ...options });
renderer.createPolygon(400, i * 100, fromPath(horseShoePath).reverse(), { ...options });
}

return renderer;
}









2 changes: 1 addition & 1 deletion demo/examples/kinetic.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ function kineticWorld(canvas) {

const canvasWidth = canvas.offsetWidth,
canvasHeight = canvas.offsetHeight,
vector = Torque.math.vector,
vector = Torque.vector,
renderer = new Renderer(canvas, canvasWidth, canvasHeight, {
gravity: vector(0, 9),
enableSleeping: true,
Expand Down
4 changes: 2 additions & 2 deletions demo/examples/stack.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
function stackWorld(canvas) {
const canvasWidth = canvas.offsetWidth,
canvasHeight = canvas.offsetHeight,
vector = Torque.math.vector,
vector = Torque.vector,
renderer = new Renderer(canvas, canvasWidth, canvasHeight, {
gravity: vector(0, 9),
gravity: vector(0, 9.8),
enableSleeping: true,
enableCache: true,
enableSATBoost: true,
Expand Down
2 changes: 1 addition & 1 deletion demo/examples/stress.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
function stressWorld(canvas) {
const canvasWidth = canvas.offsetWidth,
canvasHeight = canvas.offsetHeight,
vector = Torque.math.vector,
vector = Torque.vector,
renderer = new Renderer(canvas, canvasWidth, canvasHeight, {
gravity: vector(0, 9),
enableSleeping: true,
Expand Down
4 changes: 2 additions & 2 deletions demo/examples/vacuum.js → demo/examples/weightless.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@

function vacuumWorld(canvas) {
function weightlessWorld(canvas) {

const canvasWidth = canvas.offsetWidth,
canvasHeight = canvas.offsetHeight,
vector = Torque.math.vector,
vector = Torque.vector,
renderer = new Renderer(canvas, canvasWidth, canvasHeight, {
gravity: vector(0, 0),
enableSleeping: true,
Expand Down
2 changes: 1 addition & 1 deletion dist/torque.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@
<script src="./demo/examples/kinetic.js"></script>
<script src="./demo/examples/composite.js"></script>
<script src="./demo//examples/stress.js"></script>
<script src="./demo/examples/vacuum.js"></script>
<script src="./demo/examples/weightless.js"></script>
<script src="./demo/examples/concave.js"></script>
<script src="./demo/demo.js"></script>
</body>
</html>
12 changes: 12 additions & 0 deletions lib/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,18 @@ class Renderer {
return this.render(polygonBody, polygon);
}

createStar(x, y, v, options) {
let star = new PIXI.Graphics();

this.strokeAndFill(star, options);

star.position.x = x;
star.position.y = y;
star.drawPolygon(v.flat());

this.app.stage.addChild(star);
}

/**
* 创建复合刚体
* @param {*} bodies
Expand Down
5 changes: 1 addition & 4 deletions src/body/body.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Bound } from "../common/bound";
import { Util } from "../common/util";
import { Engine } from "../core/engine";
import { Axis } from "../common/vertices";
import { Pin } from "../constraint/pin";




Expand Down Expand Up @@ -145,8 +145,6 @@ export class Body {
parts: Body[];
// 与该刚体碰撞的刚体列表
contactBodies: { [key: string]: Body };
// 图钉约束
pinConstraint: Pin;
// 方法
methods: BodyOpt['methods'];
// 渲染函数
Expand All @@ -173,7 +171,6 @@ export class Body {
this.torque = 0;
this.friction = 10;
this.restitution = 0.8;
this.pinConstraint = null;
this.static = false;
this.kinetic = false
this.ignoreGravity = false;
Expand Down
2 changes: 1 addition & 1 deletion src/collision/sat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export type MinOverlap = {
export class SAT {
// 是否开启SAT加速
private enableSATBoost: boolean = true;
private reuseCollisionThreshold: number = 0.05;
private reuseCollisionThreshold: number = 0.1;

constructor(opt: EngineOpt) {
Util.merge(this, opt);
Expand Down
51 changes: 37 additions & 14 deletions src/common/vertices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ export type Axis = {
};


let i = 0;


// 顶点操作工具
export const Vertices = {

Expand Down Expand Up @@ -219,6 +222,8 @@ export const Vertices = {
}
},



/**
* 将凹多边形分解为多个子凸多边形
* @param vertexList
Expand All @@ -233,49 +238,67 @@ export const Vertices = {
vDiv: Vector,
dividePointA: Vector,
dividePointB: Vector,
len = vertexList.length, i, j, cur, next, next2,
len = vertexList.length,
i, j, cur, next, next2, next3,
flag = false;

i++;

for(i = 0 ; i < len; i++) {
cur = i;
next = (i + 1) % len;
next2 = (i + 2) % len;
next3 = (i + 3) % len;

xAxis = vertexList[next].sub(vertexList[cur]);
vTest = vertexList[next2].sub(vertexList[cur]);

if(xAxis.cro(vTest) < 0) {
for(j = i + 3; j < len; j++) {
vDiv = vertexList[j].sub(vertexList[cur]);
if(xAxis.cro(vDiv) > 0) {
flag = true;
break;
}
j = next3;

do {
vDiv = vertexList[j].sub(vertexList[cur]);

if(xAxis.cro(vDiv) * xAxis.cro(vTest) <= 0) {
flag = true;
break;
}

if(flag) break;
}
j = (j + 1) % len;
} while(j !== i);

if(flag) break;
}

// 获取两个分割点
dividePointA = vertexList[next],
dividePointB = vertexList[j];

if(j > next2) {
vertexListB = vertexList.splice(next2, j - next2);
}
else {
vertexListB = [];
vertexListB.push(...vertexList.splice(next2, len - (next2 - 1)));
vertexListB.push(...vertexList.splice(0, j));
}

// 拆分为两个多边形vertexListA和vertexListB
vertexListB = vertexList.splice(next2, j - next2);
vertexListA = vertexList;
vertexListB.unshift(dividePointA);
vertexListB.push(dividePointB);

vertexListA = Vertices.filterCollinearVertex(vertexListA);
vertexListB = Vertices.filterCollinearVertex(vertexListB);

// 检测拆分出来的两个多边形是否是凹多边形,若果是,继续递归拆分
if(Vertices.isConcave(vertexListA)) {
if(vertexListA.length > 3 && Vertices.isConcave(vertexListA)) {
parts.push(...Vertices.split(vertexListA));
}
else {
parts.push(vertexListA);
}

if(Vertices.isConcave(vertexListB)) {
if(vertexListB.length > 3 && Vertices.isConcave(vertexListB)) {
parts.push(...Vertices.split(vertexListB));
}
else {
Expand Down Expand Up @@ -465,7 +488,7 @@ export const Vertices = {
}

for(i = 0; i < removeIndex.length; i++) {
vertexList.splice(removeIndex[i], 1);
vertexList.splice(removeIndex[i] - i, 1);
}

return vertexList;
Expand Down
2 changes: 0 additions & 2 deletions src/constraint/constraint.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@





export class Constraint {
// 速度求解迭代次数
protected velocitySolverIterations: number;
Expand Down
Loading

0 comments on commit da577c6

Please sign in to comment.