// polyline线偏移 export const polylineOffset = (latlngs: any, number: any) => { const x1 = parseFloat(latlngs[0][1]), x2 = parseFloat(latlngs[1][1]), y1 = parseFloat(latlngs[0][0]), y2 = parseFloat(latlngs[1][0]); const rad1 = Math.atan((y2 - y1) / (x2 - x1)); const rad2 = rad1 - Math.PI / 2; const offsetY = number * Math.sin(rad2); const offsetX = number * Math.cos(rad2); const segment1 = [ [y1 + offsetY, x1 + offsetX], [y2 + offsetY, x2 + offsetX], ]; const segment2 = [ [y1 - offsetY, x1 - offsetX], [y2 - offsetY, x2 - offsetX], ]; const segment = x2 > x1 ? segment1 : segment2; return segment; }; export const lnglat2latlng = (cs: any) => { return Array.isArray(cs[0]) ? cs.map((c: any) => { return [c[1], c[0]]; }) : [cs[1], cs[0]]; }; export const latlng2lnglat = (cs: any) => { return Array.isArray(cs[0]) ? cs.map((c: any) => { return [c[1], c[0]]; }) : [cs[1], cs[0]]; }; function getIntersections(segmentsCopy: any) { const segments = [...segmentsCopy]; for (let i = 0, l = segments.length; i < l - 1; i++) { // 直线1 const x1 = segments[i][0][0], y1 = segments[i][0][1], x2 = segments[i][1][0], y2 = segments[i][1][1]; // 直线2 const x3 = segments[i + 1][0][0], y3 = segments[i + 1][0][1], x4 = segments[i + 1][1][0], y4 = segments[i + 1][1][1]; // 直线1:a1 * x + b1 * y + c1 = 0 const a1 = y2 - y1, b1 = x1 - x2, c1 = (x2 - x1) * y1 + (y1 - y2) * x1; // 直线2:a2 * x + b2 * y + c2 = 0 const a2 = y4 - y3, b2 = x3 - x4, c2 = (x4 - x3) * y3 + (y3 - y4) * x3; // 两直线交点坐标 const intersectionPoint = [(b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1), (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1)]; segments[i + 1][0] = segments[i][1] = intersectionPoint; } return segments; } export const latlngsOffset = (latlngs: any, offset: any) => { const roadLatlngs = [...latlngs]; const roadLatlngsReverse = [...roadLatlngs]; // 首次偏移之后的路段 const segmentsOffset = []; const segments = []; for (let i = 0, l = roadLatlngs.length; i < l - 1; i++) { const segment = [roadLatlngs[i], roadLatlngs[i + 1]]; const segmentOffset = polylineOffset(segment, offset); segmentsOffset.push(segmentOffset); segments.push(segment); } const segmentsReverseOffset = []; for (let i = 0, l = roadLatlngsReverse.length; i < l - 1; i++) { const segment = [roadLatlngsReverse[i], roadLatlngsReverse[i + 1]]; const segmentOffset = polylineOffset(segment, 0.00003); segmentsReverseOffset.push(segmentOffset); } const segmentsOffsetCopy = [...segmentsOffset]; // segmentsOffsetCopy = getIntersections(segmentsOffsetCopy); const segmentsOffsetReverseCopy = JSON.parse(JSON.stringify(segmentsReverseOffset)); // segmentsOffsetReverseCopy = getIntersections(segmentsOffsetReverseCopy); return { lines: segmentsOffsetCopy, linesReverse: segmentsOffsetReverseCopy, lineshistory: segments, }; }; // 是否顺时针 function isClockWise(latlngsCopy: any) { const latlngs = [...latlngsCopy]; // 找到多边形最右凸点 let lngMax = latlngs[0][1]; let maxIndex = 0; for (let i = 1, l = latlngs.length; i < l; i++) { if (latlngs[i][1] > lngMax) { lngMax = latlngs[i][1]; maxIndex = i; } } // 根据该凸点判断是顺时针还是逆时针 let a, c; const b = maxIndex; if (b === 0) { a = latlngs.length - 1 - 1; c = b + 1; } else if (b > 0 && b < latlngs.length - 1) { a = b - 1; c = b + 1; } else { a = b - 1; c = 0; } const Pa = latlngs[a], Pb = latlngs[b], Pc = latlngs[c]; const Xa = Pa[1], Xb = Pb[1], Xc = Pc[1], Ya = Pa[0], Yb = Pb[0], Yc = Pc[0]; // 大于0逆时针,小于0顺时针 const isClockWise = (Xb - Xa) * (Yc - Yb) - (Yb - Ya) * (Xc - Xb) > 0 ? false : true; return isClockWise; } // 按顺序计算多边形每条边偏移后,相邻两边的交点 function getPolygonIntersections(segmentsCopy: any) { const segments = [...segmentsCopy]; for (let i = 0, l = segments.length; i < l; i++) { const j1 = i; let j2; if (i < l - 1) { j2 = i + 1; } else { j2 = 0; } // 直线1 const x1 = segments[j1][0][0], y1 = segments[j1][0][1], x2 = segments[j1][1][0], y2 = segments[j1][1][1]; // 直线2 const x3 = segments[j2][0][0], y3 = segments[j2][0][1], x4 = segments[j2][1][0], y4 = segments[j2][1][1]; // 直线1:a1 * x + b1 * y + c1 = 0 const a1 = y2 - y1, b1 = x1 - x2, c1 = (x2 - x1) * y1 + (y1 - y2) * x1; // 直线2:a2 * x + b2 * y + c2 = 0 const a2 = y4 - y3, b2 = x3 - x4, c2 = (x4 - x3) * y3 + (y3 - y4) * x3; // 两直线交点坐标 const intersectionPoint = [(b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1), (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1)]; segments[j2][0] = segments[j1][1] = intersectionPoint; } return segments; } export function getExtendLatlngs(latlngs: any) { const latlngsCopy = [...latlngs]; const direction = isClockWise(latlngsCopy); // 根据多边形顺时针还是逆时针 // 顺时针向外偏移须传负数 // 逆时针向外偏移传正数,逆时针与计算道路向右偏相同 const offset = direction ? -0.0015 : 0.0015; const segments = []; // 格式化成路段,然后偏移 for (let i = 0, l = latlngsCopy.length; i < l - 1; i++) { let segment = [latlngsCopy[i], latlngsCopy[i + 1]]; segment = polylineOffset(segment, offset); segments.push(segment); } // 计算偏移后的路段(交点) const segmentsIntersections = getPolygonIntersections(segments); // 格式化成闭环,用于生成polygon const polygonLatlngs = []; for (let i = 0, l = segmentsIntersections.length; i < l; i++) { polygonLatlngs.push(segmentsIntersections[i][0]); if (i === l - 1) { polygonLatlngs.push(segmentsIntersections[i][1]); } } return polygonLatlngs; }