-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdata.js
More file actions
150 lines (129 loc) · 5.16 KB
/
data.js
File metadata and controls
150 lines (129 loc) · 5.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// parcel-data.js: ULDK API, WKT parsing, geometry calculations
import { wktToGeoJSON } from 'https://cdn.jsdelivr.net/npm/betterknown@1.0.5/+esm';
// ULDK API functions
function parseUldkResponse(text) {
// Example:
// 0\nSRID=4326;POLYGON((...))|Winiary|powiat Poznań|Poznań (miasto)|wielkopolskie|powiat Poznań (wfs)|306401_1.0052.AR_21.85/1
const lines = text.trim().split(/\r?\n/);
if (lines[0] !== '0') throw new Error('ULDK error code: ' + lines[0]);
const parts = lines[1].split('|');
if (parts.length < 7) throw new Error('Nieprawidłowa odpowiedź ULDK');
const [geom_wkt, region, county, commune, voivodeship, datasource, id] = parts;
return {
geom_wkt: geom_wkt.replace(/^SRID=\d+;/, ''),
region,
county,
commune,
voivodeship,
datasource,
id
};
}
export async function fetchParcelById(id) {
const url = `https://uldk.gugik.gov.pl/?request=GetParcelById&id=${encodeURIComponent(id)}&result=geom_wkt,region,county,commune,voivodeship,datasource,id&srid=4326`;
const resp = await fetch(url);
const text = await resp.text();
const response = parseUldkResponse(text);
return response;
}
export async function fetchParcelByXY(lng, lat) {
const url = `https://uldk.gugik.gov.pl/?request=GetParcelByXY&xy=${lng},${lat},4326&result=geom_wkt,region,county,commune,voivodeship,datasource,id&srid=4326`;
const resp = await fetch(url);
const text = await resp.text();
const response = parseUldkResponse(text);
return response;
}
// Drawing and geometry functions
export function drawParcel(map, geojson) {
if (map._parcelLayer) map.removeLayer(map._parcelLayer);
map._parcelLayer = L.geoJSON(geojson, {
className: 'parcel-polygon'
}).addTo(map);
map.fitBounds(map._parcelLayer.getBounds(), { maxZoom: 17 });
// Draw vertex markers with indices
if (map._vertexMarkers) map._vertexMarkers.forEach(m => map.removeLayer(m));
map._vertexMarkers = [];
const coords = geojson.coordinates[0];
coords.forEach((coord, i) => {
const [lng, lat] = coord;
const marker = L.marker([lat, lng], {
icon: L.divIcon({
html: i.toString(),
className: 'vertex-label',
iconSize: [20, 20],
iconAnchor: [10, 10]
})
}).addTo(map);
map._vertexMarkers.push(marker);
});
return map._parcelLayer;
}
// Geometry calculations
export function findNearestVertex(uniqueCoords, userPosition) {
const userPt = turf.point([userPosition.lng, userPosition.lat]);
let minDist = Infinity, minIdx = -1;
uniqueCoords.forEach(([lng, lat], i) => {
const dist = turf.distance(userPt, turf.point([lng, lat]), { units: 'meters' });
if (dist < minDist) {
minDist = dist;
minIdx = i;
}
});
if (minIdx === -1) return null;
return { index: minIdx, lat: uniqueCoords[minIdx][1], lng: uniqueCoords[minIdx][0], distance: minDist };
}
export function measureEdges(uniqueCoords, idx, userPosition) {
const userPt = [userPosition.lng, userPosition.lat];
const len = uniqueCoords.length;
const prevIdx = (idx - 1 + len) % len;
const nextIdx = (idx + 1) % len;
const edges = [
{ idx: prevIdx, start: uniqueCoords[prevIdx], end: uniqueCoords[idx] },
{ idx: idx, start: uniqueCoords[idx], end: uniqueCoords[nextIdx] }
];
return edges.map(ed => {
const distProj = distanceToInfiniteLine(userPt, ed.start, ed.end);
return {
edgeIndex: ed.idx,
distanceM: distProj.distance,
projLat: distProj.proj[1],
projLng: distProj.proj[0]
};
});
}
function distanceToInfiniteLine(point, start, end) {
const [px, py] = point;
const [x1, y1] = start;
const [x2, y2] = end;
// Use turf.js for proper distance calculations instead of manual conversion
// Create points for calculation
const userPoint = turf.point([px, py]);
const startPoint = turf.point([x1, y1]);
const endPoint = turf.point([x2, y2]);
if (turf.distance(startPoint, endPoint, { units: 'meters' }) === 0) {
// start == end, distance to point
const dist = turf.distance(userPoint, startPoint, { units: 'meters' });
return { distance: dist, proj: [x1, y1] };
}
// Calculate bearing and distance from start to end
const bearing = turf.bearing(startPoint, endPoint);
const lineDistance = turf.distance(startPoint, endPoint, { units: 'meters' });
// Calculate the projection parameter t using spherical geometry
const userBearing = turf.bearing(startPoint, userPoint);
const userDistance = turf.distance(startPoint, userPoint, { units: 'meters' });
// Convert bearings to radians and calculate dot product equivalent
const lineBearingRad = bearing * Math.PI / 180;
const userBearingRad = userBearing * Math.PI / 180;
const dotProduct = Math.cos(userBearingRad - lineBearingRad);
const t = (userDistance * dotProduct) / lineDistance;
// Calculate projection point along the infinite line
const projectionDistance = t * lineDistance;
const projPoint = turf.destination(startPoint, projectionDistance, bearing, { units: 'meters' });
// Calculate perpendicular distance
const dist = turf.distance(userPoint, projPoint, { units: 'meters' });
return {
distance: dist,
proj: projPoint.geometry.coordinates
};
}
export { wktToGeoJSON };