-
Notifications
You must be signed in to change notification settings - Fork 470
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
Declarative styling #2
Comments
The immediate need for declarative 3D Tiles styling is to be able to write a simple expression that maps a feature's property (or properties) value to its appearance (initially,
There's early implementation work in Cesium's 3d-tiles-style branch. The styling format is JSON, and the schema is not at all final. Here's a few examples: // Show all buildings greater than 10 meters tall, e.g., `${Height} > 10`
{
"show" : {
"leftOperand" : "${Height}",
"operator" : ">",
"rightOperand" : 10
}
} // Create a color ramp with the provided palette based on the number of floors in a building
{
"color" : {
"expression" : { // Will make this less verbose soon, just ${Floors}
"leftOperand" : "${Floors}",
"operator" : "+",
"rightOperand" : 0
},
"intervals" : [
1, // [1, 10)
10, // [10, 19)
20 // [20, infinity)
],
"colors" : [
[237, 248, 251],
[158, 188, 218],
[129, 15, 124]
]
}
} // Map a feature's ID to a color
{
"color" : {
"propertyName" : "id",
"map" : {
"1" : [255, 0, 0],
"2" : [0, 255, 0]
},
"default" : [255, 255, 255]
}
} In Cesium, a style can be applied to a tileset.style = new Cesium.Cesium3DTileStyle(tileset, styleJson); Creating the After the style is compiled, it can be changed, e.g., tileset.style.show.operator = '==='; Feature properties that may impact how the style is evaluated can also be changed, e.g., feature.setProperty('id', 1); In addition to declarative styling, the lower-level API can be used to override the appearance of individual features, e.g., var feature = scene.pick(movement.endPosition);
if (Cesium.defined(feature)) {
feature.color = Cesium.Color.YELLOW;
} Schema Ideas
Related-ish
|
I'd much rather use a concise syntax (e.g. "{Height} > 100") than individual properties, which would get really messy for complex rules. A simple parser can transform the concise syntax into the equivalent structure in a precompilation step. Something that I could see being used is also the ability to specify styling programmatically, so maybe define an abstract "Cesium3DTileStyleFormatter" interface in Cesium that can be implemented by the developer to specify the styling at runtime, e.g.: var sf = new MyStyleFormatter();
// ...
tileset.style = new Cesium.Cesium3DTileStyle(tileset, sf); Where MyStyleFormatter implements: show: function(tile){
return tile.Height > 100;
} It could be useful to do things like: color: function(tile){
return new StaticColor(Math.random() * 255, Math.random() * 255, Math.random() * 255);
} To color buildings at randoms (and other possibilities). In fact a JSON style could be a special case of programmatic styling: var sf = new JsonStyleFormatter(styleJson);
// ...
tileset.style = new Cesium.Cesium3DTileStyle(tileset, sf); |
Thanks for the input, @pierotofy. We definitely want to support custom functions for expressions, and, I agree, will most likely go with the concise syntax. Thanks for the code snippets! |
This is one area where I think Cesium's current Property system can be On Fri, Feb 5, 2016 at 10:16 AM, Patrick Cozzi notifications@github.com
|
Update #2 (comment) to account for the latest implementation work and offline discussion with @mramato. |
The styling spec will be in the 3d-tiles/spec branch (just a placeholder for now). I'll bootstrap the prose/schema writing as things start to solidify. |
Notes on parsers
We'll start with jsep. |
Notes on expressionsNow
"show" : true // Boolean literal "show" : !false // Unary NOT "show" : true && true // Logical AND "show" : false && true // Logical AND, short-circuit "show" : false || true // Logical OR "show" : true || false // Logical OR, short-circuit "show" : (false && false) || (true && true) "show" : true ? true : false // Conditional, short-circuit-ish "show" : false ? false : true // Conditional, short-circuit-ish "show" : 2 > 1 // And similiar for <, <=, >=, ===, !=== "show" : 0 > -1 // Unary NEGATE "show" : (1 + 1) > 1 // *, /, % // For now, do not support:
// * Unary: ~, +
// * Binary : |, ^, &, ==, !=, <<, >>, >>>
// * Expressions
// * Array, e.g., [1, 2]
// * Compound, e.g., 1; 2; 3
// * Member, e.g., feature.name // might need this soon
// * This, e.g., this
// See node types, operations, and literals in the annotated source: http://jsep.from.so/annotated_source/jsep.html "show" : "${SomeFeatureProperty}" // Feature property is a boolean "show" : "${ZipCode} === 19341" // Variable equals number "show" : "${Temperature} > 100" "show" : "(${Temperature} > 100) && ((${Weight} / ${Area}) > 2.0)" "show" : "${County} === 'Chester'" // Property name equals string "show" : "${County} === regExp('/^Chest/')" // String compare with RegEx. Open to other syntax "show" : "${County} !== null" // I guess we should support null, what about undefined? "show" : 1 // Convert number to boolean I suppose // CSS colors
"color" : "#EAA56C"
"color" : "cyan"
"color" : "rgb(100, 255, 190)"
"color" : "hsl(250, 60%, 70%)" "color" : "(${Temperature} === 'hot') ? 'red', '#ffffff'" "color" : "rgb(255, 0, 0, (${Visible} ? 255 : 0))" "color" : "rgb(${red}, ${green}, ${blue}, 255)" // Number properties "color" : "rgb(${red} * 255, ${green} * 255, ${blue} * 255, 255)" // Convert 0..1 to 0..255 |
For RegEx syntax we could also use (borrowed from Perl/Ruby): "show" : "${County} =~ /^Chest/" // Matches
"show" : "${County} !~ /^Chest/" // Does not match null and undefined should probably be both supported (and enforce strong typing): "show" : "${County} !== null && ${Country} !== undefined"
"show" : "${County} !== null" // Does not match undefined values
"show" : "${County} !== undefined" // Does not match null values I would vote in favor of not allowing casts from numbers to bools, just to enforce better code practices, but it's not a big deal if they are allowed. "show" : "1" // Error: "Expected bool, got number"
"show" : "${param} === 1" // OK |
Thanks @pierotofy, @ggetz is starting the design/implementation now. We'll look at these cases; I'm not sure about introducing |
@ggetz check out the new Color section in the styling spec and let me know what you think about the TODOs (just open PRs for them) and please make sure our implementation and spec are in-sync and that we reasonably covered the edge cases. |
I added my comments in #70 |
@ggetz there is a new section on conversions. Please make sure to test all possible Note that we have to add a |
@ggetz for strings, make sure we parse both |
@ggetz are we in-sync with this:
|
I looked more at this. Just |
@ggetz do you want to design the regex support? |
Yes this is implemented |
Sure |
@ggetz is there anything here critical for 1.0? |
Is there anyway to color based on whether the lat & lng are within a polygon? |
@ronanmcnulty It sounds like classification might fit your use case better. |
Were custom functions for expressions ever implemented @pjcozzi ? I'm attempting to color a point cloud by elevation but there's no height attribute for point clouds. |
@ThornM9 no but there may be another way to achieve your use case, the best place to ask is the Cesium forum: https://groups.google.com/forum/?hl=en#!forum/cesium-dev |
I noticed that atan2(y,x) is more inaccurate than atan(y/x). (While atan(y/x) only works for x > 0 of course). In my particular use case I used the atan2 function to compute the longitude of points in the tileset. The resulting longitude from atan2(y, x) was off by about 0.00001 (ca. 10 meters), while it looked perfect with atan(y/x). Unfortunately I don't know how to tell you the exact resulting numbers since they are only in the GPU I guess, I can only give this estimate from what it looks like. My cesium version is 1.63, however this was reproducable in a sandcastle. |
See #179 for optimizing large number of conditional expressions. |
See #239 for batching vector images into a texture atlas that's part of the payload |
See #252 for mutables (like GL uniforms) |
See #266 for styling alpha separately |
See #268 for accessing feature ids in the styling language |
See #292 for accessing instanced attributes in the styling language |
More considerations for 3D Tiles Next:
|
Short-Term
Spec
@ggetz
@pjcozzi
Cesium Implementation
@ggetz
BooleanExpression
,NumberExpression
, and friendsCesium3DTileStyle
(and implicitly forCesium3DTileStyleEngine
)styleEngine
last to constructors (and make it optional?)ColorRampExpression.computeEvenlySpacedIntervals
)@pjcozzi
Later
Spec
JulianDate
datatype to support styling with date/time metadataColor
so why not here?), see Declarative styling #2 (comment)${foo[${memberName}]}
distance
czm_time
,czm_inShadow
, etc.interval
to optimizeconditional
when used for intervalsProperty
system, e.g., evaluate expressions asProperty
or vice-versa.Cesium Implementation
Cesium3DTileStyle
and friends for users writing their own styles.replaceVariables
inExpression.js
?Built-in functions
The text was updated successfully, but these errors were encountered: