How to cast parent class to child class in javascript - javascript

I am working with box2dweb and i am trying to make a function, that would add instructions how to draw a 'body' based on the 'body' shape.
That is: When received a 'b2BodyDef' get the shape, and with external information, get the shape specifications. To do this i need to cast 'b2Shape' back to 'b2CircleShape'.
I guess with C++ this would be something like
b2CircleShape* shape_circle = dynamic_cast< (b2CircleShape*) >( shape );
How do i do similar thing with javascript? I do know there are tons of other ways to do this (like pass the wanted radius on this example as parameter) but i would like to do what i feel like right and not a hack.
function Add_new_drawable_object_to_world( body, type )
{
GLOBAL_world_objects.push( body );
var s = new Sprite();
if ( type == OBJECT_TYPE_PLAYER )
{
s.graphics.beginFill ( 0x2222ff, 0.6);
var b2CircleShape = Box2D.Collision.Shapes.b2CircleShape;
var fixture_list = body.GetFixtureList();
var shape = fixture_list.GetShape() ;
// FIXME: TypeError: shape.GetRadius is not a function
var radius = shape.GetRadius();
// here i would draw fancy circle with 'radius'
And earlier i have:
// Create player
var player = new b2FixtureDef(); // ball fixture definition
player.shape = new b2CircleShape();
player.density = 0.5;
player.shape.SetRadius( 0.2 );
var bodyDef = new b2BodyDef();
bodyDef.type = b2Body.b2_dynamicBody;
bodyDef.position.Set( 0.0, 0.0 );
var body = GLOBAL_world.CreateBody(bodyDef);
body.CreateFixture( player );
Add_new_drawable_object_to_world( body, OBJECT_TYPE_PLAYER );

As Bergi says, Javascript has no classes so the concept of private/protected members does not really exist. I would suggest having a look at how box2dweb does this, because the debug draw display does almost the exact same thing you are doing here. Search for b2World.prototype.DrawShape in the box2dweb source.
If it makes you feel better, in the original C++ b2CircleShape the member variables are public, so there is no GetRadius and the 'internals' are accessed directly :)

Related

Scaling a 2D SVG group object in three.js

I'm attempting to create a map of 2d SVG tiles in three.js. I have used SVGLoader() Like so (Keep in mind some brackets are for parent scopes that aren't shown. That is not the issue):
loader = new SVGLoader();
loader.load(
// resource URL
filePath,
// called when the resource is loaded
function ( data ) {
console.log("SVG file successfully loaded");
const paths = data.paths;
for ( let i = 0; i < paths.length; i ++ ) {
const path = paths[ i ];
const material = new THREE.MeshBasicMaterial( {
color: path.color,
side: THREE.DoubleSide,
depthWrite: false
} );
const shapes = SVGLoader.createShapes( path );
console.log(`Shapes length = ${shapes.length}`);
try{
for ( let j = 0; j < shapes.length; j ++ ) {
const shape = shapes[ j ];
const geometry = new THREE.ShapeGeometry( shape );
const testGeometry = new THREE.PlaneGeometry(2,2);
try{
const mesh = new THREE.Mesh(geometry, material );
group.add( mesh );
}catch(e){console.log(e)}
}
}catch(e){console.log(e)}
}
},
// called when loading is in progress
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
// called when loading has errors
function ( error ) {
console.log( 'An error happened' );
}
);
return group;
}
Dismiss the fact that I surrounded alot of it in try{}catch(){}
I have also created grid lines and added it to my axis helper in the application that allows me to see where each cooordinate is, in relation to the X and Y axis.
This is how the svg appears on screen:
Application Output
I can't seem to figure out how to correlate the scale of the svg, with the individual grid lines. I have a feeling that Im going to have to dive deeper into the SVG loading script that I have above then scale each shape mesh specifically. I call the SVG group itself in the following code.
try{
//SVG returns a group, TGA returns a texture to be added to a material
var object1 = LOADER.textureLoader("TGA", './Art/tile1.tga', pGeometry);
var object2 = LOADER.textureLoader("SVG", '/Art/bitmap.svg');
const testMaterial = new THREE.MeshBasicMaterial({
color: 0xffffff,
map: object1,
side: THREE.DoubleSide
});
//const useMesh = new THREE.Mesh(pGeometry, testMaterial);
//testing scaling the tile
try{
const worldScale = new THREE.Vector3();
object2.getWorldScale(worldScale);
console.log(`World ScaleX: ${worldScale.x} World ScaleY: ${worldScale.y} World ScaleZ: ${worldScale.z}`);
//object2.scale.set(2,2,0);
}catch(error){console.log(error)}
scene.add(object2);
}
Keep in mind that the SVG is object2 in this case. Some of the ideas to tackle this problem I have had is looking into what a world scale is, matrix4 transformations, and the scale methods of either the object3d parent properties or the bufferGeometry parent properties of this particular svg group object. I am also fully aware that three.js is designed for 3d graphics, however I would like to master 2d graphics programming in this library before I get into the 3d aspect of things. I also have a thought that the scale of the SVG group is distinctly different from the scale of the scene and its X Y and Z axis.
If this question has already been answered a link to the corresponding answer would be of great help to me.
Thank you for the time you take to answer this question.
I messed with the dimensions of the svg file itself in the editor I used to paint it and I got it to scale. Not exactly a solution in the code, however I guess the code is just closely tied to the data that the svg file provides and cant be altered too much.

Vertices of THREE.BufferGeometry

Since r125, THREE.Geometry was deprecated. We are now updating our code base and we are running into errors that we don't know how to fix.
We create a sphere and use a raycaster on the sphere to get the intesect point.
worldSphere = new THREE.SphereGeometry(
worldSize,
worldXSegments,
worldYSegments
);
...
const intersect = raycaster.intersectObjects([worldGlobe])[0];
...
if (intersect) {
let a = worldSphere.vertices[intersect.face.a];
let b = worldSphere.vertices[intersect.face.b];
let c = worldSphere.vertices[intersect.face.c];
}
Now, normally variable a would contain 3 values for every axis namely a.x, a.y, a.z, same goes for the other variables. However, this code does not work anymore.
We already know that worldSphere is of type THREE.BufferGeometry and that the vertices are stored in a position attribute, but we cannot seem to get it working.
What is the best way to fix our issue?
It should be:
const positionAttribute = worldGlobe.geometry.getAttribute( 'position' );
const a = new THREE.Vector3();
const b = new THREE.Vector3();
const c = new THREE.Vector3();
// in your raycasting routine
a.fromBufferAttribute( positionAttribute, intersect.face.a );
b.fromBufferAttribute( positionAttribute, intersect.face.b );
c.fromBufferAttribute( positionAttribute, intersect.face.c );
BTW: If you only raycast against a single object, use intersectObject() and not intersectObjects().

Pass values from openjscad to javascript

is it possible to pass a value from openjscad to javascript?
I would like to show the dimensions of a 3d-object in a div or any other html-element.
Example:
A cube is created with openjscad with the following parameters:
function main() {
var cube = CSG.cube({
center: [0, 0, 0],
radius: [1, 2, 3]
});
return cube;
}
How can I pass the parameters for center and radius to javascript in order to use them in other areas of the website?
I did this by making my own cube object, you can add all the variables you want and add some functions too like my translate function.
function myCube(size,pos){
this.obj = cube({size:size,center:false}).translate(pos);
this.size = size;
this.pos = pos;
this.translate = function(pos){
this.obj.translate(pos);
};
}
then you can make a cube like this var MC = new myCube(radius, [x,y,z]);
and now to get your radius you can do MC.size;
it does get tricky when you try to do something with the shape itself, you'll have to do something like union(MC.obj, CIL.obj)
ps: I hope this helps although I know this isn't the ideal way and there's probably some easy way of doing it but this worked for me.

Three JS: Load an OBJ, translate to origin (center in scene), orbit

All I want to do is load an OBJ file and translate its coordinates to the world origins (0,0,0) so that orbit controls work perfectly (no Pivot points please).
I'd like to load random OBJ objects with different geometries/center points and have them translated automatically to the scene origin. In other words, a 'hard coded' translate solution for a specific model won't work
This has got to be one of the most common scenarios for Three JS (basic 3d object viewer), so I'm surprised I can't find a definitive solution on SO.
Unfortunately there are a lot of older answers with deprecated functions, so I would really appreciate a new answer even if there are similar solutions out there.
Things I've tried
the code below fits the object nicely to the camera, but doesn't solve the translation/orbiting problem.
// fit camera to object
var bBox = new THREE.Box3().setFromObject(scene);
var height = bBox.size().y;
var dist = height / (2 * Math.tan(camera.fov * Math.PI / 360));
var pos = scene.position;
// fudge factor so the object doesn't take up the whole view
camera.position.set(pos.x, pos.y, dist * 0.5);
camera.lookAt(pos);
Apparently the geometry.center() is good for translating an object's coordinates back to the origin, but the THREE.GeometryUtils.center has been replaced by geometry.center() and I keep getting errors when trying to use it.
when loading OBJs, geometry has now been replaced by bufferGeometry. I can't seem to cast the buffergeometry into geometry in order to use the center() function. do I have to place this in the object traverse > child loop like so? this seems unnecessarily complicated.
geometry = new THREE.Geometry().fromBufferGeometry( child.geometry );
My code is just a very simple OBJLoader.
var objLoader = new THREE.OBJLoader();
objLoader.setPath('assets/');
objLoader.load('BasketballNet_Skull.obj', function (object) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = material;
}
} );
scene.add(object);
});
(BTW first real question on SO so forgive any formatting / noob issues)
Why not object.geometry.center()?
var objLoader = new THREE.OBJLoader();
objLoader.setPath('assets/');
objLoader.load('BasketballNet_Skull.obj', function (object) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
child.material = material;
child.geometry.center();
}
} );
scene.add(object);
OK figured this out, using some very useful functions from Meshviewer Master, an older Three JS object viewer.
https://github.com/ideesculture/meshviewer
All credit to Gautier Michelin for this code
https://github.com/gautiermichelin
After loading the OBJ, you need to do 3 things:
1. Create a Bounding Box based on the OBJ
boundingbox = new THREE.BoundingBoxHelper(object, 0xff0000);
boundingbox.update();
sceneRadiusForCamera = Math.max(
boundingbox.box.max.y - boundingbox.box.min.y,
boundingbox.box.max.z - boundingbox.box.min.z,
boundingbox.box.max.x - boundingbox.box.min.x
)/2 * (1 + Math.sqrt(5)) ; // golden number to beautify display
2. Setup the Camera based on this bounding box / scene radius
function showFront() {
if (objectCopy !== undefined) objectCopy.rotation.z = 0;
controls.reset();
camera.position.z = 0;
camera.position.y = 0;
camera.position.x = sceneRadiusForCamera;
camera.lookAt(scene.position);
}
(the mesh viewer code also contains functions for viewing left, top, etc)
3. Reposition the OBJ to the scene origin
Like any centering exercise, the position is then the width and height divided by 2
function resetObjectPosition(){
boundingbox.update();
size.x = boundingbox.box.max.x - boundingbox.box.min.x;
size.y = boundingbox.box.max.y - boundingbox.box.min.y;
size.z = boundingbox.box.max.z - boundingbox.box.min.z;
// Repositioning object
objectCopy.position.x = -boundingbox.box.min.x - size.x/2;
objectCopy.position.y = -boundingbox.box.min.y - size.y/2;
objectCopy.position.z = -boundingbox.box.min.z - size.z/2;
boundingbox.update();
if (objectCopy !== undefined) objectCopy.rotation.z = 0;
}
From my understanding of your question, you want the objects that are added to the scene in the origin of the camera view. I believe the common way of achieving an object viewer solution is adding camera controls to your camera in the scene mostly THREE.OrbitControls and specifying the target for the camera as the object that you want to focus on. This makes the object focused to be in the center and the camera rotation and movement will be based on that object.

Working with Objects in Javascript

I am Currently Trying to work with JavaScript in a cleaner object orientated way, So Please excuse me if I'm doing this entirely incorrectly I am using this previous questions answer as a general reference, but Here's my 'test' code:
//Create some sample objects to play with.
var testJSON = {
"rectangle": [
{ "id":3 , "x":5, "y":10, "width":10, "height":50
}
]
};
//Create Rectangle Constructor
var rectangle = {
init: function( i, x, y, width, height ) {
this.id = i,
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.fields = []
},
move: function( x, y ) {
this.x += x;
this.y += y;
}
};
//Create test array to hold all the objects
var test = [];
//Create a new rectangle object
var myRectangle = Object.create( rectangle );
myRectangle.init( 1, 0, 0, 2, 4 );
myRectangle.move( 3, 5 );
//put rectangle object in array associated with id
test[myRectangle.id] = myRectangle;
//Create a new rectangle object with the same variable name as it will all be in an array anyway.
var myRectangle = Object.create( rectangle );
myRectangle.init( 2, 0, 0, 2, 4 );
myRectangle.move( 0, 0 );
//put rectangle object in array associated with id
test[myRectangle.id] = myRectangle;
//put JSON result in
test[testJSON.rectangle[0].id] = testJSON.rectangle[0];
//No Longer need this variable, is it worth getting rid of.. i dont know
myRectangle =null;
//Try and use methods created in the constructor.
test[2].move(4,8);
console.log(test);
Okay, Now the actual questions, The Application I am trying to create, has both json data and it will have users that create data, so for example: the application will generate a bunch of 'rectangles' and then the user can also create rectangles.
So the first question would be, 'Is this the correct approach' and then secondly how would i get the json data to also have the method defined in the rectangle constructor (move)?
Any Help Greatly Appreciated.
This an extension of what #Marc B and #Ray Toal mentioned...
You have created javascript functions - which is not at all that bad - but not JSON. To create graphics, you could use the canvas tag as, in effect, a "drawing div" and use the object's x and y positions to constantly update them - if you were considering doing 2d animation. If so, I would recommend CreateJs as a starting block before hard-coding JAVASCRIPT animations. Again, you're code is just fine, but having users create this data - if you were considering a server application would involve using real JSON or perhaps Node.js - but for now I'd focus on single player aspect and setting up you're objects on a graphical 'interface' like <canvas>

Categories