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

geoDesic #72

Open
bathoorn opened this issue Jul 21, 2024 · 18 comments
Open

geoDesic #72

bathoorn opened this issue Jul 21, 2024 · 18 comments

Comments

@bathoorn
Copy link

Hi,

I was messing around again and created a v2 geoDesic projection. I starts of with the icosahedron and splits up the triangle in sub triangles. For a v2 a triangle is split up into 4 sub triangles.

Here is an example
image

I am currently working on making the projection parametric so geoDesic(2) would create a v2 and geoDesic(3) would create a v3.

If you are interested in adding this I can create a pull request.

@bathoorn
Copy link
Author

bathoorn commented Jul 21, 2024

I also create a snapshot in the test directory which would look like this

geodesic

which I know see is slightly tilted :)

You can use this to create panels for your geodesic dome greenhouse so it looks like a globe from the outside

@Fil
Copy link
Member

Fil commented Jul 21, 2024

Fantastic! Can we use a better name, though? I know about https://en.wikipedia.org/wiki/Geodesic_polyhedron and https://en.wikipedia.org/wiki/Geodesic_dome but the "geodesic" term on its own is just the shortest path on the surface.

@bathoorn
Copy link
Author

Of course we can. I just needed something to start with.
Possibly we can also just add it to the Icosahedron as that is the v1. And then this is the v2.
I am still working on making the parent list parametric.

But you can see what it looks like so far here

@bathoorn
Copy link
Author

bathoorn commented Jul 29, 2024

I was looking further into creating different frequency geodesic spheres when trying to split i triangle length in three parts i do the following:

  // icosahedron based class I geodesic sphere
  const polyhedron = [
    [0, 3, 11],
    [0, 5, 3],
    [0, 7, 5],
    [0, 9, 7],
    [0, 11, 9], // North
    [2, 11, 3],
    [3, 4, 2],
    [4, 3, 5],
    [5, 6, 4],
    [6, 5, 7],
    [7, 8, 6],
    [8, 7, 9],
    [9, 10, 8],
    [10, 9, 11],
    [11, 2, 10], // Equator
    [1, 2, 4],
    [1, 4, 6],
    [1, 6, 8],
    [1, 8, 10],
    [1, 10, 2], // South
  ].map((face) => {
    const t = face.map((i) => vertices[i]);
    // create 3 polygons from these using centroid and midpoints
    const a0 = d3.geoInterpolate(t[0], t[1])(0.33333);
    const a1 = d3.geoInterpolate(t[1], t[0])(0.33333);
    const b2 = d3.geoInterpolate(t[1], t[2])(0.33333);
    const b3 = d3.geoInterpolate(t[2], t[1])(0.33333);
    const c4 = d3.geoInterpolate(t[2], t[0])(0.33333);
    const c5 = d3.geoInterpolate(t[0], t[2])(0.33333);
    const m = d3.geoCentroid({
          type: "MultiPoint",
          coordinates: t,
    });
    return [
      [t[0], a0, c5],
      [c5, m, c4], [c5, a0, m], [a0, a1, m],
      [c4, b3, t[2]], [c4, m, b3], [m, b2, b3], [m, a1, b2], [a1, t[1], b2]
    ];
  });

but it looks like it generates some artifacts. Is there a better way to do this?

@bathoorn
Copy link
Author

forgot to include an image of the kind of artifacts

image

@bathoorn
Copy link
Author

bathoorn commented Jul 31, 2024

my feeling is that there needs to be a split between 6 and 7 but for some reason there is not.

image

But it is not related to those triangles.

if I change parents from [-1, 2, 0, 2, 5, 1, 5, 3, 7] to [-1, 2, 0, 2, 5, 1, 5, 6, 7] it will look like this

image

@Fil
Copy link
Member

Fil commented Aug 11, 2024

I think what is happening here is that the triangular faces (in blue) do not correspond to the voronoi cells of their centroids (in red); for instance the top vertex defined for triangle 8 is closer to the centroid of triangle 3.

untitled (26)
untitled (27)

In fact I don't think we can use the voronoi projection for this geometry, and must instead construct the corresponding polyhedral projection.

(images generated at https://observablehq.com/d/5a8c5a187d98fa01)

@bathoorn
Copy link
Author

ah thanks for these images and all your help in getting me to understand how this works.

so why this worked in the other polyhedrons and not here is because in a geodesic sphere not all triangles are the same shape. That is why the voronoi can run into issues determining the edges. As the distance from the center will not always produce the right face now. This will work if all faces are equal shapes.

I will switch it over to the polyhedral projection.

@bathoorn
Copy link
Author

currently voronoi uses this function to determine which face a coordinate is on

  function find0(lambda, phi) {
    let d0 = Infinity;
    let found = -1;
    for (let i = 0; i < faces.length; i++) {
      const d = geoDistance(faces[i].site, [lambda, phi]);
      if (d < d0) {
        d0 = d;
        found = i;
      }
    }
    return found;
  }

i will do some homework to figure out how to do the calculations for a geodesic sphere.

have a feeling this might help me get there pentaDome_070206.pdf

@Fil
Copy link
Member

Fil commented Aug 14, 2024

Exactly: find0 is a (relatively slow) search for the closest center, which only serves geometries that are a voronoi tesselation of the sphere (hence the name of the voronoi projection helper). The most generic method is to run through all faces and return that which "polygonContains" the point. It might be a bit slower, but probably OK.

@bathoorn
Copy link
Author

i will first as quick and dirty try that using this method

even odd rule

@bathoorn
Copy link
Author

lol here they call it the fill-rule but i read it as the Fil-rule
fill-rule

@bathoorn
Copy link
Author

i am trying this

  function myfind(lambda, phi) {
    let found = -1;
    let faces = polyhedron.flat().map((face) => [...face, face[0]]);
    for (let i = 0; i < faces.length; i++) {
      if (d3.polygonContains(faces[i], [lambda, phi])) {
        found = i;
      }
    }
    return found;
  }

and feeding it into the projection like this

d3.geoPolyhedralVoronoi()
   .polygons(polygons)
   .parents(parents)
   .faceFind(myfind)
   .angle(0)
   .rotate([108,0])
   .scale(131.777)
   .center([162, 0]);

but that results in an error: TypeError: Cannot read properties of undefined (reading 'project')

so i might have to go into d3.geoPolyhedral() all the way

@Fil
Copy link
Member

Fil commented Aug 14, 2024

Note that d3.polygonContains is for planar polygons, here we need the equivalent for spherical coordinates (d3.geoPolygonContains EDIT: d3.geoContains).

@bathoorn
Copy link
Author

bathoorn commented Aug 14, 2024 via email

@bathoorn
Copy link
Author

succes! it is called geoContains and it works for any geoJson object.

  function myfind(lambda, phi) {
    let found = -1;
    let faces = polyhedron.flat().map((face) => ({
        type: "Polygon",
        coordinates: [[...face, face[0]]],
      }));
    for (let i = 0; i < faces.length; i++) {
      if (d3.geoContains(faces[i], [lambda, phi])) {
        found = i;
      }
    }
    return found;
  }

image

@Fil
Copy link
Member

Fil commented Aug 14, 2024

oops, sorry for the typo! The projection is beautiful!

@bathoorn
Copy link
Author

Using this I can generate a cover for a geodesic dome for a specific geographical location.
This one is for Amsterdam. Then Amsterdam will be at the top point. It does I frequency 3 class I dome.

Later this week I will create a pull request for it. Right now I hacked it into the voronoi by replacing the findface function.

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

No branches or pull requests

2 participants