Skip to content

Circle/Ellipse/Sector support ignoreProjection #2577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions packages/maptalks/src/core/util/path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,3 +301,29 @@ export function getMinMaxAltitude(altitude: number | number[] | number[][]): [nu
return [min, max];
}

export function pointsToCoordinates(map, points: Point[], glRes: number, altitude: number): Coordinate[] {
const ring = [];
for (let i = 0, len = points.length; i < len; i++) {
const pt = points[i];
const c = map.pointAtResToCoordinate(pt, glRes);
c.z = altitude;
ring[i] = c;
}
// ring.push(ring[0].copy());
return ring;
}

export function getEllipseGLSize(center: Coordinate, measurer, map, halfWidth: number, halfHeight: number) {
const glRes = map.getGLRes();
const c1 = measurer.locate(center, halfWidth, 0);
const c2 = measurer.locate(center, 0, halfHeight);
const pt = map.coordToPointAtRes(center, glRes);
const p1 = map.coordToPointAtRes(c1, glRes);
const p2 = map.coordToPointAtRes(c2, glRes);
return {
glWidth: pt.distanceTo(p1),
glHeight: pt.distanceTo(p2),
glCenter: pt
}
}

27 changes: 25 additions & 2 deletions packages/maptalks/src/geometry/Circle.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { extend, isNil } from '../core/util';
import { withInEllipse } from '../core/util/path';
import { getEllipseGLSize, pointsToCoordinates, withInEllipse } from '../core/util/path';
import Coordinate from '../geo/Coordinate';
import Extent from '../geo/Extent';
import Point from '../geo/Point';
Expand All @@ -14,7 +14,8 @@ import Polygon, { PolygonOptionsType, RingCoordinates, RingsCoordinates } from '
* @instance
*/
const options: CircleOptionsType = {
'numberOfShellPoints': 60
'numberOfShellPoints': 60,
'ignoreProjection': false
};

/**
Expand Down Expand Up @@ -93,6 +94,26 @@ export class Circle extends CenterMixin(Polygon) {
radius = this.getRadius();
const shell = [];
let rad, dx, dy;
const options = this.options as CircleOptionsType;
const ignoreProjection = options.ignoreProjection;
const map = this.getMap();

if (ignoreProjection && map) {
const glRes = map.getGLRes();
const { glWidth, glHeight, glCenter } = getEllipseGLSize(center, measurer, map, radius, radius);
const r = Math.max(glWidth, glHeight);
const pts: Point[] = [];
for (let i = 0, len = numberOfPoints - 1; i < len; i++) {
rad = (360 * i / len) * Math.PI / 180;
const x = Math.cos(rad) * r + glCenter.x;
const y = Math.sin(rad) * r + glCenter.y;
const p = new Point(x, y);
pts[i] = p;
}
const ring = pointsToCoordinates(map, pts, glRes, center.z);
ring.push(ring[0].copy());
return ring;
}
for (let i = 0, len = numberOfPoints - 1; i < len; i++) {
rad = (360 * i / len) * Math.PI / 180;
dx = radius * Math.cos(rad);
Expand All @@ -101,6 +122,7 @@ export class Circle extends CenterMixin(Polygon) {
vertex.z = center.z;
shell.push(vertex);
}

shell.push(shell[0]);
return shell;
}
Expand Down Expand Up @@ -221,4 +243,5 @@ export default Circle;

export type CircleOptionsType = PolygonOptionsType & {
numberOfShellPoints?: number;
ignoreProjection?: boolean;
}
41 changes: 39 additions & 2 deletions packages/maptalks/src/geometry/Ellipse.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { extend, isNil, pushIn } from '../core/util';
import { withInEllipse } from '../core/util/path';
import { getEllipseGLSize, pointsToCoordinates, withInEllipse } from '../core/util/path';
import Coordinate from '../geo/Coordinate';
import CenterMixin from './CenterMixin';
import Polygon, { PolygonOptionsType, RingCoordinates, RingsCoordinates } from './Polygon';
Expand Down Expand Up @@ -44,7 +44,8 @@ function angleT(numberOfShellPoints: number) {
* @instance
*/
const options: EllipseOptionsType = {
'numberOfShellPoints': 81
'numberOfShellPoints': 81,
'ignoreProjection': false
};

/**
Expand Down Expand Up @@ -182,6 +183,41 @@ export class Ellipse extends CenterMixin(Polygon) {
}
let deg, rad, dx, dy;

const options = this.options as EllipseOptionsType;
const ignoreProjection = options.ignoreProjection;
const map = this.getMap();
if (ignoreProjection && map) {
const glRes = map.getGLRes();
const { glWidth, glHeight, glCenter } = getEllipseGLSize(center, measurer, map, width / 2, height / 2);
//gl width
const w = glWidth * 2;
//gl width
const h = glHeight * 2;
const s = Math.pow(w / 2, 2) * Math.pow(h / 2, 2),
sx = Math.pow(w / 2, 2),
sy = Math.pow(h / 2, 2);
const pts: Point[] = [];
for (let i = 0; i < angles.length; i++) {
deg = angles[i];
rad = deg * Math.PI / 180;
dx = Math.sqrt(s / (sx * Math.pow(Math.tan(rad), 2) + sy));
dy = Math.sqrt(s / (sy * Math.pow(1 / Math.tan(rad), 2) + sx));
if (deg > 90 && deg < 270) {
dx *= -1;
}
if (deg > 180 && deg < 360) {
dy *= -1;
}
const p = glCenter.copy();
p.x += dx;
p.y += dy;
pts[i] = p;
}
const ring = pointsToCoordinates(map, pts, glRes, center.z);
ring.push(ring[0].copy());
return ring;
}

for (let i = 0; i < angles.length; i++) {
deg = angles[i];
rad = deg * Math.PI / 180;
Expand Down Expand Up @@ -319,4 +355,5 @@ export default Ellipse;
export type EllipseOptionsType = PolygonOptionsType & {
numberOfShellPoints?: number;
debug?: boolean;
ignoreProjection?: boolean;
}
22 changes: 22 additions & 0 deletions packages/maptalks/src/geometry/Sector.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { extend, isNil } from '../core/util';
import { getEllipseGLSize, pointsToCoordinates } from '../core/util/path';
import Coordinate from '../geo/Coordinate';
import Extent from '../geo/Extent';
import Point from '../geo/Point';
Expand Down Expand Up @@ -135,6 +136,27 @@ export class Sector extends Circle {
// startAngle = this.getStartAngle(),
angle = endAngle - startAngle;
let rad, dx, dy;
const options = this.options as SectorOptionsType;
const ignoreProjection = options.ignoreProjection;
const map = this.getMap();
if (ignoreProjection && map) {
const glRes = map.getGLRes();
const { glWidth, glHeight, glCenter } = getEllipseGLSize(center, measurer, map, radius, radius);
const r = Math.max(glWidth, glHeight);
const pts: Point[] = [];
for (let i = 0; i < numberOfPoints; i++) {
rad = (angle * i / (numberOfPoints - 1) + startAngle) * Math.PI / 180;
dx = radius * Math.cos(rad);
dy = radius * Math.sin(rad);
const x = Math.cos(rad) * r + glCenter.x;
const y = Math.sin(rad) * r + glCenter.y;
const p = new Point(x, y);
pts[i] = p;
}
const ring = pointsToCoordinates(map, pts, glRes, center.z);
ring.push(center.copy());
return ring;
}
for (let i = 0; i < numberOfPoints; i++) {
rad = (angle * i / (numberOfPoints - 1) + startAngle) * Math.PI / 180;
dx = radius * Math.cos(rad);
Expand Down
3 changes: 3 additions & 0 deletions packages/maptalks/src/renderer/geometry/VectorRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ const el = {
}
const map = this.getMap();
const altitude = this._getAltitude();
if (this instanceof Ellipse || this instanceof Circle) {
return true;
}
// when map is tilting, draw the circle/ellipse as a polygon by vertexes.
return altitude > 0 || map.getPitch() || ((this instanceof Ellipse) && map.getBearing());
},
Expand Down