Rotate the cylinder according to the normal vector of the tube endpoint

I'm working on creating a curved 3D arrow using three.js. My approach involves using a Tube along a curved path and a Cone shaped cylinder. Here's how they currently look:

https://i.sstatic.net/jmVB6.png

https://i.sstatic.net/P756z.png

My goal is to position the Arrow Head (Cone) at the end of the Tube, as shown in this Photoshopped image:

https://i.sstatic.net/DWfWB.png

Since I'm not very strong in math and new to three.js, I would really appreciate some guidance on how to connect the two elements. Here's the code I currently have:

        import T from 'three';

        var findY = function(r, x)
        {
           return Math.sqrt((r * r) - (x * x));
        }

        var radius = 25;
        var x = 0;
        var z = 0;
        var numberOfPoints = 10;
        var interval =  (radius/numberOfPoints);
        var points = [];

        for (var i = numberOfPoints; i >= 0; i--) 
        {
           var y = findY(radius, x);
           points.push(new T.Vector3(x, y, z))
           x = x + interval;
        }

        x = x - interval;

        for (var i = numberOfPoints - 1 ; i >= 0; i--) 
        {
           y = findY(radius, x) * -1;
           points.push(new T.Vector3(x, y, z));
           x = x - interval;
        }

        var path = new T.CatmullRomCurve3(points);

        var tubeGeometry = new T.TubeGeometry(
            path,  
            10,    
            radius / 10,     
            8,     
            false  
        );

        var coneGeometry = new T.CylinderGeometry(
            radiusTop = 0.1,
            radiusBottom = radius/5,
            height = 10,
            radialSegments = 10,
            heightSegments = 10,
            openEnded = 1
        );

        var material = new T.MeshBasicMaterial( { color: 0x00ff00 } );

        var tube = new T.Mesh( tubeGeometry, material );
        var cone = new T.Mesh( coneGeometry, material );

        // Translate and Rotate cone?

I would really appreciate some guidance on the mathematical and programmatic steps needed to:

  • Find the normal at the end of the tube
  • Move the Cone to the correct position

Any help would be greatly appreciated!

Answer №1

To avoid using rotation, you can create the arrowhead directly in place. The same can be done for the bended tube. All you need is the last line segment defined by endpoints A and B.

Designate point A as the sharp point and point B as the disc base center. To create the arrowhead, you'll need 2 additional basis vectors, let's call them U and V, along with the radius r of the base disc. You can then create the disc points using a simple circle formula like this:

https://i.sstatic.net/NWgPE.png

  1. Obtain AB endpoints

  2. Compute UV basis vectors

    The UV vectors should lie in the base of the arrowhead disc and be perpendicular to each other. The direction of the arrowhead (line BA) is the normal of the disc base, so you can use the cross product to get vectors perpendicular to U and W:

    W = B-A;
    W /= |W|;    // unit vector
    T = (1,0,0); // choose any non-zero vector not parallel to W
    if (abs(W.T)>0.75) T = (0,1,0); // if the dot product of T and W is close to 1, they are parallel so choose a different T
    U = (T x W) // U is perpendicular to T,W
    V = (U x W) // V is perpendicular to U,W
    
  3. Create/render arrowhead geometry

    The centers of the triangle fan are A and B. The base disc points are computed as follows:

    P(ang) = B + U.r.cos(ang) + V.r.sin(ang)
    

    Loop through ang around the circle with some step to generate enough points (usually 36 is adequate) and create two triangle fans from them. Remember that the last disc point must be the same as the first one to avoid gaps or irregularities.

If you prefer using rotations instead, here's how you can do it. Compute UVW in a similar manner as above and construct a transformation matrix from them. Point B will be the origin O, and the axes X, Y, Z will be U, V, W. The correct order depends on your arrowhead model, and W should align with the model axis. U and V can be in any order. Use this matrix for rendering. For more information, refer to:

  • Understanding 4x4 homogenous transform matrices

[Notes]

If you're unsure how to compute vector operations like cross/dot products or absolute value, see:

// cross product: W = U x V
W.x=(U.y*V.z)-(U.z*V.y)
W.y=(U.z*V.x)-(U.x*V.z)
W.z=(U.x*V.y)-(U.y*V.x)
// dot product: a = (U.V)
a=U.x*V.x+U.y*V.y+U.z*V.z
// abs of vector a = |U|
a=sqrt((U.x*U.x)+(U.y*U.y)+(U.z*U.z))

[Edit1] Simple GL Implementation

For a basic C++/GL implementation, here's a straightforward approach:

https://i.sstatic.net/LVlsf.png

 // GL implementation code here

This code renders a bended arrow in the XY plane with specified parameters. Feel free to adapt this code to your environment as needed.

[Edit2]

If you require a 3D version for non-axis aligned arrows, you can use this code snippet:

// 3D implementation code here

This version supports creating arrows in 3D space, allowing for more flexibility in arrow design. Make sure to adjust the parameters accordingly for your specific requirements.

For further details on vector operations used in the code, refer to the explanations provided.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can we stop the anchor jump caused by a third-party script?

I'm currently utilizing a third-party script (details provided below) to divide a form into multiple ajax'd pages. However, when I attempt to move on to the next page, it immediately jumps to an anchor at the top of the form. This behavior is unn ...

Experiment with parsing multiple outputs instead of repeatedly coding them as constants in Node.js

In my application, I am parsing multiple database data using cron and currently, I have it set up to create a const run for each data to find the dag_id and manually test the determineCron function one at a time. How can I create an array so that the "dete ...

Axios mistakenly includes an additional trailing slash in body parameters

Currently, in the process of developing an application utilizing React Native, I am faced with the challenge of communicating with an IoT chip that possesses minimal RAM memory. Due to this constraint, all logic must be executed on the client side. One sp ...

Keep only certain fields and eliminate the rest

Write a function that filters out all fields except 'firstName' and 'lastName' from the objects. Check out this code snippet I came up with. Any feedback? let people = [ { firstName: 'John', lastName: &apo ...

Having trouble with the scrollbar appearance after updating Chrome?

I've encountered an issue with my code after the latest Chrome update. Is there a way to implement cross-browser styling for scrollbars? // Looking for Scrollbar Styling Solution const scrollbarStyle = { scrollbarColor: `${themeLayers.scrollBar[0 ...

Node is throwing a 302 error on Localhost:3000

Looking for some guidance as a beginner trying to create and run a nodejs application. Encountering an error while running server.js via nodemon, the console displays the following: Express server listening on port 3000 Mongoose default connection open t ...

Utilize Google Drive and scripts to incorporate map images into a React application

I'm currently working on setting up an album feature on my react website for a friend, and I would like the images in the album to be linked to a Google Drive so that he can easily upload new images whenever he wants. After successfully inserting the ...

What is the best way to incorporate the value of a textbox into a list?

I currently have a list structured like this: <p>Please choose from the following options:</p> <script type="text/javascript"></script> <select id='pre-selected-options1' multiple='multiple'> <opt ...

css: positioning images with overlap in a responsive layout

Two divs have been created with background images, both displaying the same image but in different colors - one grey and the other green. These images are waveforms. Initially, only the grey image (div1) is visible while the green image (div2) remains hid ...

Implementing a feature to automatically set the datepicker value to the selected date upon page initialization

I am working with a datepicker element, identified by id="from_dt", and a button with id="fromToDate". When a date is selected from the datepicker and the button is clicked, the page will load. At that point, I want to transfer the selected date to a textb ...

Success callbacks parsed from AJAX requests

When dealing with a Backbone object and making an AJAX call to save it, I often wonder about the different ways the success callback can be handled. Sometimes, I see a generic success: function (data) { console.log(data); Other times, it's more spec ...

Raycaster in Three.js fails to recognize clicks on objects

Having trouble detecting clicks on Three.js objects using a raycaster in Angular? Here's the code I'm working with: @Component({ selector: 'app-viewer-3d', templateUrl: './viewer3d.component.html', styleUrls: ['./vi ...

Node.js encounters issues when attempting to rename a folder

I am facing an issue while attempting to rename a folder within a WordPress theme after performing search-replace operations using a node script. The renaming process for the folder seems to be unsuccessful. My objective is to change this public_html/wp- ...

Adding methods to a constructor's prototype in JavaScript without explicitly declaring them

In the book Crockford's JavaScript: The Good Parts, there is a code snippet that demonstrates how to enhance the Function prototype: Function.prototype.method = function (name, func) { this.prototype[name] = func; return this; }; Crockford elabo ...

Redefining the onClick function in the Redux 'presentation' component to include parameters

How can I pass an object as an argument to a function in a redux "presentation component" efficiently? In my <BookList /> container component, I display a <BookListRow/> presentation component for each book. I want to add a button in each Boo ...

Marker on Google Maps in Dark Mode is not displaying properly

I have integrated a custom map into my website using the npm module called google-map-react. The provided tutorial demonstrates how to implement a basic marker on the map, and you can find it here: . Here is an example of what it should look like: import ...

What steps should I take in modifying my existing code to use jQuery to set my div to a minimum height rather than a fixed height?

Could someone assist me in adjusting my div to have a min-height instead of a regular height? Whenever I click on the "Learn more" button, it extends past my div because the function is designed to set a specific height rather than an equal height. $.fn.e ...

Navigate through the options on the left menu by sliding your

I'm attempting to create a menu that slides in a submenu from the left on hover, but the issue is that with this code, all submenus open instead of just the one related to the hovered link. Here is my HTML code: <ul id="NavMenu"> ...

Tips on dividing a div into two separate pages when converting to PDF

I am working on an asp.net MVC project and I need to convert a HTML div into a PDF with two separate pages. Here is an example of my code: HTML Code <div class="row" id="mycanvas"> <p>This is the first part of my content.</p> <p ...

Is it possible to adjust the size of a p5.js canvas within a bootstrap Div container?

I am attempting to incorporate a p5js canvas into a bootstrap grid structure. My goal is to have each div within the grid contain its own unique p5js canvas, which should adjust in size when the browser is resized. Below is my bootstrap grid setup, showca ...