Hi I've found some code that animates 3d shapes and even gives an example of making and animating an icosahedron I'm trying to turn it in to a decahedron though and my geometry is pretty bad. The code I have for the icosahedron is:
// draw a icosahedron
var tau = 1.6180,
phi = 20.90515745, // (180-138.1896851)/2
rt3 = Math.sqrt(3),
d = sideLen/2,
foldTbl = [ 60, -60, 60, -60,
-60, -60, 60, 60,
60, -60, 60, -60,
-60, -60, 60, 60,
60, -60, 60, -60],
moveTbl = [ 0, 2*d, 0, 2*d,
2*d, 2*d, 0, 0,
0, 2*d, 0, 2*d,
2*d, 2*d, 0, 0,
0, 2*d, 0, 2*d],
triangle = ['M',0,0,0, 'L', d*rt3,d,0, 0,2*d,0, 'z'],
tri,
faces = g.createGroup3D(),
bend = -2*phi,
i;
for (i=0; i<20; i++)
{
// create the next face
tri = g.compileShape3D(triangle, "red", null, 1); // backColor irrelevant
faces.addObj(tri);
faces.translate(0, -moveTbl[i], 0);
faces.rotate(0, 0, 1, foldTbl[i]);
faces.rotate(0, 1, 0, bend);
faces.translate(0, moveTbl[i], 0);
}
return faces;
i'm sure there must be an easy way to make this a decahedron but if anyone has any advice that'd be amazing - thanks!
If you have coordinates for an icosahedron but want to draw a dodecahedron, you can make use of the duality between those two. Take the icosahedron, and put a new vertex in the middle of every one of its triangular faces. Connect two new vertices with an edge if the corresponding faces of the icosahedron had an edge in common. You will obtain a dodecahedron, with one vertex for every face of the icosahedron, and one face for every vertex.
Related
I'm trying to animate a three.js block in such a way that it returns to its original position when the animation ends, using tween.js.
Is there a way to achieve this with tween.js only using one tween?
I have got this working as shown below:
var position = {x: -200, y: 150, width: 1, height: 1, depth: 1, rotx: -0.5, roty: 0.7, rotz: 0.9};
var target = {x: 200, y: -100, width: 0.4, height: 3, depth: 8, rotx: 0.3, roty: -0.4, rotz: -0.6};
var position2 = {x: -200, y: 150, width: 1, height: 1, depth: 1, rotx: -0.5, roty: 0.7, rotz: 0.9};
var mesh = new THREE.Mesh(
new THREE.CubeGeometry(190, 45, 30),
new THREE.MeshBasicMaterial({color: 0x444444}),
0
);
mesh.position.set(position.x, position.y, 0);
mesh.rotation.set(position.rotx, position.roty, position.rotz);
scene.add(mesh);
var t1 = new TWEEN.Tween(position).to(target, 2000);
t1.onUpdate(function() {
mesh.position.set(position.x, position.y, 0);
mesh.scale.set(position.width, position.height, position.depth);
mesh.rotation.set(position.rotx, position.roty, position.rotz);
});
t1.easing(TWEEN.Easing.Quadratic.Out);
t1.onComplete(function() {t2.start();});
var t2 = new TWEEN.Tween(target).to(position2, 2000);
t2.onUpdate(function() {
mesh.position.set(target.x, target.y, 0);
mesh.scale.set(target.width, target.height, target.depth);
mesh.rotation.set(target.rotx, target.roty, target.rotz);
});
t2.easing(TWEEN.Easing.Quadratic.In);
t1.start();
And I have the tweens updating in my animation function:
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
mesh.__dirtyPosition = true;
mesh.__dirtyRotation = true;
TWEEN.update();
}
animate();
This is working as I expect it to, but it is clearly very inefficient, and difficult to work around.
Any and all help will be appreciated.
You're overcomplicating things a bit by re-naming the x, y, z properties to width, height, depth or rotx, roty, rotz. This only means you have to manually translate these properties onUpdate when you do scale.x = position.width and rotation.x = position.rotx. I recommend you keep x, y, z, to avoid these repetitive assignments.
// We set our start and target pos using the THREE.js "x, y, z" nomenclature
var startPos = {x: -200, y: 150, z: 0};
var targetPos = {x: 200, y: -100, z: 0};
// Scale also is defined in "x, y, z"
var startScale = {x: 1, y: 1, z: 1};
var targetScale = {x: 0.4, y: 3, z: 8};
// Rotation also has "x, y, z" degrees in Euler angles
var startRot = {x: -0.5, y: 0.7, z: 0.9};
var targetRot = {x: 0.3, y: -0.4, z: -0.6};
// Standard mesh setup
var mesh = new THREE.Mesh(
new THREE.CubeGeometry(190, 45, 30),
new THREE.MeshBasicMaterial({color: 0x444444})
);
mesh.position.copy(startPos);
mesh.rotation.copy(startRot);
scene.add(mesh);
// Create shortcuts for shorter easing names
var QuadOut = TWEEN.Easing.Quadratic.Out;
var QuadIn = TWEEN.Easing.Quadratic.In;
// Create one tween for position
// Notice that you can chain the animation
// back to startPos by doing double ".to().to()""
var t1 = new TWEEN.Tween(mesh.position)
.to(targetPos, 2000, QuadOut)
.to(startPos, 2000, QuadIn);
// Second, we tween the mesh's rotation
var t2 = new TWEEN.Tween(mesh.rotation)
.to(targetRot, 2000, QuadOut)
.to(startRot, 2000, QuadIn);
// Third, we tween the mesh's scale
var t3 = new TWEEN.Tween(mesh.scale)
.to(targetScale, 2000, QuadOut)
.to(startScale, 2000, QuadIn);
t1.start();
t2.start();
t3.start();
And finally, during animate(), you no longer have to change __dirtyPosition or anything, because the tween is updating the mesh's properties directly.
function animate() {
requestAnimationFrame(animate);
TWEEN.update();
renderer.render(scene, camera);
}
animate();
I need to write a function, which generates corridor path by line path and width.
For example, I have array of coords of polyline:
var coords = [
50, 50,
150, 50,
250, 100,
220, 200,
350, 100,
];
https://i.stack.imgur.com/FCCxb.png
Then I use function to get corridor path:
var width = 10;
var corridorPath = getCorridorPath(coords, width);
Function should return something like that:
[
40, 50,
50, 40,
150, 40,
157, 41,
255, 90,
260, 105,
240, 170,
340, 90,
360, 90,
360, 110,
220, 215,
205, 205,
233, 107,
147, 62,
50, 60,
40, 50,
]
https://i.stack.imgur.com/v3wxN.png
Calculate parallel polylines and conjunctions.
For two neighbor edges AB and BC find normalized vectors ab and cb.
Calculate unit bisector vector:
b = (ab + cb).normalized
Calculate length of bisector segments as
len = d / sin(fi)
where d is offset (halfwidth), and fi is angle between vectors b and ab:
fi = atan2(crossproduct(b,ab), dotproduct(b,ab))
Find offset points (left and right ones) as
B' = B + l * b
B'' = B - l * b
Note that you want to cut long triangles, so offset point is valid for side with acute angle, and you need to recalculate two points for cut cap - for example, get central point B''' = B - d * b and add vectors, perpendicular to bisector.
Can you please take a look at This Demo and let me know how I can set the beginning of the canvas from 0,0 to 500,1200? For example if I have a Point with coordinates of 583 , 1642
then be able to add the point as:
ctx.arc(583, 1642, 5, 0, Math.PI * 2, true);
$("#draw").on("click", function () {
var ctx = $('#canvas')[0].getContext("2d");
ctx.fillStyle = "#00A308";
ctx.beginPath();
ctx.arc(0, 0, 5, 0, Math.PI * 2, true);
ctx.arc(75, 75, 5, 0, Math.PI * 2, true);
ctx.arc(300, 300, 5, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fill();
});
Thanks,
You can use translate to shift the coordinate system. Just shift it the opposite direction, for example:
ctx.translate(-500, -1200);
Now when you draw something at 583, 1642 it will show up at 83, 442 relative to the view-port.
To reset just transform back or initialize with an identity matrix:
ctx.setTransform(1, 0, 0, 1, 0, 0);
Modified fiddle
I have this triangle that I have rounded corners on but I'm using the arcTo:
context.moveTo(140, 0);
context.arcTo(180, 100, 100, 100, 4);
context.arcTo(100, 100, 140, 0, 4);
context.arcTo(140, 0, 180, 100, 4);
As you will see the top angle looks a bit messed up. Any ideas how to fix it? Seems like there needs to be some calculations for the initial moveTo(x, y) but 140, 0 is where it should start.
I just got rid of the moveTo and arced them to eachother. Started the first part at 174, 176 (180-4 radius) works but 174 had no overlap at all.
Live Demo
var canvas = document.getElementsByTagName("canvas")[0],
ctx = canvas.getContext("2d");
canvas.width = canvas.height = 400;
ctx.beginPath();
ctx.arcTo(174, 100, 100, 100, 4);
ctx.arcTo(100, 100, 140, 0, 4);
ctx.arcTo(140, 0, 180, 100, 4);
ctx.arcTo(180, 100, 100, 100, 4);
ctx.stroke();
Here is what I came up with:
var r = 8;
var offset = (6 * r / 4) - 1;
context.arcTo((180 - offset), 100, 100, 100, r);
context.arcTo(100, 100, 140, 0, r);
context.arcTo(140, 0, 180, 100, r);
context.arcTo(180, 100, 100, 100, r);
Using part of what Loktar provided, I've modified it slightly to use a ratio of what I know works for a given diameter, and used this as the offset. With a diameter of 4, I know 6 works.
Seems like there should be a better way but I'm happy with this.
As a part of a course in school, we're learning to work with the Canvas element of HTML5, this also means we're learning how to work with Javascript. The assignment is to create something graphic and some sort of interaction with this something graphic.
I decided to create a few simple diagrams and have the user be able to input values and see as the diagrams change.
http://people.dsv.su.se/~tojo0551/graf/lines.html contains a few diagrams I've drawn up, now comes the tricky part- working with Javascript and creating interaction. This is probably easy, but I never touched Javascript aside from JQuery before thus a bit at loss.
Say I want the user to be able to interact with the bar diagram at the bottom and to fill in a value between 1-5 and have the bar grow accordingly.
The Canvas code is simple, it looks like this:
function bars(){
var canvas = document.getElementById("bars");
if (canvas.getContext)
{
var ctx = canvas.getContext("2d");
var bar1 = canvas.getContext("2d");
bar1.fillStyle = "rgba(0, 50, 0, .2)";
bar1.fillRect(20, 400, 30, 90);
var bar2 = canvas.getContext("2d");
bar2.fillStyle = "rgba(0, 50, 0, .4)";
bar2.fillRect(55, 360, 30, 130);
ctx.fillStyle = "rgba(0, 50, 0, .2)";
ctx.fillRect(90, 260, 30, 230);
ctx.fillStyle = "rgba(0, 50, 0, .4)";
ctx.fillRect(125, 290, 30, 200);
ctx.fillStyle = "rgba(0, 50, 0, .2)";
ctx.fillRect(160, 270, 30, 220);
ctx.fillStyle = "rgba(0, 50, 0, .4)";
ctx.fillRect(195, 250, 30, 240);
ctx.fillStyle = "rgba(0, 50, 0, .2)";
ctx.fillRect(230, 300, 30, 190);
ctx.fillStyle = "rgba(0, 50, 0, .2)";
ctx.fillRect(20, 400, 30, 90);
ctx.fillStyle = "rgba(0, 50, 0, .4)";
ctx.fillRect(55, 360, 30, 130);
ctx.fillStyle = "rgba(0, 50, 0, .2)";
ctx.fillRect(90, 260, 30, 230);
ctx.fillStyle = "rgba(0, 50, 0, .4)";
ctx.fillRect(125, 290, 30, 200);
ctx.fillStyle = "rgba(0, 50, 0, .2)";
ctx.fillRect(160, 270, 30, 220);
ctx.fillStyle = "rgba(0, 50, 0, .4)";
ctx.fillRect(195, 250, 30, 240);
ctx.fillStyle = "rgba(0, 50, 0, .2)";
ctx.fillRect(230, 300, 30, 190);
But where do I go from here? I am new to programming, I know how to create functions and control flow with selection and loops, you know, I am a beginner programmer. What is the natural path to go to create user control? I want some input before I start working so I don't work in the wrong direction. Any pages that have good advice on how to or any ideas you got are very welcome.
/Tomas
This is pretty straight forward. If you have some experience of jQuery, I would suggest including it here, it would make things simpler.
Assuming you do use jQuery, you just need to call your bars() function whenever the user changes a value in an html input. First just change your bars() declaration so that it can be called with a value. Like this:
function bars(userVal) {
// All your existing code ...
}
Then you will need to clear whatever was drawn last time bars() was called. Something like:
function bars(userVal) {
var canvas = document.getElementById("bars");
if (canvas.getContext) {
var ctx = canvas.getContext("2d");
// Clear the bars that were drawn last time
ctx.clearRect(x,y,w,h);
// The rest of your existing code ...
}
}
clearRect takes an origin location (x and y) and a height and a width (w and h), and will clear the canvas in that area. So pass in the necessary limits of the drawing area.
Next add a text input to your page, and use jQuery to call bars() whenever it's changed
$(document).ready(function() {
$("input").on("change", function() {
var value = $(this).val();
bars(value);
});
});
Finally, you must decide what you want to do with the value the user has entered. This is entirely up to you, but I guess a quick and easy test to check it will work is just to use a numerical value in one of the drawing calls.
Examples:
// This would change the start position of a bar
ctx.fillRect(userVal, 260, 30, 230);
// This would change the width of a bar
ctx.fillRect(90, 260, userVal, 230);
// This would change the colour of a bar
ctx.fillStyle = "rgba(userVal, 50, 0, .4)";
Have fun.
Take a look at fabricjs. It begins to get very complicated to do relatively simple things using canvas, and this seems to make life easier in general though it supports interaction as well. It's important to know the fundamentals, but don't try to build a house without your carpentry tools.
If plotting is what interests you more, you should take a look at flot.
Then for the adventurous amongst us, there's three which plots 3d. Though you should work up to that.