فهرست منبع

250325-1代码。

baoyubo 1 ماه پیش
والد
کامیت
2eabe91cc4
3فایلهای تغییر یافته به همراه360 افزوده شده و 0 حذف شده
  1. 2 0
      routers/api/spatialAnalysis/__init__.py
  2. 277 0
      routers/api/spatialAnalysis/point.py
  3. 81 0
      routers/api/videoResource/videoinfo.py

+ 2 - 0
routers/api/spatialAnalysis/__init__.py

@@ -16,8 +16,10 @@ from utils import *
 from utils.spatial import *
 import json
 import traceback
+from .point import router as pointrouter
 
 router = APIRouter()
+router.include_router(pointrouter, prefix="/point")
 
 
 

+ 277 - 0
routers/api/spatialAnalysis/point.py

@@ -0,0 +1,277 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from fastapi import APIRouter, Request, Depends, Query, HTTPException, status
+from common.security import valid_access_token
+from fastapi.responses import JSONResponse
+from sqlalchemy.orm import Session
+from sqlalchemy import and_, or_,text,literal
+from sqlalchemy.sql import func
+from sqlalchemy.future import select
+from common.auth_user import *
+from pydantic import BaseModel
+from database import get_db
+from typing import List
+from models import *
+from utils import *
+from utils.ry_system_util import *
+from utils.video_util import *
+from collections import defaultdict
+import traceback
+from concurrent.futures import ThreadPoolExecutor, as_completed
+from multiprocessing import Pool, cpu_count
+import json
+import time
+import math
+
+
+router = APIRouter()
+
+@router.post("/get_info")
+@router.get("/get_info")
+async def get_infos(
+        body = Depends(remove_xss_json),
+        # zoom_level: float = Query(..., description="Zoom level for clustering"),
+        # latitude_min: float = Query(..., description="Minimum latitude"),
+        # latitude_max: float = Query(..., description="Maximum latitude"),
+        # longitude_min: float = Query(..., description="Minimum longitude"),
+        # longitude_max: float = Query(..., description="Maximum longitude"),
+        # dict_value: str = Query(None),
+        # option:str  = Query(None),
+        db:  Session = Depends(get_db)
+):
+    try:
+        # 根据缩放级别动态调整分组粒度
+        zoom_level = float(body['zoom_level'])
+        zoom_levels = {
+            3: 10000,  # 全国范围
+            4: 5000,
+            5: 2500,
+            6: 1250,
+            7: 825,
+            8: 412.5,
+            9: 256.25,
+            10: 178.125,
+            11: 69.0625,
+            12: 29.53125,
+            13: 13.765625,
+            14: 5.8828125,
+            15: 2.44140625,
+            16: 1.220703125,
+            17: 0.6103515625,
+            18: 0.30517578125
+        }
+        distance_threshold=zoom_levels[int(zoom_level-1)]
+        # distance_threshold = 100000 / (2.2 ** zoom_level)  # 例如:每缩放一级,距离阈值减半
+        dict_value= body['dict_value'].split(',')
+        latitude_min = float(body['latitude_min'])
+        latitude_max = float(body['latitude_max'])
+        longitude_min = float(body['longitude_min'])
+        longitude_max = float(body['longitude_max'])
+        option = body['option'].split(',')
+        print("1",time.time())
+        videos = get_videos(db,dict_value,latitude_min,latitude_max,longitude_min,longitude_max)
+        infos = get_points(db,option,latitude_min,latitude_max,longitude_min,longitude_max)
+        # 动态分组逻辑
+        groups = group_points(videos+infos, distance_threshold)
+
+        print("4",time.time())
+
+        return {"code": 200,
+                "msg": "操作成功",
+                "data": groups}
+    except Exception as e:
+        # 处理异常
+        traceback.print_exc()
+        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
+@router.post("/get_details")
+@router.get("/get_details")
+async def get_details(
+        body = Depends(remove_xss_json),
+    # center_latitude: float = Query(..., description="网格中心点的纬度"),
+    # center_longitude: float = Query(..., description="网格中心点的经度"),
+    # zoom_level: float = Query(..., description="缩放级别"),
+    db: Session = Depends(get_db)
+):
+    try:
+        # 计算网格大小
+        zoom_level = float(body['zoom_level'])
+        zoom_levels = {
+            3: 10000,  # 全国范围
+            4: 5000,
+            5: 2500,
+            6: 1250,
+            7: 825,
+            8: 412.5,
+            9: 256.25,
+            10: 178.125,
+            11: 69.0625,
+            12: 29.53125,
+            13: 13.765625,
+            14: 5.8828125,
+            15: 2.44140625,
+            16: 1.220703125,
+            17: 0.6103515625,
+            18: 0.30517578125
+        }
+        distance_threshold=zoom_levels[int(zoom_level-1)]
+        # distance_threshold = 1000 / (1.5 ** zoom_level)  # 例如:每缩放一级,距离阈值减半
+        grid_size = calculate_grid_size(distance_threshold)  # 地球半径为6371公里
+        center_latitude = float(body['latitude'])
+        center_longitude = float(body['longitude'])
+        dict_value = body['dict_value'].split(',')
+        option = body['option'].split(',')
+        # 计算网格的经纬度范围
+        latitude_min, latitude_max, longitude_min, longitude_max = get_grid_bounds_from_center(center_latitude, center_longitude, grid_size)
+        videos = get_videos(db,dict_value,latitude_min,latitude_max,longitude_min,longitude_max)
+        infos = get_points(db,option,latitude_min,latitude_max,longitude_min,longitude_max)
+        return {"code": 200,
+                "msg": "操作成功",
+                "data": {"videos":videos,"points":infos}}
+    except Exception as e:
+        # 处理异常
+        traceback.print_exc()
+        raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
+
+def calculate_grid_size(distance_threshold):
+    # 假设地球半径为6371公里,将距离阈值转换为经纬度的差值
+    # 这里假设纬度变化对距离的影响较小,仅根据经度计算网格大小
+    earth_radius = 6371  # 地球半径,单位为公里
+    grid_size = distance_threshold / earth_radius
+    return grid_size
+
+def get_grid_key(latitude, longitude, grid_size):
+    # 根据经纬度和网格大小计算网格键
+    return (math.floor(latitude / grid_size), math.floor(longitude / grid_size))
+
+def get_grid_bounds_from_center(center_latitude, center_longitude, grid_size):
+    half_grid_size = grid_size / 2
+    min_latitude = center_latitude - half_grid_size
+    max_latitude = center_latitude + half_grid_size
+    min_longitude = center_longitude - half_grid_size
+    max_longitude = center_longitude + half_grid_size
+    return min_latitude, max_latitude, min_longitude, max_longitude
+
+def calculate_distance(point1, point2):
+    # 使用 Haversine 公式计算两点之间的距离
+    from math import radians, sin, cos, sqrt, atan2
+    R = 6371  # 地球半径(公里)
+    lat1, lon1 = radians(point1.latitude), radians(point1.longitude)
+    lat2, lon2 = radians(point2.latitude), radians(point2.longitude)
+    dlat = lat2 - lat1
+    dlon = lon2 - lon1
+    a = sin(dlat / 2) ** 2 + cos(lat1) * cos(lat2) * sin(dlon / 2) ** 2
+    c = 2 * atan2(sqrt(a), sqrt(1 - a))
+    return R * c
+
+def group_points(points, distance_threshold):
+    grid_size = calculate_grid_size(distance_threshold)
+    grid = defaultdict(lambda:{"count":0}) #,"list":[]
+    groups = []
+    tmp = defaultdict(list)
+    for point in points:
+        grid_key = get_grid_key(float(point.latitude), float(point.longitude), grid_size)
+        lovalue = str(point.latitude)+str(point.longitude)
+        if lovalue not in tmp['%s-%s'%grid_key]:
+            tmp['%s-%s'%grid_key].append(lovalue)
+        grid['%s-%s'%grid_key]['count']+=1
+        if grid['%s-%s'%grid_key]['count']>1 and len(tmp['%s-%s'%grid_key])<3:
+            grid['%s-%s'%grid_key]['dataType'] = ''
+            grid['%s-%s'%grid_key]['id'] = ""
+            if len(tmp['%s-%s'%grid_key])<2:
+                grid['%s-%s'%grid_key]['name'] = '多数据点位'
+                grid['%s-%s' % grid_key]['type'] ='1'
+            else:
+                grid['%s-%s' % grid_key]['name'] = '聚合点位'
+                grid['%s-%s' % grid_key]['type'] = '3'
+            # grid['%s-%s'%grid_key]['latitude'] = float(point.latitude) #(grid_key[0] + 0.5) * grid_size
+            # grid['%s-%s'%grid_key]['longitude'] = float(point.longitude) #(grid_key[1] + 0.5) * grid_size
+        elif grid['%s-%s'%grid_key]['count']==1:
+            if point.dataType=='video':
+                grid['%s-%s' % grid_key]['id'] = point.gbIndexCode
+            else:
+                grid['%s-%s' % grid_key]['id'] = point.id
+            grid['%s-%s'%grid_key]['dataType'] = point.dataType
+            grid['%s-%s'%grid_key]['name'] = point.name
+            grid['%s-%s'%grid_key]['type'] ='2'
+            grid['%s-%s'%grid_key]['latitude'] = float(point.latitude)
+            grid['%s-%s'%grid_key]['longitude'] = float(point.longitude)
+
+    groups = list(grid.values())
+
+    return groups
+
+def get_videos(db:Session,dict_value,latitude_min,latitude_max,longitude_min,longitude_max):
+    que = True
+    if len(dict_value)>0:
+        videolist = []
+        for value in dict_value:
+            tag_info = get_dict_data_info(db, 'video_type', value)
+            if tag_info:
+                if tag_info.dict_label == '全量视频':
+                    break
+                else:
+                    videolist += [i.video_code for i in tag_get_video_tag_list(db, value)]
+        else:
+            que = TPVideoInfo.gbIndexCode.in_(videolist)
+    # 查询分组
+    query = (
+        select(
+            TPVideoInfo.gbIndexCode,
+            TPVideoInfo.latitude,
+            TPVideoInfo.longitude,
+            TPVideoInfo.name,
+            TPVideoInfo.status,
+            literal('video').label("dataType")
+        )
+            .select_from(TPVideoInfo).where(
+            and_(
+                TPVideoInfo.latitude >= latitude_min,
+                TPVideoInfo.latitude <= latitude_max,
+                TPVideoInfo.longitude >= longitude_min,
+                TPVideoInfo.longitude <= longitude_max,
+                TPVideoInfo.longitude > 0,
+                TPVideoInfo.latitude > 0, que
+            )
+        )
+            .order_by(TPVideoInfo.status.asc())
+    )
+
+    result = db.execute(query)
+    videos = result.fetchall()
+    return videos
+
+
+def get_points(db:Session,option,latitude_min,latitude_max,longitude_min,longitude_max):
+    # 使用参数化查询避免 SQL 注入
+    if isinstance(option, list):
+        option = tuple(option)
+    query = text("""
+        SELECT 
+            A.`name`,A.`id`,A.dataType,A.longitude,A.latitude
+        FROM (
+            SELECT 
+                *,
+                ROW_NUMBER() OVER (PARTITION BY longitude, latitude, `name` 
+                                   ORDER BY longitude, latitude, `name`) AS rn
+            FROM 
+                `point_data` 
+            WHERE 
+                longitude > 0 
+                AND latitude BETWEEN :latitude_min AND :latitude_max 
+                AND longitude BETWEEN :longitude_min AND :longitude_max 
+                AND dataType IN :option
+        ) AS A 
+        WHERE rn = 1
+    """)
+
+    # 执行查询并传递参数
+    result = db.execute(query, {
+        'latitude_min': latitude_min,
+        'latitude_max': latitude_max,
+        'longitude_min': longitude_min,
+        'longitude_max': longitude_max,
+        'option': option
+    })
+    infos = result.fetchall()
+    return infos

+ 81 - 0
routers/api/videoResource/videoinfo.py

@@ -15,6 +15,87 @@ from datetime import datetime
 
 router = APIRouter()
 
+@router.get('/get_video_list_new')
+async def get_video_url_by_id(
+    longitude:float = Query(None,  description='经度'),
+    latitude:float = Query(None,  description='纬度'),
+    db: Session = Depends(get_db),
+    body=Depends(remove_xss_json),
+    user_id=Depends(valid_access_token),
+    page: int = Query(1, gt=0, description='页码'),
+    pageSize: int = Query(10, gt=0, description='每页条目数量')
+):
+    if longitude is not None and latitude is not None:
+        location = f"""ST_Distance_Sphere(
+        ST_GeomFromText(CONCAT('POINT(', longitude, ' ', latitude, ')')), 
+        ST_PointFromText('POINT({longitude} {latitude})'))"""
+        orddis = 'distance'
+    else:
+        location = 0
+        orddis = ''
+    videoIds = user_id_get_user_videoIds(db, user_id)
+    video_list = [i.video_code_int for i in videoIds]
+    if len(video_list)==0:
+        video = ''
+    else:
+        video = ""
+        for i in video_list:
+            video += f"WHEN '{i}' THEN 0 \n"
+
+        video = f"""CASE video_code_int
+    {video}
+    ELSE 1
+END """
+    if orddis != '' and video !='':
+        video += ','
+    sql  = f"""SELECT T1.indexcode,T2.`name`,T1.longitude,T1.latitude,
+        {location} AS distance,T2.area,T2.ip,T2.`status`,T2.status_lifetime,T2.record_status,T2.inspection_datetime,T2.video_code_int,T2.video_code
+    FROM tp_video_base T1 RIGHT JOIN tp_video_log T2 on T1.indexcode=T2.video_code_int -- where  T1.longitude is not NULL
+    ORDER BY {video} {orddis} """
+    totalsql = f'select count(*) from ({sql})t'
+    print(video_list)
+
+    total_items = db.execute(totalsql).first()[0]
+
+    lim = f"limit  {pageSize*(page-1)}, {pageSize};"
+    videos = db.execute(sql+lim).all()
+    # query = db.query(TpVideoLog)
+    # total_items = query.count()
+    #
+    # query = query.order_by(
+    # case(
+    #     [(TpVideoLog.video_code_int == video_code_int, 0) for video_code_int in video_list],
+    #     else_=1
+    # )
+    #     )
+    # videos = query.offset((page - 1) * pageSize).limit(pageSize).all()
+    video_list1 = []
+    for video in videos:
+        videoInfo = {
+            "name": video.name,
+            "invideoIds": video.video_code_int in video_list,
+            "area": video.area,
+            "ip": video.ip,
+            "status": video.status,
+            "status_lifetime": video.status_lifetime,
+            "record_status": video.record_status,
+            "inspection_datetime": video.inspection_datetime,
+            "video_code_int": video.video_code_int,
+            "video_code": video.video_code,
+            "longitude":video.longitude,
+            "latitude":video.latitude
+        }
+        video_list1.append(videoInfo)
+    return {
+            "code": 200,
+            "msg": "操作成功",
+            "rows": video_list1,
+            "total": total_items,
+            "page": page,
+            "pageSize": pageSize,
+            "totalPages": (total_items + pageSize - 1) // pageSize
+        }
+
 @router.get('/get_video_list_by_user')
 async def get_video_url_by_id(
     longitude:float = Query(None,  description='经度'),