Skip to content

fix Rectangle/Ellipse/Sector rotate not work #2130

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

Merged
merged 8 commits into from
Dec 13, 2023
Merged
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
16 changes: 15 additions & 1 deletion src/geometry/Ellipse.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,18 @@ class Ellipse extends CenterMixin(Polygon) {
this.onShapeChanged();
return this;
}

/**
* Gets the shell of the ellipse as a polygon, number of the shell points is decided by [options.numberOfShellPoints]{@link Circle#options}
* @return {Coordinate[]} - shell coordinates
*/
getShell() {
if (this.isRotated()) {
return this.getRotatedShell();
}
return this._getShell();
}

_getShell() {
const measurer = this._getMeasurer(),
center = this.getCoordinates(),
numberOfPoints = this.options['numberOfShellPoints'],
Expand Down Expand Up @@ -122,6 +128,11 @@ class Ellipse extends CenterMixin(Polygon) {
return shell;
}

_getPrjShell() {
const shell = super._getPrjShell();
return this._rotatePrjCoordinates(shell);
}

/**
* Ellipse won't have any holes, always returns null
* @return {Object[]} an empty array
Expand All @@ -148,6 +159,9 @@ class Ellipse extends CenterMixin(Polygon) {
}

_computePrjExtent() {
if (this.isRotated()) {
return this._computeRotatedPrjExtent();
}
return Circle.prototype._computePrjExtent.apply(this, arguments);
}

Expand Down
89 changes: 87 additions & 2 deletions src/geometry/Geometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import Painter from '../renderer/geometry/Painter';
import CollectionPainter from '../renderer/geometry/CollectionPainter';
import SpatialReference from '../map/spatial-reference/SpatialReference';
import { isFunctionDefinition } from '../core/mapbox';
import { getDefaultBBOX, pointsBBOX } from '../core/util/bbox';

const TEMP_POINT0 = new Point(0, 0);
const TEMP_EXTENT = new PointExtent();
Expand Down Expand Up @@ -929,6 +930,10 @@ class Geometry extends JSONAble(Eventable(Handlerable(Class))) {
* @returns {Geometry} this
*/
rotate(angle, pivot) {
if (!isNumber(angle)) {
console.error(`angle:${angle} is not number`);
return this;
}
if (this.type === 'GeometryCollection') {
const geometries = this.getGeometries();
geometries.forEach(g => g.rotate(angle, pivot));
Expand All @@ -939,12 +944,18 @@ class Geometry extends JSONAble(Eventable(Handlerable(Class))) {
} else {
pivot = new Coordinate(pivot);
}
this._angle = angle;
this._pivot = pivot;
const measurer = this._getMeasurer();
const coordinates = this.getCoordinates();
if (!Array.isArray(coordinates)) {
if (pivot.x !== coordinates.x || pivot.y !== coordinates.y) {
//exclude Rectangle ,Ellipse,Sector by shell judge
if ((pivot.x !== coordinates.x || pivot.y !== coordinates.y) && !this.getShell) {
const c = measurer._rotate(coordinates, pivot, angle);
this.setCoordinates(c);
} else {
//only redraw ,not to change coordinate
this.onPositionChanged();
}
return this;
}
Expand All @@ -955,6 +966,65 @@ class Geometry extends JSONAble(Eventable(Handlerable(Class))) {
return this;
}

_rotatePrjCoordinates(coordinates) {
Copy link
Collaborator Author

@deyihu deyihu Nov 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么旋转prj坐标而不是经纬度坐标?

if (!coordinates || this._angle === 0 || !this._pivot) {
return coordinates;
}
const projection = this._getProjection();
if (!projection) {
return coordinates;
}
let offsetAngle = 0;
const isArray = Array.isArray(coordinates);
const coord = isArray ? coordinates : [coordinates];
const rotatePrjCoordinates = [];
let cx, cy;
//sector is special
if (this.getRotateOffsetAngle) {
offsetAngle = this.getRotateOffsetAngle();
const center = coord[coord.length - 1];
cx = center.x;
cy = center.y;
} else {
const bbox = getDefaultBBOX();
//cal all points center
pointsBBOX(coord, bbox);
const [minx, miny, maxx, maxy] = bbox;
cx = (minx + maxx) / 2;
cy = (miny + maxy) / 2;
}
//图形按照自身的几何中心旋转
for (let i = 0, len = coord.length; i < len; i++) {
const c = coord[i];
const { x, y } = c;
const dx = x - cx, dy = y - cy;
const r = Math.sqrt(dx * dx + dy * dy);
const sAngle = getSegmentAngle(cx, cy, x, y);
const rad = (sAngle - this._angle + offsetAngle) / 180 * Math.PI;
const rx = Math.cos(rad) * r, ry = Math.sin(rad) * r;
const rc = new Coordinate(cx + rx, cy + ry);
rotatePrjCoordinates.push(rc);
}
const prjCenter = projection.project(this._pivot);
const rx = prjCenter.x, ry = prjCenter.y;
//translate rotate center
const translateX = cx - rx, translateY = cy - ry;
//平移到指定的选中中心点
for (let i = 0, len = rotatePrjCoordinates.length; i < len; i++) {
const c = rotatePrjCoordinates[i];
c.x -= translateX;
c.y -= translateY;
}
if (isArray) {
return rotatePrjCoordinates;
}
return rotatePrjCoordinates[0];
}

isRotated() {
return isNumber(this._angle) && this._pivot;
}

/**
* Get the connect points for [ConnectorLine]{@link ConnectorLine}
* @return {Coordinate[]} connect points
Expand Down Expand Up @@ -1557,7 +1627,7 @@ function getGeometryCoordinatesAlts(geometry, layerAlt, enableAltitude) {
coordinatesHasAlt(coordinates, tempAlts);
if (tempAlts.length) {
const alts = getCoordinatesAlts(coordinates, layerAlt, enableAltitude);
if (geometry.getShell) {
if (geometry.getShell && Array.isArray(alts[0])) {
return alts[0][0];
}
return alts;
Expand Down Expand Up @@ -1606,5 +1676,20 @@ function getCoordinatesAlts(coordinates, layerAlt, enableAltitude) {
}
}

function getSegmentAngle(cx, cy, x, y) {
if (cx === x) {
if (y > cy) {
return -90;
}
return 90;
}
x -= cx;
y -= cy;
//经纬坐标系和屏幕坐标正好相反,经纬度向上递增,而屏幕坐标递减
y = -y;
const rad = Math.atan2(y, x);
return rad / Math.PI * 180;
}

export default Geometry;

2 changes: 1 addition & 1 deletion src/geometry/Polygon.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ class Polygon extends Path {
//r.g. for Rectangle
this._verifyProjection();
if (this._getProjection() && !this._prjShell) {
this._prjShell = this._projectCoords(this.getShell());
this._prjShell = this._projectCoords(this._getShell ? this._getShell() : this.getShell());
}
return this._prjShell;
}
Expand Down
16 changes: 14 additions & 2 deletions src/geometry/Rectangle.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ class Rectangle extends Polygon {
* @return {Coordinate[]} - shell coordinates
*/
getShell() {
if (this.isRotated()) {
return this.getRotatedShell();
}
return this._getShell();
}

_getShell() {
const measurer = this._getMeasurer();
const nw = this._coordinates;
const map = this.getMap();
Expand Down Expand Up @@ -169,7 +176,8 @@ class Rectangle extends Polygon {
const shell = super._getPrjShell();
const projection = this._getProjection();
if (!projection.isSphere()) {
return shell;
// return shell;
return this._rotatePrjCoordinates(shell);
}
const sphereExtent = projection.getSphereExtent(),
sx = sphereExtent.sx,
Expand All @@ -187,7 +195,8 @@ class Rectangle extends Polygon {
}
shell[i]._add(dx, dy);
}
return shell;
return this._rotatePrjCoordinates(shell);
// return shell;
}

//update cached variables if geometry is updated.
Expand Down Expand Up @@ -221,6 +230,9 @@ class Rectangle extends Polygon {
}

_computePrjExtent(projection) {
if (this.isRotated()) {
return this._computeRotatedPrjExtent();
}
const se = this._getSouthEast(projection);
if (!se) {
return null;
Expand Down
23 changes: 23 additions & 0 deletions src/geometry/Sector.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ class Sector extends Circle {
* @return {Coordinate[]} - shell coordinates
*/
getShell() {
if (this.isRotated()) {
return this.getRotatedShell();
}
return this._getShell();
}

_getShell() {
const measurer = this._getMeasurer(),
center = this.getCoordinates(),
numberOfPoints = this.options['numberOfShellPoints'] - 2,
Expand All @@ -108,6 +115,22 @@ class Sector extends Circle {
return shell;
}

getRotateOffsetAngle() {
return 90;
}

_getPrjShell() {
const shell = super._getPrjShell();
return this._rotatePrjCoordinates(shell);
}

_computePrjExtent() {
if (this.isRotated()) {
return this._computeRotatedPrjExtent();
}
return Circle.prototype._computePrjExtent.apply(this, arguments);
}

_containsPoint(point, tolerance) {
const map = this.getMap();
if (map.isTransforming()) {
Expand Down
33 changes: 31 additions & 2 deletions src/renderer/geometry/VectorRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import Rectangle from '../../geometry/Rectangle';
import Path from '../../geometry/Path';
import LineString from '../../geometry/LineString';
import Polygon from '../../geometry/Polygon';
import { BBOX_TEMP, pointsBBOX, resetBBOX } from '../../core/util/bbox';
import { BBOX_TEMP, getDefaultBBOX, pointsBBOX, resetBBOX } from '../../core/util/bbox';
import Extent from '../../geo/Extent';

const TEMP_WITHIN = {
within: false,
Expand Down Expand Up @@ -49,14 +50,40 @@ Geometry.include({
}
});

function _computeRotatedPrjExtent() {
const coord = this._getPrjShell();
const bbox = getDefaultBBOX();
//cal all points center
pointsBBOX(coord, bbox);
const [minx, miny, maxx, maxy] = bbox;
return new Extent(minx, miny, maxx, maxy);
}

function getRotatedShell() {
const prjs = this._getPrjShell();
if (!prjs || !Array.isArray(prjs)) {
return [];
}
const projection = this._getProjection();
return prjs.map(prj => {
return projection.unproject(prj);
});
}

const el = {
_redrawWhenPitch: () => true,

_redrawWhenRotate: function () {
return (this instanceof Ellipse) || (this instanceof Sector);
},
_computeRotatedPrjExtent,
getRotatedShell,

_paintAsPath: function () {
//why? when rotate need draw by path
if (this.isRotated()) {
return true;
}
const map = this.getMap();
const altitude = this._getAltitude();
// when map is tilting, draw the circle/ellipse as a polygon by vertexes.
Expand Down Expand Up @@ -104,7 +131,9 @@ Rectangle.include({
return [points];
},

_paintOn: Canvas.polygon
_paintOn: Canvas.polygon,
_computeRotatedPrjExtent,
getRotatedShell
});
//----------------------------------------------------
Sector.include(el, {
Expand Down
Loading