Browse Source

Added support for curves and textdots.

Started instance definitions / references
Luis Fraguada 5 years ago
parent
commit
bb8266e1f4
2 changed files with 353 additions and 88 deletions
  1. 329 78
      examples/jsm/loaders/3DMLoader.js
  2. 24 10
      examples/webgl_loader_3dm.html

+ 329 - 78
examples/jsm/loaders/3DMLoader.js

@@ -13,8 +13,11 @@ import {
 	Mesh,
 	Color,
 	Points,
-	PointsMaterial
+	PointsMaterial,
+	Line,
+	LineBasicMaterial
 } from "../../../build/three.module.js";
+import { CSS2DObject } from '../renderers/CSS2DRenderer.js'
 
 var Rhino3dmLoader = function ( manager ) {
 
@@ -194,22 +197,24 @@ Rhino3dmLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 		var objects = data.objects;
 		var materials = data.materials;
 
-		for( var i = 0; i < objects.length; i++ ){
+		var ptMaterial = new PointsMaterial( { sizeAttenuation: true, vertexColors:true } );
+
+		for( var i = 0; i < objects.length; i++ ) {
 
 			var obj = objects[i];
 
-			//console.log(obj);
+			// console.log(obj);
 
 			var attributes = obj.attributes;
 			var geometry = null;
 			var material = null;
 			
 			switch( obj.objectType ) {
+				case 'Point':
 				case 'PointSet':
 
 					geometry = loader.parse( obj.geometry );
-					material = new PointsMaterial( { sizeAttenuation: true, vertexColors:true } );
-					var points = new Points( geometry, material );
+					var points = new Points( geometry, ptMaterial );
 					points.userData['attributes'] = attributes;
 					object.add(points);
 
@@ -254,6 +259,62 @@ Rhino3dmLoader.prototype = Object.assign( Object.create( Loader.prototype ), {
 
 					object.add( brepObject );
 
+					break;
+				
+				case 'Curve':
+
+					geometry = loader.parse( obj.geometry );
+
+					var _color = attributes.drawColor;
+					var color = new Color( _color.r / 255.0, _color.g / 255.0, _color.b / 255.0 );
+
+					var lines = new Line(geometry, new LineBasicMaterial( { color: color } ) );
+					lines.userData['attributes'] = attributes;
+					lines.userData['objectType'] = obj.objectType;
+
+					object.add(lines);
+
+					break;
+
+				case 'TextDot':
+
+					geometry = obj.geometry;
+					var dotDiv = document.createElement('div');
+					dotDiv.style.fontFamily = geometry.fontFace;
+					dotDiv.style.fontSize = `${geometry.fontHeight}px`;
+					dotDiv.style.marginTop = '-1em';
+					dotDiv.style.color = '#FFF';
+					dotDiv.style.padding = '2px';
+					dotDiv.style.paddingRight = '5px';
+					dotDiv.style.paddingLeft = '5px';
+					dotDiv.style.borderRadius = '5px';
+					var color = attributes.drawColor;
+					dotDiv.style.background = `rgba(${color.r},${color.g},${color.b},${color.a})`;
+					dotDiv.textContent = geometry.text;
+					var dot = new CSS2DObject(dotDiv);
+					var location = geometry.point;
+					dot.position.set(location[0], location[1], location[2]);
+
+					dot.userData['attributes'] = attributes;
+					dot.userData['objectType'] = obj.objectType;
+
+					object.add(dot);
+
+					break;
+				case 'InstanceDefinition':
+					
+					var instanceDefinitionObject = new Object3D();
+					var instanceReferences = [];
+
+					for( var j = 0; j < objects.length; j++ ) {
+						if( objects[j].objectType === 'InstanceReference' &&
+							objects[j].geometry.parentIdefId === attributes.id ) {
+								instanceReferences.push( objects[j] );
+						}
+					}
+
+					// console.log( instanceReferences );
+
 					break;
 			}
 
@@ -454,98 +515,56 @@ Rhino3dmLoader.Rhino3dmWorker = function () {
 		var views = [];
 		var namedViews = [];
 		var groups = [];
-		// var strings = [];
+		var strings = [];
 
 		//Handle objects
 
 		for( var i = 0; i < doc.objects().count; i++ ) {
 
 			var _object = doc.objects().get(i);
-			var _geometry = _object.geometry();
-			var _attributes = _object.attributes();
-			var objectType = _geometry.objectType;
-			var geometry = null;
-
-			// TODO: handle other geometry types
-			switch( objectType ) {
-
-				case rhino.ObjectType.Point:
-				case rhino.ObjectType.Light:
-				case rhino.ObjectType.Curve:
-				case rhino.ObjectType.Annotation:
-				case rhino.ObjectType.InstanceReference:
-				case rhino.ObjectType.TextDot:
-				case rhino.ObjectType.Hatch:
-				case rhino.ObjectType.SubD:
-				case rhino.ObjectType.ClipPlane:
-
-					console.warn(`THREE.3DMLoader: TODO: Implement ${objectType.constructor.name}`);
-					
-					break;
-
-				case rhino.ObjectType.PointSet:
-				case rhino.ObjectType.Mesh:
-
-					geometry = _geometry.toThreejsJSON();
-
-					break;
-
-				case rhino.ObjectType.Brep:
-
-					var faces = _geometry.faces();
-					geometry = [];
-
-					for (var faceIndex = 0; faceIndex < faces.count; faceIndex++) {
-
-						var face = faces.get( faceIndex );
-						var mesh = face.getMesh( rhino.MeshType.Any );
-
-						if ( mesh ) {
-
-							geometry.push( mesh.toThreejsJSON() );
-							mesh.delete();
-
-						}
-
-						face.delete();
-					}
 
-					faces.delete();
-
-					break;
+			// console.log(objectType);
 
-				case rhino.ObjectType.Extrusion:
-
-					var mesh = _geometry.getMesh(rhino.MeshType.Any);
-
-					if( mesh ) {
-
-						geometry = mesh.toThreejsJSON();
-						mesh.delete();
+			// skip instance definition objects
+			if( _object.attributes().isInstanceDefinitionObject ) { 
 
-					} 
+				continue;
+				
+			} else {
 
-					break;
+				var object = extractObjectData( _object, doc );
 
+				if( object !== undefined ){
+					objects.push( object );
+				}
 			}
 
-			if( geometry ) {
-
-				var attributes = extractProperties( _attributes );
+			_object.delete();
+			
+		}
 
-				objectType = objectType.constructor.name;
-				objectType = objectType.substring( 11, objectType.length );
+		// Handle instance definitions
 
-				objects.push( { geometry, attributes, objectType: objectType } );
+		for( var i = 0; i < doc.instanceDefinitions().count(); i++ ) {
 
+			var idef = doc.instanceDefinitions().get( i );
+			var idefAttributes = extractProperties( idef );
+			
+			var ids = idef.getObjectIds();
+			var idefObjects = [];
+
+			// extract object data from each of these
+			for( var j = 0; j < ids.length; j++ ) {
+				var _object = doc.objects().findId( ids[ j ] );
+				var object = extractObjectData( _object, doc );
+				idefObjects.push( object );
 			}
 
-			_geometry.delete();
-			_object.delete();
-			
+			objects.push( { geometry: idefObjects, attributes: idefAttributes, objectType: 'InstanceDefinition' } );
+
 		}
 
-		//Handle materials
+		// Handle materials
 
 		for( var i = 0; i < doc.materials().count(); i++) {
 
@@ -628,7 +647,6 @@ Rhino3dmLoader.Rhino3dmWorker = function () {
 
 		// Handle strings -- this seems to be broken at the moment in rhino3dm
 		// console.log(`Strings Count: ${doc.strings().count()}`); 
-
 		/*
 		for( var i = 0; i < doc.strings().count(); i++ ){
 
@@ -648,6 +666,169 @@ Rhino3dmLoader.Rhino3dmWorker = function () {
 
 		return { objects, materials, layers, views, namedViews, groups, settings };
 
+	}
+
+	function extractObjectData( object, doc ) {
+
+		var _geometry = object.geometry();
+		var _attributes = object.attributes();
+		var objectType = _geometry.objectType;
+		var geometry = null;
+		var attributes = null;
+
+		// skip instance definition objects
+		//if( _attributes.isInstanceDefinitionObject ) { continue; }
+
+		// TODO: handle other geometry types
+		switch( objectType ) {
+
+			case rhino.ObjectType.Curve:
+
+				var pts = curveToPoints( _geometry, 100 );
+
+				var position = {};
+				var color = {};
+				var attributes = {}
+				var data = {};
+
+				position.itemSize = 3;
+				position.type = 'Float32Array';
+				position.array = [];
+
+				for( var j = 0; j < pts.length; j++ ) {
+
+					position.array.push( pts[j][0] );
+					position.array.push( pts[j][1] );
+					position.array.push( pts[j][2] );
+
+				}
+
+				attributes.position = position;
+				data.attributes = attributes;
+
+				geometry = { data };
+
+				break;
+
+			case rhino.ObjectType.Point:
+
+				var pt = _geometry.location;
+
+				var position = {};
+				var color = {};
+				var attributes = {}
+				var data = {};
+
+				position.itemSize = 3;
+				position.type = 'Float32Array';
+				position.array = [ pt[0], pt[1], pt[2] ];
+
+				_color = _attributes.drawColor( doc );
+
+				color.itemSize = 3;
+				color.type = 'Float32Array';
+				color.array = [ _color.r / 255.0, _color.g / 255.0, _color.b / 255.0 ];
+
+				attributes.position = position;
+				attributes.color = color;
+				data.attributes = attributes;
+
+				geometry = { data };
+
+				break;
+
+			case rhino.ObjectType.PointSet:
+			case rhino.ObjectType.Mesh:
+
+				geometry = _geometry.toThreejsJSON();
+
+				break;
+
+			case rhino.ObjectType.Brep:
+
+				var faces = _geometry.faces();
+				geometry = [];
+
+				for (var faceIndex = 0; faceIndex < faces.count; faceIndex++) {
+
+					var face = faces.get( faceIndex );
+					var mesh = face.getMesh( rhino.MeshType.Any );
+
+					if ( mesh ) {
+
+						geometry.push( mesh.toThreejsJSON() );
+						mesh.delete();
+
+					}
+
+					face.delete();
+				}
+
+				faces.delete();
+
+				break;
+
+			case rhino.ObjectType.Extrusion:
+
+				var mesh = _geometry.getMesh(rhino.MeshType.Any);
+
+				if( mesh ) {
+
+					geometry = mesh.toThreejsJSON();
+					mesh.delete();
+
+				} 
+
+				break;
+
+			case rhino.ObjectType.TextDot:
+				
+				geometry = extractProperties( _geometry );
+
+				break;
+			
+			case rhino.ObjectType.InstanceReference:
+
+				geometry = extractProperties( _geometry );
+				geometry.xform = extractProperties( _geometry.xform );
+				geometry.xform.array = _geometry.xform.toFloatArray( true );
+
+				break;
+			
+			/*
+			case rhino.ObjectType.Light:
+			case rhino.ObjectType.Annotation:
+			case rhino.ObjectType.Hatch:
+			case rhino.ObjectType.SubD:
+			case rhino.ObjectType.ClipPlane:
+			*/
+
+			default:
+				console.warn(`THREE.3DMLoader: TODO: Implement ${objectType.constructor.name}`);
+				break;
+		}
+
+		if( geometry ) {
+
+			var attributes = extractProperties( _attributes );
+
+			if( _attributes.groupCount > 0 ) {
+				attributes.groupIds = _attributes.getGroupList();
+			}
+
+			attributes.drawColor = _attributes.drawColor( doc );
+
+			objectType = objectType.constructor.name;
+			objectType = objectType.substring( 11, objectType.length );
+
+			//objects.push( { geometry, attributes, objectType: objectType } );
+
+			return { geometry, attributes, objectType };
+
+		}
+
+		
+
 	}
 
 	function extractProperties( object ) {
@@ -671,6 +852,76 @@ Rhino3dmLoader.Rhino3dmWorker = function () {
 		return result;
 	}
 
+	function curveToPoints (curve, pointLimit) {
+
+		var pointCount = pointLimit;
+		var rc = [];
+		var ts = [];
+
+		// console.log(curve);
+	  
+		if (curve instanceof rhino.LineCurve) {
+		  return [curve.pointAtStart, curve.pointAtEnd];
+		}
+	  
+		if (curve instanceof rhino.PolylineCurve) {
+		  pointCount = curve.pointCount;
+		  for (let i = 0; i < pointCount; i++) {
+			rc.push(curve.point(i));
+		  }
+		  return rc;
+		}
+	  
+		if (curve instanceof rhino.PolyCurve) {
+		  let segmentCount = curve.segmentCount;
+		  for (let i = 0; i < segmentCount; i++) {
+			let segment = curve.segmentCurve(i);
+			let segmentArray = curveToPoints(segment);
+			rc = rc.concat(segmentArray);
+			segment.delete();
+		  }
+		  return rc;
+		}
+	  
+		if (curve instanceof rhino.NurbsCurve && curve.degree === 1) {
+		  console.info('degree 1 curve');
+		}
+	  
+		let domain = curve.domain;
+		let divisions = pointCount - 1.0;
+		for (let j = 0; j < pointCount; j++) {
+		  let t = domain[0] + (j / divisions) * (domain[1] - domain[0]);
+		  if (t === domain[0] || t === domain[1]) {
+			ts.push(t);
+			continue;
+		  }
+		  let tan = curve.tangentAt(t);
+		  let prevTan = curve.tangentAt(ts.slice(-1)[0]);
+
+		  // Duplicaated from THREE.Vector3
+		  // How to pass imports to worker?
+
+		  tS = tan[0] * tan[0] + tan[1] * tan[1] + tan[2] * tan[2];
+		  ptS = prevTan[0] * prevTan[0] + prevTan[1] * prevTan[1] + prevTan[2] * prevTan[2];
+
+		  var denominator = Math.sqrt( tS * ptS );
+
+		  var angle;
+		  if( denominator === 0 ) {
+			angle = Math.PI / 2;
+		  } else {
+			  var theta = ( tan.x * prevTan.x + tan.y * prevTan.y + tan.z * prevTan.z ) / denominator;
+			  angle = Math.acos( Math.max( - 1, Math.min( 1, theta ) ) );
+		  }
+
+		  if (angle < 0.1) { continue; }
+		  ts.push(t);
+		}
+	  
+		rc = ts.map(t => curve.pointAt(t));
+		return rc;
+	}
+
 };
 
 export { Rhino3dmLoader };

+ 24 - 10
examples/webgl_loader_3dm.html

@@ -15,14 +15,15 @@
 		<script type="module">
 
 			import * as THREE from '../build/three.module.js';
-
-			import { GUI } from './jsm/libs/dat.gui.module.js';
+			import { CSS2DRenderer } from './jsm/renderers/CSS2DRenderer.js';
 
 			import { OrbitControls } from './jsm/controls/OrbitControls.js';
 			import { Rhino3dmLoader } from './jsm/loaders/3DMLoader.js';
 
+			import { GUI } from './jsm/libs/dat.gui.module.js';
+
 			var container, controls;
-			var camera, scene, renderer;
+			var camera, scene, renderer, labelRenderer;
 			var gui;
 
 			init();
@@ -57,14 +58,22 @@
 					initGUI( object.userData.layers );
 
                 } );
-                
+				
+				var width = window.innerWidth;
+				var height = window.innerHeight;
                 
 				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
-				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( width, height );
 				container.appendChild( renderer.domElement );
 
-				controls = new OrbitControls( camera, renderer.domElement );
+				labelRenderer = new CSS2DRenderer();
+				labelRenderer.setSize( width, height );
+				labelRenderer.domElement.style.position = 'absolute';
+				labelRenderer.domElement.style.top = '0px';
+				container.appendChild( labelRenderer.domElement );
+
+				controls = new OrbitControls( camera, container );
 
 				window.addEventListener( 'resize', resize, false );
 
@@ -72,10 +81,14 @@
 
 			function resize() {
 
-				camera.aspect = window.innerWidth / window.innerHeight;
+				var width = window.innerWidth;
+				var height = window.innerHeight;
+
+				camera.aspect = width / height;
 				camera.updateProjectionMatrix();
 
-				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setSize( width, height);
+				labelRenderer.setSize( width, height);
 
 			}
 
@@ -83,6 +96,7 @@
 
 				controls.update();
 				renderer.render( scene, camera );
+				labelRenderer.render( scene, camera );
 
 				requestAnimationFrame( animate );
 
@@ -96,7 +110,7 @@
 
 				for( var i = 0; i < layers.length; i++) {
 
-					var layer = layers[i];
+					var layer = layers[ i ];
 					layersControl.add( layer, 'visible' ).name( layer.name ).onChange( function ( val ) {
 
 						var name = this.object.name;
@@ -105,7 +119,7 @@
 
 							if( child.userData.hasOwnProperty('attributes') ) {
 
-								if( 'layerIndex' in child.userData.attributes ){
+								if( 'layerIndex' in child.userData.attributes ) {
 
 									var layerName = layers[child.userData.attributes.layerIndex].name;