随着web在线CAD图查看的普及,需求也不断涌现,一些需求不再满足的在线图形的查看,而涉及到web端在线图形的几何运算。本文以如果实现与在线CAD图中的线段实时求交点这例,介绍下如何在web端cad图几何运算的功能实现。
需要实现的功能有
先上实现效果

如果在Web网页端展示CAD图形(唯杰地图云端图纸管理平台 https://vjmap.com/app/cloud),这个在前面的博文中已讲过,这里不再重复,有需要的朋友可下载工程源代码研究下。
在线获取CAD图上所有线段坐标有两种方式
在栅格模式下,可以去后台通过条件查询获取所有线段坐标。代码如下
//栅格样式去服务器获取坐标点数据
// 栅格样式获取捕捉点
// 查询所有坐标数据,字段含义可参考https://vjmap.com/guide/svrStyleVar.html
let res = await svc.conditionQueryFeature({ fields:"s3", condition:"s3 != ''", limit: 100000})
res = res.result.map(e => e.s3.split(";"))
snapObj.features = []
for(let item of res) {
let coordinates = []
for(let pt of item) {
const p = pt.split(",")
if (p.length >= 2) {
coordinates.push(map.toLngLat([+p[0], +p[1]]))
}
}
if (coordinates.length == 1) {
snapObj.features.push({
type: "Feature",
geometry: {
type: "Point",
coordinates: coordinates[0]
}
})
}
else if (coordinates.length > 1) {
snapObj.features.push({
type: "Feature",
geometry: {
type: "LineString",
coordinates: coordinates
}
})
}
}
在矢量模式下,可以直接在前端获取当前渲染的线图层的所有线坐标,代码如下
// 查询矢量图层上所有的线图层
let features = map.queryRenderedFeatures({layers: ['vector-layer-lines']})
let mapGeoDatas = {
type: "FeatureCollection",
features: features.map(f => {
return {
id: f.id,
type: f.type,
properties: f.properties,
geometry: f.geometry
}
})
}
/**
* 线段相交
* @return {{result: string, status: boolean} | {result: string, status: boolean} | {x: number, y: number, status: boolean, ratio: number} | {result: string, status: boolean}}
*/
export function segmentIntersect(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, x4: number, y4: number): {
result: string;
status: boolean;
x?: undefined;
y?: undefined;
ratio?: undefined;
} | {
status: boolean;
x: number;
y: number;
ratio: number;
result?: undefined;
};
在示例中,我们模拟了一条随机的线条,并且让这条线条实时动起来。代码如下
// 让相交线动起来
const moveLine = (newStartPoint, newEndPoint) => {
let data = map.getSourceData(intersectLine.sourceId);
let geoData = map.fromLngLat(data);
// 开始点插值函数
let mapProgressToValueStart = vjmap.interpolate(
[0, 1],
[geoData.features[0].geometry.coordinates[0], [newStartPoint.x, newStartPoint.y]]
)
// 终点插值函数
let mapProgressToValueEnd = vjmap.interpolate(
[0, 1],
[geoData.features[0].geometry.coordinates[1], [newEndPoint.x, newEndPoint.y]]
)
vjmap.createAnimation({
from: 0,
to: 1,
duration: 5000,
ease:vjmap.linear, //线性
onUpdate: latest => {
let beginPoint = mapProgressToValueStart(latest)
let endPoint = mapProgressToValueEnd(latest)
// 修改坐标
data.features[0].geometry.coordinates = map.toLngLat([beginPoint, endPoint])
map.setData(intersectLine.sourceId, data)
},
onComplete: (e) => {
map.fire("moveLineFinish"); // 发送线移动完成事件
}
})
}
相交计算如果数据量大时,会耗CPU资源,会导致图形卡顿,如果需要做到实时相交,并且运行界面不卡顿,需要用WebWorker的技术。web worker 是运行在后台的 JavaScript,不会影响页面的性能。web worker 无疑是解决 js 计算能力弱的一大利器.
在唯杰地图 vjmap中有对webworker的封装,可以直接把一个匿名函数做为一个webworker去运行。相关代码如下
/* 如果要用vjmap库中其他的函数,获取库脚本的内容
let script = await vjmap.httpHelper.get("js/vjmap/vjmap.min.js", undefined, {
raw: true
})*/
// 启动webworker计算相交函数
let intersect = vjmap.WorkerProxy(getIntersects, {
// vjmap: script.data, //脚本内容, 如果要用vjmap库中其他的函数,可以获取库脚本的内容 ,把脚本内容传给webworker
intersectFunc: vjmap.segmentIntersect // 把主进程库的相交函数做为上下文传进去,这个方法是不用引入vjmap整个库,只用里面的某个函数,但是这个函数不能调用其他函数,如果调用了其他函数会报错,这时只有用上面注释的那个办法,把整个vjmap库都导入进webworker
});
// 用webworker计算相交点
const calcIntersect = async ()=> {
// 获取线的坐标
let coordinates = map.fromLngLat(map.getSourceData(intersectLine.sourceId)).features[0].geometry.coordinates;
// 启动webworker计算相交点
let intersectPoints = await intersect(coordinates[0], coordinates[1], geoDatas)
intersectSymbols.setData(map.toLngLat(intersectPoints)); //修改数据
map.fire("calcIntersectFinish"); // 发送线移动完成事件
}
map.on("calcIntersectFinish", async ()=> setTimeout(async ()=> await calcIntersect(), 15))
calcIntersect();
// 如果要停止webworker
//intersect.worker.terminate()
最终效果如下

上面的案例代码已开源。访问 (https://vjmap.com/demo/#/demo/map/geo/geoWebWorkerIntersect) ,查看效果和代码即可。
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
如果我使用ruby版本2.5.1和Rails版本2.3.18会怎样?我有基于rails2.3.18和ruby1.9.2p320构建的rails应用程序,我只想升级ruby的版本,而不是rails,这可能吗?我必须面对哪些挑战? 最佳答案 GitHub维护apublicfork它有针对旧Rails版本的分支,有各种变化,它们一直在运行。有一段时间,他们在较新的Ruby版本上运行较旧的Rails版本,而不是最初支持的版本,因此您可能会发现一些关于需要向后移植的有用提示。不过,他们现在已经有几年没有使用2.3了,所以充其量只能让更
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO
遍历文件夹我们通常是使用递归进行操作,这种方式比较简单,也比较容易理解。本文为大家介绍另一种不使用递归的方式,由于没有使用递归,只用到了循环和集合,所以效率更高一些!一、使用递归遍历文件夹整体思路1、使用File封装初始目录,2、打印这个目录3、获取这个目录下所有的子文件和子目录的数组。4、遍历这个数组,取出每个File对象4-1、如果File是否是一个文件,打印4-2、否则就是一个目录,递归调用代码实现publicclassSearchFile{publicstaticvoidmain(String[]args){//初始目录Filedir=newFile("d:/Dev");Datebeg
通常,数组被实现为内存块,集合被实现为HashMap,有序集合被实现为跳跃列表。在Ruby中也是如此吗?我正在尝试从性能和内存占用方面评估Ruby中不同容器的使用情况 最佳答案 数组是Ruby核心库的一部分。每个Ruby实现都有自己的数组实现。Ruby语言规范只规定了Ruby数组的行为,并没有规定任何特定的实现策略。它甚至没有指定任何会强制或至少建议特定实现策略的性能约束。然而,大多数Rubyist对数组的性能特征有一些期望,这会迫使不符合它们的实现变得默默无闻,因为实际上没有人会使用它:插入、前置或追加以及删除元素的最坏情况步骤复