Skip to content

Commit 0c05a91

Browse files
committed
Allow buffer geometry to be created from a ref
1 parent 82734fe commit 0c05a91

File tree

7 files changed

+157
-36
lines changed

7 files changed

+157
-36
lines changed

examples/BufferAttributes and BufferGeometry.ipynb

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
"source": [
2020
"#\n",
2121
"# BufferAttribute\n",
22-
"# TODO: INCOMPLETE\n",
2322
"#"
2423
]
2524
},
@@ -158,6 +157,62 @@
158157
"print(repr(geometry))"
159158
]
160159
},
160+
{
161+
"cell_type": "code",
162+
"execution_count": null,
163+
"metadata": {},
164+
"outputs": [],
165+
"source": [
166+
"#\n",
167+
"# PlainBufferGeometry.from_geometry\n",
168+
"#"
169+
]
170+
},
171+
{
172+
"cell_type": "code",
173+
"execution_count": null,
174+
"metadata": {},
175+
"outputs": [],
176+
"source": [
177+
"sphere = SphereBufferGeometry(10)"
178+
]
179+
},
180+
{
181+
"cell_type": "code",
182+
"execution_count": null,
183+
"metadata": {},
184+
"outputs": [],
185+
"source": [
186+
"print(repr(sphere))"
187+
]
188+
},
189+
{
190+
"cell_type": "code",
191+
"execution_count": null,
192+
"metadata": {},
193+
"outputs": [],
194+
"source": [
195+
"plain = PlainBufferGeometry.from_geometry(sphere)"
196+
]
197+
},
198+
{
199+
"cell_type": "code",
200+
"execution_count": null,
201+
"metadata": {},
202+
"outputs": [],
203+
"source": [
204+
"plain"
205+
]
206+
},
207+
{
208+
"cell_type": "code",
209+
"execution_count": null,
210+
"metadata": {},
211+
"outputs": [],
212+
"source": [
213+
"plain.attributes"
214+
]
215+
},
161216
{
162217
"cell_type": "code",
163218
"execution_count": null,

js/scripts/prop-types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ _.extend(ArrayType.prototype, BaseType.prototype, {
264264
function ArrayBufferType(arrayType, shape_constraint) {
265265
this.arrayType = arrayType;
266266
this.shape_constraint = shape_constraint;
267-
this.defaultValue = [];
267+
this.defaultValue = null;
268268
}
269269
_.extend(ArrayBufferType.prototype, BaseType.prototype, {
270270
getTraitlet: function() {

js/scripts/three-class-config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ module.exports = {
274274
MaxIndex: new Types.Int(65535),
275275
//groups: new Types.GeometryGroup(),
276276
//drawRange: new Types.DrawRange(),
277-
_ref_geometry: new Types.ThreeType('Geometry', {allowNull: false}),
277+
_ref_geometry: new Types.ThreeType(['Geometry', 'BufferGeometry'], {allowNull: false}),
278278
},
279279
},
280280
InstancedBufferAttribute: {

js/src/core/BufferAttribute.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
var _ = require('underscore');
22
var datawidgets = require('jupyter-datawidgets');
3+
var ndarray = require('ndarray');
34
var BufferAttributeAutogen = require('./BufferAttribute.autogen').BufferAttributeModel;
45

56
var BufferAttributeModel = BufferAttributeAutogen.extend({
@@ -48,7 +49,11 @@ var BufferAttributeModel = BufferAttributeAutogen.extend({
4849
mapBufferAttributeArrayThreeToModel: function() {
4950
var attributeData = this.obj.array;
5051
var modelNDArray = this.get('array');
51-
modelNDArray.data.set(attributeData);
52+
if (modelNDArray) {
53+
modelNDArray.data.set(attributeData);
54+
} else {
55+
this.set('array', ndarray(attributeData, [this.obj.count, this.obj.itemSize]));
56+
}
5257
},
5358

5459
}, {

js/src/geometries/PlainBufferGeometry.js

Lines changed: 76 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
var _ = require('underscore');
2+
var createModel = require('../_base/utils').createModel;
3+
24
var AutogenPlainBufferGeometryModel = require('../geometries/PlainBufferGeometry.autogen').PlainBufferGeometryModel;
35

6+
var core = require('../core')
7+
var BufferGeometryModel = core.BufferGeometryModel;
8+
var BufferAttributeModel = core.BufferAttributeModel;
9+
410

511
var PlainBufferGeometryModel = AutogenPlainBufferGeometryModel.extend({
612

@@ -9,34 +15,80 @@ var PlainBufferGeometryModel = AutogenPlainBufferGeometryModel.extend({
915
this.property_assigners['attributes'] = 'assignAttributesMap';
1016
},
1117

12-
constructThreeObject: function() {
13-
18+
constructFromRef: function(ref) {
1419
var result = new THREE.BufferGeometry();
15-
16-
var ref = this.get('_ref_geometry');
17-
if (ref) {
18-
return ref.initPromise.bind(this).then(function() {
20+
// Copy ref. This will create new buffers!
21+
result.copy(ref.obj);
22+
23+
var chain = ref.initPromise.bind(this);
24+
var toSet = {};
25+
if (ref instanceof PlainBufferGeometryModel) {
26+
// TODO: Review this!
27+
chain = chain.then(
28+
// Wait for all attributes
29+
Promise.all(_.map(_.values(ref.get('attributes')), attr => {
30+
return attr.initPromise;
31+
}))
32+
).then(
33+
// Wait for all morphAttributes
34+
Promise.all(_.map(_.values(ref.get('morphAttributes')), attr => {
35+
return attr.initPromise;
36+
}))
37+
).then(() => {
38+
// Copy ref. This will create new buffers!
39+
result.copy(ref.obj);
40+
});
41+
} else if (ref instanceof BufferGeometryModel) {
42+
// We have a ref that is some other kind of buffergeometry
43+
// This ref will then not have 'attributes' as models
44+
// We need to:
45+
// - Create models for each bufferattribute
46+
// - Set attribute dicts on model
47+
// Create models for all attributes:
48+
chain = chain.then(function() {
49+
// Copy ref. This will create new buffers!
1950
result.copy(ref.obj);
2051

21-
// A bit of a hack:
22-
// Sync out all copied properties before restoring
23-
this.obj = result;
24-
var old_three = this.props_created_by_three;
25-
this.props_created_by_three = {};
26-
[
27-
'name', 'attributes', 'morphAttributes',
28-
'boundingBox', 'boundingSphere'
29-
].forEach(key => {
30-
this.props_created_by_three[key] = true;
52+
return Promise.all(_.map(_.pairs(result.attributes), kv => {
53+
return createModel(BufferAttributeModel, this.widget_manager, kv[1]).then(model => {
54+
return [kv[0], model];
55+
});
56+
}));
57+
}).then((attribModelKVs) => {
58+
toSet.attributes = _.object(attribModelKVs);
59+
60+
// Then create models for all morphAttributes:
61+
}).then(Promise.all(_.map(_.pairs(result.morphAttributes), kv => {
62+
return createModel(BufferAttributeModel, this.widget_manager, kv[1]).then(model => {
63+
return [kv[0], model];
3164
});
32-
this.syncToModel();
33-
this.props_created_by_three = old_three;
34-
return result;
65+
}))).then((attribModelKVs) => {
66+
toSet.morphAttributes = _.object(attribModelKVs);
3567
});
68+
} else {
69+
// Assume ref is GeometryModel
70+
throw new Error('Geometry -> PlainBufferGeometry not yet supported!');
3671
}
3772

38-
return Promise.resolve(result);
73+
return chain.then(function() {
74+
75+
// Sync out all copied properties not yet dealt with
76+
toSet.name = result.name;
77+
this.set(toSet, 'pushFromThree');
78+
this.save_changes();
3979

80+
return result;
81+
});
82+
},
83+
84+
constructThreeObject: function() {
85+
var ref = this.get('_ref_geometry');
86+
if (ref) {
87+
return this.constructFromRef(ref);
88+
}
89+
90+
var result = new THREE.BufferGeometry();
91+
return Promise.resolve(result);
4092
},
4193

4294
assignAttributesMap: function(obj, key, value) {
@@ -56,14 +108,10 @@ var PlainBufferGeometryModel = AutogenPlainBufferGeometryModel.extend({
56108
obj.addAttribute(key, value[key]);
57109
});
58110

59-
var current;
60-
common.forEach(key => {
61-
current = obj.getAttribute(key);
62-
if (current !== value[key]) {
63-
console.warn('Cannot reassign buffer geometry attribute:', key);
64-
return; // continue
65-
}
66-
});
111+
var commonChanged = _.filter(common, key => { return obj.getAttribute(key) !== value[key]});
112+
if (commonChanged.length > 0) {
113+
console.warn('Cannot reassign buffer geometry attribute:', commonChanged);
114+
}
67115

68116
},
69117

js/src/textures/DataTexture.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,13 @@ var DataTextureModel = DataTextureBase.extend({
6565
},
6666

6767
mapDataTextureDataThreeToModel: function() {
68-
var textureData = this.obj.image.data;
68+
var imageRecord = this.obj.image;
6969
var modelNDArray = this.get('data');
70-
modelNDArray.data.set(textureData);
70+
if (modelNDArray) {
71+
modelNDArray.data.set(imageRecord.data);
72+
} else {
73+
this.set('data', ndarray(imageRecord.data, [imageRecord.width, imageRecord.height]));
74+
}
7175
},
7276

7377
}, {

pythreejs/core/BufferAttribute.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,30 @@
11
import numpy as np
22
from ipywidgets import register
3-
from traitlets import validate, TraitError
3+
from traitlets import validate, TraitError, Undefined
4+
from ipydatawidgets import NDArray, array_serialization, NDArrayWidget
45

56
from .BufferAttribute_autogen import BufferAttribute as BaseBufferAttribute
67

78

89
@register
910
class BufferAttribute(BaseBufferAttribute):
1011

12+
def __init__(self, array=None, normalized=True, **kwargs):
13+
if array is not None:
14+
# If not supplied, leave as undefined.
15+
# This is needed for remote initialization
16+
kwargs['array'] = array
17+
kwargs['normalized'] = normalized
18+
super(BaseBufferAttribute, self).__init__(**kwargs)
19+
1120
@validate('array')
1221
def _valid_array(self, proposal):
1322
# Validate shape
1423
if np.ndim(proposal) > 2:
1524
raise TraitError('Array needs to have at most two dimensions. Given shape was: %r'
1625
% np.shape(proposal))
1726
value = proposal['value']
18-
if value.dtype == np.float64:
27+
if value is not Undefined and value.dtype == np.float64:
1928
# 64-bit not supported, coerce to 32-bit
2029
value = value.astype(np.float32)
2130
return value

0 commit comments

Comments
 (0)