This commit is contained in:
2025-07-07 20:11:59 +08:00
parent ab0fdbc447
commit 06e3aa2eb3
2009 changed files with 193082 additions and 0 deletions

View File

@ -0,0 +1,133 @@
package clt
import (
"bytes"
"compress/gzip"
"encoding/json"
"fmt"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/tiger1103/gfast/v3/api/v1/common/globe"
"github.com/tiger1103/gfast/v3/api/v1/common/tool"
"github.com/tiger1103/gfast/v3/database"
"github.com/tiger1103/gfast/v3/database/sqlite"
"io"
"net/http"
"os"
"path"
"strings"
)
func InitCltData(group *ghttp.RouterGroup) {
group.GET("/data/tileset/{source_id}/*.action", cltCallback)
group.GET("/data/bim/{source_id}/*.action", cltCallback)
}
func GetTile(sourceid, p string) []byte {
md5 := tool.Md5V(p)
tile := globe.Tile{}
database.GetSourceDB(sourceid).DB.Select("tile").Where("md5=?", md5).First(&tile)
// 创建一个字节缓冲区,并将压缩数据写入其中
buf := bytes.NewBuffer(tile.Tile)
// 创建一个gzip.Reader对象用于解压缩数据
reader, _ := gzip.NewReader(buf)
defer reader.Close()
// 读取解压缩后的数据
decompressedData, _ := io.ReadAll(reader)
return decompressedData
}
func cltCallback(request *ghttp.Request) {
sourceId := request.Get("source_id").String()
cltObj := database.GetSourceDB(sourceId)
if cltObj.DB == nil {
request.Response.WriteStatus(http.StatusNotFound)
return
}
argcs := strings.Split(request.RequestURI, "/")
argcs = argcs[7:]
md5 := tool.Md5V(strings.Join(argcs, "/"))
tile := globe.Tile{}
RowsAffected := cltObj.DB.Select("tile").Where("md5=?", md5).Find(&tile).RowsAffected
if RowsAffected == 0 {
request.Response.WriteStatus(http.StatusNotFound)
return
}
suffix := path.Ext(request.RequestURI)
if suffix == ".json" {
request.Response.Header().Set("content-type", "application/json")
} else {
request.Response.Header().Set("content-type", "application/octet-stream")
}
if cltObj.Gzip {
request.Response.Header().Set("Content-Encoding", "gzip")
}
globe.RenderData(request, tile.Tile)
}
type Info struct {
Params string `json:"params"`
}
type parseIsZip struct {
Zip bool `json:"zip"`
}
type IsJct struct {
Jct bool `json:"jct"`
}
func OpenClt(cltPath string, sourceID string) (error, *database.SourceObj) {
//if !globe.IS_OFFLINE_VERSION {
// //网络版事 需要拼接数据地址,方便服务器迁移
if !tool.PathExists(cltPath) {
getwd, err := os.Getwd()
if err != nil {
return err, nil
}
cltPath = path.Join(getwd, cltPath)
}
//}
fmt.Println(cltPath)
if tool.PathExists(cltPath) {
db, err := sqlite.OpenDB(cltPath)
if err != nil {
return err, nil
}
var obj database.SourceObj
obj.DB = db
var info []Info
db.Model(&Info{}).Find(&info)
p := parseIsZip{}
errs := json.Unmarshal([]byte(info[0].Params), &p)
if errs == nil {
obj.Gzip = p.Zip
}
suffix := path.Ext(cltPath)
if suffix == globe.CLT {
obj.Type = globe.TILESET
obj.Url = "/zm/api/v1/data/tileset/" + sourceID + "/tileset.json"
} else {
obj.Type = globe.BIM
obj.Url = "/zm/api/v1/data/bim/" + sourceID + "/tileset.json"
if len(info) < 2 {
//非jct资源
globe.CloseDB(db)
return globe.GetErrors("非jct资源"), nil
}
isjct := IsJct{}
errs := json.Unmarshal([]byte(info[1].Params), &isjct)
if errs != nil {
globe.CloseDB(db)
return globe.GetErrors("jct资源检测失败"), nil
}
}
database.SetSourceDB(sourceID, obj)
return err, &obj
}
fmt.Println("资源不存在:" + cltPath)
return globe.GetErrors("资源不存在:" + cltPath), nil
}

View File

@ -0,0 +1,123 @@
package mbt
import (
"github.com/gogf/gf/v2/net/ghttp"
"github.com/tiger1103/gfast/v3/api/v1/common/globe"
"github.com/tiger1103/gfast/v3/api/v1/common/tool"
"github.com/tiger1103/gfast/v3/database"
"github.com/tiger1103/gfast/v3/database/sqlite"
"gorm.io/gorm"
"math"
"net/http"
"os"
"path"
"strings"
)
func InitMbtData(group *ghttp.RouterGroup) {
group.GET("/data/mbt/{source_id}/{z}/{x}/{y}.*", mbtCallback)
}
func mbtCallback(request *ghttp.Request) {
sourceId := request.Get("source_id").String()
mbtobj := database.GetSourceDB(sourceId)
if mbtobj.DB == nil {
request.Response.WriteStatus(http.StatusNotFound)
return
}
z := request.Get("z").Int()
x := request.Get("x").Int()
y := request.Get("y").Int()
y = int(math.Pow(2, float64(z))) - 1 - y
tile := Tile{}
RowsAffected := mbtobj.DB.Model(&Tile{}).
Select("tile_data").
Where(&Tile{ZoomLevel: z, TileColumn: x, TileRow: y}).First(&tile).RowsAffected
if RowsAffected > 0 {
request.Response.Header().Set("content-type", mbtobj.ContentType)
globe.RenderData(request, tile.TileData)
return
} else {
request.Response.WriteStatus(http.StatusNotFound)
}
}
type Tile struct {
TileData []byte `json:"tile_data"`
ZoomLevel int `json:"zoom_level"`
TileColumn int `json:"tile_column"`
TileRow int `json:"tile_row"`
}
type Metadata struct {
Name string
Value string
}
func OpenMbt(mbtPath string, sourceID string) (error, *database.SourceObj) {
//if !globe.IS_OFFLINE_VERSION {
// //网络版事 需要拼接数据地址,方便服务器迁移
// mbtPath = path.Join(globe.SOURCE, mbtPath)
//}
getwd, err := os.Getwd()
if err != nil {
return err, nil
}
mbtPath = path.Join(getwd, mbtPath)
if !tool.PathExists(mbtPath) {
return globe.GetErrors("资源不存在," + mbtPath), nil
}
db, err := sqlite.OpenDB(mbtPath)
if err != nil {
return err, nil
}
var obj database.SourceObj
obj.DB = db
obj.Type = globe.LAYER
var meta []Metadata
db.Model(&Metadata{}).Find(&meta)
obj.Info.MinLevel, obj.Info.MaxLevel = startQueryLevel(db)
var format = "png"
for _, v := range meta {
if v.Name == "format" {
format = v.Value
}
if v.Name == "bounds" {
arr := strings.Split(v.Value, ",")
obj.Info.West = arr[0]
obj.Info.South = arr[1]
obj.Info.East = arr[2]
obj.Info.North = arr[3]
}
if v.Name == "profile" {
obj.Info.ProFile = v.Value
}
if v.Name == "description" {
//lsv下载的 自带投影,此时不需要加
if strings.Contains(v.Value, "LSV") {
obj.Info.TilingScheme = 0
} else {
obj.Info.TilingScheme = 1
}
}
}
obj.ContentType = "image/" + format
obj.Url = "/zm/api/v1/data/mbt/" + sourceID + "/{z}/{x}/{y}." + format
database.SetSourceDB(sourceID, obj)
return err, &obj
}
func startQueryLevel(db *gorm.DB) (min, max int) {
zoom_level := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22}
var existsLevels []int
for i := 0; i < len(zoom_level); i++ {
RowsAffected := db.Model(&Tile{}).Select("zoom_level").Where(&Tile{ZoomLevel: i}).Find(&Tile{}).RowsAffected
if RowsAffected > 0 {
existsLevels = append(existsLevels, i)
}
}
if len(existsLevels) > 0 {
min = existsLevels[0]
max = existsLevels[len(existsLevels)-1]
}
return
}

View File

@ -0,0 +1,148 @@
package pak
import (
"fmt"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/tiger1103/gfast/v3/api/v1/common/globe"
"github.com/tiger1103/gfast/v3/api/v1/common/tool"
"github.com/tiger1103/gfast/v3/database"
"github.com/tiger1103/gfast/v3/database/sqlite"
"math"
"net/http"
"os"
"path"
"strconv"
"strings"
)
const (
image = "image"
terrain = "terrain"
)
func InitPakData(group *ghttp.RouterGroup) {
//group.GET("/data/pak/{source_id}/{z}/{x}/{y}.*", pakCallback)
//group.GET("/data/pak/{source_id}/layer.json", pakCallback)
group.GET("/data/pak/{source_id}/*.action", pakCallback)
}
type Json struct {
Layerjson []byte `json:"layerjson"`
}
// 获取pak文件中的表名
func gettablename(x int, y int, z int) string {
if z < 10 {
return "blocks"
} else {
tx := math.Ceil(float64(x / 512))
ty := math.Ceil(float64(y / 512))
return "blocks_" + strconv.Itoa(z) + "_" + strconv.Itoa(int(tx)) + "_" + strconv.Itoa(int(ty))
}
}
type Tile struct {
Tile []byte `json:"tile"`
Z int `json:"z"`
X int `json:"x"`
Y int `json:"y"`
}
func pakCallback(request *ghttp.Request) {
sourceId := request.Get("source_id").String()
pakobj := database.GetSourceDB(sourceId)
if pakobj.DB == nil {
request.Response.WriteStatus(http.StatusNotFound)
return
}
suffix := path.Ext(request.RequestURI)
if suffix == ".json" {
json := Json{}
pakobj.DB.Model(&Info{}).First(&json)
request.Response.Header().Set("content-type", "application/json")
globe.RenderData(request, json.Layerjson)
return
} else {
uri := request.RequestURI
arr := strings.Split(uri, "/")
//z := request.Get("z").Int()
//x := request.Get("x").Int()
//y := request.Get("y").Int()
z, _ := strconv.Atoi(arr[7])
x, _ := strconv.Atoi(arr[8])
y, _ := strconv.Atoi(strings.Split(arr[9], ".")[0])
//y = int(math.Pow(2, float64(z))) - 1 - y
tile := Tile{}
RowsAffected := pakobj.DB.Table(gettablename(x, y, z)).Select("tile").Where(&Tile{Z: z, X: x, Y: y}).First(&tile).RowsAffected
if RowsAffected > 0 {
request.Response.Header().Set("content-type", pakobj.ContentType)
if pakobj.Gzip {
request.Response.Header().Set("Content-Encoding", "gzip")
}
globe.RenderData(request, tile.Tile)
return
} else {
request.Response.WriteStatus(http.StatusNotFound)
}
}
}
type Info struct {
Minx float64 `json:"minx"`
Miny float64 `json:"miny"`
Maxx float64 `json:"maxx"`
Maxy float64 `json:"maxy"`
Minlevel int `json:"minlevel"`
Maxlevel int `json:"maxlevel"`
Type string `json:"type"`
Zip int `json:"zip"`
//Layerjson []byte `json:"layerjson"`
Contenttype string `json:"contenttype"`
}
func OpenPak(pakPath string, sourceID string) (error, *database.SourceObj) {
//if !globe.IS_OFFLINE_VERSION {
// //网络版事 需要拼接数据地址,方便服务器迁移
// pakPath = path.Join(globe.SOURCE, pakPath)
//}
getwd, err := os.Getwd()
if err != nil {
return err, nil
}
pakPath = path.Join(getwd, pakPath)
if !tool.PathExists(pakPath) {
return globe.GetErrors("资源不存在," + pakPath), nil
}
fmt.Println("资源存在")
db, err := sqlite.OpenDB(pakPath)
if err != nil {
fmt.Println(err)
return err, nil
}
var obj database.SourceObj
obj.DB = db
info := Info{}
db.Model(&Info{}).First(&info)
if info.Type == image {
obj.Type = globe.LAYER
obj.ContentType = info.Contenttype
obj.Url = "/zm/api/v1/data/pak/" + sourceID + "/{z}/{x}/{y}." + strings.Split(obj.ContentType, "/")[1]
}
if info.Type == terrain {
obj.Type = globe.TERRAIN
obj.ContentType = "application/octet-stream"
obj.Url = "/zm/api/v1/data/pak/" + sourceID + "/"
}
if info.Zip > 0 {
obj.Gzip = true
}
obj.Info.MaxLevel = info.Maxlevel
obj.Info.MinLevel = info.Minlevel
obj.Info.West = strconv.FormatFloat(info.Minx, 'f', -1, 64)
obj.Info.South = strconv.FormatFloat(info.Miny, 'f', -1, 64)
obj.Info.East = strconv.FormatFloat(info.Maxx, 'f', -1, 64)
obj.Info.North = strconv.FormatFloat(info.Maxy, 'f', -1, 64)
database.SetSourceDB(sourceID, obj)
return err, &obj
}

View File

@ -0,0 +1,295 @@
package shp
import (
"context"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/tidwall/gjson"
shp2 "github.com/tiger1103/gfast/v3/api/v1/common/shp"
"io"
"net/http"
"regexp"
"strings"
)
const MaxNeighborsLen = 8 //最大邻居个数
const SOURCE = "static/source/"
const Gisfile = "gisfile/"
// 84的投影文件
const WGS84_PRJ = "GEOGCS[\"GCS_WGS_1984\",DATUM[\"D_WGS_1984\",SPHEROID[\"WGS_1984\",6378137.0,298.257223563]],PRIMEM[\"Greenwich\",0.0],UNIT[\"Degree\",0.0174532925199433]]"
func InitShp(group *ghttp.RouterGroup) {
group.Group("/shp", func(group *ghttp.RouterGroup) {
group.Bind(new(SHP))
})
}
type SHP struct {
}
type SHPLoadReq struct {
g.Meta `path:"load" summary:"cesium加载shp" method:"get" tags:"shp相关" `
//SourceID string `json:"source_id" dc:"资源id" v:"required"`
Path string `json:"path" dc:"路径" v:"required"`
}
type SHPLoadRes struct {
shp2.ShpObj
}
//func (receiver SHP) LoadSHP(ctx context.Context, req *SHPLoadReq) (res *SHPLoadRes, err error) {
// err, obj := shp2.ReadShp(req.Path)
// if err != nil {
// return nil, err
// }
// res = &SHPLoadRes{}
// res.Points = obj.Points
// res.Polylines = obj.Polylines
// res.Polygons = obj.Polygons
// return res, err
//}
type Range struct {
MinX float64 `json:"min_x"`
MinY float64 `json:"min_y"`
MaxX float64 `json:"max_x"`
MaxY float64 `json:"max_y"`
}
type Position struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Z float64 `json:"z"`
Attr map[string]interface{} `json:"attr"`
}
type Text struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Text string `json:"text"`
}
type Circle struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Z float64 `json:"z"`
Radius float64 `json:"radius"`
}
type Polyline struct {
Positions []Position `json:"positions"`
Attr map[string]interface{} `json:"attr"`
Range Range `json:"range"`
}
type Polygon struct {
Positions []Position `json:"positions"`
Attr map[string]interface{} `json:"attr"`
Range Range `json:"range"`
}
type MultiPolygon struct {
Polygons []Polygon `json:"polygons"`
Attr map[string]interface{} `json:"attr"`
Range Range `json:"range"`
}
type MultiPolyline struct {
Polylines []Polyline `json:"polylines"`
Attr map[string]interface{} `json:"attr"`
Range Range `json:"range"`
}
type LayerData struct {
LayerName string `json:"layer_name"`
Proj4 string `json:"proj4"`
Texts []Text `json:"texts"`
Circles []Circle `json:"circles"`
Points []Position `json:"points"`
Polylines []Polyline `json:"polylines"`
Polygons []Polygon `json:"polygons"`
MultiPolygons []MultiPolygon `json:"multi_polygons"`
MultiPolylines []MultiPolyline `json:"multi_polylines"`
}
type Directory struct {
Name string `json:"name"`
IsDir bool `json:"is_dir"`
Data []LayerData `json:"data"`
Children []Directory `json:"children"`
}
type Response struct {
Code int `json:"code"`
Data Directory `json:"data"`
}
// JoinLoadSHP 原本的LoadSHP有问题直接调用远程的接口
func (receiver SHP) JoinLoadSHP(ctx context.Context, req *SHPLoadReq) (res *SHPLoadRes, err error) {
res = new(SHPLoadRes)
if req.Path[0] == '/' {
req.Path = req.Path[1:]
}
url := "http://192.168.1.177:8921/yjearth5/api/v1/vector/load?path=/project/zmkg/" + req.Path
reqs, err := http.Get(url)
if err != nil {
return nil, err
}
defer reqs.Body.Close()
body, err := io.ReadAll(reqs.Body)
if err != nil {
return nil, err
}
if gjson.Get(string(body), "message").String() == "资源不存在" {
return nil, fmt.Errorf("资源不存在")
}
var list shp2.ShpObj
processShapes(body, "data.children.0.data.0.polylines", &list)
processShapes(body, "data.children.0.data.0.polygons", &list)
processShapes(body, "data.children.0.data", &list)
if list.Polylines == nil {
list.Polylines = []shp2.Polyline{}
}
if list.Polygons == nil {
list.Polygons = []shp2.Polygon{}
}
if list.Points == nil {
list.Points = []shp2.Point{}
}
res.Polygons = list.Polygons
res.Polylines = list.Polylines
res.Points = list.Points
return res, err
}
func Adasda(path string) (res *SHPLoadRes) {
fmt.Println("加载shp文件", path)
res = new(SHPLoadRes)
if path[0] == '/' {
path = path[1:]
}
url := "http://192.168.1.177:8921/yjearth5/api/v1/vector/load?path=/project/zmkg/" + path
reqs, err := http.Get(url)
if err != nil {
fmt.Println("请求数据失败")
}
defer reqs.Body.Close()
body, err := io.ReadAll(reqs.Body)
if err != nil {
fmt.Errorf("读取资源失败")
}
if gjson.Get(string(body), "message").String() == "资源不存在" {
fmt.Errorf("资源不存在")
}
var list = shp2.ShpObj{
Polylines: []shp2.Polyline{},
Polygons: []shp2.Polygon{},
Points: []shp2.Point{},
}
processShapes(body, "data.children.0.data.0.polylines", &list)
processShapes(body, "data.children.0.data.0.polygons", &list)
processShapes(body, "data.children.0.data", &list)
res.Polygons = list.Polygons
res.Polylines = list.Polylines
res.Points = list.Points
return
}
func processShapes(data []byte, path string, shapes *shp2.ShpObj) {
gjson.GetBytes(data, path).ForEach(func(key, shape gjson.Result) bool {
// 面
var pointsList []shp2.Point
psGet := shape.Get("positions")
if psGet.Exists() {
psGet.ForEach(func(posKey, value gjson.Result) bool {
longitude := value.Get("x").Float()
latitude := value.Get("y").Float()
altitude := value.Get("z").Float()
pointsList = append(pointsList, shp2.Point{
Lng: longitude,
Lat: latitude,
Alt: altitude,
})
return true
})
if len(pointsList) > 0 {
shapes.Polylines = append(shapes.Polylines, shp2.Polyline{
Positions: pointsList,
Width: "5",
Color: "#f00",
})
}
if shape.Get("attr").Exists() {
aName := shape.Get("attr.NAME").String()
fmt.Println("!!! ", aName)
shapes.Polylines[len(shapes.Polylines)-1].Property = shp2.Property{
Name: aName,
}
}
if shape.Get("range").Exists() {
minX := shape.Get("range.min_x").Float()
minY := shape.Get("range.min_y").Float()
maxX := shape.Get("range.max_x").Float()
maxY := shape.Get("range.max_y").Float()
shapes.Polylines[len(shapes.Polylines)-1].Range = shp2.Box{
MinX: minX,
MinY: minY,
MaxX: maxX,
MaxY: maxY,
}
}
} else {
//fmt.Println("!!! ", shape.Get("points"))
// 点
var point []shp2.Point
shape.Get("points").ForEach(func(posKey, value gjson.Result) bool {
aName := value.Get("attr.NAME")
if value.Get("attr.NAME").Exists() {
//排除nc 和 空
isPureNumber, _ := regexp.MatchString(`^\d+$`, aName.String())
if strings.Contains(aName.String(), "NC") || strings.TrimSpace(aName.String()) == "" || isPureNumber {
return true
}
longitude := value.Get("x").Float()
latitude := value.Get("y").Float()
altitude := value.Get("z").Float()
point = append(point, shp2.Point{
Lng: longitude,
Lat: latitude,
Alt: altitude,
Property: shp2.Property{
Name: aName.String(),
},
})
}
return true
})
if len(point) > 0 {
shapes.Points = append(shapes.Points, point...)
}
}
return true
})
}

View File

@ -0,0 +1,85 @@
package source
import (
"context"
"encoding/json"
"fmt"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gctx"
"github.com/tiger1103/gfast/v3/api/v1/common/globe"
"github.com/tiger1103/gfast/v3/api/v1/common/source/clt"
"github.com/tiger1103/gfast/v3/api/v1/common/source/pak"
"github.com/tiger1103/gfast/v3/database"
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
"path"
)
func InitSource(group *ghttp.RouterGroup) {
ReadAllSourceFromDB()
group.Group("/data/service", func(group *ghttp.RouterGroup) {
group.Bind(new(LoadSource))
})
}
type LoadSource struct {
}
type LoadSourceReq struct {
g.Meta `path:"load-compact-service" summary:"引擎加载资源" method:"post" tags:"资源相关" `
SourceID string `json:"source_id" v:"required" dc:"资源id"`
}
type LoadSourceRes struct {
Type string `json:"type"`
Url string `json:"url"`
database.SourceInfo
}
func (LoadSource) LoadCompactService(ctx context.Context, req *LoadSourceReq) (res *LoadSourceRes, err error) {
obj := database.GetSourceDB(req.SourceID)
res = &LoadSourceRes{
Url: obj.Url,
Type: obj.Type,
}
res.North = obj.Info.North
res.West = obj.Info.West
res.East = obj.Info.East
res.South = obj.Info.South
res.ProFile = obj.Info.ProFile
res.TilingScheme = obj.Info.TilingScheme
res.MaxLevel = obj.Info.MaxLevel
res.MinLevel = obj.Info.MinLevel
return
}
func ReadAllSourceFromDB() {
var sources []database.SOURCE
var gfb []database.SOURCE
g.DB().Model(&database.SOURCE{})
ctx := gctx.New()
//模型
dao.QianqiMoxing.Ctx(ctx).Scan(&sources)
//光伏板
dao.QianqiGuangfuban.Ctx(ctx).Scan(&gfb)
sources = append(sources, gfb...)
for _, v := range sources {
suffix := path.Ext(v.SourcePath)
switch suffix {
case globe.CLT:
err, obj := clt.OpenClt(v.SourcePath, v.SourceID)
if err != nil {
fmt.Println(err)
}
marshal, _ := json.Marshal(obj)
fmt.Println(string(marshal), v.SourceID)
break
case globe.PAK:
err, obj := pak.OpenPak(v.SourcePath, v.SourceID)
if err != nil {
fmt.Println(err)
}
marshal, _ := json.Marshal(obj)
fmt.Println(string(marshal), v.SourceID)
break
}
}
}