creating holes in three.js - javascript

This is actually taken from THREEJS: add hole to rendered Shape . But it's still not working.
The error is
three.js:34206 Uncaught TypeError: Cannot read property 'concat' of undefined
var plane, vertices = [], planeShape;
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xC0C0C0});
vertices.push(
new THREE.Vector3(-room_width/2,room_depth/2,0),
new THREE.Vector3(room_width/2,room_depth/2,0),
new THREE.Vector3(room_width/2,-room_depth/2,0),
new THREE.Vector3(-room_width/2,-room_depth/2,0)
);
planeShape = new THREE.Shape(vertices);
plane = new THREE.Mesh( new THREE.ShapeGeometry(planeShape), planeMaterial);
scene.add(plane);
var holes = [
new THREE.Vector3(-room_width/4,room_depth/4,0),
new THREE.Vector3(room_width/4,room_depth/4,0),
new THREE.Vector3(room_width/4,-room_depth/4,0),
new THREE.Vector3(-room_width/4,-room_depth/4,0)
],
hole = new THREE.Path();
hole.fromPoints(holes);
var shape = new THREE.Shape(plane.geometry.vertices);
shape.holes = [hole];
var points = shape.extractPoints();
plane.geometry.faces = [];
var triangles = THREE.ShapeUtils.triangulateShape ( points.vertices, points.holes );
for( var i = 0; i < triangles.length; i++ ){
plane.geometry.faces.push( new THREE.Face3( triangles[i][0], triangles[i][1], triangles[i][2] ));
}
edit::: ANS
var plane, vertices = [], planeShape;
var planeMaterial = new THREE.MeshLambertMaterial({color: 0xC0C0C0});
vertices.push(
new THREE.Vector3(-150,-150,0),
new THREE.Vector3(150,-150,0),
new THREE.Vector3(150,150,0),
new THREE.Vector3(-150,150,0)
);
planeShape = new THREE.Shape(vertices);
plane = new THREE.Mesh( new THREE.ShapeGeometry(planeShape), planeMaterial);
scene.add(plane);
var holes = [
new THREE.Vector3(-75,-75,0),
new THREE.Vector3(75,-75,0),
new THREE.Vector3(75,75,0),
new THREE.Vector3(-75,75,0)
],
hole = new THREE.Path();
hole.fromPoints(holes);
var shape = new THREE.Shape(plane.geometry.vertices);
shape.holes = [hole];
var points = shape.extractPoints();
plane.geometry.faces = [];
var triangles = THREE.ShapeUtils.triangulateShape ( points.shape, points.holes );
plane.geometry.vertices.push(
new THREE.Vector3(-75,-75,0),
new THREE.Vector3(75,-75,0),
new THREE.Vector3(75,75,0),
new THREE.Vector3(-75,75,0)
);
for( var i = 0; i < triangles.length; i++ ){
plane.geometry.faces.push( new THREE.Face3( triangles[i][0], triangles[i][1], triangles[i][2] ));
}

For anyone stumbling onto this, there is now a much simpler way to work with holes compared to the old "THREE.ShapeUtils.triangulateShape" and constructing the triangles yourself.
//vertices is the main shape/contour/exterior, a "ring" as a list of THREE.Vector2 instances
//holes is a list of THREE.Path instances, created from THREE.Vector2
//If you pass THREE.Vector3 then the Z property is ignored.
var shape = new THREE.Shape(vertices);
shape.holes = holes;
var geometry = new THREE.ShapeBufferGeometry( shape );
...

Related

Photoshop script select all layers with same name as current layer

I need a photoshop script that selects all layers with the same name as the currently selected layer. The following code does the job:
if (app.documents.length > 0) {
activeDocument.suspendHistory('stuff', 'main()');
function main(){
if(!documents.length) return;
var myDoc = app.activeDocument;
var theName = myDoc.activeLayer.name;
var theResults = new Array;
selectAllLayers();
var selectedLayers = getSelectedLayersIdx();
for(var a = 0; a < selectedLayers.length; a++){
var thisName = layerName(Number(selectedLayers[a]));
if (thisName == theName) {
theResults.push(Number(selectedLayers[a]))
};
};
selectLayerByIndex(theResults[0], false);
for (var m = 1; m < theResults.length; m++) {
selectLayerByIndex(theResults[m], true);
};
}
};
function getSelectedLayersIdx(){
var selectedLayers = new Array;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var desc = executeActionGet(ref);
if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ){
desc = desc.getList( stringIDToTypeID( 'targetLayers' ));
var c = desc.count
var selectedLayers = new Array();
for(var i=0;i<c;i++){
try{
activeDocument.backgroundLayer;
selectedLayers.push( desc.getReference( i ).getIndex() );
}catch(e){
selectedLayers.push( desc.getReference( i ).getIndex()+1 );
}
}
}else{
var ref = new ActionReference();
ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "ItmI" ));
ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
try{
activeDocument.backgroundLayer;
selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" ))-1);
}catch(e){
selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" )));
}
}
return selectedLayers;
};
function selectAllLayers() {
var desc29 = new ActionDescriptor();
var ref23 = new ActionReference();
ref23.putEnumerated( charIDToTypeID('Lyr '), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
desc29.putReference( charIDToTypeID('null'), ref23 );
executeAction( stringIDToTypeID('selectAllLayers'), desc29, DialogModes.NO );
};
function layerName(idx){
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), idx);
var desc = executeActionGet(ref);
return desc.getString(stringIDToTypeID("name"));
};
function selectLayerByIndex(index,add){
add = undefined ? add = false:add
var ref = new ActionReference();
ref.putIndex(charIDToTypeID("Lyr "), index);
var desc = new ActionDescriptor();
desc.putReference(charIDToTypeID("null"), ref );
if(add) desc.putEnumerated( stringIDToTypeID( "selectionModifier" ), stringIDToTypeID( "selectionModifierType" ), stringIDToTypeID( "addToSelection" ) );
desc.putBoolean( charIDToTypeID( "MkVs" ), false );
try{
executeAction(charIDToTypeID("slct"), desc, DialogModes.NO );
}catch(e){
alert(e.message);
}
};
BUT, there is one problem, my files have a ton of layers and so it appears that this code must iterate through them all, as such each time i need to run this script it takes 7minutes to execute. Is there a way to optimize this such that it will be faster even in files with VERY HIGH layer counts? Thanks
Each Photoshop layer is given a unique ID - (generated at creation in numerical order - I think - don't quote me on that) So you can access each layer by the ID instead of layer.getByname. The code below will show you the ID of the currently selected layer. - The upshot being, if you know the ID, you can get by layerID. :)
To select more than one layer at a time: reuse the select_layer_by_ID with layer and true to add to the current selection.
Get layer by ID:
// Switch off any dialog boxes
displayDialogs = DialogModes.NO; // OFF
var srcDoc = app.activeDocument;
var theLayer = srcDoc.activeLayer;
var myLayerID = get_layer_id(theLayer);
srcDoc.activeLayer = srcDoc.layers[0]; //top layer
// now go back to original layer via layer ID!
// select by layer ID
select_layer_by_ID(myLayerID);
alert("Layer ID: " + myLayerID + "\n" + srcDoc.activeLayer.name);
// Switch off any dialog boxes
displayDialogs = DialogModes.ALL; // ON
// function SELECT LAYER BY ID(int, boolean)
// --------------------------------------------------------
function select_layer_by_ID(id, add)
{
if (add == undefined) add = false;
var desc1 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putIdentifier(charIDToTypeID('Lyr '), id);
desc1.putReference(charIDToTypeID('null'), ref1);
if (add) desc1.putEnumerated(stringIDToTypeID("selectionModifier"), stringIDToTypeID("selectionModifierType"), stringIDToTypeID("addToSelection"));
executeAction(charIDToTypeID('slct'), desc1, DialogModes.NO);
}
// function GET LAYER ID(obj)
// --------------------------------------------------------
function get_layer_id(alayer)
{
return alayer.id;
}

Creating a reusable function for loaders in three.js

I am trying to find a way how to create a reusable function that prevents me from repeating the same loader code over and over again. An example can be seen below:
one = new THREE.Group();
var loader1 = new THREE.TextureLoader();
loader1.crossOrigin = '';
loader1.load('',
function (texture) {
this.geo = new THREE.BoxGeometry(10,10,10);
this.mat = new THREE.MeshBasicMaterial({color:'white'});
this.mesh = new THREE.Mesh(this.geo, this.mat);
one.add(mesh)
}
);
twp = new THREE.Group();
var loader2 = new THREE.TextureLoader();
loader2.crossOrigin = '';
loader2.load('',
function (texture) {
this.geo = new THREE.BoxGeometry(10,10,10);
this.mat = new THREE.MeshBasicMaterial({color:'white'});
this.mesh = new THREE.Mesh(this.geo, this.mat);
two.add(mesh)
}
);
My attempt was as follows:
example = new THREE.Group();
function reuse(obj) {
this.loader = new THREE.TextureLoader();
this.loader.crossOrigin = '';
this.loader.load('',
function (texture) {
this.geo = new THREE.BoxGeometry(10,10,10);
this.mat = new THREE.MeshBasicMaterial({color:'white'});
this.mesh = new THREE.Mesh(this.geo, this.mat);
obj.name.add(mesh)
}
)
};
var test = new reuse({name: 'example'});
I also tried pushing the mesh in an array within the function:
arr.push(mesh);
arr.mesh[0].position.x
etc.
I also tried returning it.
What exactly is the best and working method to avoid such disaster?
when dealing with duplicate code the most common and easiest way is to create a simple function
example with your code:
function getTexturedCube(path){
var geometry = new THREE.BoxGeometry(10,10,10);
var loader = new THREE.TextureLoader();
//you dont have to put onLoad function in,
//the texture returned will automatically update when it is loaded
var texture = loader.load(path);
var material = new THREE.MeshBasicMaterial({map:texture});
return new THREE.Mesh(geometry, material)
}
var group = new THREE.Group();
var cube1 = getTexturedCube("/path/to/image");
var cube2 = getTexturedCube("/path/to/other/image");
group.add(cube1);
group.add(cube2);
var anotherGroup = new THREE.Group();
var cube3 = getTexturedCube("/path/to/yet/another/image")
anotherGroup.add(cube3);
you can also pass the function a reference to your group and make it push the object into it
function addTexturedCube(path, object){
var geometry = new THREE.BoxGeometry(10,10,10);
var loader = new THREE.TextureLoader();
var texture = loader.load(path);
var material = new THREE.MeshBasicMaterial({map:texture});
object.add(new THREE.Mesh(geometry, material));
}
var group = new THREE.Group();
addTexturedCube("/path/to/image", group);
addTexturedCube("/path/to/other/image", group);

How can I detect a specific 3d model collision three.js

I am trying to make clickable 3d objects with Leap Motion. I have two 3D models, IronMan helmet and a Hammer of Thor. If one of those two object is selected, then will change color. For the Iron Man will be green and for the Hammer will be white. But when I am selecting the Hammer, it changes to green instead of white. I use a cube as a pointer to select the object. Can you help?
This is the code to insert 3d models:
var colladaMeshlist = [];
model = new THREE.Object3D()
var object;
var skin;
var objectScale = 1.5;
rotX=0, rotY=0, rotZ=0;
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load( 'models/IronMan.dae', function (collada) {
object = collada.scene;
object.scale.x = object.scale.y = object.scale.z = objectScale;
object.position.x= 20;
object.position.y= -40;
object.position.z= 0;
object.rotation.x= rotX;
object.rotation.y= rotY;
object.rotation.z= rotZ;
object.name="IronMan";
colladaMeshlist.push(object);
model.add(object);
});
scene.add(model);
model2 = new THREE.Object3D()
var object2;
var skin2;
var objectScale2 = 1;
posX=0, posY=-40, posZ=0;
rotX=0, rotY=0, rotZ=0;
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load( 'models/Hammer.dae', function (collada) {
object2 = collada.scene;
object2.scale.x = object2.scale.y = object2.scale.z = objectScale2;
object2.position.x= -20;
object2.position.y= -20;
object2.position.z= posZ;
object2.rotation.x= rotX;
object2.rotation.y= rotY;
object2.rotation.z= rotZ;
object2.name="Hammer";
colladaMeshlist.push(object2);
model2.add(object2);
});
scene.add(model2);
This is the code for selecting the objects:
var originPoint = cube.position.clone();
for(var vertexIndex = 0; vertexIndex < cube.geometry.vertices.length; vertexIndex++)
{
var localVertex = cube.geometry.vertices[vertexIndex].clone();
var globalVertex = localVertex.applyMatrix4( cube.matrix );
var directionVector = globalVertex.sub( cube.position );
var ray = new THREE.Raycaster( originPoint, directionVector.clone().normalize() );
var collisionResults = ray.intersectObjects(colladaMeshlist, true);
if(collisionResults.length > 0 && collisionResults[0].distance < directionVector.length())
{
collisionResults[0].object.material.color.setHex(0x4CAF50);
}
else if (collisionResults.length > 0 && collisionResults[1].distance < directionVector.length())
{
collisionResults[1].object.material.color.setHex(0xffffff);
}
}

problems with a popup in openlayes

I need to make permanent popup but only managed to make it show when a mouse event, i found an example but nothing to adapt achievement: http://openlayers.org/dev/examples/osm-marker-popup.html
anyone can help me to make permanent the popup, Thanks.
var mapa;
OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
OpenLayers.ImgPath = "/openlayers/img/"
mapa = new OpenLayers.Map('map',{
controls: [
new OpenLayers.Control.Attribution(),
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
],
theme: null
});
var osm = new OpenLayers.Layer.OSM( " Open Street Map" );
var markers = new OpenLayers.Layer.Markers( "Ruta" );
$.each(info, function(i, data){
var size = new OpenLayers.Size(21,25);
var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
var icon = new OpenLayers.Icon('/openlayers/img/data.png',size,offset);
var lonlat = new OpenLayers.LonLat(parseFloat(data.long),parseFloat(data.lat));
var proj_1 = new OpenLayers.Projection("EPSG:4326");
var proj_2 = new OpenLayers.Projection("EPSG:900913");
var EPSG = lonlat.transform(proj_1,proj_2);
var marker = new OpenLayers.Marker(EPSG, icon);
markers.addMarker(marker);
// popup
marker.events.register("click", marker, function(e){
var popup = new OpenLayers.Popup.FramedCloud(data.idunidad,
marker.lonlat,
new OpenLayers.Size(200,200),
'<p>info in the popup, mouse event</p>',
null,true);
popup.idunidad = data.idunidad;
mapa.addPopup(popup);
arrPopup.push(popup);
});
});
var lonlat = new OpenLayers.LonLat(-74.075833,4.598056);
var proj_1 = new OpenLayers.Projection("EPSG:4326");
var proj_2 = new OpenLayers.Projection("EPSG:900913");
var centrar = lonlat.transform(proj_1,proj_2);
mapa.addLayers([osm,markers]);
mapa.setCenter(centrar, 5);
mapa.addControl(new OpenLayers.Control.LayerSwitcher());
Why not use vector layers, you know this example?
http://openlayers.org/dev/examples/dynamic-text-layer.html

"Object has no method 'getBounds'" error in OpenLayers

I'm using this code to draw a point on a map:
function addPointToMap(pMap){
var coordinates = new Array();
// Style Point
var style_blue = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
style_blue.strokeColor = "blue";
style_blue.fillColor = "blue";
// Make Point
coordinates.push(new OpenLayers.Geometry.Point(33, 33));
var pointFeature = new OpenLayers.Feature.Vector(coordinates, null, style_blue);
// Layer
var pointsLayer = new OpenLayers.Layer.Vector("Points Layer");
pointsLayer.addFeatures([pointFeature]);
pMap.addLayer(pointsLayer);
}
I'm getting this error from the console:
Uncaught TypeError: Object POINT(33, 33) has no method 'getBounds'
What am I doing wrong?
For the sake of completeness, I received a similar error while adding a polygon (not a point) from raw WKT data. The error that there are no bounds occur because the object was of the wrong type.
When you call addFeatures, it expects an array of OpenLayers.Feature.Vector objects, which are created by Format.read.
var wkt_parser = new OpenLayers.Format.WKT();
var wkt_data_parsed = wkt_parser.read(some_raw_wkt_data_string);
layer.addFeatures([wkt_data_parsed]);
The answer is to add a multipoint geometry:
function addPointToMap(pMap){
var coordinates = new Array();
// Style Point
var style_blue = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
style_blue.strokeColor = "blue";
style_blue.fillColor = "blue";
// Make Point
coordinates.push(new OpenLayers.Geometry.Point(lon, lat));
var pointsGeometry = new OpenLayers.Geometry.MultiPoint(coordinates);
var pointFeature = new OpenLayers.Feature.Vector(pointsGeometry, null, style_blue);
// Layer
var pointsLayer = new OpenLayers.Layer.Vector("Points Layer");
pointsLayer.addFeatures([pointFeature]);
pMap.addLayer(pointsLayer);
}
Does your map have a 'baselayer'? Otherwise you should add option 'alloverlays'=true to your map options. I'm not sure if this solves your problem though...

Categories

Resources