引言

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交互组件绘制两种方式绘制椭圆过程详解相关推荐

  1. java jframe添加面板_JFrame添加组件的两种方式

    对JFrame添加组件有两种方式:1) 用getContentPane()方法获得JFrame的内容面板,再对其加入组件:frame.getContentPane().add(childCompont ...

  2. vue 在线编辑excel表格(原生和使用组件的两种方式)

    vue 在线编辑excel表格(原生和使用组件的两种方式) top表头和left表头格式的表格 <template><div><!-- 用组件写的编辑表格 -->& ...

  3. Vue渲染组件的两种方式

    <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8" ...

  4. Qt Qml动态创建对象/组件的两种方式

    Qml动态创建对象有两种方式: a.使用Loader b.使用javaScript 1.Loader加载机制: 加载过程: 通过source,来加载qml文件. 通过sourceComponent,来 ...

  5. 将Eclipse代码导入到Android Studio的两种方式

    转: http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2015/0104/2259.html 说到使用Android Studio,除了新建 ...

  6. 子组件改变父组件的两种方式

    首先父子组件传值:很简单 子组件改变父组件的方式一: adddata: function () {this.$emit('addnum:datanum', this.datanum)} 通过this. ...

  7. 用VLC开发视频播放器/组件(两种方式:libVLC / VLC-Qt)

    测试环境 MSVC-2015 Qt 5.14.2 QCreator 1. libVLC(关键步骤) 参考:心流剑 libVLC 各版本 下载链接 我的下载版本为:3.0.11 sdk/lib文件夹目录 ...

  8. android line分享代码,Android 分享到Line的两种方式

    写这篇文章主要目的是搜索到的答案都不是很完善,所以在此整理一下,防止有这需求的小伙伴们抓瞎 ;实现之前查了官方的文档,没有找到关于sdk支持分享的地方,只是提供了scheme支持(而且很难找..) 通 ...

  9. 代码编译时光标闪烁的两种方式

    两种反射的切换,按ins键.也就是把numberlock键关了后的0键.

最新文章

  1. 创建型模式:单例模式(懒汉+饿汉+双锁校验+内部类+枚举)
  2. datagrip mysql乱码_DataGrip和IDEA无法连接上Mysql问题解决方法详解
  3. KXMovie基于ffmpeg的播放器
  4. (转)向SDE库中写入栅格和矢量数据
  5. 人工智能语音电视能“听话”吗?
  6. java中PriorityQueue优先级队列使用方法
  7. 关于UIText换行
  8. tensorflow安装以及在Anaconda中安装使用
  9. TI DSP 28335 自学之路,到此止步
  10. 甘特图控件VARCHART XGantt:XGantt的用途
  11. 【C++教程】04.求1加到100
  12. Spring控制反转(IOC)之注解配置
  13. java web 注册登录_javaweb实现登录注册功能实例
  14. 计算机右键菜单更换顺序,笔记本电脑怎么样调整右键选项顺序
  15. WMF,双立人,菲仕乐,法国OQO——国际顶级厨具
  16. 前端面试题汇总(四)
  17. linus开启snmp_Linux开通snmp
  18. MYSQL POLARDB 学习系列之 拆解 POLARDB 6 Auto-Scaling 与性能优化 (翻译)
  19. 致传统企业码友的一封信:不够痛就别微服务!
  20. 磁盘挂载失败Couldn't create temporary archive name

热门文章

  1. iOS 开发 解决UICollectionView的多组头部视图样式不一样复用时发生错乱问题
  2. MySQL 部门员工工资表 综合练习
  3. Tumblr营销大法(二)
  4. Javaweb中上传图片,获取相对路径,绝对路径
  5. sqlServer简单建数据库,建表操作
  6. java计算机毕业设计vue健康餐饮管理系统设计与实现MyBatis+系统+LW文档+源码+调试部署
  7. react-router4.2使用js控制路由跳转的3种方式
  8. 2020年,这个算法团队都干了啥?
  9. shader拖尾_u3d拖尾特效组件-------TrailRenderer
  10. Android——TextView指定字符串颜色高亮,实现类似微信、支付宝搜索结果中搜索字段高亮的效果