OpenLayers 6 代码绘制/draw交互组件绘制两种方式绘制椭圆过程详解
引言
OpenLayers可以通过代码绘制多种几何形状,也可以通过draw类型的交互组件绘制几何形状,官方实例提供了类如圆、折线、矩形、星形等方法。除此之外,椭圆这种图形其实也是非常常见的几何图形,但是官方没有提供现成的API,本文从使用代码绘制和交互绘制两种途径详细讲解一下椭圆的绘制。
一点理论基础
众所周知,OGC提供的标准geometry类型只有点、线、面以及它们的组合,并没有圆和椭圆,OpenLayers绘制圆的时候,采用的是正多边形逼近法拟合的“圆形”。虽然渲染到canvas上的实际图形是个多边形,但是在数据结构上,它仍然是个圆。圆形的公式可以写为:
相对的,椭圆的公式可以写为:
椭圆公式中的Y可以看做圆公式中的Y变换了倍之后得来。这里的公式中的X和Y对应的就是横纵坐标值。
OpenLayers的SimpleGeometry类及其子类提供了具有这种功能的函数scale,可以对横纵坐标进行按比例的拉伸变换。可以利用这个函数实现椭圆的绘制。
核心代码
下面是实现绘制椭圆的核心代码,无论是用代码绘制还是用draw交互组件绘制都需要用到它:
function genEllipseGeom(radiusMajor, radiusMinor, center, rotation) {var circle = new Circle(center, radiusMinor);var polygon = fromCircle(circle, 64);polygon.scale(radiusMajor / radiusMinor, 1);polygon.rotate(rotation, center);return polygon;
}
参数radiusMajor, radiusMinor, center, rotation分别对应椭圆的长半轴、短半轴、重心和旋转角度。
算法的主要思想是:首先以短半轴为半径生成了一个Circle类型的几何,然后通过这个理想圆生成了一个正64边形多边形,拟合这个圆。再将这个多边形进行按比例变换,变换之后的结果再进行旋转,最后得到的就是使用多边形拟合的椭圆。
代码控制绘制椭圆的完整代码
import { Map, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import Circle from 'ol/geom/Circle';
import { fromCircle } from 'ol/geom/Polygon'
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import Feature from 'ol/Feature';let tileLayer = new TileLayer({source: new OSM()
})
let map = new Map({target: 'map',layers: [tileLayer],view: new View({center: [11936406.337013, 3786384.633134],zoom: 5,constrainResolution: true})
});var vSource = new VectorSource()
var vLayer = new VectorLayer({source: vSource,}
)function genEllipseGeom(radiusMajor, radiusMinor, center, rotation) {var circle = new Circle(center, radiusMinor);var polygon = fromCircle(circle, 64);polygon.scale(radiusMajor / radiusMinor, 1);polygon.rotate(rotation, center);return polygon;
}var elGeom = genEllipseGeom(600000, 400000, [11936406.337013, 3786384.633134], Math.PI / 4);
var ef = new Feature(elGeom);
vSource.addFeature(ef);
map.addLayer(vLayer)
draw交互组件绘制椭圆
使用draw交互组件绘制椭圆与绘制圆形是类似的,可以有两种思路:
- 两点法:第一个点确定重心,第二个点与重心的横坐标之差确定长半轴,纵坐标值差确定短半轴。这个方案的缺点是无法通过绘制来自由定义椭圆的旋转角度。
- 三点法:同样第一个点确定重心,第二个点与重心的连线确定长半轴,连线与横坐标轴的夹角确定旋转角度;第三个点到长半轴的距离确定短半轴。
本文使用三点法来实现椭圆的交互绘制。主要思路是通过自定义draw组件的geometryFunction来实现三点法绘制的逻辑。
draw交互组件绘制椭圆的完整代码
import { Map, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import OSM from 'ol/source/OSM';
import Circle from 'ol/geom/Circle';
import Polygon from 'ol/geom/Polygon';
import { fromCircle } from 'ol/geom/Polygon'
import VectorSource from 'ol/source/Vector';
import VectorLayer from 'ol/layer/Vector';
import Feature from 'ol/Feature';
import Draw from 'ol/interaction/Draw';
import Style from 'ol/style/Style';
import Fill from 'ol/style/Fill';
import Stroke from 'ol/style/Stroke';
import CircleStyle from 'ol/style/Circle';
import GeometryType from 'ol/geom/GeometryType';function createEditingStyle(feature) {const styles = {};const white = [255, 255, 255, 1];const blue = [0, 0, 255, 1];const width = 3;styles[GeometryType.POLYGON] = [new Style({fill: new Fill({color: [255, 255, 255, 0.3]}),stroke: new Stroke({color: "#00FF00",})})];styles[GeometryType.MULTI_POLYGON] =styles[GeometryType.POLYGON];styles[GeometryType.LINE_STRING] = [new Style({stroke: new Stroke({color: [0, 255, 0, 0.3],width: width})})];styles[GeometryType.POINT] = [new Style({image: new CircleStyle({radius: width * 2,fill: new Fill({color: blue}),stroke: new Stroke({color: white,width: width / 2})}),zIndex: Infinity})];return styles[feature.getGeometry().getType()]
}
let tileLayer = new TileLayer({source: new OSM()
})
let map = new Map({target: 'map',layers: [tileLayer],view: new View({center: [11936406.337013, 3786384.633134],zoom: 5,constrainResolution: true})
});
var vSource = new VectorSource()
var vLayer = new VectorLayer({source: vSource,}
)
function genEllipseGeom(radiusMajor, radiusMinor, center, rotation) {var circle = new Circle(center, radiusMinor);var polygon = fromCircle(circle, 64);polygon.scale(radiusMajor / radiusMinor, 1);polygon.rotate(rotation, center);return polygon;
}
var elGeom = genEllipseGeom(600000, 400000, [11936406.337013, 3786384.633134], 0);
var ef = new Feature(elGeom);
vSource.addFeature(ef);
map.addLayer(vLayer)
var value = 'Polygon';
var geometryFunction;
var maxPoints = 3;
function geometryFunction(coordinates, geometry) {let cArray = coordinates[0]let center = cArray[0];let startPoint = cArray[1];let endPoint = cArray[2];if (!geometry) {geometry = new Polygon([]);}if (cArray.length == 3) {let coordinatesRing = cArray.slice()coordinatesRing.push(center)let plg = new Polygon([coordinatesRing])let plygArea = plg.getArea()let radiusMajor = Math.sqrt(Math.pow(center[0] - startPoint[0], 2) +Math.pow(center[1] - startPoint[1], 2))let radiusMinor = (plygArea * 2) / radiusMajor;let dx = startPoint[0] - center[0];let dy = startPoint[1] - center[1];let rotation = Math.atan(dx / dy);rotation = dy > 0 ? -rotation - Math.PI * 0.5 : -(Math.PI * 0.5 + rotation);let f = genEllipseGeom(radiusMajor, radiusMinor, center, rotation)geometry.setCoordinates(f.getCoordinates())}return geometry
}
var draw = new Draw({source: vSource,type: value,geometryFunction: geometryFunction,maxPoints: maxPoints,style: createEditingStyle});
map.addInteraction(draw);
我在企鹅家的课堂和CSDN学院都开通了《OpenLayers实例详解》课程,欢迎报名学习。
OpenLayers 6 代码绘制/draw交互组件绘制两种方式绘制椭圆过程详解相关推荐
- java jframe添加面板_JFrame添加组件的两种方式
对JFrame添加组件有两种方式:1) 用getContentPane()方法获得JFrame的内容面板,再对其加入组件:frame.getContentPane().add(childCompont ...
- vue 在线编辑excel表格(原生和使用组件的两种方式)
vue 在线编辑excel表格(原生和使用组件的两种方式) top表头和left表头格式的表格 <template><div><!-- 用组件写的编辑表格 -->& ...
- Vue渲染组件的两种方式
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...
- Qt Qml动态创建对象/组件的两种方式
Qml动态创建对象有两种方式: a.使用Loader b.使用javaScript 1.Loader加载机制: 加载过程: 通过source,来加载qml文件. 通过sourceComponent,来 ...
- 将Eclipse代码导入到Android Studio的两种方式
转: http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0104/2259.html 说到使用Android Studio,除了新建 ...
- 子组件改变父组件的两种方式
首先父子组件传值:很简单 子组件改变父组件的方式一: adddata: function () {this.$emit('addnum:datanum', this.datanum)} 通过this. ...
- 用VLC开发视频播放器/组件(两种方式:libVLC / VLC-Qt)
测试环境 MSVC-2015 Qt 5.14.2 QCreator 1. libVLC(关键步骤) 参考:心流剑 libVLC 各版本 下载链接 我的下载版本为:3.0.11 sdk/lib文件夹目录 ...
- android line分享代码,Android 分享到Line的两种方式
写这篇文章主要目的是搜索到的答案都不是很完善,所以在此整理一下,防止有这需求的小伙伴们抓瞎 ;实现之前查了官方的文档,没有找到关于sdk支持分享的地方,只是提供了scheme支持(而且很难找..) 通 ...
- 代码编译时光标闪烁的两种方式
两种反射的切换,按ins键.也就是把numberlock键关了后的0键.
最新文章
- 创建型模式:单例模式(懒汉+饿汉+双锁校验+内部类+枚举)
- datagrip mysql乱码_DataGrip和IDEA无法连接上Mysql问题解决方法详解
- KXMovie基于ffmpeg的播放器
- (转)向SDE库中写入栅格和矢量数据
- 人工智能语音电视能“听话”吗?
- java中PriorityQueue优先级队列使用方法
- 关于UIText换行
- tensorflow安装以及在Anaconda中安装使用
- TI DSP 28335 自学之路,到此止步
- 甘特图控件VARCHART XGantt:XGantt的用途
- 【C++教程】04.求1加到100
- Spring控制反转(IOC)之注解配置
- java web 注册登录_javaweb实现登录注册功能实例
- 计算机右键菜单更换顺序,笔记本电脑怎么样调整右键选项顺序
- WMF,双立人,菲仕乐,法国OQO——国际顶级厨具
- 前端面试题汇总(四)
- linus开启snmp_Linux开通snmp
- MYSQL POLARDB 学习系列之 拆解 POLARDB 6 Auto-Scaling 与性能优化 (翻译)
- 致传统企业码友的一封信:不够痛就别微服务!
- 磁盘挂载失败Couldn't create temporary archive name
热门文章
- iOS 开发 解决UICollectionView的多组头部视图样式不一样复用时发生错乱问题
- MySQL 部门员工工资表 综合练习
- Tumblr营销大法(二)
- Javaweb中上传图片,获取相对路径,绝对路径
- sqlServer简单建数据库,建表操作
- java计算机毕业设计vue健康餐饮管理系统设计与实现MyBatis+系统+LW文档+源码+调试部署
- react-router4.2使用js控制路由跳转的3种方式
- 2020年,这个算法团队都干了啥?
- shader拖尾_u3d拖尾特效组件-------TrailRenderer
- Android——TextView指定字符串颜色高亮,实现类似微信、支付宝搜索结果中搜索字段高亮的效果