| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294 | // ******* Region MANAGER ******** //$axure.internal(function($ax) {    var _geometry = $ax.geometry = {};    var regionMap = {};    var regionList = [];    var _unregister = function(label) {        var regionIndex = regionList.indexOf(label);        if(regionIndex != -1) {            var end = $ax.splice(regionList, regionIndex + 1);            $ax.splice(regionList, regionIndex, regionList.length - regionIndex);            regionList = regionList.concat(end);        }        delete regionMap[label];    };    _geometry.unregister = _unregister;    var clear = function() {        regionMap = {};        regionList = [];    };    var _polygonRegistered = function(label) {        return Boolean(regionMap[label]);    };    _geometry.polygonRegistered = _polygonRegistered;    // Must be counterclockwise, or enter/exit will be wrong    var _registerPolygon = function(label, points, callback, info) {        var regionIndex = regionList.indexOf(label);        if(regionIndex == -1) regionList.push(label);        regionMap[label] = { points: points, callback: callback, info: info };    };    _geometry.registerPolygon = _registerPolygon;    var _getPolygonInfo = function(label) {        if(!_polygonRegistered(label)) return undefined;        return regionMap[label].info;    };    _geometry.getPolygonInfo = _getPolygonInfo;    var _genRect = function(info, roundHalfPixel) {        var x = info.pagex();        var y = info.pagey();        var w = info.width();        var h = info.height();        if(roundHalfPixel) {            if(x % 1 != 0) {                x = Math.floor(x);                w++;            }            if(y % 1 != 0) {                y = Math.floor(y);                h++;            }        }        var r = x + w;        var b = y + h;        var rect = {            X: function() { return x; },            Y: function() { return y; },            Wigth: function() { return w; },            Height: function() { return h; },            Left: function() { return x; },            Right: function() { return r; },            Top: function() { return y; },            Bottom: function() { return b; }        };        return rect;    };    _geometry.genRect = _genRect;    var _genPoint = function(x, y) {        return { x: x, y: y };    };    _geometry.genPoint = _genPoint;    var oldPoint = _genPoint(0, 0);    _geometry.tick = function(x, y, end) {        var lastPoint = oldPoint;        var nextPoint = oldPoint = _genPoint(x, y);        var line = { p1: lastPoint, p2: nextPoint };        if(!regionList.length) return;        for(var i = 0; i < regionList.length; i++) {            var region = regionMap[regionList[i]];            var points = region.points;            for(var j = 0; j < points.length; j++) {                var startSegment = points[j];                var endSegment = points[(j + 1) % points.length];                var intersectInfo = linesIntersect(line, { p1: startSegment, p2: endSegment });                if(intersectInfo) {                    region.callback(intersectInfo);                    break;                }            }        }        if(end) clear();    };    // Info if the one line touches the other (even barely), false otherwise    // Info includes point, if l1 is entering or exiting l2, and any ties that happened, or parallel info    var linesIntersect = function(l1, l2) {        var retval = {};        var ties = {};        var l1p1 = l1.p1.x < l1.p2.x || (l1.p1.x == l1.p2.x && l1.p1.y < l1.p2.y) ? l1.p1 : l1.p2;        var l1p2 = l1.p1.x < l1.p2.x || (l1.p1.x == l1.p2.x && l1.p1.y < l1.p2.y) ? l1.p2 : l1.p1;        var m1 = (l1p2.y - l1p1.y) / (l1p2.x - l1p1.x);        var l2p1 = l2.p1.x < l2.p2.x || (l2.p1.x == l2.p2.x && l2.p1.y < l2.p2.y) ? l2.p1 : l2.p2;        var l2p2 = l2.p1.x < l2.p2.x || (l2.p1.x == l2.p2.x && l2.p1.y < l2.p2.y) ? l2.p2 : l2.p1;        var m2 = (l2p2.y - l2p1.y) / (l2p2.x - l2p1.x);        var l1Vert = l1.p1.x == l1.p2.x;        var l2Vert = l2.p1.x == l2.p2.x;        if(l1Vert || l2Vert) {            if(l1Vert && l2Vert) {                // If the lines don't follow the same path, return                if(l1p1.x != l2p1.x) return false;                // if they never meet, return                if(l1p2.y < l2p1.y || l1p1.y > l2p2.y) return false;                var firstVert = l1p1.y >= l2p1.y ? l1p1 : l2p1;                var secondVert = l1p2.y <= l2p2.y ? l1p2 : l2p2;                // First is from the perspective of l1                retval.parallel = {                    first: l1p1 == l1.p1 ? firstVert : secondVert,                    second: l1p2 == l1.p2 ? secondVert : firstVert,                    sameDirection: (l1p1 == l1.p1) == (l2p1 == l2.p1)                };                return retval;            }            var x1 = l2Vert ? l1p1.x : l2p1.x;            var x2 = l2Vert ? l1p2.x : l2p2.x;            var xVert = l2Vert ? l2p1.x : l1p1.x;            var y = l2Vert ? l1p1.y + (xVert - x1) * m1 : l2p1.y + (xVert - x1) * m2;            var y1 = l2Vert ? l2p1.y : l1p1.y;            var y2 = l2Vert ? l2p2.y : l1p2.y;            if(xVert >= x1 && xVert <= x2 && y >= y1 && y <= y2) {                retval.point = { x: xVert, y: y };                retval.exiting = l2Vert == (y1 == (l2Vert ? l2.p1.y : l1.p1.y)) == (x1 == (l2Vert ? l1.p1.x : l2.p1.x));                retval.entering = !retval.exiting;                // Calculate ties                if(x1 == xVert) {                    ties[l2Vert ? 'l1' : 'l2'] = (x1 == (l2Vert ? l1.p1.x : l2.p1.x)) ? 'start' : 'end';                    retval.ties = ties;                } else if(x2 == xVert) {                    ties[l2Vert ? 'l1' : 'l2'] = (x2 == (l2Vert ? l1.p2.x : l2.p2.x)) ? 'end' : 'start';                    retval.ties = ties;                }                if(y1 == y) {                    ties[l2Vert ? 'l2' : 'l1'] = (y1 == (l2Vert ? l2.p1.y : l1.p1.y)) ? 'start' : 'end';                    retval.ties = ties;                } else if(y2 == y) {                    ties[l2Vert ? 'l2' : 'l1'] = (y2 == (l2Vert ? l2.p2.y : l1.p2.y)) ? 'end' : 'start';                    retval.ties = ties;                }                return retval;            }            return false;        }        // If here, no vertical lines        if(m1 == m2) {            // If the lines don't follow the same path, return            if(l1p1.y != (l2p1.y + (l1p1.x - l2p1.x) * m1)) return false;            // if they never meet, return            if(l1p2.x < l2p1.x || l1p1.x > l2p2.x) return false;            var first = l1p1.x >= l2p1.x ? l1p1 : l2p1;            var second = l1p2.x <= l2p2.x ? l1p2 : l2p2;            // First is from the perspective of l1            retval.parallel = {                first: l1p1 == l1.p1 ? first : second,                second: l1p2 == l1.p2 ? second : first,                sameDirection: (l1p1 == l1.p1) == (l2p1 == l2.p1)            };            return retval;        }        var x = (l2p1.y - l2p1.x * m2 - l1p1.y + l1p1.x * m1) / (m1 - m2);        // Check if x is out of bounds        if(x >= l1p1.x && x <= l1p2.x && x >= l2p1.x && x <= l2p2.x) {            var y = l1p1.y + (x - l1p1.x) * m1;            retval.point = { x: x, y: y };            retval.entering = m1 > m2 == (l1p1 == l1.p1) == (l2p1 == l2.p1);            retval.exiting = !retval.entering;            // Calculate ties            if(l1.p1.x == x) {                ties.l1 = 'start';                retval.ties = ties;            } else if(l1.p2.x == x) {                ties.l1 = 'end';                retval.ties = ties;            }            if(l2.p1.x == x) {                ties.l2 = 'start';                retval.ties = ties;            } else if(l2.p2.x == x) {                ties.l2 = 'end';                retval.ties = ties;            }            return retval;        }        return false;    };    var _checkInsideRegion = function(label, point) {        if(!_polygonRegistered(label)) return false;        return _checkInside(regionMap[label].points, point || $ax.mouseLocation);    };    _geometry.checkInsideRegion = _checkInsideRegion;    // Returns true if point is inside the polygon, including ties    var _checkInside = function(polygon, point) {        // Make horizontal line wider than the polygon, with the y of point to test location        var firstX = polygon[0].x;        var secondX = firstX;        var i;        for(i = 1; i < polygon.length; i++) {            var polyX = polygon[i].x;            firstX = Math.min(firstX, polyX);            secondX = Math.max(secondX, polyX);        }        var line = {            p1: _genPoint(--firstX, point.y),            p2: _genPoint(++secondX, point.y)        };        // If entered true, with closest intersection says you are inside the polygon.        var entered = false;        // Closest is the closest intersection to the left of the point        var closest = line.p1.x;        // This is for if intersections hit the same point, to find out which is correct        var cos = -2;        var getCos = function(line) {            var x = line.p2.x - line.p1.x;            var y = line.p2.y - line.p1.y;            return x / Math.sqrt(x * x + y * y);        };        for(i = 0; i < polygon.length; i++) {            var polyLine = { p1: polygon[i], p2: polygon[(i + 1) % polygon.length] };            var intersectInfo = linesIntersect(line, polyLine);            if(!intersectInfo) continue;            if(intersectInfo.parallel) {                // Only really care about this if it actually touches the point                if(intersectInfo.parallel.first.x <= point.x && intersectInfo.parallel.second.x >= point.x) return true;                continue;            }            var intersectionX = intersectInfo.point.x;            if(intersectionX > point.x || intersectionX < closest) continue;            if(intersectionX == point.x) return true;            // If closer than last time, reset cosine.            if(intersectionX != closest) cos = -2;            // For getting cosine, need to possibly reverse the direction of polyLine.            if(intersectInfo.ties) {                // Tie must be on l2, if the ties is end, reverse so cosine indicates how close the angle is to that of 'point' from here.                if(intersectInfo.ties.l2 == 'end') polyLine = { p1: polyLine.p2, p2: polyLine.p1 };            } else {                // It is on both side, so you can take the larger one                if(polyLine.p1.x > polyLine.p2.x) polyLine = { p1: polyLine.p2, p2: polyLine.p1 };            }            var currCos = getCos(polyLine);            if(currCos > cos) {                cos = currCos;                closest = intersectionX;                entered = intersectInfo.entering;            }        }        return entered;    };    _geometry.checkInside = _checkInside;});
 |