Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3D Tiles - Batch Table Hierarchy #4625

Merged
merged 27 commits into from
Dec 13, 2016
Merged

3D Tiles - Batch Table Hierarchy #4625

merged 27 commits into from
Dec 13, 2016

Conversation

lilleyse
Copy link
Contributor

@lilleyse lilleyse commented Nov 8, 2016

For #3241
Spec: CesiumGS/3d-tiles#66

This adds initial support for hierarchies in the batch table to help reduce the amount of duplicate metadata. More details behind this are in the linked spec issue. The 3D Tiles Hierarchy demo has some example styles

doors

New features:

Cesium API:

  • Cesium3DTileFeature.isClass(className) - returns whether the feature's class is className. This does not check ancestor classes.
  • Cesium3DTileFeature.isDerived(className) - returns whether the feature derives from className. This checks the feature's class and ancestor classes.

Styling language:

  • isClass - same as above - isClass('door') - styles just doors
  • isDerived - same as above - isDerived('door') - styles doors and doorknobs
  • Styling a feature based on ancestor properties: "show" : "${building_name} === 'building0'" will style building0 and all descendants of building0

Todo:

  • Support multiple parents
  • Support updates across multiple tiles
  • Update Cesium3DTileBatchTable.hasProperty, Batched3DModel3DTileContent.hasProperty, etc to take the hierarchy into account. It will need to accept a batchId argument because not all features have the same properties anymore. Or this doesn't change and just continues to check only base-level batch table properties (like area and height in the sample below).
  • Same idea for getPropertyNames
  • LATER For parity with the styling language the Cesium API could include functions like
    • getFeaturesByProperty(propertyName, value)
    • getFeaturesByClass(className)
    • There can be many variants to these. It may be best to leave these out of the Cesium API and let the apps themselves do this checking.
  • Add documentation
  • Better error checking
    • Recognize cyclical dependencies? Or let validator point that out?
  • Add tests
  • Naming
  • Think about supporting for GLSL backend
    • If not supported, write tests that disallow any of the new functions like isClass and isDerived

Questions:

  • Should hierarchy properties exist in the tileset.json properties section?
  • Currently a parentId of -1 signifies no parent. However this makes it harder to store the parentIds in binary unless the only allowed componentType are SHORT or INT.
  • Is it useful to have a ${CLASS} property for styling? This would allow regular expressions against the class name. Or is isClass good enough?
  • Should a feature be able to set a property of its ancestor's class. Say the feature is a door, should feature.setProperty('building_name', 'new_name') be allowed? Currently this is supported in the code and is probably ok because otherwise we would need some other interface to represent abstract instances - like an analog to Cesium3DTileFeature, and that can get complicated.

Sample hierarchy:
Doorknobs are children of doors

zone0
  building0
    roof0
    wall0
    door0 - doorknob0
    door1 - doorknob1
    door2 - doorknob2
    door3 - doorknob3
  building1
    roof1
    wall1
    door4 - doorknob4
    door5 - doorknob5
    door6 - doorknob6
    door7 - doorknob7
  building2
    roof2
    wall2
    door8 - doorknob8
    door9 - doorknob9
    door10 - doorknob10
    door11 - doorknob11

Sample batch table json:

{
    "height": [0.1, 0.1, 0.1, 0.1, 5, 5, 5, 5, 10, 6, 0.1, 0.1, 0.1, 0.1, 5, 5, 5, 5, 10, 6, 0.1, 0.1, 0.1, 0.1, 5, 5, 5, 5, 10, 6],
    "area": [0.2, 0.2, 0.2, 0.2, 10, 10, 10, 10, 20, 12, 0.2, 0.2, 0.2, 0.2, 10, 10, 10, 10, 20, 12, 0.2, 0.2, 0.2, 0.2, 10, 10, 10, 10, 20, 12],
    "HIERARCHY": {
        "instancesLength": 34,
        "classes": [
            {
                "name": "doorknob",
                "length": 12,
                "instances": {
                    "doorknob_size": [0.3, 0.43, 0.32, 0.2, 0.21, 0.35, 0.3, 0.23, 0.43, 0.32, 0.41, 0.33],
                    "doorknob_name": ["doorknob0", "doorknob1", "doorknob2", "doorknob3", "doorknob4", "doorknob5", "doorknob6", "doorknob7", "doorknob8", "doorknob9", "doorknob10", "doorknob11"]
                }
            },
            {
                "name": "door",
                "length": 12,
                "instances": {
                    "door_mass": [10, 11, 14, 7, 8, 12, 3, 6, 3, 5, 9, 10],
                    "door_width": [1.2, 1.3, 1.21, 1.5, 1.1, 1.15, 1.32, 1.54, 1.8, 2, 2.1, 1.3],
                    "door_name": ["door0", "door1", "door2", "door3", "door4", "door5", "door6", "door7", "door8", "door9", "door10", "door11"]
                }
            },
            {
                "name": "roof",
                "length": 4,
                "instances": {
                    "roof_paint": ["red", "blue", "yellow", "green"],
                    "roof_name": ["roof0", "roof1", "roof2", "roof3"]
                }
            },
            {
                "name": "wall",
                "length": 4,
                "instances": {
                    "wall_paint": ["pink", "orange", "blue", "gray"],
                    "wall_windows": [1, 2, 4, 2],
                    "wall_name": ["wall0", "wall1", "wall2", "wall3"]
                }
            },
            {
                "name": "building",
                "length": 4,
                "instances": {
                    "building_area": [20, 21.98, 39.3],
                    "building_name": ["building0", "building1", "building2"]
                }
            },
            {
                "name": "zone",
                "length": 1,
                "instances": {
                    "zone_buildings": [4],
                    "zone_name": ["zone0"]
                }
            }
        ],
        "classId": [0, 0, 0, 0, 1, 1, 1, 1, 2, 3, 0, 0, 0, 0, 1, 1, 1, 1, 2, 3, 0, 0, 0, 0, 1, 1, 1, 1, 2, 3, 4, 4, 4, 5],
        "parentId": [4, 5, 6, 7, 30, 30, 30, 30, 30, 30, 14, 15, 16, 17, 31, 31, 31, 31, 31, 31, 24, 25, 26, 27, 32, 32, 32, 32, 32, 32, 33, 33, 33, -1]
    }
}

Same example using the batch table binary:

{
    "height": {
        "byteOffset": 0,
        "componentType": "FLOAT",
        "type": "SCALAR"
    },
    "area": {
        "byteOffset": 120,
        "componentType": "FLOAT",
        "type": "SCALAR"
    },
    "HIERARCHY": {
        "instancesLength": 34,
        "classes": [
            {
                "name": "doorknob",
                "length": 12,
                "instances": {
                    "doorknob_size": {
                        "byteOffset": 512,
                        "componentType": "FLOAT",
                        "type": "SCALAR"
                    },
                    "doorknob_name": ["doorknob0", "doorknob1", "doorknob2", "doorknob3", "doorknob4", "doorknob5", "doorknob6", "doorknob7", "doorknob8", "doorknob9", "doorknob10", "doorknob11"]
                }
            },
            {
                "name": "door",
                "length": 12,
                "instances": {
                    "door_mass": {
                        "byteOffset": 560,
                        "componentType": "FLOAT",
                        "type": "SCALAR"
                    },
                    "door_width": {
                        "byteOffset": 608,
                        "componentType": "FLOAT",
                        "type": "SCALAR"
                    },
                    "door_name": ["door0", "door1", "door2", "door3", "door4", "door5", "door6", "door7", "door8", "door9", "door10", "door11"]
                }
            },
            {
                "name": "roof",
                "length": 4,
                "instances": {
                    "roof_paint": ["red", "blue", "yellow", "green"],
                    "roof_name": ["roof0", "roof1", "roof2", "roof3"]
                }
            },
            {
                "name": "wall",
                "length": 4,
                "instances": {
                    "wall_paint": ["pink", "orange", "blue", "gray"],
                    "wall_windows": {
                        "byteOffset": 656,
                        "componentType": "FLOAT",
                        "type": "SCALAR"
                    },
                    "wall_name": ["wall0", "wall1", "wall2", "wall3"]
                }
            },
            {
                "name": "building",
                "length": 4,
                "instances": {
                    "building_area": {
                        "byteOffset": 672,
                        "componentType": "FLOAT",
                        "type": "SCALAR"
                    },
                    "building_name": ["building0", "building1", "building2"]
                }
            },
            {
                "name": "zone",
                "length": 1,
                "instances": {
                    "zone_buildings": {
                        "byteOffset": 684,
                        "componentType": "FLOAT",
                        "type": "SCALAR"
                    },
                    "zone_name": ["zone0"]
                }
            }
        ],
        "classIds": {
            "byteOffset": 240,
            "componentType": "INT"
        },
        "parentIds": {
            "byteOffset": 376,
            "componentType": "INT"
        }
    }
}

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 8, 2016

Styling a feature based on ancestor properties: "show" : "${building_name} === 'building0'" will style all descendants of building0

Do you mean "style building0 and all descendants of building0?"

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 8, 2016

CC @pmconne

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 8, 2016

isClass - same as above - isClass('door') - styles just doors
isDerived - same as above - isDerived('door') - styles doors and doorknobs

Are you happy with these names? isClass is awkward because, for example, with parent-child A->B, a B still is an A. Likewise, isDerived is awkward because B is not derived from B.

Did you have alternatives perhaps borrowed from popular OO languages? isExactClass and isClass come to mind but better names may exist.

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 8, 2016

Update Cesium3DTileBatchTable.hasProperty, Batched3DModel3DTileContent.hasProperty, etc to take the hierarchy into account. It will need to accept a batchId argument because not all features have the same properties anymore. Or this doesn't change and just continues to check only base-level batch table properties (like area and height in the sample below).

We can brainstorm in person, but ideally we can expose each feature's full set of properties just like C++ inheritance puts everything into the derived class. If there are real performance or synchronization problems, maybe we would rely on the user being able to get parent classes and read/write those properties.

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 8, 2016

For parity with the styling language the Cesium API could include functions like

  • getFeaturesByProperty(propertyName, value)
  • getFeaturesByClass(className)
  • There can be many variants to these. It may be best to leave these out of the Cesium API and let the apps themselves do this checking.

Let's roadmap these; I suspect they will be useful, but let's wait until requested and perhaps they will be good beginner issues or external contributions.

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 8, 2016

Recognize cyclical dependencies? Or let validator point that out?

We probably have to detect this in Cesium (and in the validator); for example, we do this for shaders: https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Renderer/ShaderSource.js#L129

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 8, 2016

Think about supporting for GLSL backend

Let's discuss in person when you are ready, but I think it can be done by storing class info in the batch table; we need to think through the memory usage.

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 8, 2016

Should hierarchy properties exist in the tileset.json properties section?

I suspect all properties should be listed there. We may need to update the wording in the spec to clarify this.

Currently a parentId of -1 signifies no parent. However this makes it harder to store the parentIds in binary unless the only allowed componentType are SHORT or INT.

Maybe use MAX_TYPE, but I suspect that will be error prone for both the client and server.

There could also be a dummy parent (all classes inherit from Class) that is index 0.

Let me know if you want to discuss in person.

Is it useful to have a ${CLASS} property for styling? This would allow regular expressions against the class name. Or is isClass good enough?

${CLASS} is likely useful for the gmail labels use case where there could be a ton of labels.

If it is not hard to implement, I suggest we do it.

Should a feature be able to set a property of its ancestor's class. Say the feature is a door, should feature.setProperty('building_name', 'new_name') be allowed? Currently this is supported in the code and is probably ok because otherwise we would need some other interface to represent abstract instances - like an analog to Cesium3DTileFeature, and that can get complicated.

This is what I meant above:

We can brainstorm in person, but ideally we can expose each feature's full set of properties just like C++ inheritance puts everything into the derived class. If there are real performance or synchronization problems, maybe we would rely on the user being able to get parent classes and read/write those properties.

We need to think through basically if each derived class gets a copy of its parent's properties or not. It sounds like no in the current implementation. That could be fine, but let's discuss in person to consider all the use cases.

@@ -369,13 +431,103 @@ define([
return names;
};

Cesium3DTileBatchTable.prototype.isDerived = function(batchId, className) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is called per feature when applying a style, right?

It could be a hot spot for tilesets with deep feature hierarchies. I don't think it is worth changing now, but perhaps add a PERFORMANCE_IDEA that we could cache the results in the derived classes if the memory usage is worth it (and replace the string with one string->integer and then integer compares if that is faster).

@@ -338,6 +338,22 @@ define([
}
val = createRuntimeAst(expression, args[0]);
return new Node(ExpressionNodeType.UNARY, call, val);
} else if (call === 'isClass') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we reduce some of the duplication here?

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 8, 2016

Looking good so far. Love the Sandcastle example.

@lilleyse
Copy link
Contributor Author

lilleyse commented Nov 9, 2016

Did you have alternatives perhaps borrowed from popular OO languages? isExactClass and isClass come to mind but better names may exist.

Ruby has instance_of to represent isExactClass and kind_of/is_a to represent isClass.

Java has obj.getClass().equals(Foo.class) for isExactClass and instanceof/isInstance for isClass.

C# is somewhat similar to Java

At this point I'm fine with using isExactClass and isClass

Think about supporting for GLSL backend

Thinking some more, I don't believe this is needed in the GLSL backend. For points at least, it would seem kind of overkill to store class ids and parent ids for every point. If someone needs to represent hierarchies within point clouds they can create a batched point cloud (setting BATCH_ID in the feature table), which uses Cesium3DTileBatchTable under the hood and not the GLSL backend.

Maybe use MAX_TYPE, but I suspect that will be error prone for both the client and server.
There could also be a dummy parent (all classes inherit from Class) that is index 0.

As discussed offline, we may try something else. Instead of using -1, if the parent id equals itself then it does not have a parent. This allows unsigned types to be used and is possibly simpler than a dummy at index 0.

${CLASS} is likely useful for the gmail labels use case where there could be a ton of labels.

Instead this may become a built-in function, like getClassName.

We need to think through basically if each derived class gets a copy of its parent's properties or not. It sounds like no in the current implementation. That could be fine, but let's discuss in person to consider all the use cases.

Yes, the current implementation does not create copies.

We can brainstorm in person, but ideally we can expose each feature's full set of properties just like C++ inheritance puts everything into the derived class. If there are real performance or synchronization problems, maybe we would rely on the user being able to get parent classes and read/write those properties.

Supporting .parent and .children along with a Cesium3DTileInstance type class seems doable. This would act similar to the existing system, but in a more organized way, but also more complexity. I want to wait a bit on this though in case I have other ideas.

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 9, 2016

All sounds good, except:

Thinking some more, I don't believe this is needed in the GLSL backend. For points at least, it would seem kind of overkill to store class ids and parent ids for every point. If someone needs to represent hierarchies within point clouds they can create a batched point cloud (setting BATCH_ID in the feature table), which uses Cesium3DTileBatchTable under the hood and not the GLSL backend.

So point cloud users would use BATCH_ID to emulate a hierarchy batch table? Instead, could the hierarchy batch table replace the BATCH_ID.

If not, update CesiumGS/3d-tiles#140 with this limitation.

@lilleyse
Copy link
Contributor Author

lilleyse commented Nov 9, 2016

So point cloud users would use BATCH_ID to emulate a hierarchy batch table? Instead, could the hierarchy batch table replace the BATCH_ID.

More like, the BATCH_ID attribute and batch table hierarchy work together just like it would for batched models.

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 9, 2016

More like, the BATCH_ID attribute and batch table hierarchy work together just like it would for batched models.

If I understand correctly, your saying that the Cesium implementation falls back to the JavaScript backend in this case so it just works?

@lilleyse
Copy link
Contributor Author

lilleyse commented Nov 9, 2016

Yes

@lilleyse lilleyse force-pushed the batch-table-hierarchy branch from c3b463e to d70d618 Compare November 15, 2016 21:02
@lilleyse
Copy link
Contributor Author

Updated based on the initial round of comments. It now supports multiple parents. In the process I generalized the hierarchy traversal and added back hasProperty and getPropertyNames both of which now require a batchId parameter.

classifier

building0 has two parents - zone0 and classifier_new
buiding1 has two parents - zone0 and classifier_old
building3 has three parents - zone0, classifier_new, and classifier_old

{
    "color" : {
        "conditions" : [
            ["isClass('classifier_new') && isClass('classifier_old')", "color('purple')"],
            ["isClass('classifier_new')", "color('red')"],
            ["isClass('classifier_old')", "color('blue')"],
            ["true", "color()"]
        ]
    }
}

Sample JSON:

{
    "HIERARCHY": {
        "instancesLength": 36,
        "classes": [
            {
                "name": "doorknob",
                "length": 12,
                "instances": {
                    "doorknob_size": [0.3, 0.43, 0.32, 0.2, 0.21, 0.35, 0.3, 0.23, 0.43, 0.32, 0.41, 0.33],
                    "doorknob_name": ["doorknob0", "doorknob1", "doorknob2", "doorknob3", "doorknob4", "doorknob5", "doorknob6", "doorknob7", "doorknob8", "doorknob9", "doorknob10", "doorknob11"]
                }
            },
            {
                "name": "door",
                "length": 12,
                "instances": {
                    "door_mass": [10, 11, 14, 7, 8, 12, 3, 6, 3, 5, 9, 10],
                    "door_width": [1.2, 1.3, 1.21, 1.5, 1.1, 1.15, 1.32, 1.54, 1.8, 2, 2.1, 1.3],
                    "door_name": ["door0", "door1", "door2", "door3", "door4", "door5", "door6", "door7", "door8", "door9", "door10", "door11"]
                }
            },
            {
                "name": "roof",
                "length": 4,
                "instances": {
                    "roof_paint": ["red", "blue", "yellow", "green"],
                    "roof_name": ["roof0", "roof1", "roof2", "roof3"]
                }
            },
            {
                "name": "wall",
                "length": 4,
                "instances": {
                    "wall_paint": ["pink", "orange", "blue", "gray"],
                    "wall_windows": [1, 2, 4, 2],
                    "wall_name": ["wall0", "wall1", "wall2", "wall3"]
                }
            },
            {
                "name": "building",
                "length": 4,
                "instances": {
                    "building_area": [20, 21.98, 39.3],
                    "building_name": ["building0", "building1", "building2"]
                }
            },
            {
                "name": "zone",
                "length": 1,
                "instances": {
                    "zone_buildings": [4],
                    "zone_name": ["zone0"]
                }
            },
            {
                "name": "classifier_new",
                "length": 1,
                "instances": {
                    "year": [2000],
                    "color": ["red"],
                    "name": ["project"],
                    "architect": ["architect"]
                }
            },
            {
                "name": "classifier_old",
                "length": 1,
                "instances": {
                    "description": ["built in 1980"],
                    "inspection": [2009]
                }
            }
        ],
        "classIds": [0, 0, 0, 0, 1, 1, 1, 1, 2, 3, 0, 0, 0, 0, 1, 1, 1, 1, 2, 3, 0, 0, 0, 0, 1, 1, 1, 1, 2, 3, 4, 4, 4, 5, 6, 7],
        "parentIds": [4, 5, 6, 7, 30, 30, 30, 30, 30, 30, 14, 15, 16, 17, 31, 31, 31, 31, 31, 31, 24, 25, 26, 27, 32, 32, 32, 32, 32, 32, 33, 34, 33, 35, 33, 34, 35],
        "parentCounts": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 3, 0, 0, 0]
    },
    "height": [0.1, 0.1, 0.1, 0.1, 5, 5, 5, 5, 6, 10, 0.1, 0.1, 0.1, 0.1, 5, 5, 5, 5, 6, 10, 0.1, 0.1, 0.1, 0.1, 5, 5, 5, 5, 6, 10],
    "area": [0.2, 0.2, 0.2, 0.2, 10, 10, 10, 10, 12, 20, 0.2, 0.2, 0.2, 0.2, 10, 10, 10, 10, 12, 20, 0.2, 0.2, 0.2, 0.2, 10, 10, 10, 10, 12, 20]
}

@lilleyse
Copy link
Contributor Author

This is ready with the exception of Support updates across multiple tiles which is very involved and possibly not feasible to support.

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 22, 2016

If the marker is reset then the array also needs to be reset, which I'm trying to avoid. Rather than resetting I just increment it so on the second call tiles that are visited are marked 2, on the third call they are marked as 3, etc.

Is the array likely to grow very large over time?

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 22, 2016

I can't think of a great way that doesn't involve closures since name has to get the the function in same way. Possibly using scratch options objects and pass that to traverseHierarchy as a third parameter would work, but is not as clean.

OK, just leave it. We can reevaluate if needed.

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 22, 2016

Will aim to do another review tomorrow.

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 23, 2016

This is ready with the exception of Support updates across multiple tiles which is very involved and possibly not feasible to support.

OK for now since this is only a Cesium API issue.

What is the state of this? I would be OK with all classes being readonly in the Cesium API so the only thing that can change is the leaf nodes, which are the actual features.


//>>includeStart('debug', pragmas.debug);
function validateHierarchy(hierarchy) {
var stack = scratchStack;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would caution against using scratchStack here since it will have different debug/release usage and could lead to subtle bugs when new code is written. To make the validation code self-contained just use a different scratch for it.

if (defined(propertyValues.typedArray)) {
return getBinaryProperty(propertyValues, indexInClass);
}
return clone(propertyValues[indexInClass], true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and below, what is the context in which this is call? Is the memory allocation in clone OK?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I modeled this after getProperty. I believe the idea is that we don't want to make batch table properties that are objects editable via the getProperty function.

if (!defined(name)) {
throw new DeveloperError('name is required.');
}
//>>includeEnd('debug');

var json = this.batchTableJson;
return defined(json) && defined(json[name]);
if (defined(json) && defined(json[name])) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style but why not write this entire block as

return (defined(json) && defined(json[name]) || (defined(this._batchTableHierarchy) && hasPropertyInHierarchy(this, batchId, name));

Or at least change the last block to just:

return (defined(this._batchTableHierarchy) && hasPropertyInHierarchy(this, batchId, name));

@@ -55,7 +55,7 @@ define([
asin : Math.asin,
atan : Math.atan,
radians : CesiumMath.toRadians,
degrees : CesiumMath.toDegrees
degrees : CesiumMath.toDegrees,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra comma?


addStyle('No style', {});

addStyle('Color by building', {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an example using getClassName?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, I think this example needs more context; it is a bit hard to hack on without knowing what the semantic hierarchy looks like. Perhaps there should be comments in this example with similar info to what you put in the opening comment of this PR.

//>>includeEnd('debug');
val = createRuntimeAst(expression, args[0]);
return new Node(ExpressionNodeType.UNARY, call, val);
} else if (call === 'getClassName') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Throughout, should this be called getExactClassName?

@pjcozzi
Copy link
Contributor

pjcozzi commented Nov 23, 2016

Looking good, just those comments!

@lilleyse
Copy link
Contributor Author

Is the array likely to grow very large over time?

Not too large. At most the size of the array will equal the tile with the most instances.

What is the state of this? I would be OK with all classes being readonly in the Cesium API so the only thing that can change is the leaf nodes, which are the actual features.

This might be a good idea... I'm okay with the keeping the code as it is now since it gives a little bit more flexibility within the tile. But if others are confused that setting hierarchy properties don't apply to different tiles then it may be worth making it read only.

@lilleyse
Copy link
Contributor Author

Updated.

@pjcozzi
Copy link
Contributor

pjcozzi commented Dec 12, 2016

What is the state of this? I would be OK with all classes being readonly in the Cesium API so the only thing that can change is the leaf nodes, which are the actual features.

This might be a good idea... I'm okay with the keeping the code as it is now since it gives a little bit more flexibility within the tile. But if others are confused that setting hierarchy properties don't apply to different tiles then it may be worth making it read only.

OK, let's go with readonly. Freeze it too. Will this remove the clone, #4625 (comment)

@pjcozzi
Copy link
Contributor

pjcozzi commented Dec 12, 2016

Is the array likely to grow very large over time?

Not too large. At most the size of the array will equal the tile with the most instances.

That's actually kind of a lot - could be, for example, 50,000. Assuming there is no reasonable way around this, please add a comment about the potential bounds.

@lilleyse
Copy link
Contributor Author

OK, let's go with readonly. Freeze it too. Will this remove the clone, #4625 (comment)

The whole hierarchy can't be frozen since you are still allowed to set properties on an instance's own class. Clone still needs to exist just like it does with the normal setProperty. I'm now just throwing a developer error if it detects that you are setting an inherited property.

@lilleyse
Copy link
Contributor Author

This is ready.

@pjcozzi
Copy link
Contributor

pjcozzi commented Dec 13, 2016

Very nice, looking forward to the spec updates

@pjcozzi pjcozzi merged commit 1b440ff into 3d-tiles Dec 13, 2016
@pjcozzi pjcozzi deleted the batch-table-hierarchy branch December 13, 2016 17:24
@Dylan-Brown Dylan-Brown mentioned this pull request Dec 15, 2016
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants