const { ObjLoops } = require(".");
const Vector = require("./tools/vector");
const PhSim = require("./index");
var Matter;
if(typeof window === "object") {
Matter = window.Matter;
}
else {
Matter = require("matter-js");
}
/**
* @namespace
* @memberof PhSim
*/
PhSim.Query = {}
/**
*
* Get the special points of a rectangle
*
* @function
* @param {Object} rectangle
*/
PhSim.Query.getSpecialRectanglePoints = function(rectangle) {
var o = {
"center": {
"rel": {
"x": 0.5 * rectangle.w,
"y": 0.5 * rectangle.h
},
"abs": {
"x": rectangle.x + o.center.rel.x,
"y": rectangle.h + o.center.rel.y
},
},
"sidepoint": {
"rel": {
"x": rectangle.w,
"y": 0.5 * rectangle.h
},
"abs": {
"x": o.sidepoint.rel.x + rectangle.x,
"y": o.sidepoint.rel.y + rectangle.y
}
},
}
return o;
}
/**
* Get the status string of the the dynamic simulation
* @function
*/
PhSim.prototype.getStatusStr = function() {
return PhSim.Query.getStatusStr(this);
}
/**
* Get the status string of a PhSim instance.
* @param {PhSim} dynObject
*/
PhSim.Query.getStatusStr = function(phSim) {
return PhSim.statusStruct[phSim.status];
}
/**
*
* Get collision classes
*
* @function
* @param {PhSim.DynObject} dynObject - Dynamic Object
* @returns {String[]}
*
*/
PhSim.Query.getCollisionClasses = function(dynObject) {
if(dynObject.collisionClass) {
var a = dynObject.collisionClass;
var b = a.split(" ");
return b;
}
else {
return [];
}
}
/**
* @function
*/
PhSim.prototype.getUniversalObjArray = function() {
var array = []
for(let i = 0; i < this.matterJSWorld.composites.length; i++) {
var a = this.matterJSWorld.composites[i].bodies;
for(let j = 0; j < a.length; j++) {
array.push(a[j]);
}
}
for(let i = 0; i < this.matterJSWorld.bodies.length; i++) {
array.push(this.matterJSWorld.bodies[i]);
}
return array;
}
/**
* Check widget type and return the widget type
* @param {WidgetOptions} widget
*/
PhSim.Query.chkWidgetType = function(widget) {
for(var i = 0; i < PhSim.boolKey_lc.length; i++) {
if(widget[PhSim.boolKey_lc[i]]) {
return PhSim.boolKey_lc[i];
}
}
return "unknown_widget";
}
/**
* Get static object of a dynamic object
* @param {PhSim.DynObject} dynObject - The dynamic object
*/
PhSim.prototype.getStatic = function(dynObject) {
if(dynObject.static || dynObject.static) {
return null;
}
else {
return dynObject.static;
}
}
/**
* Get object by name in PhSim simulation
*
* @function
* @param {String} str - String for the name
* @returns {PhSimObject|null} - Returns the object if found, but returns "null" object if not.
*/
PhSim.prototype.getObjectByName = function(str) {
for(var i = 0; i < this.objUniverse.length; i++) {
if(this.objUniverse[i].name === str) {
return this.objUniverse[i];
}
}
}
/**
* Get Object By Name
* @param {Simulation|Layer|PhSimObject[]} o
* @param {string} str - Name of Object
*/
PhSim.Query.getObjectByName = function(o,str) {
var x;
if(Array.isArray(o)) {
for(var i = 0; i < o.length; i++) {
if(o.name === str) {
return o[i];
}
}
}
// Get object by name in static composite simulation object
else if(Array.isArray(o.simulations)) {
ObjLoops.global(o,function(p){
if(p.name === str) {
x = p;
}
})
return x;
}
// Get object by name in simulation object with layers
else if(Array.isArray(o.layers)) {
ObjLoops.layer(o,function(p){
if(p.name === str) {
x = p;
}
})
return x;
}
// Get object by name in simulation object with objUniverse
else if(Array.isArray(o.objUniverse)) {
PhSim.Query.getObjectByName(o.objUniverse,str);
}
}
/**
* Check if two objects are colliding
* @function
* @param {PhSim.DynObject} dynObjectA
* @param {PhSim.DynObject} dynObjectB
* @returns {Boolean}
*/
PhSim.prototype.collided = function(dynObjectA,dynObjectB) {
return Matter.SAT.collides(dynObjectA.matter,dynObjectB.matter).collided;
}
/**
* Check if an object is in a collision
* @function
* @param {PhSim.DynObject} dynObject
* @returns {Boolean}
*/
PhSim.prototype.isInCollision = function(dynObject) {
var self = this;
var returnValue = false;
this.forAllObjects(function(object) {
var a = self.collided(dynObject,object);
if(a === true) {
returnValue = a;
return false;
}
});
return returnValue;
}
/**
* See if point is contained in shape defined by vertices set.
* @function
* @param {Vector[]} a - Set of vertices
* @param {Vector} v - The vertex to be checked.
* @return {Boolean} - Returns true if `v` is contained in the shape defined by `a` and false if otherwise.
*/
PhSim.Query.pointInVerts = function(a,v) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(a[0].x,a[0].y);
for(var i = 0; i < a.length; i++) {
ctx.lineTo(a[i].x,a[i].y);
}
ctx.closePath();
var p = ctx.isPointInPath(v.x,v.y);
ctx.stroke();
return p;
}
/**
*
* See if point is in vertices border
*
* @function
* @param {Vector[]} a - Vertices to check
* @param {Vector} v - Point to check.
* @param {Number} width - Width of vertices border
* @returns {Boolean} - Returns `true` if `v` is in the border of the
* polygon defined by `a` and false otherwise.
*/
PhSim.Query.pointInVertsBorder = function(a,v,width) {
if(width) {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.lineWidth = width;
ctx.beginPath();
ctx.lineTo(a[0].x,a[0].y);
for(var i = 0; i < a.length; i++) {
ctx.moveTo(a[i].x,a[i].y);
}
ctx.closePath();
var p = ctx.isPointInPath(v.x,v.y);
ctx.stroke();
return p;
}
else {
return false;
}
}
/**
* Deep clone a JavaScript object.
* @param {Object} o
*/
PhSim.Query.deepClone = function(o) {
return JSON.parse(JSON.stringify(o));
}
/**
* @function
* @param {*} o
* @param {*} x
* @param {*} y
*/
PhSim.Query.pointInRectangle = function(o,x,y) {
var a = PhSim.Vertices.rectangle(o);
return PhSim.Query.pointInVerts(a,new Vector(x,y));
}
/**
*
* Check if a point (x,y) is in a dynamic object
*
* @function
* @param {PhSim.DynObject} dynObject - Dynamic Object
* @param {Number} x - x-coordinate
* @param {Number} y - y-coordinate
* @returns {Boolean}
*/
PhSim.Query.pointInObject = function(o,x,y) {
if(o.shape === "rectangle") {
return PhSim.Query.pointInRectangle(o,x,y);
}
else if(o.shape === "circle") {
var d = Vector.distance(o,new Vector(x,y));
if(d < o.radius) {
return true;
}
else {
return false;
}
}
else if(o.shape === "regPolygon") {
var a = PhSim.Vertices.regPolygon(o);
return PhSim.Query.pointInVerts(a,new Vector(x,y));
}
else if(o.shape === "polygon") {
return PhSim.Query.pointInVerts(o.verts,new Vector(x,y));
}
}
PhSim.prototype.pointInObject = function(o,x,y) {
return PhSim.Query.pointInObject(o,x,y)
}
/**
* Get object by ID
*
* @function
* @param {String} idNum
* @returns {PhSim.DynObject}
*
*/
PhSim.prototype.getDynObjectByID = function(idNum) {
var a = this.getUniversalObjArray();
for(var i = 0; i < a.length; i++) {
if(a[i].id === idNum) {
return a[i];
}
}
}
/**
*
* Get array of objects that contain a certain point
*
* @function
* @param {Number} x - x-coordinate
* @param {Number} y - y-coordinate
* @returns {PhSim.DynObject[]}
*
*/
PhSim.prototype.pointObjArray = function(x,y) {
var b = [];
var a = this.objUniverse || [];
for(var i = 0; i < a.length; i++) {
if(this.pointInObject(a[i],x,y)) {
b.push(a[i]);
}
}
return b;
}
/**
* Get the collison pairs that contain a certain object
*
* @function
* @param {PhSim.DynObject} dynObject
* @returns {PhSim.phSimCollision[]}
*
*/
PhSim.prototype.getCollisionList = function(dynObject) {
var a = [];
this.matterJSEngine.pairs.list.forEach(function(c){
if(c.bodyA.plugin.dynObject === dynObject || c.bodyB.plugin.dynObject === dynObject) {
var p = new PhSim.Events.PhSimCollision();
p.bodyA = c.bodyA.plugin.dynObject;
p.bodyB = c.bodyA.plugin.dynObject;
p.matter = c;
a.push(p);
}
});
return a;
}
PhSim.prototype.getCollidingMatterBodies = function(body) {
var a = [];
for(var i = 0; i < this.matterJSEngine.pairs.list.length; i++) {
var o = this.matterJSEngine.pairs.list[i];
if(o.bodyA === body) {
a.push(o.bodyB);
}
if(o.bodyB === body) {
a.push(o.bodyA);
}
}
return a;
}
/**
*
* Get array of Dynamic Object colliding some specified colliding object.
*
* @function
* @param {PhSim.DynObject} dynObject - Dynamic Object
* @returns {PhSim.DynObject[]}
*
*/
PhSim.prototype.getCollidingObjects = function(dynObject) {
var a = this.getCollisionList(dynObject);
var b = []
for(var i = 0; i < a.length; i++) {
if(a[i].matter.bodyA.plugin.id === dynObject.id) {
b.push(a[i].bodyB);
}
if(a[i].matter.bodyB.plugin.id === dynObject.id) {
b.push(a[i].bodyA);
}
}
return b;
}
/**
* Get senor classes
*
* @function
* @param {PhSim.DynObject} dynObject
* @returns {String[]}
*/
PhSim.Query.getSensorClasses = function(dynObject) {
if(dynObject.sensorClass) {
var a = dynObject.sensorClass;
var b = a.split(" ");
return b;
}
else {
return [];
}
}
/**
*
* Check if two objects share at least one sensor class
*
* @function
* @param {PhSim.DynObject} dynObjectA
* @param {PhSim.DynObject} dynObjectB
* @returns {Boolean}
*/
PhSim.Query.sameSensorClasses = function(dynObjectA,dynObjectB) {
return PhSim.Query.intersectionExists(PhSim.Query.getSensorClasses(dynObjectA),PhSim.Query.getSensorClasses(dynObjectB));
}
/**
* Sees if `array1` and `array2` share at least one element.
*
* @param {Array} array1
* @param {Array} array2
* @returns {Boolean}
*/
PhSim.Query.intersectionExists = function(array1,array2) {
for(var i = 0; i < array1.length; i++) {
var a = array2.indexOf(array1[i]);
if(a !== -1) {
return true;
}
}
return false;
}
/**
*
* Get objects colliding some object that share the same sensor classes.
*
* @function
* @param {PhSim} phSim - PhSim instance
* @param {PhSim.DynObject} dynObject - Object to check for colliding sensor objects
* @returns {PhSim.DynObject[]}
*/
PhSim.Query.getCollidingSensorObjects = function(phSim,dynObject) {
var a = phSim.getCollisionList(dynObject);
var b = []
for(var i = 0; i < a.length; i++) {
var dynCol = a[i]
var matterCol = dynCol.matter;
if(matterCol.bodyA.plugin.dynObject.id === dynObject.id && PhSim.Query.sameSensorClasses(dynObject,dynCol.bodyB)) {
b.push(dynCol.bodyB);
}
if(matterCol.bodyB.plugin.dynObject.id === dynObject.id && PhSim.Query.sameSensorClasses(dynObject,dynCol.bodyA)) {
b.push(dynCol.bodyA);
}
}
return b;
}
/**
*
* Get objects colliding some object that share the same sensor classes.
*
*
* @function
* @param {PhSim.DynObject} dynObject - Object to check for colliding sensor objects
* @returns {PhSim.DynObject[]}
*/
PhSim.prototype.getCollidingSensorObjects = function(dynObject) {
//return PhSim.Query.getCollidingSensorObjects(this,dynObject)
var a = this.getCollisionList(dynObject);
var b = []
for(var i = 0; i < a.length; i++) {
var dynCol = a[i]
var matterCol = dynCol.matter;
if(matterCol.bodyA.plugin.dynObject.id === dynObject.id && PhSim.Query.sameSensorClasses(dynObject,dynCol.bodyB)) {
b.push(dynCol.bodyB);
}
if(matterCol.bodyB.plugin.dynObject.id === dynObject.id && PhSim.Query.sameSensorClasses(dynObject,dynCol.bodyA)) {
b.push(dynCol.bodyA);
}
}
return b;
}
/**
* @function
* @param {PhSim.DynObject} dynObject
* @returns {Boolean}
*/
PhSim.prototype.inSensorCollision = function(dynObject) {
var a = this.getCollidingSensorObjects(dynObject);
if(a.length > 0) {
return true;
}
else {
return false;
}
}
/**
* @function
* @param {Number} cx - x-coordinate of upper left corner.
* @param {Number} cy - y-coordinate of upper left corner.
* @param {Number} cw - width of rectangle
* @param {Number} ch - height of rectangle
* @param {Number} px - x-coordinate of point to be checked.
* @param {Number} py - y-coordinate of point to be checked.
* @returns {Boolean}
*/
PhSim.Query.isPointInRawRectangle = function(cx,cy,cw,ch,px,py) {
var cond = (cx < px) && (px < cx + cw) && (cy < py) && (py < cy + ch)
if(cond) {
return true;
}
else {
return false;
}
}
/**
*
* Get object that checks the collision relations between two objects
*
* @function
* @param {PhSim.DynObject} dynObjectA - The first object
* @param {PhSim.DynObject} dynObjectB - The second object
* @returns {PhSim.CollisionReport} - A collision report that updates itself after each update
*/
PhSim.prototype.getCollisionChecker = function(dynObjectA,dynObjectB) {
var self = this;
var report = new PhSim.CollisionReport();
report.before = null;
report.current = null;
report.difference = null;
report.objectA = dynObjectA;
report.objectB = dynObjectB;
this.on("beforeupdate",function() {
report.before = self.collided(dynObjectA,dynObjectB);
});
this.on("afterupdate",function() {
report.current = self.collided(dynObjectA,dynObjectB);
report.difference = report.current - report.before;
if(report.difference) {
var eventObj = new PhSim.Events.PhSimDynEvent();
eventObj.report = report;
eventObj.difference = report.difference;
self.callEventClass("collisionchange",self,eventObj);
}
})
return report;
}