123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662 |
- var grendCAD = (function grentWall() {
- var util = {
- isInfinity(num) {
- return num === Infinity || num === -Infinity
- },
- /**
- * 获取一组坐标的XY坐标区间
- * @param {*} points
- */
- getSection(points) {
- var ret = {
- minx: points[0].x,
- maxx: points[0].x,
- miny: points[0].y,
- maxy: points[0].y
- }
- points.forEach(function (point) {
- if (ret.minx > point.x) {
- ret.minx = point.x
- }
- if (ret.maxx < point.x) {
- ret.maxx = point.x
- }
- if (ret.miny > point.y) {
- ret.miny = point.y
- }
- if (ret.maxy < point.y) {
- ret.maxy = point.y
- }
- })
- return ret
- },
- /**
- * 计算垂直向量
- * @param {向量} arr
- */
- verticalLine(line) {
- var arr = [
- line.points[1].x - line.points[0].x,
- line.points[1].y - line.points[0].y
- ]
- if (arr.length !== 0) {
- var x, y;
- y = Math.sqrt(1 / ((arr[1] * arr[1]) / (arr[0] * arr[0]) + 1));
- x = Math.sqrt(1 - y * y);
- return [x, y];
- }
- return [];
- },
- /**
- * 将所有坐标转化为指定范围之间的值,但是保持比例不变
- * @param {*} points 要转化的坐标
- * @param {*} section 指定范围
- * @returns Array 转化后的值
- */
- tranProp(points, section) {
- var args = util.getSection(points)
- var xlen = args.maxx - args.minx
- var ylen = args.maxy - args.miny
- var prop = xlen > ylen ? xlen : ylen
- var offsetX = -(args.minx + xlen / 2)
- var offsetY = -(args.miny + ylen / 2)
- var range = section[1] - section[0]
- return {
- offset: {
- x: offsetX,
- y: offsetY
- },
- prop,
- range: range
- }
- },
- /**
- * 将屏幕转化为真实坐标
- * @param {*} point
- * @param {*} section
- */
- tranPoint(point, section) {
- return {
- x: point.x + section.minx,
- y: point.y + section.miny
- }
- },
- /**
- * 判断点是否在线上
- * @param {*} point 要判断的点
- * @param {*} line 线段
- * @param {*} width 线宽
- */
- isContainPoint(point, line, width) {
- var dis = 0
- var s1 = line[1].x - line[0].x
- var s2 = point.x - line[0].x
- var s3 = point.x - line[1].x
- var k1 = line[1].y - line[0].y
- var k2 = point.y - line[0].y
- var k3 = point.y - line[1].y
- var max = width / 2
- var min = 0 - max
- var cross = s1 * s2 + k1 * k2;
- var d2 = s1 * s1 + k1 * k1;
- if (cross <= 0) {
- dis = Math.sqrt(s2 * s2 + k2 * k2);
- } else if (cross >= d2) {
- dis = Math.sqrt(s3 * s3 + k3 * k3);
- } else {
- var r = cross / d2;
- var px = line[0].x + s1 * r;
- var py = line[0].y + k1 * r;
- dis = Math.sqrt((point.x - px) * (point.x - px) + (py - point.y) * (py - point.y));
- }
- return dis >= min && dis <= max
- },
- /**
- * 判断两条线段是否相交
- * @param {*} line1
- * @param {*} line2
- */
- isLineIntersect(line1, line2) {
- var a1 = line1[1].y - line1[0].y;
- var b1 = line1[0].x - line1[1].x;
- var c1 = a1 * line1[0].x + b1 * line1[0].y;
- //转换成一般式: Ax+By = C
- var a2 = line2[1].y - line2[0].y;
- var b2 = line2[0].x - line2[1].x;
- var c2 = a2 * line2[0].x + b2 * line2[0].y;
- // 计算交点
- var d = a1 * b2 - a2 * b1;
- // 当d==0时,两线平行
- if (d == 0) {
- return false;
- } else {
- var x = (b2 * c1 - b1 * c2) / d;
- var y = (a1 * c2 - a2 * c1) / d;
- // 检测交点是否在两条线段上
- if ((isInBetween(line1[0].x, x, line1[1].x) || isInBetween(line1[0].y, y, line1[1].y)) &&
- (isInBetween(line2[0].x, x, line2[1].x) || isInBetween(line2[0].y, y, line2[1].y))) {
- return true;
- }
- }
- function isInBetween(a, b, c) {
- // 如果b几乎等于a或c,返回false.为了避免浮点运行时两值几乎相等,但存在相差0.00000...0001的这种情况出现使用下面方式进行避免
- if (Math.abs(a - b) < 0.000001 || Math.abs(b - c) < 0.000001) {
- return false;
- }
- return (a <= b && b <= c) || (c <= b && b <= a);
- }
- return false;
- },
- /**
- * 判断两个点是否相同
- * @param {*} point1
- * @param {*} poin2
- */
- equalPoint(point1, poin2) {
- return point1.x === poin2.x && point1.y === poin2.y
- },
- /**
- * 判断两个面是否相交,
- * @param {*} face1
- * @param {*} face2
- */
- isFaceIntersect(face1, face2) {
- for (var i = 0; i < face1.length; i++) {
- var next = i + 1 === face1.length ? 0 : i + 1
- var line1 = [face1[i], face1[next]]
- for (var j = 0; j < face2.length; j++) {
- var next = j + 1 === face2.length ? 0 : j + 1
- var line2 = [face2[j], face2[next]]
- var isIntersect1 = util.isLineIntersect(line2, line1)
- var isIntersect2 = util.isLineIntersect(line1, line2)
- if (isIntersect1 && isIntersect2) {
- return true
- }
- }
- }
- },
- /**
- * 判断一个点是否在面上
- * @param {*} face1
- * @param {*} face2
- */
- pointInside(point, face) {
- var inside = false;
- var x = point.x,
- y = point.y;
- for (var i = 0, j = face.length - 1; i < face.length; j = i++) {
- var xi = face[i].x,
- yi = face[i].y;
- var xj = face[j].x,
- yj = face[j].y;
- if (((yi > y) != (yj > y)) &&
- (x < (xj - xi) * (y - yi) / (yj - yi) + xi)) {
- inside = !inside;
- }
- }
- return inside;
- }
- }
- var drawShape = {
- line(context, line, width) {
- context.strokeStyle = 'red';
- context.lineWidth = width;
- context.beginPath();
- context.moveTo(line[0].x, line[0].y);
- context.lineTo(line[1].x, line[1].y);
- context.closePath();
- context.stroke();
- },
- camera(context, point, width) {
- context.fillStyle = "#00cc00";
- context.fillRect(point.x - width / 2, point.y - width / 2, width, width);
- }
- }
- /**
- * 获取面的所有点
- * @param {*} face
- */
- function getFacePoints(face) {
- var start = face[0]
- var ret = []
- var iteration = start
- do {
- ret.push(iteration.points[0])
- iteration = face.find(function (item) {
- return item.id === iteration.linkedLineID[1]
- })
- } while (start !== iteration)
- return ret
- }
- /**
- * 获取一个元素在指定父元素或文档中的位置
- */
- function getPosition(dom, parent) {
- var ret = {
- x: 0,
- y: 0
- }
- while (dom && dom !== parent && dom !== document.documentElement) {
- console.log(dom)
- ret.x += dom.offsetLeft
- ret.y += dom.offsetTop
- dom = dom.offsetParent
- }
- return ret
- }
- function addMouseEvent(dom, event) {
- dom.addEventListener('mousedown', function downHandle(ev) {
- var prevPoint = {
- x: ev.pageX,
- y: ev.pageY
- }
- var con = event.down(prevPoint)
- if (!con) return;
- document.documentElement.addEventListener('mousemove', moveHandle, {
- passive: false
- })
- document.documentElement.addEventListener('mouseup', endHandle, {
- passive: false
- })
- function moveHandle(ev) {
- event.move({
- x: ev.pageX,
- y: ev.pageY
- }, prevPoint)
- prevPoint = {
- x: ev.pageX,
- y: ev.pageY
- }
- }
- function endHandle(ev) {
- document.documentElement.removeEventListener('mousemove', moveHandle, {
- passive: false
- })
- document.documentElement.removeEventListener('mouseup', endHandle, {
- passive: false
- })
- event.up()
- }
- }, false)
- }
- function Wall(canvas, data, cameras, cal) {
- this.canvas = canvas
- this.context = canvas.getContext('2d')
- this.origin = data
- this.lineWidth = 2
- this.cameras = cameras
- this.cal = cal
- this.stateStack = []
- this.init()
- this.draw()
- }
- Wall.prototype.init = function () {
- this.width = this.canvas.width
- this.height = this.canvas.height
- this.wMultiple = this.canvas.width / this.canvas.offsetWidth
- this.hMultiple = this.canvas.height / this.canvas.offsetHeight
- this.context.translate(this.width / 2, this.height / 2);
- this.screenOffset = getPosition(this.canvas)
-
- var points = []
- var faces = {}
- this.origin.forEach(function (line) {
- if (faces[line.roomIndex]) {
- faces[line.roomIndex].push(line)
- } else {
- faces[line.roomIndex] = [line]
- }
- points = points.concat(...line.points)
- })
- var result = util.tranProp(points, [-0.99, 0.99])
- this.status = {
- offset: result.offset,
- prop: result.prop,
- range: result.range
- }
- this.faces = faces
- this.regEvent()
- }
- Wall.prototype.transScreenPoint = function (point) {
- var spoint = {
- x: point.x,
- y: point.y
- }
- spoint.x += this.status.offset.x
- spoint.y += this.status.offset.y
- spoint.x = (spoint.x * this.status.range / this.status.prop) * (this.width / 2)
- spoint.y = (spoint.y * this.status.range / this.status.prop) * (this.height / 2)
- return spoint
- }
- Wall.prototype.transRealPoint = function (point) {
- return {
- x: (point.x * this.status.prop) / (this.status.range * this.width / 2) - this.status.offset.x,
- y: (point.y * this.status.prop) / (this.status.range * this.height / 2) - this.status.offset.y
- }
- }
- Wall.prototype.regEvent = function () {
- var sinfo;
- var section = {
- minx: -this.width / 2,
- maxx: this.width / 2,
- miny: -this.height / 2,
- maxy: this.height / 2
- }
- var startPoint = null
- var dirct = null
- var event = {
- down(offset) {
- console.log(offset, this.screenOffset)
- offset.x = (offset.x - this.screenOffset.x) * this.wMultiple
- offset.y = (offset.y - this.screenOffset.y) * this.hMultiple
- startPoint = this.transRealPoint(util.tranPoint(offset, section))
- sinfo = this._down(startPoint)
- prevPoint = startPoint
- return !!sinfo
- },
- move(move) {
- console.log(move)
- move.x = (move.x - this.screenOffset.x) * this.wMultiple
- move.y = (move.y - this.screenOffset.y) * this.hMultiple
- var point = this.transRealPoint(util.tranPoint(move, section))
- if (!dirct) {
- dirct = sinfo.dire[0] - sinfo.dire[1] > 0 ? 'X' : 'Y'
- }
- this._move(point, prevPoint, sinfo, dirct)
- prevPoint = point
- },
- up() {
- dirct = null
- startPoint = null
- }
- }
- event.down = event.down.bind(this)
- event.move = event.move.bind(this)
- event.up = event.up.bind(this)
- addMouseEvent(this.canvas, event)
- }
- Wall.prototype._down = function (point) {
- this.preservationState()
- for (var key in this.faces) {
- var face = this.faces[key]
- for (var i = 0, line; line = face[i]; i++) {
- if (util.isContainPoint(point, line.points, (this.lineWidth + 4) / this.status.prop)) {
- return {
- face: face,
- line: line,
- dire: util.verticalLine(line)
- }
- }
- }
- }
- }
- Wall.prototype.updateLine = function (line, x, y) {
- if (!x && !y) return;
- var face
- for (var key in this.faces) {
- var index = this.faces[key].findIndex(function (item) {
- return item === line
- })
- if (~index) {
- face = this.faces[key]
- break
- }
- }
- if (!face) return
- var prevLine = face.find(function (cLine) {
- return line.linkedLineID[0] === cLine.id
- })
- var lastLine = face.find(function (cLine) {
- return line.linkedLineID[1] === cLine.id
- })
- var prevK = (prevLine.points[1].y - prevLine.points[0].y) / (prevLine.points[1].x - prevLine.points[0].x)
- var lastK = (lastLine.points[1].y - lastLine.points[0].y) / (lastLine.points[1].x - lastLine.points[0].x)
- var prevX, prevY, lastX, lastY
- if (x) {
- prevX = prevLine.points[1].x + x
- prevY = (prevX - prevLine.points[0].x) * prevK + prevLine.points[0].y
- lastX = lastLine.points[0].x + x
- lastY = (lastX - lastLine.points[0].x) * lastK + lastLine.points[0].y
- } else {
- prevY = prevLine.points[1].y + y
- prevX = (prevY - prevLine.points[0].y) / prevK + prevLine.points[0].x
- lastY = lastLine.points[0].y + y
- lastX = (lastY - lastLine.points[0].y) / lastK + lastLine.points[0].x
- }
- if (util.isInfinity(prevX) ||
- util.isInfinity(prevY) ||
- util.isInfinity(lastX) ||
- util.isInfinity(lastY)) {
- console.log('???')
- prevX = prevLine.points[1].x + x
- prevY = prevLine.points[1].y + y
- lastX = lastLine.points[0].x + x
- lastY = lastLine.points[0].y + y
- }
- prevLine.points[1].x = prevX
- prevLine.points[1].y = prevY
- lastLine.points[0].x = lastX
- lastLine.points[0].y = lastY
- line.points[0].x = prevLine.points[1].x
- line.points[0].y = prevLine.points[1].y
- line.points[1].x = lastLine.points[0].x
- line.points[1].y = lastLine.points[0].y
- }
- Wall.prototype._move = function (point, prevPoint, movePosition, dirct) {
- var xdis = point.x - prevPoint.x
- var ydis = point.y - prevPoint.y
- var revoke = false
- if (dirct === 'X') {
- this.updateLine(movePosition.line, xdis, 0)
- } else {
- this.updateLine(movePosition.line, 0, ydis)
- }
- var activeFacePoint = getFacePoints(movePosition.face)
- for (let key in this.faces) {
- if (this.faces[key] !== movePosition.face &&
- util.isFaceIntersect(activeFacePoint, getFacePoints(this.faces[key]))) {
- revoke = true;
- break;
- }
- }
- var cameras;
- if (this.cameras && (cameras = this.cameras[movePosition.face[0].roomIndex])) {
- for (var i = 0, camera; camera = cameras[i]; i++) {
- if (!util.pointInside(camera, activeFacePoint)) {
- revoke = true
- break;
- }
- }
- }
- if (revoke) {
- if (dirct === 'X') {
- this.updateLine(movePosition.line, -xdis, 0)
- } else {
- this.updateLine(movePosition.line, 0, -ydis)
- }
- } else {
- this.cal && this.cal.changePoint && this.cal.changePoint(movePosition.line)
- this.draw()
- }
- }
- Wall.prototype.draw = function () {
- this.context.clearRect(-this.width / 2, -this.height / 2, this.width, this.height)
- for (var key in this.faces) {
- var face = this.faces[key]
- for (var i = 0, line; line = face[i]; i++) {
- drawShape.line(
- this.context,
- [
- this.transScreenPoint(line.points[0]),
- this.transScreenPoint(line.points[1])
- ],
- this.lineWidth
- )
- }
- }
- if (this.cameras) {
- for (var key in this.cameras) {
- for (var i = 0; i < this.cameras[key].length; i++) {
- drawShape.camera(this.context, this.transScreenPoint(this.cameras[key][i]), this.lineWidth)
- }
- }
- }
- }
- Wall.prototype.preservationState = function () {
- var state = {}
- for (var key in this.faces) {
- state[key] = {}
- for (var i = 0; i < this.faces[key].length; i++) {
- var line = this.faces[key][i]
- state[key][line.id] = [
- {x: line.points[0].x, y: line.points[0].y},
- {x: line.points[1].x, y: line.points[1].y}
- ]
- }
- }
- this.stateStack.push(state)
- }
- Wall.prototype.revokeState = function () {
- var state = this.stateStack.pop()
- for (var key in state) {
- for (var id in state[key]) {
- var cline = state[key][id]
- var line = this.faces[key].find(function (line) {
- return line.id === id
- })
- line.points[0].x = cline[0].x
- line.points[0].y = cline[0].y
- line.points[1].x = cline[1].x
- line.points[1].y = cline[1].y
- }
- }
- this.draw();
- }
- return function (dom, line2Ds, cameras) {
- function getLine(id) {
- return line2Ds.find(function (line) {
- return line.id === id
- })
- }
- let wall = new Wall(dom, line2Ds, cameras, {
- changePoint: function (line2D) {
- if (line2D.updateLine3D) {
- line2D.updateLine3D()
- getLine(line2D.linkedLineID[0]).updateLine3D()
- getLine(line2D.linkedLineID[1]).updateLine3D()
- } else {
- console.error('当前线条没有注册3D线条方法')
- }
- }
- });
- line2Ds.forEach(function (line2D) {
- var update = line2D.update
- line2D.update = function (dirs, len) {
- var args = [{
- x: 0,
- y: 0
- },
- {
- x: 0,
- y: 0
- },
- {
- line: this,
- face: wall.faces[this.roomIndex]
- }
- ]
- args[0][dirs[0]] = len;
- wall._move.apply(wall, args.concat([dirs[1]]))
- update && update.bind(this)()
- }
- })
- return wall;
- }
- })();
|