-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
Support label rotation #1247
Comments
Have you gotten around to implemnting this feature yet? |
@Nirco96 sorry, we haven't had a chance to add support for this yet. We'd be happy to review a pull request if anyone has time to implement this! |
@hpinkos could you please give us some pointers about where to start to implement this? |
@lydonchandra I would look at the Label class where individual glyphs are drawn and the LabelCollection where it's all put together. The labels use billboards under the hood for rotation, so it may be as simple as passing that through to some "parent" billboard that contains all the glyphs, or it may require handling the fact that all the glyphs may be separate billboards. |
@lydonchandra thanks for being interested in taking a look at this!
All glyphs are always separate billboards. It's been a while, but I'm pretty sure 99% of the work is simply modifying To start, I would just recommend reviewing |
Thanks for the pointers @OmarShehata @mramato Screenshot from As all glyphs are in separate billboards,
Is copying all glyphs to another billboard (that can be rotated easily) an acceptable solution? |
@lydonchandra, unfortunately that's not an acceptable solution. The reason labels are rendered as individual glyphs and not as a single billboard are for runtime performance and memory usage. Obviously it complicates the implementation, but it's necessary technique. Otherwise creating/updating labels would be slower and consume a large amount of texture memory. |
@mramato This is extremely necessary feature fo e.g in order to change the angle of labels according to camera position. is this on the roadmap? |
@jony89 can you describe your use case for that? Do you mean rotating the label based on camera distance, around the axis between the camera and the label? |
That's one usecase. correct. to change the label position according to the heading of the camera. but in our app we would like to rotate the label for many other reasons. another use case is for measurement tools with labels next to the polyline that measures height. |
@jony89 we would happily take a look at a pull request if you or your team is interested in contributing this feature, otherwise it is not on our near term roadmap. See our Contributing Guide to get started if you are interested. |
@jony89 I reviewed that PR and asked you a question back on Feb 26th that you have yet to reply to: #8591 (comment) |
Is there any news on this? |
If anyone is curious, I ended up needing something like this, (I wanted to show bearing and distance for each leg of a flight leg) and created some react components for this, and it works quite well for me. Of course, figuring out the angle to rotate your stuff by will be different than mine. import React, { useEffect, useState } from 'react';
import { Cartesian3, Color, ScreenSpaceEventHandler } from 'cesium';
import { PolylineEntity } from './PolylineEntity';
import { LabelEntity } from './LabelEntity';
import { useCalcBearingAndDistanceMutation } from '../../../redux/api/vfr3d/navlog.api';
import { BearingAndDistanceResponseDto, Waypoint } from 'vfr3d-shared';
interface PolylineWithLabelProps {
positions: Cartesian3[];
color: Color;
id: string;
width: number;
waypoints: Waypoint[];
onLeftClick: (
event: ScreenSpaceEventHandler.PositionedEvent,
polylinePoints: Cartesian3[]
) => void;
}
export const BearingDistancePolyline: React.FC<PolylineWithLabelProps> = ({
positions,
color,
id,
width,
onLeftClick,
waypoints,
}) => {
const [bearingAndDistance, setBearingAndDistance] = useState<BearingAndDistanceResponseDto>();
const [bearingAndDistanceText, setBearingAndDistanceText] = useState<string>('');
const [calcBearingAndDistance] = useCalcBearingAndDistanceMutation();
const midpoint = Cartesian3.midpoint(positions[0], positions[1], new Cartesian3());
useEffect(() => {
const getBearingAndDistance = async () => {
const bearingAndDistance = await calcBearingAndDistance({
startPoint: waypoints[0],
endPoint: waypoints[1],
}).unwrap();
setBearingAndDistance(bearingAndDistance);
setBearingAndDistanceText(
`TC: ${Math.round(bearingAndDistance.trueCourse)} - Distance: ${Math.round(bearingAndDistance?.distance)}`
);
};
getBearingAndDistance();
}, [calcBearingAndDistance, waypoints]);
return (
<>
<PolylineEntity
positions={positions}
color={color}
id={id}
width={width}
onLeftClick={onLeftClick}
/>
{bearingAndDistance && (
<LabelEntity
position={midpoint}
text={bearingAndDistanceText}
rotation={bearingAndDistance.trueCourse - 90}
/>
)}
</>
);
}; import {
Cartesian3,
Color,
ConstantProperty,
Entity,
PolylineGraphics,
ScreenSpaceEventHandler,
ScreenSpaceEventType,
} from 'cesium';
import { useEffect, useRef } from 'react';
import { useCesium } from 'resium';
interface PolylineEntityProps {
positions: Cartesian3[];
color?: Color;
width?: number;
id: string;
onLeftClick?: (
position: ScreenSpaceEventHandler.PositionedEvent,
polylinePoints: Cartesian3[]
) => void;
}
export const PolylineEntity: React.FC<PolylineEntityProps> = ({
positions,
color = Color.BLUE,
width = 3,
id,
onLeftClick: onLeftClick,
}) => {
const { viewer } = useCesium();
const entityRef = useRef<Entity | null>(null);
useEffect(() => {
if (!viewer) return;
const polylineGraphics = new PolylineGraphics({
positions: new ConstantProperty(positions),
material: color,
width: new ConstantProperty(width),
});
const entity = viewer.entities.add({
polyline: polylineGraphics,
id,
});
entityRef.current = entity;
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
if (onLeftClick) {
handler.setInputAction((movement: ScreenSpaceEventHandler.PositionedEvent) => {
const pickedObject = viewer.scene.pick(movement.position);
if (pickedObject && pickedObject.id === entity) {
onLeftClick(movement, positions);
}
}, ScreenSpaceEventType.LEFT_CLICK);
}
return () => {
if (onLeftClick) {
if (viewer && entity) {
viewer.entities.remove(entity);
handler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
}
}
};
}, [viewer, positions, color, width, id, onLeftClick]);
return null;
}; // LabelEntity.tsx
import {
Entity,
Color,
ConstantProperty,
NearFarScalar,
Cartesian2,
Property,
Cartesian3,
Plane,
writeTextToCanvas,
PlaneGraphics,
ImageMaterialProperty,
Transforms,
HeadingPitchRoll,
Math,
} from 'cesium';
import React, { useEffect, useRef } from 'react';
import { useCesium } from 'resium';
interface LabelEntityProps {
position: Cartesian3;
text: string;
show?: boolean | Property;
scale?: number | Property;
color?: Color | Property;
rotation?: number;
id?: string;
}
export const LabelEntity: React.FC<LabelEntityProps> = ({
position,
text,
show = true,
scale = 1.0,
color = Color.WHITE,
rotation,
id,
}) => {
const { viewer } = useCesium();
const entityRef = useRef<Entity | null>(null);
useEffect(() => {
if (!viewer) return;
const image = writeTextToCanvas(text, {
backgroundColor: Color.MAGENTA.withAlpha(0.1),
padding: 2,
fill: true,
fillColor: Color.WHITE,
stroke: true,
strokeWidth: 1,
strokeColor: Color.BLACK,
});
if (image) {
const angle = rotation ? rotation : 0;
const orientation = Transforms.headingPitchRollQuaternion(
position,
new HeadingPitchRoll(Math.toRadians(angle), 0, 0)
);
const offsetPosition = Cartesian3.add(
position,
Cartesian3.multiplyByScalar(new Cartesian3(-1, 0, 0), 1000, new Cartesian3()),
new Cartesian3()
);
const entity = viewer.entities.add({
position: offsetPosition,
plane: new PlaneGraphics({
plane: new ConstantProperty(new Plane(Cartesian3.UNIT_Z, 0.0)),
dimensions: new ConstantProperty(new Cartesian2(image?.width * 50, image?.height * 50)),
material: new ImageMaterialProperty({
image: image,
}),
outline: false,
}),
orientation: orientation,
id,
});
entityRef.current = entity;
return () => {
if (viewer && entity) {
viewer.entities.remove(entity);
}
};
}
}, [viewer, position, text, show, scale, color, rotation, id]);
return null;
}; |
Wow it's been ten years,this feature is still not implemented |
As requested on the mailing list: https://groups.google.com/d/msg/cesium-dev/dnqBUH3Fx7M/iswm2vMz8DMJ
This might involve the same difficulties that prevent us from doing label scaling by distance, but I would have to check the label code to know for sure.
The text was updated successfully, but these errors were encountered: