diff --git a/libs/events.js b/libs/events.js index 098b9c77..15745e4e 100644 --- a/libs/events.js +++ b/libs/events.js @@ -53,6 +53,31 @@ module.exports = function(s,config,lang){ if(callback)callback(foundInRegion,collisions) return foundInRegion } + const scanMatricesforCollisions = function(region,matrices){ + var matrixPoints = [] + var collisions = [] + if (!region || !matrices){ + if(callback)callback(collisions) + return collisions + } + var polyPoints = [] + region.points.forEach(function(point){ + polyPoints.push(new V(parseInt(point[0]),parseInt(point[1]))) + }) + var regionPoly = new P(new V(0,0), polyPoints) + matrices.forEach(function(matrix){ + if (matrix){ + var matrixPoly = new B(new V(matrix.x, matrix.y), matrix.width, matrix.height).toPolygon() + var response = new SAT.Response() + var collided = SAT.testPolygonPolygon(matrixPoly, regionPoly, response) + if(collided === true){ + collisions.push(matrix) + } + } + }) + return collisions + } + const nonEmpty = (element) => element.length !== 0; const moveLock = {} const getLargestMatrix = (matrices) => { var largestMatrix = {width: 0, height: 0} @@ -161,13 +186,14 @@ module.exports = function(s,config,lang){ s.onEventTriggerBeforeFilterExtensions.forEach(function(extender){ extender(d,filter) }) - var detailString = JSON.stringify(d.details); if(!s.group[d.ke]||!s.group[d.ke].activeMonitors[d.id]){ return s.systemLog(lang['No Monitor Found, Ignoring Request']) } d.mon=s.group[d.ke].rawMonitorConfigurations[d.id]; var currentConfig = s.group[d.ke].rawMonitorConfigurations[d.id].details var hasMatrices = (d.details.matrices && d.details.matrices.length > 0) + var allMatrices = d.details.matrices + var matchedMatrices = [] //read filters if( currentConfig.use_detector_filters === '1' && @@ -192,74 +218,126 @@ module.exports = function(s,config,lang){ } return newVal } + var defaultDrop = true; // forces unmatched events to be dropped + var testMatrices = [...allMatrices] // default var filters = currentConfig.detector_filters + var hasFilters = (filters.length > 0) Object.keys(filters).forEach(function(key){ var conditionChain = {} + testMatrices = [...allMatrices] // for new filter reset the matrices to be tested against var dFilter = filters[key] dFilter.where.forEach(function(condition,place){ conditionChain[place] = {ok:false,next:condition.p4,matrixCount:0} - if(d.details.matrices)conditionChain[place].matrixCount = d.details.matrices.length + if(testMatrices)conditionChain[place].matrixCount = testMatrices.length var modifyFilters = function(toCheck,matrixPosition){ var param = toCheck[condition.p1] var pass = function(){ - if(matrixPosition && dFilter.actions.halt === '1'){ - delete(d.details.matrices[matrixPosition]) - }else{ - conditionChain[place].ok = true - } + conditionChain[place].ok = true + } + var fail = function(){ + if (matrixPosition !== undefined) delete(testMatrices[matrixPosition]) } switch(condition.p2){ case'indexOf': if(param.indexOf(condition.p3) > -1){ pass() + } else { + fail() } break; case'!indexOf': if(param.indexOf(condition.p3) === -1){ pass() + } else { + fail() } break; default: if(eval('param '+condition.p2+' "'+condition.p3.replace(/"/g,'\\"')+'"')){ pass() + } else { + fail() } break; } } - switch(condition.p1){ - case'tag': - case'x': - case'y': - case'height': - case'width': - case'confidence': - if(d.details.matrices){ - d.details.matrices.forEach(function(matrix,position){ - modifyFilters(matrix,position) - }) - } - break; - case'time': - var timeNow = new Date() - var timeCondition = new Date() - var doAtTime = condition.p3.split(':') - var atHour = parseInt(doAtTime[0]) - 1 - var atHourNow = timeNow.getHours() - var atMinuteNow = timeNow.getMinutes() - var atSecondNow = timeNow.getSeconds() - if(atHour){ - var atMinute = parseInt(doAtTime[1]) - 1 || timeNow.getMinutes() - var atSecond = parseInt(doAtTime[2]) - 1 || timeNow.getSeconds() - var nowAddedInSeconds = atHourNow * 60 * 60 + atMinuteNow * 60 + atSecondNow - var conditionAddedInSeconds = atHour * 60 * 60 + atMinute * 60 + atSecond - if(eval('nowAddedInSeconds '+condition.p2+' conditionAddedInSeconds')){ - conditionChain[place].ok = true + if (testMatrices.some(nonEmpty)){ + switch(condition.p1){ + case'tag': + case'x': + case'y': + case'height': + case'width': + case'confidence': + if(testMatrices){ + testMatrices.forEach(function(matrix,position){ + if (matrix) modifyFilters(matrix,position) + }) } - } - break; - default: - modifyFilters(d.details) - break; + break; + case'name': + if (testMatrices){ + var regions = s.group[d.ke].activeMonitors[d.id].parsedObjects.cords + regions.forEach(function(region,position){ + switch(condition.p2){ + case'indexOf': + if(region.name.indexOf(condition.p3) > -1){ + testMatrices = testMatrices.concat(scanMatricesforCollisions(region,testMatrices)); + if(testMatrices.some(nonEmpty)) conditionChain[place].ok = true; // default is false + } + break; + case'!indexOf': + if(region.name.indexOf(condition.p3) === -1){ + testMatrices = testMatrices.concat(scanMatricesforCollisions(region,testMatrices)); + if(testMatrices.some(nonEmpty)) conditionChain[place].ok = true; // default is false + } + break; + case'===': + if(region.name === condition.p3){ + testMatrices = scanMatricesforCollisions(region,testMatrices); + if(testMatrices.some(nonEmpty)) conditionChain[place].ok = true; // default is false + } + break; + case'!==': + if(region.name !== condition.p3){ + testMatrices = testMatrices.concat(scanMatricesforCollisions(region,testMatrices)); + if(testMatrices.some(nonEmpty)) conditionChain[place].ok = true; // default is false + } + break; + default: + //s.systemLog(lang['Numeric criteria unsupported for Region tests, Ignoring Conditional']) + s.systemLog('Numeric criteria unsupported for Region tests, Ignoring Conditional') + break; + } + }); + } + break; + case'time': + var timeNow = new Date() + var timeCondition = new Date() + var doAtTime = condition.p3.split(':') + var atHour = parseInt(doAtTime[0]) - 1 + var atHourNow = timeNow.getHours() + var atMinuteNow = timeNow.getMinutes() + var atSecondNow = timeNow.getSeconds() + if(atHour){ + var atMinute = parseInt(doAtTime[1]) - 1 || timeNow.getMinutes() + var atSecond = parseInt(doAtTime[2]) - 1 || timeNow.getSeconds() + var nowAddedInSeconds = atHourNow * 60 * 60 + atMinuteNow * 60 + atSecondNow + var conditionAddedInSeconds = atHour * 60 * 60 + atMinute * 60 + atSecond + if(eval('nowAddedInSeconds '+condition.p2+' conditionAddedInSeconds')){ + conditionChain[place].ok = true + } + } + break; + default: + modifyFilters(d.details) + break; + } + } + if (condition.p4 === '||' || dFilter.where.length-1 === place){ + if (testMatrices.length > 0) matchedMatrices = matchedMatrices.concat(testMatrices) + testMatrices = [...allMatrices] // reset matrices for next group of conditions } }) var conditionArray = Object.values(conditionChain) @@ -277,19 +355,28 @@ module.exports = function(s,config,lang){ var value = dFilter.actions[key] filter[key] = parseValue(key,value) }) + defaultDrop = false; }else{ filter.halt = true } } }) - if(d.details.matrices && d.details.matrices.length === 0 || filter.halt === true){ + if(filter.halt === true){ return }else if(hasMatrices){ - var reviewedMatrix = [] - d.details.matrices.forEach(function(matrix){ - if(matrix)reviewedMatrix.push(matrix) - }) - d.details.matrices = reviewedMatrix + // remove empty elements + matchedMatrices = matchedMatrices.filter(value => Object.keys(value).length !== 0) + // remove duplicate matches + matchedMatrices = matchedMatrices.filter((matrix, index, self) => + index === self.findIndex((t) => ( + t.x === matrix.x && t.y === matrix.y && t.tag === matrix.tag && t.confidence === matrix.confidence + )) + ) + d.details.matrices = matchedMatrices + } + // -- delayed decision here -- + if (defaultDrop && hasFilters) { + return; } } var eventTime = new Date() @@ -325,8 +412,21 @@ module.exports = function(s,config,lang){ // check if object should be in region if(hasMatrices && currentConfig.detector_obj_region === '1'){ var regions = s.group[d.ke].activeMonitors[d.id].parsedObjects.cords - var isMatrixInRegions = isAtleastOneMatrixInRegion(regions,d.details.matrices) - if(isMatrixInRegions){ + testMatrices = d.details.matrices // matrices that made it passed filters + matchedMatrices = [] + regions.forEach(function(region,position){ + matchedMatrices = matchedMatrices.concat(scanMatricesforCollisions(region,testMatrices)); + }) + if (matchedMatrices.length > 2){ + // remove duplicate matches + matchedMatrices = matchedMatrices.filter((matrix, index, self) => + index === self.findIndex((t) => ( + t.x === matrix.x && t.y === matrix.y && t.tag === matrix.tag && t.confidence === matrix.confidence + )) + ) + } + d.details.matrices = matchedMatrices // pass matrices that are within a region + if(d.details.matrices && d.details.matrices.length > 0){ s.debugLog('Matrix in region!') if(filter.countObjects && currentConfig.detector_obj_count === '1' && currentConfig.detector_obj_count_in_region === '1' && !didCountingAlready){ countObjects(d) @@ -369,6 +469,7 @@ module.exports = function(s,config,lang){ } //save this detection result in SQL, only coords. not image. if(forceSave || (filter.save && currentConfig.detector_save === '1')){ + var detailString = JSON.stringify(d.details); s.sqlQuery('INSERT INTO Events (ke,mid,details,time) VALUES (?,?,?,?)',[d.ke,d.id,detailString,eventTime]) } if(currentConfig.detector === '1' && currentConfig.detector_notrigger === '1'){