3

Using Three.js, (although I believe this is more math related) I have a set of 2D points that can create a 2D geometry. such as square, rectangle, pentagon, or custom 2D shape. Based of the original 2D shape, I would like to create a method to offset the points inward or outward uniformly in such a way like the attached image.

I don't know if there is a simple way to offset/grow/shrink all the points (vector3) uniformly on the 2D shape inward or outward. And if so, it'll be cool if I can offset the points by X distance? Kinda of like saying offset the points on the 2D shape outward or inward by X distance.

And no, I'm not referring to scaling from a center point. While scaling may work for symmetrical shapes, it won't work when it comes to non-symmetrical shapes.

see image for example enter image description here

Thanks in advance.

blackStrings
  • 63
  • 1
  • 6
  • 1
    Possibly related: https://stackoverflow.com/questions/45727683/reduce-polygon-area-by-percentage – meowgoesthedog Jun 20 '18 at 22:14
  • Have a look at this [forum post](https://discourse.threejs.org/t/profiledcontourgeometry/2330?u=prisoner849). Not exactly what you need, but very similar. Instead of a set of points in profile, you need to transform just one point. – prisoner849 Jun 21 '18 at 07:46

2 Answers2

2

You can read that forum thread.

enter image description here

I've made some changes with ProfiledContourGeometry and got OffsetContour, so I leave it here, just in case, what if it helps :)

  function OffsetContour(offset, contour) {

    let result = [];

    offset = new THREE.BufferAttribute(new Float32Array([offset, 0, 0]), 3);
    console.log("offset", offset);

    for (let i = 0; i < contour.length; i++) {
      let v1 = new THREE.Vector2().subVectors(contour[i - 1 < 0 ? contour.length - 1 : i - 1], contour[i]);
      let v2 = new THREE.Vector2().subVectors(contour[i + 1 == contour.length ? 0 : i + 1], contour[i]);
      let angle = v2.angle() - v1.angle();
      let halfAngle = angle * 0.5;

      let hA = halfAngle;
      let tA = v2.angle() + Math.PI * 0.5;

      let shift = Math.tan(hA - Math.PI * 0.5);
      let shiftMatrix = new THREE.Matrix4().set(
             1, 0, 0, 0, 
        -shift, 1, 0, 0,
             0, 0, 1, 0,
             0, 0, 0, 1
      );


      let tempAngle = tA;
      let rotationMatrix = new THREE.Matrix4().set(
        Math.cos(tempAngle), -Math.sin(tempAngle), 0, 0,
        Math.sin(tempAngle),  Math.cos(tempAngle), 0, 0,
                          0,                    0, 1, 0,
                          0,                    0, 0, 1
      );

      let translationMatrix = new THREE.Matrix4().set(
        1, 0, 0, contour[i].x,
        0, 1, 0, contour[i].y,
        0, 0, 1, 0,
        0, 0, 0, 1,
      );

      let cloneOffset = offset.clone();
      console.log("cloneOffset", cloneOffset);
        shiftMatrix.applyToBufferAttribute(cloneOffset);
      rotationMatrix.applyToBufferAttribute(cloneOffset);
      translationMatrix.applyToBufferAttribute(cloneOffset);

      result.push(new THREE.Vector2(cloneOffset.getX(0), cloneOffset.getY(0)));
    }


    return result;
  }

Feel free to modify it :)

prisoner849
  • 16,894
  • 4
  • 34
  • 68
1

I have some doubts about solutions that do not include number of edges modification.

I faced the same issue in this project where I wanted to ensure a known distance between voronoi cells, and I quickly figured out that scale does not fulfill the use case. But one complication I faced was the disappearance of some edges that I had to handle in a while loop. It was so difficult to debug that I had to create a debug mode that helps see the points and lines, that I also left available. It's possible to activate this debug mode with a checkbox:

Note for the images, I have them as links not embedded as I'm still new contributor (might improve that later).

The edges that shall disappear are shown in red retraction snapshot1

retraction with edges discard 1

retraction with edges discard 2

Here a link to the function in action, you might have to modify it to have another points format though : https://github.com/WebSVG/voronoi/blob/8893768e3929ea713a47dba2c4d273b775e0bd82/src/voronoi_diag.js#L278

And here a link to the complete project integrating this function, it has link to a live demo too https://github.com/WebSVG/voronoi

wassfila
  • 1,173
  • 8
  • 18