import * as turf from '@turf/turf'
import {
Point,
Polygon,
LineString,
MultiLineString,
SpatialReference
} from '../../base/geometry'
import GeometryEngine from '../../base/geometry/GeometryEngine'
import { Projection } from '../../base'
import { defaultValue } from '../../util'
/**
* 草图捕捉工具类
* @class SketchPolygonDrawTool
* @moduleEX SketchEditorModule
* @param {Object} options 构造参数
* @param {Object} [options.pixelTolerance] 容差(像素单位)
* @param {Object} [options.tolerance] 容差(米单位)
* @param {Object} [options.isSnapVertex] 是否自动捕捉顶点
* @param {Object} [options.isSnapVertexInLine] 是否自动捕捉线上的点
* @param {Object} [options.isSnapPerpendicular] 是否自动捕捉垂点
* @param {Object} [options.isSnapParallel] 是否自动捕捉水平交点
*/
class SketchSnappingTool {
constructor(options) {
/**
* 像素容差
* @member {Number} SketchSnappingTool.prototype.pixelTolerance
*/
this.pixelTolerance = 10
/**
* 容差(米单位)
* @member {Number} SketchSnappingTool.prototype.tolerance
*/
this.tolerance = 5
/**
*斜率容差
* @member {Number} SketchSnappingTool.prototype.toleranceSlope
*/
this.toleranceSlope = 0.02
/**
*是否自动捕捉顶点
* @member {Boolean} SketchSnappingTool.prototype.isSnapVertex
*/
this.isSnapVertex = false
/**
*是否自动捕捉顶点重合
* @member {Boolean} SketchSnappingTool.prototype.isSnapVertexCoincident
*/
this.isSnapVertexCoincident = defaultValue(
options.isSnapVertexCoincident,
false
)
/**
*是否自动捕捉线上的点
* @member {Boolean} SketchSnappingTool.prototype.isSnapVertexInLine
*/
this.isSnapVertexInLine = defaultValue(options.isSnapVertexInLine, false)
/**
*是否自动捕捉垂线垂点
* @member {Boolean} SketchSnappingTool.prototype.isSnapPerpendicular
*/
this.isSnapPerpendicular = defaultValue(options.isSnapPerpendicular, false)
/**
*是否自动捕捉平行线
* @member {Boolean} SketchSnappingTool.prototype.isSnapParallel
*/
this.isSnapParallel = defaultValue(options.isSnapParallel, false)
/**
*是否捕捉正在绘制的图形的边界
* @member {Boolean} SketchSnappingTool.prototype.snapSketchGeometry
*/
this.snapSketchGeometry = defaultValue(options.snapSketchGeometry, false)
this._view = defaultValue(options.view, null)
}
setSnapOption(snapOption) {
this.isSnapVertexCoincident =
snapOption.isSnapVertexCoincident !== undefined
? snapOption.isSnapVertexCoincident
: this.isSnapVertexCoincident
this.isSnapVertexInLine =
snapOption.isSnapVertexInLine !== undefined
? snapOption.isSnapVertexInLine
: this.isSnapVertexInLine
this.isSnapParallel =
snapOption.isSnapParallel !== undefined
? snapOption.isSnapParallel
: this.isSnapParallel
this.isSnapPerpendicular =
snapOption.isSnapPerpendicular !== undefined
? snapOption.isSnapPerpendicular
: this.isSnapPerpendicular
this.snapSketchGeometry =
snapOption.snapSketchGeometry !== undefined
? snapOption.snapSketchGeometry
: this.snapSketchGeometry
}
/**
* 绘制时捕捉
* @param {Point} targetPoint 捕获结果
* @param {LineString} targetLine 捕获结果
* @param {Array} pointArray 被捕获的面端点数组
* @param {Array} lineSlopes 被捕获的面线段斜率
* @return {Object} 捕获结果
*/
snapGeometries(targetPoint, moveLine, geometries, tolerance) {
let coordinateArray
const snapResult = {}
const coincidentPoints = []
let pointInLines = []
let parallelLines = []
let perpendicularLines = []
geometries.forEach((geometry) => {
if (geometry instanceof Polygon) {
coordinateArray = geometry.coordinates[0]
} else if (geometry instanceof LineString) {
coordinateArray = geometry.coordinates
} else if (geometry instanceof Point) {
coordinateArray = [geometry.coordinates]
}
const result = this.drawingSnap(
targetPoint,
moveLine,
coordinateArray,
tolerance
)
if (result.coincidentPoint) {
coincidentPoints.push(result.coincidentPoint)
}
if (result.pointInLines) {
pointInLines = pointInLines.concat(result.pointInLines)
}
if (result.parallelLines) {
parallelLines = parallelLines.concat(result.parallelLines)
}
if (result.perpendicularLines) {
perpendicularLines = perpendicularLines.concat(
result.perpendicularLines
)
}
})
snapResult.coincidentPoint = this._getBestResult(
coincidentPoints,
targetPoint
)
snapResult.pointInLine = this._getBestResult(pointInLines, targetPoint)
snapResult.parallelLine = this._getBestResult(parallelLines, targetPoint)
snapResult.perpendicularLine = this._getBestResult(
perpendicularLines,
targetPoint
)
// 同时满足点在线上和平行
if (snapResult.pointInLine && snapResult.parallelLine) {
let realPoint = this.getLineCrossPoint(
snapResult.pointInLine.line,
new LineString({
coordinates: [
moveLine.coordinates[0],
snapResult.parallelLine.realPoint.coordinates
],
spatialReference: targetPoint.spatialReference
})
)
if (realPoint) {
if (targetPoint.coordinates.length === 3) {
const hight = this._getHight()
realPoint = new Point({
coordinates: [...realPoint.coordinates, hight],
spatialReference: targetPoint.spatialReference
})
}
snapResult.inLineAndParallel = {
realPoint,
lines: [snapResult.pointInLine.line, snapResult.parallelLine.line],
symbolGeometry: snapResult.parallelLine.symbolGeometry
}
}
}
if (snapResult.pointInLine && snapResult.perpendicularLine) {
let realPoint = this.getLineCrossPoint(
snapResult.pointInLine.line,
new LineString({
coordinates: [
moveLine.coordinates[0],
snapResult.perpendicularLine.realPoint.coordinates
],
spatialReference: targetPoint.spatialReference
})
)
if (realPoint) {
if (targetPoint.coordinates.length === 3) {
const hight = this._getHight()
realPoint = new Point({
coordinates: [...realPoint.coordinates, hight],
spatialReference: targetPoint.spatialReference
})
}
snapResult.inLineAndPerpendicular = {
realPoint,
lines: [
snapResult.pointInLine.line,
snapResult.perpendicularLine.line
],
symbolGeometry: snapResult.perpendicularLine.symbolGeometry
}
}
}
return snapResult
}
getLineCrossPoint(line1, line2) {
const point1 = {
x: line1.coordinates[0][0],
y: line1.coordinates[0][1]
}
const point2 = {
x: line1.coordinates[1][0],
y: line1.coordinates[1][1]
}
const point3 = {
x: line2.coordinates[0][0],
y: line2.coordinates[0][1]
}
const point4 = {
x: line2.coordinates[1][0],
y: line2.coordinates[1][1]
}
const x =
((point3.x - point4.x) * (point2.x * point1.y - point1.x * point2.y) -
(point1.x - point2.x) * (point4.x * point3.y - point3.x * point4.y)) /
((point3.x - point4.x) * (point1.y - point2.y) -
(point1.x - point2.x) * (point3.y - point4.y))
const y =
((point3.y - point4.y) * (point2.y * point1.x - point1.y * point2.x) -
(point1.y - point2.y) * (point4.y * point3.x - point3.y * point4.x)) /
((point3.y - point4.y) * (point1.x - point2.x) -
(point1.y - point2.y) * (point3.x - point4.x))
let crossPoint = undefined
if (
!isNaN(x) &&
!isNaN(y) &&
x <= Math.max(point3.x, point4.x) &&
x >= Math.min(point3.x, point4.x) &&
y <= Math.max(point3.y, point4.y) &&
y >= Math.min(point3.y, point4.y)
) {
crossPoint = new Point({
coordinates: [x, y],
spatialReference: line1.spatialReference
})
}
return crossPoint
}
drawingSnap(targetPoint, targetLine, pointArray, tolerance) {
this.tolerance = tolerance
const spatialReference = targetLine.spatialReference
targetPoint = this._convertReference(targetPoint)
targetLine = this._convertReference(targetLine)
const snapGeometry = this.getSnapGeometryByPointArray(
pointArray,
spatialReference
)
const snapResult = {}
if (this.isSnapVertexCoincident) {
// 捕捉顶点重合
snapResult.coincidentPoint = this.pointCoincident(
targetPoint,
snapGeometry.points,
spatialReference
)
}
if (this.isSnapVertexInLine) {
// 捕捉点在线上
if (!snapResult.coincidentPoint) {
snapResult.pointInLines = this.getPointInLines(
targetPoint,
snapGeometry.lines,
spatialReference
)
}
}
if (this.isSnapParallel) {
// 捕捉平行线
snapResult.parallelLines = this.getParallelLine(
targetPoint,
targetLine,
snapGeometry.lines,
spatialReference
)
}
if (this.isSnapPerpendicular) {
// 捕捉垂线垂点
snapResult.perpendicularLines = this.getPerpendicularLine(
targetPoint,
targetLine,
snapGeometry.lines,
spatialReference
)
}
return snapResult
}
_getBestResult(resultItem, targetPoint) {
let bestItem = undefined
let minDistance = 0
resultItem.forEach((item, i) => {
const distance = GeometryEngine.distance(item.realPoint, targetPoint)
if (i === 0) {
bestItem = item
minDistance = distance
} else {
if (distance < minDistance) {
minDistance = distance
bestItem = item
}
}
})
return bestItem
}
getSnapGeometryByPointArray(pointArray, spatialReference) {
const points = []
const lines = []
pointArray.forEach((coord, index) => {
const point = this._convertReference(
new Point({
coordinates: coord,
spatialReference
})
)
points.push(point)
if (index > 0) {
const line = this._convertReference(
new LineString({
coordinates: [pointArray[index - 1], pointArray[index]],
spatialReference
})
)
lines.push(line)
}
})
return { points, lines }
}
_convertReference(geometry) {
if (!geometry.isWSG48) {
let newGeometry = geometry.clone()
newGeometry = Projection.project(
newGeometry,
new SpatialReference('EPSG:4326')
)
return newGeometry
} else {
return geometry
}
}
getDistance(point1, point2) {
const distance = turf.distance(turf.point(point1), turf.point(point2), {
units: 'kilometers'
})
return distance * 1000
}
/**
* 两点是否重合
* @param {Point} targetPoint
* @param {Array} points
*/
pointCoincident(targetPoint, points) {
let containPoint = undefined
const targetScreenPoint = this._view.toScreen(targetPoint)
for (let i = 0; i < points.length; i++) {
const screenPoint = this._view.toScreen(points[i])
if (
Math.sqrt(
Math.pow(targetScreenPoint.x - screenPoint.x, 2) +
Math.pow(targetScreenPoint.y - screenPoint.y, 2)
) <= this.pixelTolerance
) {
if (
targetPoint.coordinates.length === 3 &&
points[i].coordinates.length < 3
) {
containPoint = new Point({
coordinates: [...points[i].coordinates, this._getHight()],
spatialReference: this._getHight().spatialReference
})
} else {
containPoint = points[i]
}
break
}
}
return containPoint ? { realPoint: containPoint } : undefined
}
/**
*捕获目标点所在在多个被捕获的直线上,返回被捕获的的直线
* @param {Point} targetPoint
* @param {Array} lines
* @return {Object} 被捕获的的直线对象
*/
getPointInLines(targetPoint, lines, spatialReference) {
const containLines = []
lines.forEach((line) => {
// 计算容差范围内点到线的垂点
const inLineResult = this.getPerpendicularPoint(
targetPoint,
new Point({
coordinates: line.coordinates[0],
spatialReference
}),
new Point({
coordinates: line.coordinates[1],
spatialReference
})
)
if (inLineResult) {
line = Projection.project(line, spatialReference)
containLines.push({
line,
realPoint: inLineResult.realPoint,
deltaTolerance: inLineResult.deltaTolerance
})
}
})
return containLines
}
// 根据点坐标和直线,获取垂足坐标
getPerpendicularPoint(targetPoint, targetLinePoint1, targetLinePoint2) {
// const point = this._view.toScreen(targetPoint)
// const linePoint1 = this._view.toScreen(targetLinePoint1)
// const linePoint2 = this._view.toScreen(targetLinePoint2)
const point = {
x: targetPoint.coordinates[0],
y: targetPoint.coordinates[1]
}
const linePoint1 = {
x: targetLinePoint1.coordinates[0],
y: targetLinePoint1.coordinates[1]
}
const linePoint2 = {
x: targetLinePoint2.coordinates[0],
y: targetLinePoint2.coordinates[1]
}
let perpendicularPoint
let x
let y
if (linePoint2.x !== linePoint1.x) {
const k = (linePoint2.y - linePoint1.y) / (linePoint2.x - linePoint1.x)
x =
(k * k * linePoint1.x + k * (point.y - linePoint1.y) + point.x) /
(k * k + 1)
y = k * (x - linePoint1.x) + linePoint1.y
} else {
x =
(targetLinePoint1.coordinates[0] + targetLinePoint2.coordinates[0]) / 2
y = targetPoint.coordinates[1]
}
if (targetPoint.coordinates.length === 3) {
const hight = this._getHight()
perpendicularPoint = new Point({
coordinates: [x, y, hight],
spatialReference: targetPoint.spatialReference
})
} else {
perpendicularPoint = new Point({
coordinates: [x, y],
spatialReference: targetPoint.spatialReference
})
}
const endScreenPoint = this._view.toScreen(perpendicularPoint)
const startScreenPoint = this._view.toScreen(targetPoint)
const deltaPixel = Math.sqrt(
Math.pow(startScreenPoint.x - endScreenPoint.x, 2) +
Math.pow(startScreenPoint.y - endScreenPoint.y, 2)
)
const valid = deltaPixel <= this.pixelTolerance
return valid
? {
realPoint: perpendicularPoint,
deltaTolerance: deltaPixel
}
: null
}
/**
* 获取目标直线的平行线捕获结果。判断目标直线与被捕获的直线是否平行,返回平行线结果
* @private
* @param {Point} targetPoint
* @param {LineString} targetLine 目标直线
* @param {Array} lines 被捕获的直线对象
* @param {Array} lineSlopes 被捕获的直线斜率
* @return {Object} 平行线捕获结果
*/
getParallelLine(targetPoint, targetLine, lines, spatialReference) {
const parallelLines = []
if (lines && lines.length > 0) {
lines.forEach((line) => {
const linePoint1 = new Point({
coordinates: line.coordinates[0],
spatialReference
})
const linePoint2 = new Point({
coordinates: line.coordinates[1],
spatialReference
})
const parallelResult = this.getParallelPoint(
targetPoint,
new Point({
coordinates: targetLine.coordinates[0],
spatialReference
}),
linePoint1,
linePoint2,
'parallel'
)
if (parallelResult) {
const realPoint = parallelResult.realPoint
const symbolGeometry = this._getParallelSymbolGeometry(
linePoint1,
linePoint2
)
parallelLines.push({
line,
symbolGeometry,
realPoint,
deltaTolerance: parallelResult.deltaTolerance
})
}
})
}
return parallelLines.length > 0 ? parallelLines : undefined
}
// 计算平行或垂直时的标准坐标
getParallelPoint(
targetPoint,
targetLastPoint,
targetLinePoint1,
targetLinePoint2,
type = 'parallel'
) {
// const point = this._view.toScreen(targetPoint)
// const lastPoint = this._view.toScreen(targetLastPoint)
// const linePoint1 = this._view.toScreen(targetLinePoint1)
// const linePoint2 = this._view.toScreen(targetLinePoint2)
const point = {
x: targetPoint.coordinates[0],
y: targetPoint.coordinates[1]
}
const lastPoint = {
x: targetLastPoint.coordinates[0],
y: targetLastPoint.coordinates[1]
}
const linePoint1 = {
x: targetLinePoint1.coordinates[0],
y: targetLinePoint1.coordinates[1]
}
const linePoint2 = {
x: targetLinePoint2.coordinates[0],
y: targetLinePoint2.coordinates[1]
}
// 计算point,lastPoint的长度
const distance = Math.sqrt(
Math.pow(point.x - lastPoint.x, 2) + Math.pow(point.y - lastPoint.y, 2)
)
// 计算点(point)到直线(lineP1、lineP2)的距离
const isTolerance = function (point, lineP1, lineP2, pixelTolerance) {
const pointToLineD =
Math.abs(
(lineP2.x - lineP1.x) * (point.x - lineP1.x) +
(lineP2.y - lineP1.y) * (point.y - lineP1.y)
) /
Math.sqrt(
Math.pow(lineP2.x - lineP1.x, 2) + Math.pow(lineP2.y - lineP1.y, 2)
)
return pointToLineD <= pixelTolerance
}
let k
let kValid = true
let x
let y
if (type === 'parallel') {
if (linePoint2.x === linePoint1.x) {
kValid = false
x = lastPoint.x
if (point.y > lastPoint.y) {
y = lastPoint.y + distance
} else {
y = lastPoint.y - distance
}
} else {
k = (linePoint2.y - linePoint1.y) / (linePoint2.x - linePoint1.x)
}
} else if (type === 'perpendicular') {
if (linePoint2.y === linePoint1.y) {
kValid = false
y = lastPoint.y
if (point.x > lastPoint.x) {
x = lastPoint.x + distance
} else {
x = lastPoint.x - distance
}
} else {
k = -(linePoint2.x - linePoint1.x) / (linePoint2.y - linePoint1.y)
}
}
if (kValid) {
const b = lastPoint.y - k * lastPoint.x
// 第二步:求得在直线y=kx+b上,距离当前坐标距离为L的某点
const H = Math.pow(k, 2) + 1 // A=k^2+1;
const I = 2 * ((b - lastPoint.y) * k - lastPoint.x) // B=2[(b-y0)k-x0];
const J =
Math.pow(b - lastPoint.y, 2) +
Math.pow(lastPoint.x, 2) -
Math.pow(distance, 2)
const Dx1 = (-I + Math.sqrt(Math.pow(I, 2) - 4 * H * J)) / (2 * H)
const Dx2 = (-I - Math.sqrt(Math.pow(I, 2) - 4 * H * J)) / (2 * H)
x = 0 // 最后确定是在已知两点之间的某点
if ((point.x - lastPoint.x) * (Dx1 - lastPoint.x) > 0) {
x = Dx1
} else {
x = Dx2
}
y = k * x + b
// parallelPoint = this._view.toMap({ x, y })
}
// 临时
if (isNaN(x) || isNaN(x)) {
return null
}
let parallelPoint
if (targetPoint.coordinates.length === 3) {
const hight = this._getHight()
parallelPoint = new Point({
coordinates: [x, y, hight],
spatialReference: point.spatialReference
})
} else {
parallelPoint = new Point({
coordinates: [x, y],
spatialReference: point.spatialReference
})
}
// const deltaPixel = Math.sqrt(
// Math.pow(point.x - x, 2) + Math.pow(point.y - y, 2)
// )
const endScreenPoint = this._view.toScreen(parallelPoint)
const startScreenPoint = this._view.toScreen(targetPoint)
const deltaPixel = Math.sqrt(
Math.pow(startScreenPoint.x - endScreenPoint.x, 2) +
Math.pow(startScreenPoint.y - endScreenPoint.y, 2)
)
const valid = deltaPixel <= this.pixelTolerance
// isTolerance(point, lastPoint, { x, y }, this.pixelTolerance)
return valid
? {
realPoint: parallelPoint,
deltaTolerance: deltaPixel
}
: null
}
/**
* 获取地理点高度
* @private
* @param {Point} point
* @return {Number} 高度
*/
_getHight() {
return 0
}
/**
* 获取描述平行线的特殊符号
* @private
* @param {LineString} targetLine
* @param {Array} lines 被捕获的直线对象
* @return {Object} 平行线的特殊符号对象
*/
_getParallelSymbolGeometry(linePoint1, linePoint2) {
const scale = 1 / 4
const panPixel = this.pixelTolerance / 2
const linePointScreen1 = this._view.toScreen(linePoint1)
const linePointScreen2 = this._view.toScreen(linePoint2)
const lineScalePoint1 = {
x:
((1 - scale) / 2) * (linePointScreen2.x - linePointScreen1.x) +
linePointScreen1.x,
y:
((1 - scale) / 2) * (linePointScreen2.y - linePointScreen1.y) +
linePointScreen1.y
}
const lineScalePoint2 = {
x:
((1 + scale) / 2) * (linePointScreen2.x - linePointScreen1.x) +
linePointScreen1.x,
y:
((1 + scale) / 2) * (linePointScreen2.y - linePointScreen1.y) +
linePointScreen1.y
}
let symbol1ScreenPoint1
let symbol1ScreenPoint2
let symbol2ScreenPoint1
let symbol2ScreenPoint2
if (lineScalePoint2.x === lineScalePoint1.x) {
symbol1ScreenPoint1 = {
x: lineScalePoint1.x + panPixel,
y: lineScalePoint1.y
}
symbol1ScreenPoint2 = {
x: lineScalePoint2.x + panPixel,
y: lineScalePoint2.y
}
symbol2ScreenPoint1 = {
x: lineScalePoint1.x - panPixel,
y: lineScalePoint1.y
}
symbol2ScreenPoint2 = {
x: lineScalePoint2.x - panPixel,
y: lineScalePoint2.y
}
} else if (lineScalePoint2.y === lineScalePoint1.y) {
symbol1ScreenPoint1 = {
x: lineScalePoint1.x,
y: lineScalePoint1.y + panPixel
}
symbol1ScreenPoint2 = {
x: lineScalePoint2.x,
y: lineScalePoint2.y + panPixel
}
symbol2ScreenPoint1 = {
x: lineScalePoint1.x,
y: lineScalePoint1.y - panPixel
}
symbol2ScreenPoint2 = {
x: lineScalePoint2.x,
y: lineScalePoint2.y - panPixel
}
} else {
const symbolK =
-(lineScalePoint2.x - lineScalePoint1.x) /
(lineScalePoint2.y - lineScalePoint1.y)
// const symbolK = -1 / k
const symbolAngle = Math.atan(symbolK)
const translatedPoint = function (point, angle, panPixel) {
const symbol1Center = {
x: Math.cos(angle) * panPixel + point.x,
y: Math.sin(angle) * panPixel + point.y
}
return symbol1Center
}
symbol1ScreenPoint1 = translatedPoint(
lineScalePoint1,
symbolAngle,
panPixel
)
symbol1ScreenPoint2 = translatedPoint(
lineScalePoint2,
symbolAngle,
panPixel
)
symbol2ScreenPoint1 = translatedPoint(
lineScalePoint1,
symbolAngle,
-panPixel
)
symbol2ScreenPoint2 = translatedPoint(
lineScalePoint2,
symbolAngle,
-panPixel
)
}
const symbol1point1 = this._view.toMap(symbol1ScreenPoint1)
const symbol1point2 = this._view.toMap(symbol1ScreenPoint2)
const symbol2point1 = this._view.toMap(symbol2ScreenPoint1)
const symbol2point2 = this._view.toMap(symbol2ScreenPoint2)
return new MultiLineString({
coordinates: [
[symbol1point1.coordinates, symbol1point2.coordinates],
[symbol2point1.coordinates, symbol2point2.coordinates]
]
})
}
_getParallelSymbolGeometry0(targetLine, line) {
const scale = 1 / 4
const pan = this.tolerance / 1000
const translatedLine = function (line, scale, pan) {
const polyline = turf.lineString(line.coordinates)
const translatedPolyline = turf.transformTranslate(polyline, pan, 180)
const scaledLine = turf.transformScale(translatedPolyline, scale)
return scaledLine.geometry.coordinates
}
return new MultiLineString({
coordinates: [
translatedLine(targetLine, scale, pan),
translatedLine(targetLine, scale, -pan),
translatedLine(line, scale, pan),
translatedLine(line, scale, -pan)
]
})
}
/**
* 获取目标直线的垂线捕获结果
* @private
* @param {Point} targetPoint
* @param {LineString} targetLine
* @param {Array} lines 被捕获的直线对象
* @param {Array} lineSlopes 被捕获的直线斜率
* @return {Object} 垂线结果
*/
getPerpendicularLine(targetPoint, targetLine, lines, spatialReference) {
const perpendicularLines = []
lines.forEach((line) => {
const perpendicularResult = this.getParallelPoint(
targetPoint,
new Point({
coordinates: targetLine.coordinates[0],
spatialReference
}),
new Point({
coordinates: line.coordinates[0],
spatialReference
}),
new Point({
coordinates: line.coordinates[1],
spatialReference
}),
'perpendicular'
)
if (perpendicularResult) {
const realPoint = perpendicularResult.realPoint
const symbolGeometry = undefined
// 暂时屏蔽计算垂足图形方法,方法需进一步修复
// const symbolGeometry = this.getPerpendicularSymbolGeometry(
// new LineString({
// coordinates: [targetLine.coordinates[0], realPoint.coordinates],
// spatialReference
// }),
// lines[i],
// realPoint
// )
perpendicularLines.push({
line,
realPoint,
symbolGeometry,
deltaTolerance: perpendicularResult.deltaTolerance
})
}
})
return perpendicularLines.length ? perpendicularLines : undefined
}
/**
* 获取目标点到目标线的垂点对象
* @private
* @param {Point} targetPoint 目标点
* @param {LineString} targetLine 目标线
* @param {Number} lineSlope 直线斜率
* @return {Array} 垂点坐标
*/
_getPerpendicularPoint(targetPoint, targetLine, lineSlope) {
const delta1 =
targetLine.coordinates[0][1] - lineSlope * targetLine.coordinates[0][0]
const delta2 =
targetPoint.coordinates[1] + (1 / lineSlope) * targetPoint.coordinates[0]
const x = ((delta2 - delta1) * lineSlope) / (lineSlope * lineSlope + 1)
const y = (-1 / lineSlope) * x + delta2
return [x, y]
}
/**
* 获取描述垂线的特殊符号
* @private
* @param {LineString} targetLine
* @param {LineString} line 被捕获的直线对象
* @param {Point} perpendicularPoint 垂足坐标点
* @return {Object} 垂线的特殊符号对象
*/
getPerpendicularSymbolGeometry(targetLine, line, perpendicularPoint) {
const linePoints1 = [
turf.point(targetLine.coordinates[0]),
turf.point(targetLine.coordinates[1])
]
const linePoints2 = [
turf.point(line.coordinates[0]),
turf.point(line.coordinates[1])
]
const distance1 = turf.distance(linePoints1[0], linePoints1[1]) // GeometryEngine.geodesicLength(targetLine)
const distance2 = turf.distance(linePoints2[0], linePoints2[1]) // GeometryEngine.geodesicLength(line)
const distance = Math.min(distance1, distance2) / 8
perpendicularPoint = turf.point(perpendicularPoint.coordinates)
let bearing2 = 0
if (
linePoints2[0].geometry.coordinates[0] ===
perpendicularPoint.geometry.coordinates[0] &&
linePoints2[0].geometry.coordinates[1] ===
perpendicularPoint.geometry.coordinates[1]
) {
bearing2 = turf.rhumbBearing(perpendicularPoint, linePoints2[1])
} else {
bearing2 = turf.rhumbBearing(perpendicularPoint, linePoints2[0])
}
let bearing1 = 0
if (
linePoints1[0].geometry.coordinates[0] ===
perpendicularPoint.geometry.coordinates[0] &&
linePoints1[0].geometry.coordinates[1] ===
perpendicularPoint.geometry.coordinates[1]
) {
bearing1 = turf.rhumbBearing(perpendicularPoint, linePoints1[1])
} else {
bearing1 = turf.rhumbBearing(perpendicularPoint, linePoints1[0])
}
const bearing3 = (bearing1 + bearing2) / 2
const destination1 = turf.rhumbDestination(
perpendicularPoint,
distance,
bearing1
)
const destination2 = turf.rhumbDestination(
perpendicularPoint,
distance,
bearing2
)
const destination3 = turf.rhumbDestination(
perpendicularPoint,
distance * Math.sqrt(2),
bearing3
)
const point1 = destination1.geometry.coordinates
const point2 = destination2.geometry.coordinates
const point3 = destination3.geometry.coordinates
return new LineString({
coordinates: [point1, point3, point2]
})
}
/**
* 正在测试中的方法
* @private
*/
getPerpendicularSymbolGeometry2(targetLine, line, perpendicularPoint) {
let p1 = turf.point(targetLine.coordinates[0])
if (
targetLine.coordinates[0][0] === perpendicularPoint.coordinates[0] &&
targetLine.coordinates[0][1] === perpendicularPoint.coordinates[1]
) {
p1 = turf.point(targetLine.coordinates[1])
}
const p2 = turf.point(line.coordinates[0])
const p3 = turf.point(line.coordinates[1])
const distance1 = turf.distance(p1, perpendicularPoint)
const distance2 = turf.distance(p2, perpendicularPoint)
const distance3 = turf.distance(p3, perpendicularPoint)
let distance = Math.min(distance1, distance2, distance3) / 8
if (distance2 === 0) {
distance = Math.min(distance1, distance3) / 8
} else if (distance3 === 0) {
distance = Math.min(distance1, distance2) / 8
}
perpendicularPoint = turf.point(perpendicularPoint.coordinates)
const bearing1 = turf.rhumbBearing(perpendicularPoint, p1)
const destination1 = turf.rhumbDestination(
perpendicularPoint,
distance,
bearing1
)
const bearing2 = turf.rhumbBearing(perpendicularPoint, p2)
const destination2 = turf.rhumbDestination(
perpendicularPoint,
distance,
bearing2
)
const bearing3 = (bearing1 + bearing2) / 2
const dis = distance * Math.cos(((bearing3 - bearing2) * Math.PI) / 180) * 2
const destination3 = turf.rhumbDestination(
perpendicularPoint,
dis,
bearing3
)
const point1 = destination1.geometry.coordinates
const point2 = destination2.geometry.coordinates
const point3 = destination3.geometry.coordinates
return new LineString({
coordinates: [point1, point3, point2]
})
}
/**
*根据垂足获取真正终点位置
* @private
* @param {Feature} currentPoint 当前终点
* @param {Feature} startPoint 线段起点
* @param {Feature} perpendicularPoint 垂点位置
*/
getPerpendicularRealPosition(currentPoint, startPoint, perpendicularPoint) {
let realPosition = null
const distance = GeometryEngine.distance(startPoint, currentPoint)
const direction = turf.rhumbBearing(
turf.point(startPoint.coordinates),
turf.point(perpendicularPoint.currentPoint)
)
realPosition = turf.rhumbDestination(startPoint, distance, direction)
.geometry.coordinates
return realPosition
}
/**
*面和线是否相交
*/
isPolylineCrossPolygon() {}
/**
*两个面是否相交
*/
isPolygonCross() {}
}
export default SketchSnappingTool