forked from VinokurovVE/tests
Tile generation
This commit is contained in:
@ -7,7 +7,7 @@ import { Draw, Modify, Select, Snap, Translate } from 'ol/interaction'
|
||||
import { ImageStatic, OSM, TileDebug, Vector as VectorSource, XYZ } from 'ol/source'
|
||||
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'
|
||||
import { Divider, IconButton, Slider, Stack, Select as MUISelect, MenuItem, Box, Typography } from '@mui/material'
|
||||
import { Add, Adjust, Api, CircleOutlined, OpenWith, RectangleOutlined, Straighten, Timeline, Undo, Warning } from '@mui/icons-material'
|
||||
import { Add, Adjust, Api, CircleOutlined, OpenWith, RectangleOutlined, Straighten, Timeline, Undo, Upload, Warning } from '@mui/icons-material'
|
||||
import { Type } from 'ol/geom/Geometry'
|
||||
import { click, never, noModifierKeys, platformModifierKeyOnly, primaryAction, shiftKeyOnly } from 'ol/events/condition'
|
||||
import Feature from 'ol/Feature'
|
||||
@ -26,6 +26,7 @@ import { Stroke, Fill, Circle as CircleStyle, Style } from 'ol/style'
|
||||
import { calculateExtent, calculateRotationAngle, rotateProjection } from './mapUtils'
|
||||
import MapBrowserEvent from 'ol/MapBrowserEvent'
|
||||
import { get } from 'ol/proj'
|
||||
import axios from 'axios'
|
||||
|
||||
const MapComponent = () => {
|
||||
const [currentCoordinate, setCurrentCoordinate] = useState<Coordinate | null>(null)
|
||||
@ -33,15 +34,29 @@ const MapComponent = () => {
|
||||
const [currentX, setCurrentX] = useState<number | undefined>(undefined)
|
||||
const [currentY, setCurrentY] = useState<number | undefined>(undefined)
|
||||
|
||||
const [testExtent, setTestExtent] = useState<Extent | null>(null)
|
||||
|
||||
const [file, setFile] = useState(null)
|
||||
const [polygonExtent, setPolygonExtent] = useState<Extent | undefined>(undefined)
|
||||
const [bottomLeft, setBottomLeft] = useState<Coordinate | undefined>(undefined)
|
||||
const [topLeft, setTopLeft] = useState<Coordinate | undefined>(undefined)
|
||||
const [topRight, setTopRight] = useState<Coordinate | undefined>(undefined)
|
||||
const [bottomRight, setBottomRight] = useState<Coordinate | undefined>(undefined)
|
||||
|
||||
const mapElement = useRef<HTMLDivElement | null>(null)
|
||||
const [currentTool, setCurrentTool] = useState<Type | null>(null)
|
||||
|
||||
const map = useRef<Map | null>(null)
|
||||
|
||||
const [satMapsProvider, setSatMapsProvider] = useState<SatelliteMapsProvider>('yandex')
|
||||
const [satMapsProvider, setSatMapsProvider] = useState<SatelliteMapsProvider>('custom')
|
||||
|
||||
const gMapsSatSource = useRef<XYZ>(googleMapsSatelliteSource)
|
||||
|
||||
const customMapSource = useRef<XYZ>(new XYZ({
|
||||
url: `${import.meta.env.VITE_API_EMS_URL}/tile/custom/{z}/{x}/{y}`,
|
||||
attributions: 'Custom map data'
|
||||
}))
|
||||
|
||||
const yMapsSatSource = useRef<XYZ>(yandexMapsSatelliteSource)
|
||||
|
||||
const satLayer = useRef<TileLayer>(new TileLayer({
|
||||
@ -204,6 +219,7 @@ const MapComponent = () => {
|
||||
const files = event.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
const file = files[0];
|
||||
setFile(file)
|
||||
|
||||
if (file.type.startsWith('image/')) {
|
||||
const reader = new FileReader();
|
||||
@ -316,6 +332,12 @@ const MapComponent = () => {
|
||||
const topRight = polygonFeature.getGeometry()?.getCoordinates()[0][2]
|
||||
const bottomRight = polygonFeature.getGeometry()?.getCoordinates()[0][3]
|
||||
|
||||
setPolygonExtent(newExtent)
|
||||
setBottomLeft(bottomLeft)
|
||||
setTopLeft(topLeft)
|
||||
setTopRight(topRight)
|
||||
setBottomRight(bottomRight)
|
||||
|
||||
if (newExtent && bottomLeft && bottomRight && topRight && topLeft) {
|
||||
const originalExtent = calculateExtent(bottomLeft, topLeft, topRight, bottomRight)
|
||||
|
||||
@ -332,17 +354,59 @@ const MapComponent = () => {
|
||||
|
||||
const mapWidth = Math.abs(worldExtent[0] - worldExtent[2])
|
||||
const mapHeight = Math.abs(worldExtent[1] - worldExtent[3])
|
||||
const tileWidth = mapWidth / (zoomLevel * 4)
|
||||
const tileHeight = mapHeight / (zoomLevel * 4)
|
||||
const newMinX = worldExtent[0] + (tileWidth * minX)
|
||||
const newMaxX = worldExtent[0] + (tileWidth * (maxX + 1))
|
||||
|
||||
const newMinY = worldExtent[1] + (tileHeight * (maxY + 1))
|
||||
const newMaxY = worldExtent[1] + (tileHeight * minY)
|
||||
const tilesH = Math.sqrt(Math.pow(4, zoomLevel))
|
||||
const tileWidth = mapWidth / (Math.sqrt(Math.pow(4, zoomLevel)))
|
||||
const tileHeight = mapHeight / (Math.sqrt(Math.pow(4, zoomLevel)))
|
||||
|
||||
let minPosX = minX - (tilesH / 2)
|
||||
let maxPosX = maxX - (tilesH / 2) + 1
|
||||
let minPosY = -(minY - (tilesH / 2))
|
||||
let maxPosY = -(maxY - (tilesH / 2) + 1)
|
||||
console.log(`tileWidth: ${tileWidth} minPosX: ${minPosX} maxPosX: ${maxPosX} minPosY: ${minPosY} maxPosY: ${maxPosY}`)
|
||||
|
||||
const newMinX = tileWidth * minPosX
|
||||
const newMaxX = tileWidth * maxPosX
|
||||
const newMinY = tileHeight * maxPosY
|
||||
const newMaxY = tileHeight * minPosY
|
||||
|
||||
console.log('Tile slippy bounds: ', minX, maxX, minY, maxY)
|
||||
console.log('Tile bounds: ', newMinX, newMaxX, newMinY, newMaxY)
|
||||
|
||||
const angleDegrees = calculateRotationAngle(bottomLeft, bottomRight) * 180 / Math.PI
|
||||
|
||||
const paddingLeft = Math.abs(newExtent[0] - newMinX)
|
||||
const paddingRight = Math.abs(newExtent[2] - newMaxX)
|
||||
const paddingTop = Math.abs(newExtent[3] - newMaxY)
|
||||
const paddingBottom = Math.abs(newExtent[1] - newMinY)
|
||||
|
||||
const pixelWidth = Math.abs(minX - (maxX + 1)) * 256
|
||||
const pixelHeight = Math.abs(minY - (maxY + 1)) * 256
|
||||
|
||||
const width = Math.abs(newMinX - newMaxX)
|
||||
const perPixel = width / pixelWidth
|
||||
|
||||
const paddingLeftPixel = paddingLeft / perPixel
|
||||
const paddingRightPixel = paddingRight / perPixel
|
||||
const paddingTopPixel = paddingTop / perPixel
|
||||
const paddingBottomPixel = paddingBottom / perPixel
|
||||
|
||||
console.log('Rotation angle degrees: ', angleDegrees)
|
||||
|
||||
console.log('Padding top pixel: ', paddingTopPixel)
|
||||
console.log('Padding left pixel: ', paddingLeftPixel)
|
||||
console.log('Padding right pixel: ', paddingRightPixel)
|
||||
console.log('Padding bottom pixel: ', paddingBottomPixel)
|
||||
|
||||
console.log('Per pixel: ', width / pixelWidth)
|
||||
|
||||
const boundsWidthPixel = Math.abs(newExtent[0] - newExtent[2]) / perPixel
|
||||
const boundsHeightPixel = Math.abs(newExtent[1] - newExtent[3]) / perPixel
|
||||
console.log('Bounds width pixel', boundsWidthPixel)
|
||||
console.log('Bounds height pixel', boundsHeightPixel)
|
||||
|
||||
// Result will be sharp rotate(angleDegrees), resize(boundsWidthPixel), extend()
|
||||
|
||||
const newImageSource = new ImageStatic({
|
||||
url: imageUrl,
|
||||
imageExtent: originalExtent,
|
||||
@ -623,10 +687,31 @@ const MapComponent = () => {
|
||||
|
||||
// Satellite tiles setting
|
||||
useEffect(() => {
|
||||
satLayer.current?.setSource(satMapsProvider == 'google' ? gMapsSatSource.current : satMapsProvider == 'yandex' ? yMapsSatSource.current : gMapsSatSource.current)
|
||||
satLayer.current?.setSource(satMapsProvider == 'google' ? gMapsSatSource.current : satMapsProvider == 'yandex' ? yMapsSatSource.current : satMapsProvider == 'custom' ? customMapSource.current : gMapsSatSource.current)
|
||||
satLayer.current?.getSource()?.refresh()
|
||||
}, [satMapsProvider])
|
||||
|
||||
const submitOverlay = async () => {
|
||||
if (file && polygonExtent && bottomLeft && topLeft && topRight && bottomRight) {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
formData.append('extentMinX', polygonExtent[0].toString())
|
||||
formData.append('extentMinY', polygonExtent[1].toString())
|
||||
formData.append('extentMaxX', polygonExtent[2].toString())
|
||||
formData.append('extentMaxY', polygonExtent[3].toString())
|
||||
formData.append('blX', bottomLeft[0].toString())
|
||||
formData.append('blY', bottomLeft[1].toString())
|
||||
formData.append('tlX', topLeft[0].toString())
|
||||
formData.append('tlY', topLeft[1].toString())
|
||||
formData.append('trX', topRight[0].toString())
|
||||
formData.append('trY', topRight[1].toString())
|
||||
formData.append('brX', bottomRight[0].toString())
|
||||
formData.append('brY', bottomRight[1].toString())
|
||||
|
||||
await fetch(`${import.meta.env.VITE_API_EMS_URL}/upload`, { method: 'POST', body: formData })
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack flex={1} flexDirection='column'>
|
||||
<Stack my={1} spacing={1} direction='row' divider={<Divider orientation='vertical' flexItem />}>
|
||||
@ -634,15 +719,24 @@ const MapComponent = () => {
|
||||
<Add />
|
||||
</IconButton>
|
||||
|
||||
<Typography>
|
||||
{currentCoordinate?.[0]}-{currentCoordinate?.[1]}
|
||||
</Typography>
|
||||
<Stack>
|
||||
<Typography>
|
||||
x: {currentCoordinate?.[0]}
|
||||
</Typography>
|
||||
<Typography>
|
||||
y: {currentCoordinate?.[1]}
|
||||
</Typography>
|
||||
</Stack>
|
||||
|
||||
<Typography>
|
||||
Z={currentZ}
|
||||
X={currentX}
|
||||
Y={currentY}
|
||||
</Typography>
|
||||
|
||||
<IconButton onClick={() => submitOverlay()}>
|
||||
<Upload />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
<Stack my={1} spacing={1} direction='row' divider={<Divider orientation='vertical' flexItem />}>
|
||||
|
||||
@ -660,6 +754,7 @@ const MapComponent = () => {
|
||||
>
|
||||
<MenuItem value={'google'}>Google</MenuItem>
|
||||
<MenuItem value={'yandex'}>Яндекс</MenuItem>
|
||||
<MenuItem value={'custom'}>Custom</MenuItem>
|
||||
</MUISelect>
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user