@mapcatch/util 1.0.15 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/catchUtil.min.esm.js +67984 -14011
- package/dist/catchUtil.min.js +2695 -55
- package/package.json +22 -3
- package/src/constants/annotation_color.js +7 -0
- package/src/constants/annotation_draw_style.js +228 -0
- package/src/constants/annotation_label_style.js +76 -0
- package/src/constants/annotation_style.js +118 -0
- package/src/constants/cameras.js +1 -1
- package/src/constants/crs.js +31473 -31473
- package/src/constants/error_codes.js +44 -0
- package/src/constants/height_colors.js +1 -0
- package/src/constants/index.js +9 -2
- package/src/constants/map_style.js +11 -0
- package/src/constants/measurement_fields.js +3 -3
- package/src/{event.js → event/event.js} +1 -14
- package/src/event/event_bus.js +5 -0
- package/src/event/index.js +2 -0
- package/src/gl-operations/constants.js +9 -11
- package/src/gl-operations/default_options.js +5 -5
- package/src/gl-operations/index.js +166 -239
- package/src/gl-operations/reglCommands/contours.js +20 -20
- package/src/gl-operations/reglCommands/default.js +34 -34
- package/src/gl-operations/reglCommands/hillshading.js +116 -116
- package/src/gl-operations/reglCommands/index.js +6 -6
- package/src/gl-operations/reglCommands/multiLayers.js +55 -55
- package/src/gl-operations/reglCommands/transitions.js +24 -24
- package/src/gl-operations/reglCommands/util.js +54 -54
- package/src/gl-operations/renderer.js +69 -69
- package/src/gl-operations/shaders/transform.js +2 -2
- package/src/gl-operations/shaders/util/rgbaToFloat.glsl +11 -11
- package/src/gl-operations/texture_manager.js +58 -58
- package/src/gl-operations/util.js +154 -154
- package/src/index.js +14 -2
- package/src/measure/index.js +198 -0
- package/src/measure/tile_cache.js +88 -0
- package/src/mvs/index.js +26 -0
- package/src/mvs/protos/index.js +12 -0
- package/src/mvs/protos/proto_10.js +155 -0
- package/src/observation_pretict.js +168 -0
- package/src/photo-parser/exif/gps_tags.js +33 -0
- package/src/photo-parser/exif/ifd1_tags.js +22 -0
- package/src/photo-parser/exif/index.js +130 -0
- package/src/photo-parser/exif/parse_image.js +290 -0
- package/src/photo-parser/exif/string_values.js +137 -0
- package/src/photo-parser/exif/tags.js +75 -0
- package/src/photo-parser/exif/tiff_tags.js +35 -0
- package/src/photo-parser/exif/util.js +103 -0
- package/src/photo-parser/image-size/detector.js +24 -0
- package/src/photo-parser/image-size/fromFile.js +55 -0
- package/src/photo-parser/image-size/index.js +2 -0
- package/src/photo-parser/image-size/lookup.js +37 -0
- package/src/photo-parser/image-size/types/bmp.js +10 -0
- package/src/photo-parser/image-size/types/cur.js +16 -0
- package/src/photo-parser/image-size/types/dds.js +10 -0
- package/src/photo-parser/image-size/types/gif.js +11 -0
- package/src/photo-parser/image-size/types/heif.js +35 -0
- package/src/photo-parser/image-size/types/icns.js +112 -0
- package/src/photo-parser/image-size/types/ico.js +74 -0
- package/src/photo-parser/image-size/types/index.js +43 -0
- package/src/photo-parser/image-size/types/j2c.js +11 -0
- package/src/photo-parser/image-size/types/jp2.js +22 -0
- package/src/photo-parser/image-size/types/jpg.js +157 -0
- package/src/photo-parser/image-size/types/ktx.js +18 -0
- package/src/photo-parser/image-size/types/png.js +36 -0
- package/src/photo-parser/image-size/types/pnm.js +74 -0
- package/src/photo-parser/image-size/types/psd.js +10 -0
- package/src/photo-parser/image-size/types/svg.js +100 -0
- package/src/photo-parser/image-size/types/tga.js +14 -0
- package/src/photo-parser/image-size/types/tiff.js +92 -0
- package/src/photo-parser/image-size/types/utils.js +83 -0
- package/src/photo-parser/image-size/types/webp.js +67 -0
- package/src/photo-parser/index.js +181 -0
- package/src/report/annotations_report.js +446 -0
- package/src/report/index.js +2 -0
- package/src/report/map_util.js +81 -0
- package/src/report/pdf_creator.js +247 -0
- package/src/report/report.js +583 -0
- package/src/transform.js +204 -0
- package/src/util.js +371 -75
- package/CHANGELOG.md +0 -60
- /package/src/constants/{colors.js → dsm_colors.js} +0 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import {getPhotoMetadata} from './exif'
|
|
2
|
+
import moment from 'moment'
|
|
3
|
+
import * as util from '../util'
|
|
4
|
+
import _ from 'lodash'
|
|
5
|
+
|
|
6
|
+
export async function parsePhoto (file) {
|
|
7
|
+
let tags = await getPhotoMetadata(file)
|
|
8
|
+
const {width, height, exif, xmp, filesize} = tags
|
|
9
|
+
let imageMetaData = {width, height, filesize}
|
|
10
|
+
let lng = NaN, lat = NaN, alt = NaN
|
|
11
|
+
let yaw = NaN, pitch = NaN, roll = NaN
|
|
12
|
+
let x_std = NaN, y_std = NaN, z_std = NaN
|
|
13
|
+
let pos = [lng, lat, alt]
|
|
14
|
+
let flatedXmp = util.flatObject(xmp)
|
|
15
|
+
let {GPSAltitude, GPSLatitude, GPSLatitudeRef, GPSLongitude, GPSLongitudeRef} = exif
|
|
16
|
+
if (GPSLongitude && GPSLatitude) {
|
|
17
|
+
pos = [
|
|
18
|
+
util.getGeoCoordOperator(GPSLongitudeRef) * util.toRadian(GPSLongitude),
|
|
19
|
+
util.getGeoCoordOperator(GPSLatitudeRef) * util.toRadian(GPSLatitude),
|
|
20
|
+
+GPSAltitude
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
for(let key in flatedXmp) {
|
|
24
|
+
let value = flatedXmp[key]
|
|
25
|
+
if (key === 'drone-dji:GpsLongtitude' || key === 'drone-dji:GpsLongitude') {
|
|
26
|
+
lng = Number(value)
|
|
27
|
+
} else if (key === 'drone-dji:GpsLatitude') {
|
|
28
|
+
lat = Number(value)
|
|
29
|
+
} else if (key === 'drone-dji:AbsoluteAltitude') {
|
|
30
|
+
alt = Number(value)
|
|
31
|
+
} else if (key === 'drone-dji:GimbalYawDegree') {
|
|
32
|
+
yaw = Number(value)
|
|
33
|
+
} else if (key === 'drone-dji:GimbalPitchDegree') {
|
|
34
|
+
pitch = Number(value)
|
|
35
|
+
} else if (key === 'drone-dji:GimbalRollDegree') {
|
|
36
|
+
roll = Number(value)
|
|
37
|
+
} else if (key === 'drone-dji:RtkStdLon') {
|
|
38
|
+
x_std = Number(value)
|
|
39
|
+
} else if (key === 'drone-dji:RtkStdLat') {
|
|
40
|
+
y_std = Number(value)
|
|
41
|
+
} else if (key === 'drone-dji:RtkStdHgt') {
|
|
42
|
+
z_std = Number(value)
|
|
43
|
+
} else if (key === 'drone-dji:DewarpFlag') {
|
|
44
|
+
imageMetaData.dewarp_flag = Boolean(Number(value))
|
|
45
|
+
} else if (key === 'drone-dji:RtkFlag') {
|
|
46
|
+
imageMetaData.rtk_flag = Number(value)
|
|
47
|
+
} else if (key === 'drone-dji:RelativeAltitude') {
|
|
48
|
+
imageMetaData.relative_altitude = Number(value)
|
|
49
|
+
} else if (key === 'tiff:Model') {
|
|
50
|
+
imageMetaData.camera_model = value
|
|
51
|
+
} else if (key === 'drone-dji:DewarpData') {
|
|
52
|
+
let params = value.split(';')[1].split(',')
|
|
53
|
+
let pre_calib_param = params.map(d => Number(d))
|
|
54
|
+
pre_calib_param[2] = width / 2 + pre_calib_param[2]
|
|
55
|
+
pre_calib_param[3] = height / 2 + pre_calib_param[3]
|
|
56
|
+
imageMetaData.pre_calib_param = pre_calib_param
|
|
57
|
+
} else if (key === 'drone-dji:CaptureUUID') {
|
|
58
|
+
imageMetaData.capture_uuid = value
|
|
59
|
+
} else if (key === 'drone-dji:DroneID') {
|
|
60
|
+
imageMetaData.drone_id = value
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for(let key in flatedXmp) {
|
|
64
|
+
let value = flatedXmp[key]
|
|
65
|
+
if (key === 'drone-dji:GpsStatus' && value === 'RTK' && Number.isNaN(x_std)) {
|
|
66
|
+
x_std = 0.02
|
|
67
|
+
y_std = 0.02
|
|
68
|
+
} else if (key === 'drone-dji:AltitudeType' && value === 'RtkAlt' && Number.isNaN(z_std)) {
|
|
69
|
+
z_std = 0.02
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (!Number.isNaN(x_std) && !Number.isNaN(y_std) && !Number.isNaN(z_std)) {
|
|
73
|
+
imageMetaData.pos_std = [x_std, y_std, z_std]
|
|
74
|
+
}
|
|
75
|
+
if (!Number.isNaN(yaw) && !Number.isNaN(pitch) && !Number.isNaN(roll)) {
|
|
76
|
+
imageMetaData.pitch_roll_yaw = [pitch, roll, yaw]
|
|
77
|
+
imageMetaData.orientation = util.getRotationMatrix(pitch, roll, yaw)
|
|
78
|
+
}
|
|
79
|
+
if (exif.DateTimeOriginal) {
|
|
80
|
+
imageMetaData.capture_time = moment(exif.DateTimeOriginal, 'YYYY:MM:DD HH:mm:ss').valueOf()
|
|
81
|
+
}
|
|
82
|
+
if (exif.FocalLengthIn35mmFilm) {
|
|
83
|
+
imageMetaData.focal_length_in_35mm = exif.FocalLengthIn35mmFilm
|
|
84
|
+
}
|
|
85
|
+
if (util.hasNaN(pos)) {
|
|
86
|
+
pos = [lng, lat, alt]
|
|
87
|
+
}
|
|
88
|
+
if (!util.hasNaN(pos)) {
|
|
89
|
+
imageMetaData.pos = pos
|
|
90
|
+
imageMetaData.absolute_altitude = pos[2]
|
|
91
|
+
imageMetaData.coordinate_system = {
|
|
92
|
+
type: 2,
|
|
93
|
+
label: 'WGS 84',
|
|
94
|
+
type_name: 'Geographic',
|
|
95
|
+
epsg_code: 4326
|
|
96
|
+
}
|
|
97
|
+
if (!util.hasNaN([x_std, y_std, z_std])) { // 估算pos_sigma
|
|
98
|
+
let pos_sigma = []
|
|
99
|
+
let accuracy = Math.sqrt(Math.pow(x_std, 2) + Math.pow(y_std, 2))
|
|
100
|
+
if (accuracy < 0.03) {
|
|
101
|
+
pos_sigma[0] = pos_sigma[1] = 0.03
|
|
102
|
+
} else if (accuracy < 0.2) {
|
|
103
|
+
pos_sigma[0] = pos_sigma[1] = 0.2
|
|
104
|
+
} else {
|
|
105
|
+
pos_sigma[0] = pos_sigma[1] = 2.0
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (z_std < 0.03) {
|
|
109
|
+
pos_sigma[2] = 0.06
|
|
110
|
+
} else if (z_std < 0.2) {
|
|
111
|
+
pos_sigma[2] = 0.5
|
|
112
|
+
} else {
|
|
113
|
+
pos_sigma[2] = 5.0
|
|
114
|
+
}
|
|
115
|
+
imageMetaData.pos_sigma = pos_sigma
|
|
116
|
+
} else {
|
|
117
|
+
imageMetaData.pos_sigma = [2, 2, 5]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return imageMetaData
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export function parsePhotos (files, cb) {
|
|
124
|
+
let cameras = []
|
|
125
|
+
let processQueue = files
|
|
126
|
+
let total = files.length
|
|
127
|
+
let concurrence = 20 // 并发数
|
|
128
|
+
let request = 0 // 当前正在解析的照片数
|
|
129
|
+
|
|
130
|
+
return new Promise((resolve) => {
|
|
131
|
+
const run = () => {
|
|
132
|
+
for(let i = request;i < concurrence;i++) {
|
|
133
|
+
let file = processQueue.pop()
|
|
134
|
+
if (!file) {
|
|
135
|
+
break
|
|
136
|
+
}
|
|
137
|
+
request++
|
|
138
|
+
this.parsePhoto(file).then(meta_data => {
|
|
139
|
+
request--
|
|
140
|
+
let ext = file.split('.').pop()
|
|
141
|
+
let camera = {
|
|
142
|
+
width: meta_data.width,
|
|
143
|
+
height: meta_data.height,
|
|
144
|
+
ext,
|
|
145
|
+
parameters: meta_data.pre_calib_param || null
|
|
146
|
+
}
|
|
147
|
+
let item = cameras.find(d => {
|
|
148
|
+
return d.width === camera.width && d.height === camera.height && d.ext === camera.ext && _.isEqual(d.parameters, camera.parameters)
|
|
149
|
+
})
|
|
150
|
+
if (!item) {
|
|
151
|
+
item = camera
|
|
152
|
+
item.fileList = []
|
|
153
|
+
cameras.push(item)
|
|
154
|
+
}
|
|
155
|
+
item.fileList.push({
|
|
156
|
+
name: file.split('\\').pop(),
|
|
157
|
+
filePath: file,
|
|
158
|
+
meta_data
|
|
159
|
+
})
|
|
160
|
+
done()
|
|
161
|
+
}).catch(err => {
|
|
162
|
+
request--
|
|
163
|
+
done()
|
|
164
|
+
console.error(err)
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
const done = () => {
|
|
169
|
+
if (processQueue.length) {
|
|
170
|
+
run()
|
|
171
|
+
} else if (!request) {
|
|
172
|
+
resolve(cameras)
|
|
173
|
+
}
|
|
174
|
+
let parsed = total - processQueue.length - request
|
|
175
|
+
if (cb) {
|
|
176
|
+
cb(parsed, total)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
run()
|
|
180
|
+
})
|
|
181
|
+
}
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import _ from 'lodash'
|
|
2
|
+
import { formatDate, getAnnotationFeature } from '../util'
|
|
3
|
+
import {mapStyle, layerFolders} from '../constants'
|
|
4
|
+
import * as turf from '@turf/turf'
|
|
5
|
+
import mapboxgl from 'mapbox-gl'
|
|
6
|
+
mapboxgl.accessToken =
|
|
7
|
+
'pk.eyJ1Ijoid2FueWFueWFuIiwiYSI6Im1uNVZnTncifQ.90XY40_yjpItUHO8HnbbpA'
|
|
8
|
+
|
|
9
|
+
export async function generateReport (params) {
|
|
10
|
+
let {projectInfo, taskInfo, annotations} = params
|
|
11
|
+
return {
|
|
12
|
+
title: '标注报告',
|
|
13
|
+
projectName: projectInfo.name,
|
|
14
|
+
taskName: taskInfo.name,
|
|
15
|
+
user_id: taskInfo.user_id,
|
|
16
|
+
project_id: taskInfo.project_id,
|
|
17
|
+
task_id: taskInfo.task_id,
|
|
18
|
+
data_type: taskInfo.data_type,
|
|
19
|
+
sections: [
|
|
20
|
+
{
|
|
21
|
+
title: '任务概览',
|
|
22
|
+
content: [
|
|
23
|
+
{
|
|
24
|
+
type: 'form',
|
|
25
|
+
items: getTaskPreview(taskInfo)
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: 'image',
|
|
29
|
+
imageType: 'overview'
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
title: '标注列表',
|
|
35
|
+
content: [
|
|
36
|
+
{
|
|
37
|
+
type: 'sub-title',
|
|
38
|
+
label: '点标注'
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
type: 'annotation-list',
|
|
42
|
+
colums: getPointColums(taskInfo.data_type),
|
|
43
|
+
data: getAnnoData(annotations, 'point')
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: 'sub-title',
|
|
47
|
+
label: '线标注'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: 'annotation-list',
|
|
51
|
+
colums: getLineColums(taskInfo.data_type),
|
|
52
|
+
data: getAnnoData(annotations, 'line')
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: 'sub-title',
|
|
56
|
+
label: '面标注'
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'annotation-list',
|
|
60
|
+
colums: getPolygonColums(taskInfo.data_type),
|
|
61
|
+
data: getAnnoData(annotations, 'polygon')
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
type: 'page-line' // 分页
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
title: '标注详情',
|
|
70
|
+
content: [
|
|
71
|
+
{
|
|
72
|
+
type: 'details',
|
|
73
|
+
data: getAnnotationDetails(annotations, taskInfo)
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function getTaskPreview (taskInfo) {
|
|
82
|
+
return [
|
|
83
|
+
{
|
|
84
|
+
label: '任务名称',
|
|
85
|
+
value: taskInfo.name
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
label: '任务类型',
|
|
89
|
+
value: getDataType(taskInfo.data_type)
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
label: '数据采集时间',
|
|
93
|
+
value: formatDate(taskInfo.captured_at)
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
label: '重建时间',
|
|
97
|
+
value: formatDate(taskInfo.completed_at)
|
|
98
|
+
}
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function getDataType (type) {
|
|
103
|
+
if (type === 'infrared') {
|
|
104
|
+
return '热红外'
|
|
105
|
+
} else if (type === 'multispectral') {
|
|
106
|
+
return '多光谱'
|
|
107
|
+
} else {
|
|
108
|
+
return '可见光'
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function getPointColums (data_type) {
|
|
113
|
+
return [
|
|
114
|
+
{
|
|
115
|
+
title: '',
|
|
116
|
+
slot: 'color',
|
|
117
|
+
key: 'color',
|
|
118
|
+
width: 100
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
title: '名称',
|
|
122
|
+
key: 'name'
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
title: '经度(X)',
|
|
126
|
+
key: 'x'
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
title: '纬度(Y)',
|
|
130
|
+
key: 'y'
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
title: data_type === 'infrared' ? '温度(℃)' : '高度(Z)',
|
|
134
|
+
key: data_type === 'infrared' ? 'temprature' : 'height'
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function getLineColums (data_type) {
|
|
140
|
+
if (data_type === 'infrared') {
|
|
141
|
+
return [
|
|
142
|
+
{
|
|
143
|
+
title: '',
|
|
144
|
+
slot: 'color',
|
|
145
|
+
key: 'color',
|
|
146
|
+
width: 100
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
title: '名称',
|
|
150
|
+
key: 'name'
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
title: '长度(m)',
|
|
154
|
+
key: 'distance2d'
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
title: '最低温度(℃)',
|
|
158
|
+
key: 'temprature_min'
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
title: '最高温度(℃)',
|
|
162
|
+
key: 'temprature_max'
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
} else {
|
|
166
|
+
return [
|
|
167
|
+
{
|
|
168
|
+
title: '',
|
|
169
|
+
slot: 'color',
|
|
170
|
+
key: 'color',
|
|
171
|
+
width: 100
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
title: '名称',
|
|
175
|
+
key: 'name'
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
title: '2D长度(m)',
|
|
179
|
+
key: 'distance2d'
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
title: '3D长度(m)',
|
|
183
|
+
key: 'distance3d'
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
title: '最小坡度(°)',
|
|
187
|
+
key: 'slope_min'
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
title: '最大坡度(°)',
|
|
191
|
+
key: 'slope_max'
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
title: '最小高度(m)',
|
|
195
|
+
key: 'height_min'
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
title: '最大高度(m)',
|
|
199
|
+
key: 'height_max'
|
|
200
|
+
}
|
|
201
|
+
]
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function getPolygonColums (data_type) {
|
|
206
|
+
if (data_type === 'infrared') {
|
|
207
|
+
return [
|
|
208
|
+
{
|
|
209
|
+
title: '',
|
|
210
|
+
slot: 'color',
|
|
211
|
+
key: 'color',
|
|
212
|
+
width: 100
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
title: '名称',
|
|
216
|
+
key: 'name'
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
title: '面积(㎡)',
|
|
220
|
+
key: 'area2d'
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
title: '周长(m)',
|
|
224
|
+
key: 'distance2d'
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
title: '最低温度(℃)',
|
|
228
|
+
key: 'temprature_min'
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
title: '最高温度(℃)',
|
|
232
|
+
key: 'temprature_max'
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
} else {
|
|
236
|
+
return [
|
|
237
|
+
{
|
|
238
|
+
title: '',
|
|
239
|
+
slot: 'color',
|
|
240
|
+
key: 'color',
|
|
241
|
+
width: 100
|
|
242
|
+
},
|
|
243
|
+
{
|
|
244
|
+
title: '名称',
|
|
245
|
+
key: 'name'
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
title: '2D面积(㎡)',
|
|
249
|
+
key: 'area2d'
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
title: '3D面积(㎡)',
|
|
253
|
+
key: 'area3d'
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
title: '2D周长(m)',
|
|
257
|
+
key: 'distance2d'
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
title: '3D周长(m)',
|
|
261
|
+
key: 'distance3d'
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
title: '最小高度(m)',
|
|
265
|
+
key: 'height_min'
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
title: '最大高度(m)',
|
|
269
|
+
key: 'height_max'
|
|
270
|
+
}
|
|
271
|
+
]
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function getAnnoData (annotations, type) {
|
|
276
|
+
return annotations.filter(d => d.type === type).map(d => {
|
|
277
|
+
let obj = _.cloneDeep(d)
|
|
278
|
+
if (type === 'point') {
|
|
279
|
+
let coord = d.geometry.coordinates
|
|
280
|
+
obj.x = _.round(coord[0], 6)
|
|
281
|
+
obj.y = _.round(coord[1], 6)
|
|
282
|
+
}
|
|
283
|
+
delete obj.geometry
|
|
284
|
+
return obj
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function getAnnotationDetails (annotations, taskInfo) {
|
|
289
|
+
let {data_type} = taskInfo
|
|
290
|
+
let colums = {
|
|
291
|
+
point: getPointColums(data_type),
|
|
292
|
+
line: getLineColums(data_type),
|
|
293
|
+
polygon: getPolygonColums(data_type)
|
|
294
|
+
}
|
|
295
|
+
let sortIndex = {point: 1, line: 2, polygon: 3}
|
|
296
|
+
let sorted = annotations.sort((a, b) => sortIndex[a.type] - sortIndex[b.type])
|
|
297
|
+
let items = []
|
|
298
|
+
let features = []
|
|
299
|
+
sorted.forEach(anno => {
|
|
300
|
+
let {id, type, name, color} = anno
|
|
301
|
+
let data = {}
|
|
302
|
+
colums[type].forEach(col => {
|
|
303
|
+
if (col.key === 'color' || col.key === 'name') {
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
if (type === 'point') {
|
|
307
|
+
let coord = anno.geometry.coordinates
|
|
308
|
+
anno.x = _.round(coord[0], 6)
|
|
309
|
+
anno.y = _.round(coord[1], 6)
|
|
310
|
+
}
|
|
311
|
+
data[col.title] = anno[col.key]
|
|
312
|
+
})
|
|
313
|
+
let feature = getAnnotationFeature(anno)
|
|
314
|
+
features.push(feature)
|
|
315
|
+
items.push({
|
|
316
|
+
id,
|
|
317
|
+
name,
|
|
318
|
+
type,
|
|
319
|
+
color,
|
|
320
|
+
data,
|
|
321
|
+
feature,
|
|
322
|
+
image: ''
|
|
323
|
+
})
|
|
324
|
+
})
|
|
325
|
+
return items
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
function getStyle (features, report) {
|
|
329
|
+
let style = _.cloneDeep(mapStyle)
|
|
330
|
+
style.layers.push({
|
|
331
|
+
id: 'background',
|
|
332
|
+
type: 'background',
|
|
333
|
+
paint: {
|
|
334
|
+
'background-color': '#000000'
|
|
335
|
+
}
|
|
336
|
+
})
|
|
337
|
+
let {taskName, projectName, user_id, data_type} = report
|
|
338
|
+
let type = data_type === 'infrared' ? 'tmp' : 'dom'
|
|
339
|
+
let tileUrl = `http://127.0.0.1:10024/${user_id}/${projectName}/${taskName}/result/2D/${layerFolders[type]}/{z}/{x}/{y}.webp`
|
|
340
|
+
style.sources.dom_image = {
|
|
341
|
+
'type': 'raster',
|
|
342
|
+
'tiles': [ tileUrl ],
|
|
343
|
+
'tileSize': 512
|
|
344
|
+
}
|
|
345
|
+
style.sources.annotation = {
|
|
346
|
+
type: 'geojson',
|
|
347
|
+
data: {
|
|
348
|
+
type: 'FeatureCollection',
|
|
349
|
+
features
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
style.layers.push({
|
|
353
|
+
'id': 'dom_image',
|
|
354
|
+
'source': 'dom_image',
|
|
355
|
+
'type': 'raster'
|
|
356
|
+
})
|
|
357
|
+
style.layers.push({
|
|
358
|
+
'id': 'annotation-point',
|
|
359
|
+
'type': 'circle',
|
|
360
|
+
filter: ['==', '$type', 'Point'],
|
|
361
|
+
source: 'annotation',
|
|
362
|
+
'paint': {
|
|
363
|
+
'circle-radius': 10,
|
|
364
|
+
'circle-color': ['get', 'color']
|
|
365
|
+
}
|
|
366
|
+
})
|
|
367
|
+
style.layers.push({
|
|
368
|
+
'id': 'annotation-line',
|
|
369
|
+
'type': 'line',
|
|
370
|
+
filter: ['!=', '$type', 'Point'],
|
|
371
|
+
source: 'annotation',
|
|
372
|
+
'layout': {
|
|
373
|
+
'line-cap': 'round',
|
|
374
|
+
'line-join': 'round'
|
|
375
|
+
},
|
|
376
|
+
'paint': {
|
|
377
|
+
'line-color': ['get', 'color'],
|
|
378
|
+
'line-width': 4
|
|
379
|
+
}
|
|
380
|
+
})
|
|
381
|
+
style.layers.push({
|
|
382
|
+
'id': 'annotation-polygon',
|
|
383
|
+
'type': 'fill',
|
|
384
|
+
filter: ['==', '$type', 'Polygon'],
|
|
385
|
+
source: 'annotation',
|
|
386
|
+
'paint': {
|
|
387
|
+
'fill-color': ['get', 'color'],
|
|
388
|
+
'fill-opacity': 0.1
|
|
389
|
+
}
|
|
390
|
+
})
|
|
391
|
+
return style
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export function initMap (features, report) {
|
|
395
|
+
return new Promise((resolve) => {
|
|
396
|
+
let style = getStyle(features, report)
|
|
397
|
+
let div = document.createElement('div')
|
|
398
|
+
div.style.width = '800px'
|
|
399
|
+
div.style.height = '400px'
|
|
400
|
+
div.style.position = 'absolute'
|
|
401
|
+
div.style.zIndex = '-1'
|
|
402
|
+
document.body.appendChild(div)
|
|
403
|
+
let map = new mapboxgl.Map({
|
|
404
|
+
container: div,
|
|
405
|
+
style: style,
|
|
406
|
+
bearing: 0,
|
|
407
|
+
pitch: 0,
|
|
408
|
+
center: [110.9, 32.79],
|
|
409
|
+
zoom: 4.2,
|
|
410
|
+
interactive: true,
|
|
411
|
+
doubleClickZoom: false,
|
|
412
|
+
dragRotate: false,
|
|
413
|
+
pitchWithRotate: false,
|
|
414
|
+
preserveDrawingBuffer: true,
|
|
415
|
+
localFontFamily: 'sans-serif'
|
|
416
|
+
})
|
|
417
|
+
map.on('load', () => {
|
|
418
|
+
resolve(map)
|
|
419
|
+
})
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
export function removeMap (map) {
|
|
425
|
+
map.remove()
|
|
426
|
+
document.body.removeChild(map.getContainer())
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
export function getImage (map, feature) {
|
|
430
|
+
let extent = turf.bbox(feature)
|
|
431
|
+
let {id} = feature.properties
|
|
432
|
+
map.fitBounds(extent, {
|
|
433
|
+
animate: false,
|
|
434
|
+
padding: 50,
|
|
435
|
+
maxZoom: 19
|
|
436
|
+
})
|
|
437
|
+
map.setFilter('annotation-point', ['all', ['==', '$type', 'Point'], ['==', 'id', id]])
|
|
438
|
+
map.setFilter('annotation-line', ['all', ['!=', '$type', 'Point'], ['==', 'id', id]])
|
|
439
|
+
map.setFilter('annotation-polygon', ['all', ['==', '$type', 'Polygon'], ['==', 'id', id]])
|
|
440
|
+
return new Promise((resolve) => {
|
|
441
|
+
map.once('idle', () => {
|
|
442
|
+
let canvas = map.getCanvas()
|
|
443
|
+
resolve(canvas.toDataURL('image/png'))
|
|
444
|
+
})
|
|
445
|
+
})
|
|
446
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as turf from '@turf/turf'
|
|
2
|
+
import _ from 'lodash'
|
|
3
|
+
import { transformCoordinateToLngLat } from '../transform'
|
|
4
|
+
|
|
5
|
+
const EARTH_RADIUS = 6378137
|
|
6
|
+
|
|
7
|
+
export function getFeatures (photoList, imagePosDiff, zoom) {
|
|
8
|
+
let features = []
|
|
9
|
+
let minDiff_z = Infinity
|
|
10
|
+
let maxDiff_z = -Infinity
|
|
11
|
+
let ratio = getRatio(zoom, imagePosDiff)
|
|
12
|
+
let endPoints = []
|
|
13
|
+
// 先获取坐标系
|
|
14
|
+
let item = photoList.find(d => d.meta_data.pos)
|
|
15
|
+
if (item) {
|
|
16
|
+
let coordinate_system = _.cloneDeep(item.meta_data.coordinate_system)
|
|
17
|
+
photoList.forEach((photo, index) => {
|
|
18
|
+
let {meta_data} = photo
|
|
19
|
+
let startPoint = transformCoordinateToLngLat(meta_data.pos, coordinate_system)
|
|
20
|
+
if (!startPoint) {
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
let id = index + 1
|
|
24
|
+
let diffItem = imagePosDiff.find(d => d.id === id)
|
|
25
|
+
if (!diffItem) {
|
|
26
|
+
return
|
|
27
|
+
}
|
|
28
|
+
// 计算z方向的误差最大值,用于给椭圆设置颜色
|
|
29
|
+
let diffs = diffItem.pos_diff
|
|
30
|
+
minDiff_z = Math.min(minDiff_z, diffs[2])
|
|
31
|
+
maxDiff_z = Math.max(maxDiff_z, diffs[2])
|
|
32
|
+
let endPoint = _.cloneDeep(startPoint)
|
|
33
|
+
endPoint[0] += diffs[0] * ratio * getDegreePerMeters()
|
|
34
|
+
endPoint[1] += diffs[1] * ratio * getDegreePerMeters()
|
|
35
|
+
endPoints.push(endPoint)
|
|
36
|
+
features.push(turf.lineString([startPoint, endPoint], {
|
|
37
|
+
diff_x: 100 * diffs[0],
|
|
38
|
+
diff_y: 100 * diffs[1],
|
|
39
|
+
diff_z: 100 * diffs[2]
|
|
40
|
+
}))
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
geojson: turf.featureCollection(features),
|
|
45
|
+
ratio,
|
|
46
|
+
minDiff_z,
|
|
47
|
+
maxDiff_z,
|
|
48
|
+
endPoints
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// 获取误差椭圆的缩放系数。要把误差直观反应到地图上需要对误差椭圆进行缩放,其缩放的大小跟误差的大小和当前地图的级别有关
|
|
53
|
+
// 本函数假设要让最大的误差在当前地图层级上显示出30像素的大小,以此来预估缩放系数
|
|
54
|
+
function getRatio (zoom, diffs) {
|
|
55
|
+
// 最大误差值
|
|
56
|
+
let max = diffs.reduce((m, item) => {
|
|
57
|
+
if (!item.pos_diff?.length) {
|
|
58
|
+
return m
|
|
59
|
+
}
|
|
60
|
+
let d = Math.max(Math.abs(item.pos_diff[0]), Math.abs(item.pos_diff[1]))
|
|
61
|
+
return m > d ? m : d
|
|
62
|
+
})
|
|
63
|
+
// 地图上30像素代表的距离
|
|
64
|
+
let distance = 30 * 2 * Math.PI * EARTH_RADIUS / (Math.pow(2, zoom) * 512)
|
|
65
|
+
let ratio = distance / max
|
|
66
|
+
if (ratio < 1) {
|
|
67
|
+
return Number(ratio.toFixed(1))
|
|
68
|
+
}
|
|
69
|
+
if (ratio < 10) {
|
|
70
|
+
return Math.round(ratio)
|
|
71
|
+
}
|
|
72
|
+
if (ratio < 100) {
|
|
73
|
+
return 10 * parseInt(ratio / 10)
|
|
74
|
+
}
|
|
75
|
+
return Math.max(Math.round(ratio / 100) * 100, 100)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 墨卡托坐标系每米对应的经纬度度数
|
|
79
|
+
function getDegreePerMeters () {
|
|
80
|
+
return 180 / (Math.PI * EARTH_RADIUS)
|
|
81
|
+
}
|