circle-arc-ellipse
本文回答:
CircleEnt/ArcEnt/EllipseEnt—— 圆、弧、椭圆的参数、角度约定、填充、与 Polyline 互转。
一、圆 (CircleEnt)
创建
const circle = new vjmapext.CircleEnt([cx, cy], radius);
circle.color = 0x4488ff;
circle.fillColor = 0x4488ff;
circle.fillOpacity = 0.3;
mapcadLayer.addEntity(circle);
⚠️ 封闭图形默认带填充:
CircleEnt、整椭圆EllipseEnt、闭合PolylineEnt/SplineEnt默认fillColor = -1(跟随color)、fillOpacity = 0.2——不设也会有一层 20% 半透明面。只要轮廓就显式fillOpacity = 0。
属性
| 属性 | 类型 | 说明 |
|---|---|---|
center |
Point2D |
圆心 |
radius |
number | 半径(CAD 单位) |
修改
circle.radius = 150;
circle.changed();
查询
// 实体上没有 area()/perimeter()/length() 这类测量方法;自己按几何算:
const area = Math.PI * circle.radius ** 2; // π r²
const girth = 2 * Math.PI * circle.radius; // 2 π r
circle.boundingBox(); // 与半径对齐的外接矩形
// CircleEnt 另有静态构造:fromTwoPoints(直径两点) / fromThreePoints(外接圆,共线返 null) / fromCenterDiameter
二、弧 (ArcEnt)
创建
const arc = new vjmapext.ArcEnt(
[cx, cy], // 圆心
radius, // 半径
startAngle, // 起始角,弧度
endAngle, // 终止角,弧度
isCCW // 可选,默认 true(逆时针);false = 顺时针
);
重要:ArcEnt 用弧度(不是度):
const arc = new vjmapext.ArcEnt([0, 0], 100, 0, Math.PI); // 上半圆
度 → 弧度:
const deg2rad = d => d * Math.PI / 180;
const quarter = new vjmapext.ArcEnt([0, 0], 100, 0, deg2rad(90));
方向约定
isCCW=true(默认)逆时针扫、false 顺时针扫;构造第 5 参控制- 0 弧度 = X 正方向
- π/2 = Y 正方向
fromThreePoints会按三点转向自动判定isCCW
端点和中点
arc.startPoint; // 只读 getter,按 startAngle 计算
arc.endPoint;
arc.midPoint; // 弧中点(按 midAngle)
arc.midAngle; // 中点角度
// 没有 arc.length();弧长按实际扫掠角算(与渲染同规则,考虑 isCCW 与跨 0 回绕):
let sweep = arc.endAngle - arc.startAngle;
if (arc.isCCW && sweep < 0) sweep += 2 * Math.PI;
if (!arc.isCCW && sweep > 0) sweep -= 2 * Math.PI;
const arcLen = arc.radius * Math.abs(sweep);
用三点构造弧
const arc = vjmapext.ArcEnt.fromThreePoints(
[0, 0], [50, 80], [100, 0]
);
mapcadLayer.addEntity(arc);
三、椭圆 / 椭圆弧 (EllipseEnt)
创建完整椭圆
// new EllipseEnt(center?, majorRadius?, minorRadius?, rotation?)
// 注意:第三参是短半轴长度(不是比例);起始/终止角是属性不是构造参数
const ell = new vjmapext.EllipseEnt(
[cx, cy], // 圆心
majorRadius, // 长半轴长度
minorRadius, // 短半轴长度(= 长半轴 × ratio)
rotation // 旋转(弧度)
);
创建椭圆弧
const ellArc = new vjmapext.EllipseEnt([100, 100], 80, 40, 0);
ellArc.startAngle = 0; // 弧度(属性)
ellArc.endAngle = Math.PI;
// ellArc.isFullEllipse → false
rotation/startAngle/endAngle单位都是弧度startAngle/endAngle是参数角 t(相对长轴、旋转前:x = a·cos t, y = b·sin t再转rotation),不是从圆心看过去的几何极角——非正圆时两者不等;要从几何角 θ 换算:t = Math.atan2(a * Math.sin(θ), b * Math.cos(θ))(θ 同样相对长轴)- 椭圆弧没有 isCCW 标志:
endAngle < startAngle时按顺时针扫;endAngle - startAngle ≈ 0视为整圆
典型场景
// 横向椭圆,长半轴 100,短半轴 20
const oval = new vjmapext.EllipseEnt([0, 0], 100, 20, 0);
oval.fillColor = 0xffcc00;
oval.fillOpacity = 0.4;
mapcadLayer.addEntity(oval);
四、填充效果组合
const c = new vjmapext.CircleEnt([0, 0], 100);
// 空心
c.fillOpacity = 0; c.borderOpacity = 1;
// 实心
c.fillOpacity = 1; c.borderOpacity = 0; c.fillColor = 0xff4488;
// 半透明 + 粗边框
c.fillColor = 0x4488ff; c.fillOpacity = 0.3; c.lineWidth = 3;
五、与 PolylineEnt 互转
圆弧转多段线(近似):
// vjmap.getCirclePolygonCoordinates(center, radius, points?, startAngle?, endAngle?)
// 平面坐标计算(非球面),返回已闭合点串;startAngle/endAngle 单位是【度】
const poly = new vjmapext.PolylineEnt(
vjmap.getCirclePolygonCoordinates([cx, cy], radius, 64)
, true);
多段线转圆弧(已知三点):
const arc = vjmapext.ArcEnt.fromThreePoints(p1, p2, p3);
六、交互编辑夹点
CircleEnt:中心点 + 四向半径点(quad0..3)ArcEnt:圆心(平移)+start/end端点夹点(拖动同时改角度和半径)+mid中点夹点(只改半径,即曲率)EllipseEnt:中心(平移)+major长轴夹点(同时改 majorRadius 和 rotation)+minor短轴夹点(改 minorRadius)
可自定义夹点集合,见 drawing/grip。
七、性能建议
| 量级 | 推荐 |
|---|---|
| < 1000 个 | CircleEnt / ArcEnt / EllipseEnt |
| 1000 ~ 50000 | 转 GeoJSON 走 primitive/circle-arc |
| > 10000 点状圆 | symbol/circle-symbol |
八、常见坑
- 角度单位:ArcEnt/EllipseEnt 的
startAngle/endAngle/rotation和rotate(center, angle)全都用弧度(SCALE 命令把用户输入的度 × π/180 才传给 rotate);只有命令交互输入的是度。 - EllipseEnt 没有
ratio字段——构造直接收minorRadius长度(内部Math.abs取绝对值);minorRadius > majorRadius不报错,只是长短轴含义对调,语义上保持 minor ≤ major。 - Arc 的 start/end 写反:想要半圆上半却画出下半 → 方向是逆时针。
- 想要 Arc 填充:Arc 本身不填充;用闭合的 Polyline 或 Ellipse(完整)。
- 大量椭圆导致卡顿:考虑用 Symbol 或贴图。