Skip to content
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

[Bug] Icon Layer on Globe Projection #9554

Open
3 of 7 tasks
charlieforward9 opened this issue Mar 29, 2025 · 2 comments
Open
3 of 7 tasks

[Bug] Icon Layer on Globe Projection #9554

charlieforward9 opened this issue Mar 29, 2025 · 2 comments
Labels

Comments

@charlieforward9
Copy link
Contributor

charlieforward9 commented Mar 29, 2025

Description

I am not able to properly visualize IconLayers on my Globe-projected DeckGL instance.

In my React-Maplibre-MapboxOverlay implementation mercator projection shows up great, but globe projection glitches out. (tested both interleaved/overlaid)

Screen.Recording.2025-03-29.at.4.14.08.PM.mov

In my (codepen using script tag) reproduction, I am actually able to see the point when the globe is oriented such that the Icon extrudes in the right direction, however, in my implementation, the point disappears after any user interaction.

Additionally, in the reproduction, the IconLayer instances do not show up in the right location. Notice how the coordinates of the sample points are all within Florida, however, the IconLayer shows up at the origin

Image

Original Comment: #9199 (comment)

Flavors

  • Script tag
  • React
  • Python/Jupyter notebook
  • MapboxOverlay
  • GoogleMapsOverlay
  • CARTO
  • ArcGIS

Expected Behavior

I would expect the IconLayer to behave as it normally does in the "mercator" projection.

Steps to Reproduce

https://gist.github.com/charlieforward9/7637c8598caa1537ac965ed1603dcdbe

Environment

  • Framework version: ^9.1.0
  • Browser: Chrome
  • OS: MacOS

Logs

No response

@charlieforward9
Copy link
Contributor Author

charlieforward9 commented Apr 8, 2025

I managed to work around this by turning off depthTest and filter my dataset with this method based on the camera position:

// Helper function to determine if a feature is visible from a camera's pov on globe projection
function isFeatureVisibleOnGlobe(
  cameraLat: number,
  cameraLon: number,
  featureLat: number,
  featureLon: number,
  zoom: number,
): boolean {
  const toRad = (deg: number) => (deg * Math.PI) / 180;

  // Convert lat/lon to radians
  const camLatRad = toRad(cameraLat);
  const camLonRad = toRad(cameraLon);
  const featLatRad = toRad(featureLat);
  const featLonRad = toRad(featureLon);

  // Convert to unit vectors
  const toVec3 = (lat: number, lon: number): [number, number, number] => {
    return [
      Math.cos(lat) * Math.cos(lon),
      Math.sin(lat),
      Math.cos(lat) * Math.sin(lon),
    ];
  };

  const camVec = toVec3(camLatRad, camLonRad);
  const featVec = toVec3(featLatRad, featLonRad);

  // Compute dot product
  const dot =
    camVec[0] * featVec[0] + camVec[1] * featVec[1] + camVec[2] * featVec[2];

  // Convert zoom level to a tighter FOV threshold
  const fovDegrees = zoomToFOV(zoom); // field of view in degrees
  const halfFovCos = Math.cos(toRad(fovDegrees / 2));

  // If the angle between the vectors is within the cone, dot ≥ cos(halfFOV)
  return dot >= halfFovCos;
}

// Tune this mapping to match your renderer behavior
function zoomToFOV(zoom: number): number {
  const clamped = Math.max(Math.min(zoom, 20), 1);
  // At zoom 1 → full hemisphere (≈130° FOV), at zoom 20 → tight 0° FOV
  return 130 * (1 - (clamped - 1) / 19); // Range: 130 → 0 degrees
}
//assumes data is a geojson feature collection with Point geometries
new IconClusterLayer<
  GeoJSON.Feature<GeoJSON.MultiPoint, GeoJSON.GeoJsonProperties>
>({
  data: data.features
    .flatMap((feature) =>
      feature.geometry.coordinates.map((coordinate) => ({
        type: "Feature",
        geometry: {
          type: "Point",
          coordinates: coordinate,
        },
        properties: feature.properties,
      })),
    )
    .filter((feature) => {
      const [lng, lat] = feature.geometry.coordinates;
      return isFeatureVisibleOnGlobe(
        vs.longitude,
        vs.latitude,
        lng,
        lat,
        vs.zoom,
      );
    }),
  ...
  parameters: {
    depthTest: false,
  },
}),
Globe.Spin.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant