【小沐学GIS】基于Openstreetmap创建Sionna RT场景(Python)
文章目录
- 1、简介
- 1.1 blender
- 2、下载和安装
- 2.1 Python
- 2.2 jupyter
- 3、运行
- 结语
1、简介
1.1 blender
https://www.blender.org/
Blender 是一款免费开源的3D创作套件。
使用 Blender,您可以创建3D可视化效果,例如静态图像、3D动画、VFX(视觉特效)快照和视频编辑。它非常适合那些受益于其统一解决方案和响应式开发过程的独立和小型工作室。
Blender 是一款跨平台的应用工具,可以在 Linux、macOS 以及 Windows 系统下运行。与其他三维建模工具相比,Blender 对内存和驱动的需求更低。其界面使用 OpenGL,在所有支持的硬件与平台都能提供一致的用户体验。
Blender 是一个完整集成的 3D 创作套件,提供了大量的基础工具,包括建模、渲染、动画 & 绑定、视频编辑、视觉效果、合成、贴图,以及多种类型的模拟。
跨平台,使用了 OpenGL 的 GUI 可以在所有主流平台上都表现出一致的显示效果(并且可通过 Python 脚本来自定义界面)。
2、下载和安装
2.1 Python
https://www.python.org/
Python是一种广泛使用的高级编程语言,它以其清晰的语法和代码可读性而闻名。Python支持多种编程范式,包括面向对象、命令式、函数式和过程式编程。
安装后打印Python版本信息如下:
python -v
pip -v
2.2 jupyter
Jupyter Notebook 是一个基于 Web 的交互式计算环境,支持多种编程语言,包括 Python、R、Julia 等。它的主要功能是将代码、文本、数学方程式、可视化和其他相关元素组合在一起,创建一个动态文档,用于数据分析、机器学习、科学计算和数据可视化等方面。Jupyter Notebook 提供了一个交互式的界面,使用户能够以增量和可视化的方式构建和执行代码,同时支持 Markdown 格式的文本和 LaTeX 数学符号。
安装 Jupyter Notebook:在命令提示符中输入以下命令,使用 pip 安装 Jupyter Notebook。
pip install jupyter notebook
启动 Jupyter Notebook:在命令提示符中输入以下命令,启动 Jupyter Notebook。
jupyter notebook
接下来Jupyter Notebook 会在默认的浏览器中打开,如果没有自动打开,可以在浏览器中输入 http://localhost:8888/tree 来访问。
http://localhost:8888/tree
新建文件如下:
界面如下:
3、运行
https://github.com/manoj-kumar-joshi/sionna_osm_scene
从 Openstreetmap 数据创建 Sionna 光线追踪的场景文件
这是一个实用程序项目,它使用 Openstreetmap 数据生成与 Mitsuba 兼容的 3D 场景文件以及建筑物、地面和道路的 3D 对象。使用 OSM_to_Sionna 生成的文件可以直接用作 Sionna Ray 追踪应用程序的输入。
打开文件:
https://github.com/manoj-kumar-joshi/sionna_osm_scene/blob/main/OSM_to_Sionna.ipynb
测试代码如下:
import ipyleaflet
import IPython.display
import ipyvolume.pylab as p3
import pyproj
import shapely
from shapely.geometry import shape
from shapely.ops import transform
import math
import pyvista as pv
import numpy as np
import osmnx as ox
from shapely.geometry import Polygon, Point, LineString
import os
from pyproj import Transformer
import open3d as o3d
import xml.etree.ElementTree as ET
import xml.dom.minidom as minidom
初始化Sionna Scene XML对象并添加默认值:
# Set the center position lat and lon as a starting point. Use any string of your choice for LOCATION_STR
center_lat = 14.557097311312177
center_lon = 121.02000072883868
LOCATION_STR = "PHILLIPINES# Set up default values for resolution
spp_default = 4096
resx_default = 1024
resy_default = 768# Define camera settings
camera_settings = {"rotation": (0, 0, -90), # Assuming Z-up orientation"fov": 42.854885
}# Define material colors. This is RGB 0-1 formar https://rgbcolorpicker.com/0-1
material_colors = {"mat-itu_concrete": (0.539479, 0.539479, 0.539480),"mat-itu_marble": (0.701101, 0.644479, 0.485150),"mat-itu_metal": (0.219526, 0.219526, 0.254152),"mat-itu_wood": (0.043, 0.58, 0.184),"mat-itu_wet_ground": (0.91,0.569,0.055),
}
transformer = Transformer.from_crs("EPSG:4326", "EPSG:26915")
center_26915 = transformer.transform(center_lat,center_lon)
sionna_center_x = center_26915[0]
sionna_center_y = center_26915[1]
sionna_center_z = 0scene = ET.Element("scene", version="2.1.0")
# Add defaults
ET.SubElement(scene, "default", name="spp", value=str(spp_default))
ET.SubElement(scene, "default", name="resx", value=str(resx_default))
ET.SubElement(scene, "default", name="resy", value=str(resy_default))
# Add integrator
integrator = ET.SubElement(scene, "integrator", type="path")
ET.SubElement(integrator, "integer", name="max_depth", value="12")# Define materials
for material_id, rgb in material_colors.items():bsdf_twosided = ET.SubElement(scene, "bsdf", type="twosided", id=material_id)bsdf_diffuse = ET.SubElement(bsdf_twosided, "bsdf", type="diffuse")ET.SubElement(bsdf_diffuse, "rgb", value=f"{rgb[0]} {rgb[1]} {rgb[2]}", name="reflectance")# Add emitter
emitter = ET.SubElement(scene, "emitter", type="constant", id="World")
ET.SubElement(emitter, "rgb", value="1.000000 1.000000 1.000000", name="radiance")# Add camera (sensor)
sensor = ET.SubElement(scene, "sensor", type="perspective", id="Camera")
ET.SubElement(sensor, "string", name="fov_axis", value="x")
ET.SubElement(sensor, "float", name="fov", value=str(camera_settings["fov"]))
ET.SubElement(sensor, "float", name="principal_point_offset_x", value="0.000000")
ET.SubElement(sensor, "float", name="principal_point_offset_y", value="-0.000000")
ET.SubElement(sensor, "float", name="near_clip", value="0.100000")
ET.SubElement(sensor, "float", name="far_clip", value="10000.000000")
sionna_transform = ET.SubElement(sensor, "transform", name="to_world")
ET.SubElement(sionna_transform, "rotate", x="1", angle=str(camera_settings["rotation"][0]))
ET.SubElement(sionna_transform, "rotate", y="1", angle=str(camera_settings["rotation"][1]))
ET.SubElement(sionna_transform, "rotate", z="1", angle=str(camera_settings["rotation"][2]))
camera_position = np.array([0, 0, 100]) # Adjust camera height
ET.SubElement(sionna_transform, "translate", value=" ".join(map(str, camera_position)))
sampler = ET.SubElement(sensor, "sampler", type="independent")
ET.SubElement(sampler, "integer", name="sample_count", value="$spp")
film = ET.SubElement(sensor, "film", type="hdrfilm")
ET.SubElement(film, "integer", name="width", value="$resx")
ET.SubElement(film, "integer", name="height", value="$resy")
打开交互式地图,选择要使用的区域:
m = ipyleaflet.Map(center=(center_lat, center_lon), zoom=16)
dc = ipyleaflet.DrawControl()
m.add(dc)
m
# Get coordinates in meter for the area of interst polygon (This will be used in next steps)
wsg84 = pyproj.CRS("epsg:4326")
lambert = pyproj.CRS("epsg:26915")
transformer = pyproj.Transformer.from_crs(wsg84, lambert, always_xy=True)
coords = [transformer.transform(x, y) for x, y in dc.last_draw['geometry']['coordinates'][0]]
print(coords)
print(dc.last_draw['geometry']['coordinates'][0])
aoi_polygon = shapely.geometry.Polygon(coords)# Store center of the selected area to be used in calculations later on
center_x = aoi_polygon.centroid.x
center_y = aoi_polygon.centroid.y# Set Location of the directory where scene and objects will be stored
LOCATION_DIR = f"{LOCATION_STR}_{center_x}_{center_y}"
print(LOCATION_DIR)# Create Directories
os.mkdir(f"d:/simple_scene")
os.mkdir(f"d:/simple_scene/mesh") # Utility Function
def points_2d_to_poly(points, z):"""Convert a sequence of 2d coordinates to a polydata with a polygon."""faces = [len(points), *range(len(points))]poly = pv.PolyData([p + (z,) for p in points], faces=faces)return poly
创建地面网格并添加到场景中:
# Utility Function
def points_2d_to_poly(points, z):"""Convert a sequence of 2d coordinates to a polydata with a polygon."""faces = [len(points), *range(len(points))]poly = pv.PolyData([p + (z,) for p in points], faces=faces)return polywsg84 = pyproj.CRS("epsg:4326")
lambert = pyproj.CRS("epsg:26915")
transformer = pyproj.Transformer.from_crs(wsg84, lambert, always_xy=True)
coords = [transformer.transform(x, y) for x, y in dc.last_draw['geometry']['coordinates'][0]]ground_polygon = shapely.geometry.Polygon(coords)
z_coordinates = np.full(len(ground_polygon.exterior.coords), 0) # Assuming the initial Z coordinate is zmin
exterior_coords = ground_polygon.exterior.coords
oriented_coords = list(exterior_coords)
# Ensure counterclockwise orientation
if ground_polygon.exterior.is_ccw:oriented_coords.reverse()
points = [(coord[0]-center_x, coord[1]-center_y) for coord in oriented_coords]
# bounding polygon
boundary_points_polydata = points_2d_to_poly(points, z_coordinates[0])
edge_polygon = boundary_points_polydata
footprint_plane = edge_polygon.delaunay_2d()
footprint_plane.points[:] = (footprint_plane.points - footprint_plane.center)*1.5 + footprint_plane.center
pv.save_meshio(f"d:/simple_scene/mesh/ground.ply",footprint_plane)material_type = "mat-itu_wet_ground"
sionna_shape = ET.SubElement(scene, "shape", type="ply", id=f"mesh-ground")
ET.SubElement(sionna_shape, "string", name="filename", value=f"mesh/ground.ply")
bsdf_ref = ET.SubElement(sionna_shape, "ref", id=material_type, name="bsdf")
ET.SubElement(sionna_shape, "boolean", name="face_normals",value="true")
创建建筑网格并添加到场景中:
import osmnx as ox
wsg84 = pyproj.CRS("epsg:4326")
lambert = pyproj.CRS("epsg:4326")
transformer = pyproj.Transformer.from_crs(wsg84, lambert, always_xy=True)
coords = [transformer.transform(x, y) for x, y in dc.last_draw['geometry']['coordinates'][0]]osm_polygon = shapely.geometry.Polygon(coords)
# Query the OpenStreetMap data
buildings = ox.geometries.geometries_from_polygon(osm_polygon, tags={'building': True})# Filter buildings that intersect with the polygon
filtered_buildings = buildings[buildings.intersects(osm_polygon)]filtered_buildings.head(5)
以下代码使用建筑足迹并拉伸它们来创建三角形网格,并逐一添加Sionna场景。
buildings_list = filtered_buildings.to_dict('records')
source_crs = pyproj.CRS(filtered_buildings.crs)
target_crs = pyproj.CRS('EPSG:26915')
transformer = pyproj.Transformer.from_crs(source_crs, target_crs, always_xy=True).transform
for idx, building in enumerate(buildings_list):# Convert building geometry to a shapely polygonbuilding_polygon = shape(building['geometry'])if building_polygon.geom_type != 'Polygon':continuebuilding_polygon = transform(transformer, building_polygon)if math.isnan(float(building['building:levels'])):building_height = 3.5else:building_height = int(building['building:levels']) * 3.5z_coordinates = np.full(len(building_polygon.exterior.coords), 0) # Assuming the initial Z coordinate is zminexterior_coords = building_polygon.exterior.coordsoriented_coords = list(exterior_coords)# Ensure counterclockwise orientationif building_polygon.exterior.is_ccw:oriented_coords.reverse()points = [(coord[0]-center_x, coord[1]-center_y) for coord in oriented_coords]# bounding polygonboundary_points_polydata = points_2d_to_poly(points, z_coordinates[0])edge_polygon = boundary_points_polydatafootprint_plane = edge_polygon.delaunay_2d()footprint_plane = footprint_plane.triangulate()footprint_3D = footprint_plane.extrude((0, 0, building_height), capping=True)footprint_3D.save(f"d:/simple_scene/mesh/building_{idx}.ply")local_mesh = o3d.io.read_triangle_mesh(f"d:/simple_scene/mesh/building_{idx}.ply")o3d.io.write_triangle_mesh(f"d:/simple_scene/mesh/building_{idx}.ply", local_mesh)material_type = "mat-itu_marble"# Add shape elements for PLY files in the foldersionna_shape = ET.SubElement(scene, "shape", type="ply", id=f"mesh-building_{idx}")ET.SubElement(sionna_shape, "string", name="filename", value=f"mesh/building_{idx}.ply")bsdf_ref = ET.SubElement(sionna_shape, "ref", id= material_type, name="bsdf")ET.SubElement(sionna_shape, "boolean", name="face_normals",value="true")
创建道路网格并添加到场景中:
def convert_lane_to_numeric(lane):try:return int(lane)except ValueError:try:return float(lane)except ValueError:return None# Helper function to calculate edge geometry if missing
def calculate_edge_geometry(u, v, data):u_data = graph.nodes[u]v_data = graph.nodes[v]return LineString([(u_data['x'], u_data['y']), (v_data['x'], v_data['y'])])G = ox.graph_from_polygon(polygon = osm_polygon, simplify= False, retain_all=True,truncate_by_edge=True,network_type = 'all_private')
graph = ox.project_graph(G, to_crs='epsg:26915')
ox.plot_graph(graph)
现在,使用车道作为参数将每条线段转换为道路网格,以设置道路宽度:
# Create a list to store GeoDataFrames for each road segment
gdf_roads_list = []
# Set the fixed Z coordinate for the buffer polygons
Z0 = .25 # You can adjust this value based on the desired elevation of the roads
# Create a list to store the meshes
mesh_list = []
mesh_collection = pv.PolyData()
# Iterate over each edge in the graph
for u, v, key, data in graph.edges(keys=True, data=True):# Check if the edge has geometry, otherwise create geometries from the nodesif 'geometry' not in data:data['geometry'] = calculate_edge_geometry(u, v, data)# Get the lanes attribute for the edgelanes = data.get('lanes', 1) # Default to 1 lane if lanes attribute is not availableif not isinstance(lanes, list):lanes = [lanes]# Convert lane values to numeric (integers or floats) using the helper functionnum_lanes = [convert_lane_to_numeric(lane) for lane in lanes]# Filter out None values (representing non-numeric lanes) and calculate the road widthnum_lanes = [lane for lane in num_lanes if lane is not None]road_width = num_lanes[0] * 3.5# Buffer the LineString with the road width and add Z coordinateline_buffer = data['geometry'].buffer(road_width)# Convert the buffer polygon to a PyVista meshexterior_coords = line_buffer.exterior.coordsz_coordinates = np.full(len(line_buffer.exterior.coords), Z0)oriented_coords = list(exterior_coords)# Ensure counterclockwise orientationif line_buffer.exterior.is_ccw:oriented_coords.reverse()points = [(coord[0]-center_x, coord[1]-center_y) for coord in oriented_coords]# bounding polygonboundary_points_polydata = points_2d_to_poly(points, z_coordinates[0])mesh = boundary_points_polydata.delaunay_2d()# Add the mesh to the listmesh_collection = mesh_collection + meshmesh_list.append(mesh)
output_file = f"d:/simple_scene/mesh/road_mesh_combined.ply"
pv.save_meshio(output_file,mesh_collection)
material_type = "mat-itu_concrete"
# Add shape elements for PLY files in the folder
sionna_shape = ET.SubElement(scene, "shape", type="ply", id=f"mesh-roads_{idx}")
ET.SubElement(sionna_shape, "string", name="filename", value=f"mesh/road_mesh_combined.ply")
bsdf_ref = ET.SubElement(sionna_shape, "ref", id= material_type, name="bsdf")
ET.SubElement(sionna_shape, "boolean", name="face_normals",value="true")
最后保存场景文件:
# Create and write the XML file
tree = ET.ElementTree(scene)
xml_string = ET.tostring(scene, encoding="utf-8")
xml_pretty = minidom.parseString(xml_string).toprettyxml(indent=" ") # Adjust the indent as neededwith open(f"d:/simple_scene/simple_OSM_scene.xml", "w", encoding="utf-8") as xml_file:xml_file.write(xml_pretty)
生成模型文件如下:
在blender加载上面结果文件如下:
结语
如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;
╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;
o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;
(✿◡‿◡)
感谢各位大佬童鞋们的支持!
( ´ ▽´ )ノ ( ´ ▽´)っ!!!
相关文章:

【小沐学GIS】基于Openstreetmap创建Sionna RT场景(Python)
文章目录 1、简介1.1 blender 2、下载和安装2.1 Python2.2 jupyter 3、运行结语 1、简介 1.1 blender https://www.blender.org/ Blender 是一款免费开源的3D创作套件。 使用 Blender,您可以创建3D可视化效果,例如静态图像、3D动画、VFX(…...
网安面试题1
深信服厂商面 自我介绍 我看到你介绍里面有提到独立设计网络拓扑图,你知道内网有哪些攻击途径吗 护网红队有什么成果 sql注入有哪些类型 sql注入的防御方式 讲一个你工作中遇到的应急响应 怎么判断内网的攻击是不是真实攻击 Windows中了勒索病毒你应该怎么办 linux被…...

你了解system V的ipc底层如何设计的吗?消息队列互相通信的原理是什么呢?是否经常将信号量和信号混淆呢?——问题详解
前言:本节主要讲解消息队列, 信号量的相关知识。 ——博主主要是以能够理解为目的进行讲解, 所以对于接口的使用或者底层原理很少涉及。 主要的讲解思路就是先讨论消息队列的原理, 提一下接口。 然后讲解ipc的设计——这个设计一些…...

python爬虫初体验(一)
文章目录 1. 什么是爬虫?2. 为什么选择 Python?3. 爬虫小案例3.1 安装python3.2 安装依赖3.3 requests请求设置3.4 完整代码 4. 总结 1. 什么是爬虫? 爬虫(Web Scraping)是一种从网站自动提取数据的技术。简单来说&am…...

ER 图 Entity-Relationship (ER) diagram 101 电子商城 数据库设计
起因, 目的: 客户需求, 就是要设计一个数据库。 过程, 关于工具: UI 设计,我最喜欢的工具其实是 Canva, 但是 Canva 没有合适的模板。我用的是 draw.io, 使用感受是,很垃圾。 各种快捷键不适应,箭头就是点不住&…...

JavaSE--IO流总览06:字符转换输入(输出)流: InputStreamReader ,OutputStreamWrite
IO流体系(学到哪扩展到哪): 学习字符转换流的目的是为了什么? InputStreamReader---解决不同编码时字符流读取文本内容乱码的问题 OutPutStreamWrite---可以控制写出去的字符使用什么字符集编码 为什么会有乱码呢?因为读取的文件内容编码与…...

浙版传媒思迈特软件大数据分析管理平台建设项目正式启动
近日,思迈特软件与出版发行及电商书城领域的领军企业——浙江出版传媒股份有限公司,正式启动大近日,思迈特软件与出版发行及电商书城领域的领军企业——浙江出版传媒股份有限公司,正式启动大数据分析管理平台建设项目。浙版传媒相…...

漏洞——CVE简介
1、什么是CVE CVE (Common Vulnerabilities and Exposures)(常见漏洞与暴露)是一个标准化的命名系统,用于识别和描述公开披露的网络安全漏洞。CVE 的目的是为漏洞提供唯一的标识符,使安全专家、软件供应商和用户能够统一参考和讨…...
IT行业中的技术趋势与未来展望
IT行业中的技术趋势与未来展望 IT行业作为全球经济发展的重要引擎,正在以惊人的速度推动着科技进步与创新。随着技术的不断演进,一些新的趋势正悄然改变着我们的工作方式和生活方式。本文将探讨当前IT行业中的主要技术趋势以及未来展望,帮助…...
解决 webpack 配置 sass-loader后报错,无法正常build
1. 问题描述 总是打包build报错,本质上css样式语法也没写错在使用 sass-resources-loader 的项目中,开发者常常遇到构建错误或意外的样式行为,这是因为 sass-resources-loader 的作用和使用场景并不总是被正确理解。sass-resources-loader 主…...

CentOS中使用DockerCompose方式部署带postgis的postgresql(附kartoza/docker-postgis镜像下载)
场景 CentOS中使用Docker部署带postgis的postgresql: CentOS中使用Docker部署带postgis的postgresql_centos postgis插件在容器中如何安装-CSDN博客 上面使用Docker搜索和拉取kartoza/postgis时并没有任何限制。 当下如果不能科学上网时,大部分镜像源…...

初识elasticsearch
初识elasticsearch 1.什么是elasticsearch 一个开源的分布式搜索引擎,可以用来实现搜索、日志统计、分析、系统监控等功能;elasticsearch 是结合kibana、Logstash、Beats,也就是elastic stach(ELK)。被广泛应用在日志数据分析、实时监控等领域。 elastic…...

react hooks--React.memo
基本语法 React.memo 高阶组件的使用场景说明: React 组件更新机制:只要父组件状态更新,子组件就会无条件的一起更新。 子组件 props 变化时更新过程:组件代码执行 -> JSX Diff(配合虚拟 DOM)-> 渲…...
App端测——稳定性测试
稳定性测试项:Crash、ANR、OOM、内存泄漏 crash:应用崩溃,从提测后开始关注,monkey持续上报跟踪 ANR:系统无响应,使用低端机内存小的机型测试,及monkey中关注ANR问题。关于ANR详细:…...

[数据结构与算法·C++] 笔记 1.4 算法复杂性分析
1.4 算法复杂性分析 算法的渐进分析 数据规模 n 逐步增大时, f(n)的增长趋势当 n 增大到一定值以后,计算公式中影响最大的就是 n 的幂次最高的项其他的常数项和低幂次项都可以忽略 大O表示法 函数f,g定义域为自然数,值域非负实数集定义: …...
Hive parquet表通过csv文件导入数据
1. background 已建好了 hive parquet 格式的表, 需要从服务器的csv导入数据至该hive表 2. step 提前上传csv至服务器 /path/temp.csv 创建 textfile 格式的中转表(这里使用内部表,方便删除) ,源表名dw_procurement.dwd_tc_comm_plant ,这里中转表加上了csv后缀 CREATE TA…...
C++ 构造函数最佳实践
文章目录 1. 构造函数应该做什么1.1 初始化成员变量1.2 分配资源1.3 遵循 RAII 原则1.4 处理异常情况 2. 构造函数不应该做什么2.1 避免做大量的工作2.2 不要在构造函数中调用虚函数2.3 避免在构造函数中执行复杂的初始化逻辑2.4 避免调用可能抛出异常的代码 3. 构造函数的其他…...

C++——关联式容器(4):set和map
在接触了诸如二叉搜索树、AVL树、红黑树的树形结构之后,我们对树的结构有了大致的了解,现在引入真正的关联式容器。 首先,先明确了关联式容器的概念。我们之前所接触到的如vector、list等容器,我们知道他们实际上都是线性的数据结…...
Spring Mybatis 基本使用 总结
1. 简介 Mybatis库可以简化数据库的操作,专注于sql语句。 2.搭建步骤 2.1 在pom.xml引入mybatis <dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.11</version> </dep…...

接口幂等性和并发安全的区别?
目录标题 幂等性并发安全总结 接口幂等性和并发安全是两个不同的概念,虽然它们在设计API时都很重要,但侧重点不同。 幂等性 定义:幂等性指的是无论对接口进行多少次相同的操作,结果都是一致的。例如,HTTP的PUT和DELE…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题
在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件,这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下,实现高效测试与快速迭代?这一命题正考验着…...

佰力博科技与您探讨热释电测量的几种方法
热释电的测量主要涉及热释电系数的测定,这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中,积分电荷法最为常用,其原理是通过测量在电容器上积累的热释电电荷,从而确定热释电系数…...

NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...