-
-
Notifications
You must be signed in to change notification settings - Fork 27
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 Arc primitive for rendering #41
Comments
Well, any resolution-dependent circle would be interpolated as a polygon anyway. I guess what you mean is that you want the circle be interpolated with different precision based on current map resolution. Is that right? |
No, I meant that I’d like the circle to have different dimensions at different levels of zoom. Currently, |
So, you want to draw a circle on the map around a given point with fixed real-world radius. Something like a zone with radius of 1km. When rendered to the screen, that circle will be approximated as a polygon anyways, that's what I meant. Currently, feature layers are not documented, but the basic Idea behind them is that:
So to achieve what you want, you don't need to change your features to be polygons instead of points, instead you can create a symbol that will draw them as polygons with given parameters. For example, the symbol can take some There is also a notion of LODs (levels of detail) in feature layers that allow you to draw your features with different precision based on resolution (see In future, I'm planning to add |
Considering my use case is for circles of radius < 10km, with no regards for projection, I thought it might be more performant to use a signed distance function for rendering, instead of going through the tessellation pipeline. But for now, I'll draw them as polygons as you suggested. |
That's true, just creating a circle without tessellation would be more efficient, but for simple shapes like circles it shouldn't really matter. Anyway, adding Arc primitive would solve that also, as it will do exactly that. So, I guess, we can rename this issue into "Support Arc primitive for rendering". |
I tried to implement the suggestion to have a symbol render a polygon from a point with a radius but failed to satisfy the constraints on the render function of the trait. I may be missing something obvious so here is the current implementation that does not compile: impl Symbol<Spot> for SpotSymbol {
#[allow(clippy::cast_possible_truncation)]
#[allow(clippy::cast_precision_loss)]
fn render<'a, N, P>(
&self,
feature: &Spot,
geometry: &'a Geom<P>,
min_resolution: f64,
) -> Vec<
galileo::render::render_bundle::RenderPrimitive<
'a,
N,
P,
galileo_types::impls::Contour<P>,
galileo_types::impls::Polygon<P>,
>,
>
where
N: AsPrimitive<f32>,
P: galileo_types::cartesian::CartesianPoint3d<Num = N> + Clone,
{
match geometry {
Geom::Point(point) => {
let mut render_primitives = vec![];
let color = Color::rgba(0, 0, 255, 128);
let circle_subdivision = 25;
let mut points = vec![];
let mut i: f64 = 0.0;
let step_size = std::f64::consts::PI / f64::from(circle_subdivision);
let radius = feature.radius;
while i < std::f64::consts::PI * 2.0 {
let x = i.sin();
let y = i.cos();
let new_pos = Point3::new(
point.x().as_() + (x as f32 * radius as f32),
point.y().as_() + (y as f32 * radius as f32),
point.z().as_(),
);
points.push(new_pos);
i += step_size;
}
let contour = ClosedContour::new(points);
let poly = Polygon::new(contour, vec![]);
render_primitives.push(RenderPrimitive::new_polygon(poly, PolygonPaint { color }));
render_primitives
}
_ => vec![],
}
}
} with the error:
I am guessing, that I should not create a new I also tried to implement the polygon construction within the feature itself but I am unsure if this is the right way to do (Code compiled but the radius of the resulting circle was off, which may be a different problem with projection etc.) Is there any example code for the symbol rendering implementation for manual construction of shapes? Within the examples of the repository I could only find parts where the geometry that is rendered is already present in the given feature. Thanks in advance for any advice! |
@lennart This is what I have: struct PositionGeometry {
geometry: Polygon<Point2d>,
}
impl galileo_types::Geometry for PositionGeometry {
type Point = Point2d;
fn project<Proj>(&self, projection: &Proj) -> Option<Geom<Proj::OutPoint>>
where
Proj: galileo_types::geo::Projection<InPoint = Self::Point> + ?Sized,
{
self.geometry.project(projection)
}
}
impl CartesianGeometry2d<Point2d> for PositionGeometry {
fn is_point_inside<Other: CartesianPoint2d<Num = f64>>(
&self,
point: &Other,
tolerance: f64,
) -> bool {
// TODO(alexkirsz) Quick check?
self.geometry.is_point_inside(point, tolerance)
}
fn bounding_rectangle(&self) -> Option<Rect> {
// TODO(alexkirsz)
None
}
}
impl Feature for PositionGeometry {
type Geom = Self;
fn geometry(&self) -> &Self::Geom {
self
}
}
fn generate_circle_polygon(
point: GeoPoint2d,
radius_meters: f64,
num_points: usize,
) -> Vec<GeoPoint2d> {
let earth_radius_meters = 6_371_000.0;
let lat_rad = point.lat_rad();
let lon_rad = point.lon_rad();
let angular_distance = radius_meters / earth_radius_meters;
let mut polygon_points = Vec::with_capacity(num_points);
for i in 0..num_points {
let bearing = 2.0 * std::f64::consts::PI * (i as f64) / (num_points as f64);
let lat_point = (lat_rad.sin() * angular_distance.cos()
+ lat_rad.cos() * angular_distance.sin() * bearing.cos())
.asin();
let lon_point = lon_rad
+ (bearing.sin() * angular_distance.sin() * lat_rad.cos())
.atan2(angular_distance.cos() - lat_rad.sin() * lat_point.sin());
polygon_points.push(GeoPoint2d::latlon(
lat_point.to_degrees(),
lon_point.to_degrees(),
));
}
polygon_points
}
// then
features.insert(PositionGeometry {
geometry: Polygon::new(
ClosedContour::new(generate_circle_polygon(
GeoPoint2d::latlon(
lat,
lon,
),
radius,
50,
))
.project_points(&projection)
.expect("projection failed"),
vec![],
),
}); I then use a simple symbol to render theses: #[derive(Debug, Copy, Clone)]
pub struct CircleSymbol {
pub color: Color,
}
impl CircleSymbol {
pub fn new(color: Color) -> Self {
Self { color }
}
}
impl<F> Symbol<F> for CircleSymbol {
fn render<'a, N, P>(
&self,
_feature: &F,
geometry: &'a Geom<P>,
min_resolution: f64,
) -> Vec<RenderPrimitive<'a, N, P, Contour<P>, Polygon<P>>>
where
N: AsPrimitive<f32>,
P: CartesianPoint3d<Num = N> + Clone,
{
match geometry {
Geom::Polygon(polygon) => {
vec![RenderPrimitive::new_polygon_ref(
polygon,
PolygonPaint { color: self.color },
)]
}
_ => vec![],
}
}
} |
thanks for this @alexkirsz ! |
Hey!
I'd like to draw a circle with a radius that's resolution-dependent (i.e. specified in meters, instead of view units). That breaks down at small resolutions because of projection, but my use case is for radii that are < 10km.
A workaround right now is to draw a circle-like polygon.
The text was updated successfully, but these errors were encountered: