A payday lender loans you $200 with a $30 fee, to be paid back in 2 weeks. If you don't pay it back in 2 weeks, you'll be charged another $30 fee, and another $30 for each 2 weeks after that.  What is the expected value of the loan for the lender?


You can access Indonesian Beat Saber Multiplayer Server from:
https://bsrepo.sena.dev/CompatibleServers.json


Will update…
ha… homepage… I want to go home
Corey, originally from Allentown, Pennsylvania, is a Biomedical Engineering PhD student at UVA. He attended the University of Pittsburgh, earning a BS in Bioengineering and a minor in Chemistry. His research focuses on in vitro cardiomyocyte differentiation and its relation to embryonic heart development.


People from Tulsa, in Oklahoma, can clearly see values substituted into the text.
People from Demoines, in Iowa, can clearly see values substituted into the text.
 Please vote for cherry, blueberry, peach, almond, as the best flavors.| Tulsa | is better than | Tulsa | for cherry |
| Tulsa | is better than | Tulsa | for blueberry |
| Tulsa | is better than | Tulsa | for peach |
| Tulsa | is better than | Tulsa | for almond |
| Tulsa | is better than | Demoines | for cherry |
| Tulsa | is better than | Demoines | for blueberry |
| Tulsa | is better than | Demoines | for peach |
| Tulsa | is better than | Demoines | for almond |
| Demoines | is better than | Tulsa | for cherry |
| Demoines | is better than | Tulsa | for blueberry |
| Demoines | is better than | Tulsa | for peach |
| Demoines | is better than | Tulsa | for almond |
| Demoines | is better than | Demoines | for cherry |
| Demoines | is better than | Demoines | for blueberry |
| Demoines | is better than | Demoines | for peach |
| Demoines | is better than | Demoines | for almond |


Having trouble figuring out your triangles try this tracker...Put your triangles back on track. Enter your values and be ready to go!!!!
Hey just click to checkout your triangle.


You got many ways to use, depending of your modules builds standards system you use or not. I anticipated three cases for you!: CommonJs (Node/browserify), AMD (require JS) and Global.windows.
You have to :
- Install the package in your project (command line)
npm install chronoCanvas
- require it in a js file, foo.js
for example.
var chronoCanvas = require('chronoCanvas');
- execute commonJS task (here with browserify)
browserify dev/foo.js --outfile prod/bar.js
- include the output file in your front page.
<script type="text/javascript" src="prod/bar.js"></script>
And then you can use it and customise as here
You have to :
- Install the package in your project (command line)
npm install chronoCanvas
- Download and include requireJs.js in your web page.
<script type="text/javascript" src="requireJs.js"></script>
- In a script you call whatever you want (foo.js
in the example), require the package with require AMD command.
require(['chronoCanvas.js'], function(chronoCanvas){
... Your code here...
})
- include this script (after requireJs.js call).
<script type="text/javascript" src="foo.js"></script>
You have to download (via npm or not) at least index.js
from the package, and include it on your webpage.
<script type="text/javascript" src="chronoCanvas/index.js"></script>
- And then, use it in the js you want (online or external file) with object ChronoCanvas. Don't forget event handler!
document.addEventListener('DOMContentLoaded', function(){
chronoCanvas({
canvasTarget: yournode string
});
})


{% extends "admin/skeleton.html" %} {% block title %}Devices{% endblock %} {% block head %} {% endblock %} {% block content %}
To find the devices for a particular user, enter their email address below, then click “Search”.
Send this user a message:


Employee Details
Meal Selection
Defaulters
Student ID:
Store name:
Food Menu
Product Name
Quantity
Price
Total Price
Operation
{{item.Name}}
{{item.price | currency}}
{{item.price * item.quantity | currency}}
Add to cart
Total Cost: {{total}}


{% extends "mvo/voterreg_area.html" %} {% block pagetitle %}Nominees for {{ long_award_name }}{% endblock %} {% block content %} {% include "mvo/awards_banner.html" %} {{ long_award_name }} To learn more about the nominees just click on their name below. Then click the Facebook "Like" button to cast your vote. Feel free to vote for as many candidates as you wish! {% for nom in nominees %} {{ nom.name|capfirst|safe }} {% comment %}{% endcomment %} {% endfor %} Submit a nominee {% endblock content %}
To learn more about the nominees just click on their name below. Then click the Facebook "Like" button to cast your vote. Feel free to vote for as many candidates as you wish!


Code listing for: ZRA12_05
Description: Local class exercise
*&---------------------------------------------------------------------*
*& Report ZRA12_05
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
include zra12_05top. " Global Data
include zra12_05s01. " Selection Screen
include zra12_05c01. " Class
*INCLUDE zra12_05o01 . " PBO-Modules
*INCLUDE zra12_05i01 . " PAI-Modules
include zra12_05f01. " FORM-Routines
**********************************************************************
* INITIALIZATION.
**********************************************************************
INITIALIZATION.
PERFORM set_init_value.
**********************************************************************
* START-OF-SELECTION.
**********************************************************************
START-OF-SELECTION.
PERFORM exec_inst_method. " Execute instance method.
PERFORM exec_static_method. " Execute static instance method.
** Using global calss
PERFORM global_book_info. "Global instance method
PERFORM global_flight_info. "Global static method
*Text elements
*----------------------------------------------------------
* T01 condition
*Selection texts
*----------------------------------------------------------
* P_CARRID D .
Extracted by Direct Download Enterprise version 1.3.1 - E.G.Mellodew. 1998-2005 UK. Sap Release 751


Please select your desire court
Tennis Court 1
Tennis Court 2
Tennis Court 3
Tennis Court 4
Tennis Court 5
Tennis Court 6
Submit


DigiByte is a rapidly growing open-source blockchain created in late 2013 and released in early 2014. After 9 years of forward thinking development, DigiByte has become one of the safest, fastest, longest and most decentralized UTXO blockchain in existence.
The three layers are the most innovative parts of the DigiByte blockchain providing the network infrastructure, security and communications to function with cutting edge speed.
The top layer is like an app store with clear real-world uses. All types of digital assets can be created with the DigiAssets protocol on top of the DigiByte blockchain. Decentralized applications (dApps) can be built on top of the DigiByte blockchain. Also smart contracts that leverage the rigidity and security of the DigiByte blockchain can be encoded easily.
The middle layer provides security and administration. A Digital Byte of data, a representation of larger data or a unit that holds value, and cannot be counterfeited, duplicated or hacked. An immutable public ledger where all transactions of DigiBytes are recorded. DigiByte uses five proof of work algorithms for security. New DigiBytes come from mining only.
The bottom layer provides communication and operating procedures. A very low-level way nodes on the DigiByte global network communicate. Thousands of people are running DigiByte software all across the planet. Any server, computer, tablet or mobile phone connected to the DigiByte network becomes a node that helps relay transactions. Start contributing to the DigiByte blockchain in the optimal way.
Just like this website, the DigiByte blockchain is completely open source and free to use released under the MIT license, which gives you the power to run and modify the software. Transparency allows for independent verification of binaries and their corresponding source code.
DigiByte Protocol on GitHub.
DigiByte Core Development on GitHub.
Discover the major development milestones of the DigiByte blockchain.
DigiByte (DGB) is a highly scalable peer-to-peer digital currency that enables industry-leading transaction speeds with negligible fees. DigiByte is the best means of making digital payments.
Getting started to use DigiByte is even easier than sending an SMS. You can send and receive DigiBytes using the devices you already know and love. All you need is installing a DigiByte supported wallet then click scan, scan the QR code and send DigiByte. As easy as 1..2..3.
DigiByte has never been funded through an ICO or significant amount of premined coins (0% remaining). There is no CEO or a company controlling the DigiByte blockchain. The founder, developers and the community are unpaid volunteers that eliminate the bankrupt risk.
DigiByte has been built on the uncrackable technology of the Bitcoin blockchain and implemented various advanced enhancements over it such as DigiShield guard, MultiAlgo mining and the Odocrypt algorithm. Also Dandelion++ privacy protocol helps keep you safe by hiding your IP and physical location. Learn more.
DigiByte is a 100% Proof of Work (PoW) blockchain that can be mined with five algorithms called Sha256, Scrypt, Skein, Qubit and Odocrypt. MultiAlgo mining contributes to decentralization, security of the network and gives you the freedom to use different kind of hardware's such as an ASIC a FPGA or a GPU. Learn more.
Compared to 21 million Bitcoin, 21 billion DigiByte (1000:1 ratio to BTC) have been designed to be ready for mass adoption. DigiByte block rewards reduces by 1% every month instead of halving every 4 years. All 21 billion DigiByte will be mined by the year 2035. After 2035 the miners will then rely on transaction fees alone. Learn more.
All exchanges and services that support DigiByte can be found on the DigiByte Wiki.
Exchange Disclaimer
The exchanges introduced here or on CoinMarketCap are for informational purposes only and they are not affiliated with the DigiByte community. Any exchange can list DigiByte without permission. Please always do your own research before using them, then store your DGB on a personal wallet.
DigiAssets is a secure, scalable layer on top of the DigiByte blockchain that allows for the decentralized issuance of digital assets, tokens, smart contracts, digital identity and more.
DigiAssets can be used to securely represent anything we find in the physical world. From tangible assets such as real estate or cars, through to scarce digital pieces of art. Signed documents such as deeds and medical bills can be protected.
DigiAssets as an ecosystem and platform already has interested parties either planning on or currently building platforms in real estate, finance, remittance, identity, point of sale, racing, trade, healthcare, supply chain, government and more.
DigiAssets leverages unique aspects of a truly decentralized blockchain only found within a permissionless blockchain like DigiByte. This allows DigiAssets to be more secure, scalable and decentralized than any other platform in the market.
Discover the open-source DigiAssets protocol specifications for detailed information about issuing and transacting digital assets on top of the DigiByte Blockchain. DigiAssets Protocol on GitHub.
Not a developer? Definitely not a problem! Anyone can easily issue a DigiAsset by using one of the tools available without having technical knowledge about the protocol. DigiAssets supported services.
Wondering how to use DigiAssets? Use the DigiByte Mobile application to send, accept and store your assets or explore the DigiAssets supported services to buy, sell and swap DigiAssets.
Do you need more assistance about DigiAssets? Please feel free to join the DigiByte Developers group on Telegram to ask your questions or share your ideas. DigiByte Developers on Telegram.
Discover DigiAssets supported services to experience DigiAssets.
Digi-ID is a security protocol built on DigiByte blockchain technology that empowers users to effortlessly sign-in to websites, applications, and even into the internet of things.
Digi-ID eliminates the username, password and 2fa requirements for authentication. Because Digi-ID uses public / private key cryptography, there are no passwords or usernames at risk. This method not only protects the consumer, it also protects the services that the consumer uses.
Digi-ID does not store any data about its users on the DigiByte blockchain. This further strengthens the security while also bolstering end-user’s confidence that their data is neither tracked nor at risk by others negligence. There is no external point of failure for an hacker to exploit your platform.
Digi-ID is completely free! There are no fees, subscription services, or maintenance costs. But the cost is its second best feature. Its primary feature is that, in accordance with DigiBytes security prioritization, Digi-ID is a more secure, yet simple method available to log in to websites, apps and more.
The website, application or product generates a unique Digi-ID QR code and presents it.
The user scans the QR code from the DigiByte Mobile or any Digi-ID supported app.
The user authenticates the request by entering their app PIN code or scanning their fingerprint/face.
Digi-ID sends the cryptographically-signed request back and the user is successfully logged in.
The best place to start is Digi-ID.io. If you want to know more about the details and advantages of Digi-ID, you can refer to the user guide, vendor guide or integration guide. If you are looking for the media kit, please get the intro sheet and logos.
Since Digi-ID is open-source, multiple code repositories can be found on GitHub such as DigiByte Core Development , Matthew Cornelisse and WHMCSSnow. If you need more assistance please join the DigiByte Developers group on Telegram.
If you are not a developer, you may want to use integration ready solutions for your website or product. digiassetX provides a nodejs plugin for easy integration. You can also use the WordPress plugin for the WordPress platforms.
Of course! Digi-ID is a rapidly growing platform. Multiple standalone authenticator apps and Digi-ID supported wallets can be found at the Downloads section.
Discover Digi-ID supported services to experience seamless authentication.
Thousands of volunteers from all over the world have contributed to DigiByte in countless ways for years to make it what it is today. It is a truly grassroots movement. We warmly welcome you to join us!
The DigiByte Foundation is a volunteer managed organization that operates in a non-profit way. They protect and promote the true principles of decentralization and empower DigiByte and its community to establish and maintain a sustainable decentralized world.
Learn more - Donate - Contact.
The DigiByte Alliance is a public non-profit foundation under section 501(c)(3) with public charity status in the US. They aim to solidify DigiByte as a trusted and decentralized blockchain network to reliably and efficiently protect, secure, express, create, and transfer value.
Learn more - Contact.
DGBAT is a community-driven outreach initiative. They are led by a team, whose members in turn manage teams across social media, outreach, education, writers and developers. They aim to promote the DigiByte blockchain through education, outreach and marketing campaigns.
Learn more - Donate - Contact.
Everyone that is working on the DigiByte blockchain is an unpaid volunteer who devoted their time and skills to a project they believe in. Start contributing to the DGB development today or build your own app on top of the DigiByte blockchain.
DigiByte Developers on Gitter.
DigiByte Core Protocol on GitHub.
Telegram is the most popular and simple way to engage with the global DigiByte community. Please join the groups below which you are interested in or see the list of all DigiByte groups.
Alerts Discussion Support Developers Mining Marketing Speculation Translations
The DigiByte Wiki is an online encyclopedia built by the community, for the community. It contains useful and up to date data such as the DigiByte Ecosystem and how to guides. Anyone can positively contribute to the Wiki by creating a free user account and start adding or updating information on the DigiByte Wiki.
Warning Avoid shameless self-promotion and referral links.
Jared Tate is the founder and creator of the DigiByte blockchain. Jared dedicated full-time development towards DigiByte since October 2013. He has been invited by MIT, Harvard and the US Capitol to speak on blockchain tech. He is also the co-author of the book Blockchain 2035 The Digital DNA of Internet 3.0, which is the first book written by a blockchain founder.
Social Media Disclaimer
The personal opinion, beliefs and viewpoints expressed by Jared Tate, DigiByte Core Team, DigiByte Foundation & DigiByte Awareness Team do not necessarily reflect the personal opinion, beliefs and viewpoints of the community.
Donate to DigiByte organizations or use services below to support us.
Select an application to send, accept and store your DigiByte & DigiAssets or securely authenticate by using Digi-ID.
Current DigiByte Core v7.17.3
DigiByte Core contains a full copy of the blockchain and builds the backbone of the network. However, it needs a lot of disk space, high memory usage and long sync time. If you are not an experienced user, you may want to use a simplified software wallet.
DigiByte Core
Available for Windows, macOS, Linux & Snapcraft (64 Bit only)
DigiByte Mobile
Available for iOS & Android
TestFlight Android Beta
Looking for more documentation? Whether you need basic information for an article or technical information for an integration process. You can reach all the necessary guides below.
Wallet Disclaimer
All the Third-Party wallets introduced here are hosted by their own servers or application stores. We have no responsibility for possible issues you may have about any Third-Party wallet. In such case you should contact the related wallet's support service.
Social media.
Follow DigiByte across all primary social media platforms to keep up with the latest DigiByte news and share the posts with your friends to help us make our voices heard all over the world.


{% extends "withnav_template.html" %} {% from "service_navigation.html" import broadcast_service_name_tag %} {% from "components/page-header.html" import page_header %} {% from "components/page-footer.html" import page_footer %} {% from "components/form.html" import form_wrapper %} {% from "govuk_frontend_jinja/components/back-link/macro.html" import govukBackLink %} {% block service_page_title %} Confirm emergency alert settings {% endblock %} {% block backLink %} {{ govukBackLink({ "href": url_for('main.service_set_broadcast_channel', service_id=current_service.id) }) }} {% endblock %} {% block maincolumn_content %}
{{ broadcast_service_name_tag( form.account_type.service_mode == 'training', form.account_type.broadcast_channel, form.account_type.provider_restriction, left_margin=False, ) }}
{% if form.account_type.service_mode == 'training' %}No phones will receive alerts sent from this service.
{% else %}Members of the public {% if form.account_type.broadcast_channel in ['test', 'operator'] %} who have switched on the {{ form.account_type.broadcast_channel }} channel on their phones {% endif %} will receive alerts sent from this service {%- if form.account_type.broadcast_channel == 'government' -%} , even if they’ve opted out {%- endif %}.
{% endif %}All team member permissions will be removed.
{% call form_wrapper() %} {{ page_footer('Confirm') }} {% endcall %}


scrapers module¶
Perform webscraping related to typosquatting on PyPI.
A module that contains any functions that can make internet calls to gather data related to typosquatting.
-
scrapers.
get_all_packages
(page='https://pypi.org/simple/')¶ Download simple list of PyPI package names.
pypi.org/simple conveniently lists all the names of current packages. This function scrapes that listing and then places the package names in a python list structure.
- Parameters
page (str) – webpage from which to download pypi package names
- Returns
package names on pypi
- Return type
list
-
scrapers.
get_top_packages
(top_n=50, stored=False)¶ Identify top packages by download count on pypi.
A friendly person has already provided an occasionally updated JSON feed to enable this program to build a list of the top pypi packages by download count. The default does a fresh pull of this feed. If the user wants to use a stored list, that is possible if the user sets the stored flag to true.
- Parameters
top_n (int) – the number of top packages to retrieve
stored (bool) – whether to use the stored package list
- Returns
top packages
- Return type
dict


{{errormessage}}
you've got
{{uuids.length}}
sensor{{plural(uuids)}}
{{ item.name || item.uuid }}
Chart period (UTC)
{{ showHours()}}
{{ showDates() }}
Chart type
stacked area
line with focus
multi bar
Options
manual refresh
auto refresh is {{autorefresh.status}}
getting data and transform to chart. please wait.
{{dashboard.title}}
loading


{% load onepage_tags %} {% with object_instance.files.all|dictsort:'weighting' as files and object_instance.files.all|length as size %}


@wizardofcheeze is a very funny man. I’ve had this image in my head for days. Those are generic cats mind you… they don’t belong to a specific ethereum game that at this time won’t be mentioned… But it’s clear as day!
Feeling good about what we’ve made
Sometimes the level of creativity of this platform just astounds me.  This picture may not be the world’s most precious piece of art, but it’s so freaking good and simple. It’s like a meme. The message of the meme is that Steem Monsters is infinitely better than other crypto styled games out there. But we don’t have to say it. We just have to show our T-Rex eat some kitties.
We’re getting stories built, art built, I hope to see steembay integrated into the game, trading through the site get up and running and of course fighting. Before the end of the year we should be able to move out of alpha and into beta. During beta we’ll have tons of tournaments. If you haven’t heard yet there will definitely be tournaments that will be worth 1000 SBD.
Fighting system highlights
Yaba and I keep working on how to tweak the fighting system to be fun and fair. A few questions I’ve had are basically how often should a legendary and common of the same mana cost be able to fight each other and the common pull off an upset. In one of the many hours of conversations I’ve had about this game the group helped me decide that 90:10 was a good ratio. Meaning that if two cards 1v1ed each other and they cost the same mana and had the same basic role in the game that the legendary would win 90% of the time and common would pull off an upset 10% of the time.
We have a lot of work done on the skill and fighting system, but when we’re tweaking stuff it’s important to find how the crowd and people this this working.
Combat roles
In a standard RPG you have 3 roles: tank, dps, and healer. We’re looking to implement this too, but we’re also going to build in a 4th class called assassin. How you place monsters in the fight will matter. By default the tank is going to be the monster that you place in the first slot. Doesn’t mean they have to be tanky… but it does mean that’s who the other team shoots first. That then protects some of the other dudes on your team. So, in order to kill the other dudes on the team we’re introducing a role called assassin. This isn’t just a dps class, but one that’s meant to kill the backline of the opposing party.

Yeah, well the basics will be you’re forming a party of adventurers. You’re going to play a summoner who summons monsters. You’ll arrange those monsters to build a team. it could be a balanced team. it could be specialized to do something. But essentially in your head it should go something like:
Zintar stands at the edge of the Earthen Arena.  The stadium gasps as dark laughter fills the floor. The lava whip. The huge wings. The dark cackle of his laughter. Zintar summoned the Lord of Darkness. Behind him crawled a limping undead priest seemingly pulling life from the living and feeding it’s strength into the Lord of Darkness. The last monster that Zintar summons before his eyes return to normal looks like a clown… or a jester… but this is no ordinary jester. The crooked grin speaks of a touch of insanity. It’s even hard to watch it walk… it has a uneven gate, and the head seems to be able to rotate more than a normal head should. The three stand ready.
Zintar is pleased. He shouts at Lyanna from across the way “The Lord of Darkness can withstand your mightiest attacks. My jester will rip you to pieces, and the priest can heal any feeble spell you happen to get through. You’re doomed Lyanna… bring forth your monsters and feed them to the Lord of Darkness!”
The party
Zintar summoned a Lord of Darkness that’s a powerful tank and able to dole out some good damage. He summoned an undead priest for heals on his tank, and he summoned a twisted jester to rip out some DPS. Zintar feels comfortable talking trash because he’s against Green. The black team has a natural advantage vs the green team. it’s like a big game of rocks paper scissors. Red is strong vs white. White is strong vs black. Black is strong vs Green. Green is strong vs blue. Blue is strong vs red.

To bring this back to kitties
This is a full fledged game. This isn’t just a little collectible. This game is going to keep you up at night thinking about the best combination of monsters, summoners, and items to buff them. You’re going to walk through the halls of your house pretending to blast apart monsters from the other team. You’re gonna win prize money from tournaments or at least walk away slowly leveling your team and watch your deck and power grow. This is a strategy game that’s going to be fun regardless of whether it was steem based or blockchain based. It’s going to be amazing because of those things.
Imagination
The universe teaches through contrast.  Imagine your army decimating her poor trees and nymphs…. Now think of yourself playing cryptokitties. Now imagine that you own a cat…
Steem Monsters is going to explode.
This page is synchronized from the post: ‘Here kitty, kitty, kitty’


Welcome to PyU4V’s documentation!¶
Overview¶
PyU4V is a python module that simplifies integration with the Unisphere for VMAX RestAPI interface.
It wraps REST calls with simple APIs and abstracts the HTTP request and response handling. For specifics on API arguments, consult the REST API guide for the VMAX release currently running on the target array. To get this documentation, navigate to https://{ip-address}:{port-number}/univmax/restapi/docs, where {ip-address}: the ip of your Unisphere server and {port-number}: the corresponding port to connect through, eg: https://<IP_ADDRESS>:8443/univmax/restapi/docs.
Getting Started¶
- Installation Guide
- How to get the source code, and how to build or install the python package.
- Quick Start Guide
- A quick start guide for PyU4V.
- API Glossary
- A glossary of all available functions.
Supported Versions¶
PyU4V supports Unisphere for VMAX version 8.4 and higher. VMAX 3 and VMAX All Flash arrays are supported. PyU4V officially supports Python 2.7 & 3.4-3.7 (but do remember that Python 2 will soon be retired.)
Please note that PyU4V V3.0 is NOT BACKWARDS COMPATIBLE with existing scripts written for previous versions of PyU4V, and does not support any Unisphere for VMAX version earlier that 8.4. PyU4V version <IP_ADDRESS> is still available on Pip, and there is a ‘stable/2.0’ branch available on Github. Version 3 will be the version maintained going forward, and we do suggest you move to this version when possible.
Feedback, Bug Reporting, Feature Requests¶
We greatly value your feedback! Please file bugs and issues on the Github issues page for this project. This is to help keep track and document everything related to this repo. For general discussions and further support you can join the {code} Community slack channel. Lastly, for questions asked on Stackoverflow.com, please tag them with Dell or Dell EMC. The code and documentation are released with no warranties or SLAs and are intended to be supported through a community driven process.


Plugin Information |
|---|
View Python Wrapper on the plugin site for more information. |
This plugin provides the runtime library for plugins written in Python.
If you want to develop plugins in Python, see the GitHub wiki page.
Changelog
Version 1.0.3 (May 23, 2014)
- Bug fix release
- This release fixes failures caused by classpaths with spaces. (%20 -> " ").
Version 1.0.2 (March 31, 2014)
- Critical bug fix release
Version 1.0.1 (March 30, 2014)
- Critical bug fix release
Version 1.0 (March 24, 2014)
- Initial release
- Wrappers of this version covers extension points of the Jenkins version 1.509.4


{% extends "loggedinheader.html" %} {% block content %}
Welcome to Monster's Ink! This page will guide you through all the steps to get you battling your freinds and sharing your monster drawing abilities.
There are two ways that you can edit your monsters for gameplay. The first is by going to the "Draw Monster" page. The second, is by opting to draw your own monsters prior to starting a game. Here, there are different drawing ablilites you can use to draw with your mouse. You can also upload an image by entering your local image url and clicking "Upload Image." Once your monster masterpiece is complete. Give him a name and click "save" to add him to your deck. Once a monster is in your deck, he will be available for use in challenging your freinds. Some examples of Monsters you can draw are in the site deck.
To begin a game, click on the "Lobby" link from your home page. This will give you the option of starting your own game or joining a game with strangers.
 If the name is not already taken, you will be given a link to share with your friends so they can join your game.
If you choose to join a random game, you will be taken to a game with a number of strangers, and will be ready to start playing.
 Each player in the game begins with five monsters. Your monsters will be shown at the bottom of the page. Simply click on your requested monsters to draft them onto your team. If you wish to let fate decide your monster team, click "Random" to get a random set of monsters drafted to your team.
When this is completed, confirm your team to begin battling your friends.
Each round, there are three roles: attacker, defender, and citizens.
Once a monster has been captured, they go into the deck of the winning monster owner. The monster owner then has the power to edit them to fit in with their monster team. They will return to the Draw Monster page and will be prompted to add features to the monster to make him a better warrior.
When any monster owner has lost all of his monsters due to capture, the game ends. At this time, the monster owner who has the largest monster team will be crowned the winner.


ResultFormatter Class
The ResultFormatter takes the response gathered by all connectors and merges them to one formatted result.
Constructor
ResultFormatter
-
result
Parameters:
-
result
ArrayArray holding the result gathered from all connectors
Item Index
Methods
findConnectorResponse
-
connectorIndex
-
index
-
Returns
Helper function to retrieve a ConnectorReponse
Parameters:
-
connectorIndex
IntThe order index of the connector that should be retrieved. connectorIndex = 0 is the first connector used to retrieve the data
-
index
IntUsed to retrieve a connector response matching this index
-
Returns
ConnectorResponsea ConnectorResponse object
-
result
-
config
The constructor. The result given to the constructor is always cloned to ensure that the raw result isn't altered in any way
raw
()
Array
public
Returns a cloned version of the raw result.
Returns:
config
-
key
Returns a configuration value for a given configuration if found
Parameters:
-
key
StringString Name of the configuration
Returns:
setConfig
-
key
-
value
Sets config file which is used by the ResultFormatter when mergin the result, e.g. merge method
setRaw
-
rawResult
Sets the raw value that is used when all results is merged. Always cloned to make sure that it can't be changed after it is set
Parameters:
-
rawResult
ArrayThe result generated by all connectors involved in a routine
findConnectorResults
-
connectorIndex
-
Returns
Helper function to retrieve all results generated by a connector given the connector index.
Parameters:
-
connectorIndex
IntThe order index of the connector that should be retrieved. connectorIndex = 0 is the first connector used to retrieve the data
-
Returns
Arrayall results generated by a connector
removeUnusedResult
-
connectorResult
-
pathToArray
-
indexToRemvoe
Remove results in an object given an array holding parts of an path (i.e. keys in an object)
sortByIndexAndCallIndex
-
a
-
b
Used to sort an array with ConnectorResponse object by call index and then index
indexOfFirstArrayInPath
-
valueSourcePath
Helper function to retrieve the index of the first array found in the given path
Parameters:
-
valueSourcePath
StringString containing a dot notated path used to traverse an object. Every dot indicates a new level in the object.
Returns:
createAddPath
-
valueSourcePath
-
key
Helper function to create a path used when adding data to a connector result
Parameters:
Returns:
mergeConnectorResults
-
connectorIndex
Merges all results from a given connector with all other connector result. Depending on merge method unused results may be removed.
Parameters:
-
connectorIndex
IntThe index of the connector the merge should use
Returns:
mergeResult
()
Array
public
Merges the result using the merge method found in config


--- layout: blog title: 博客 section_id: blog --- {% for post in paginator.posts %}
{{ post.date | date: "%B %Y" }}
by {{post.author}}
{{post.excerpt}}
阅读详情


SCRUMtious
"An Android app that helps manage the logistics of remote teams working on projects in a Agile Scrum environments. We keep track of their user stories, tasks, sprint backlog, product backlog, amongst many other things."
"An Android app that helps manage the logistics of remote teams working on projects in a Agile Scrum environments. We keep track of their user stories, tasks, sprint backlog, product backlog, amongst many other things."


1. CityJSON Object
A CityJSON object represents one 3D city model of a given area, this model may contain features of different types, as defined in the CityGML data model.
A CityJSON object:
-
is a JSON object.
-
must have one member with the name
"type"
. The value must be"CityJSON"
. -
must have one member with the name
"version"
. The value must be a string with the version (X.Y) of the CityJSON object. Observe that while schemas can have a version with patch version (X.Y.Z), a CityJSON object points only to the minor version (X.Y), and for validation the latest schema of that minor version should be used. -
must have one member with the name
"transform"
. The value is a JSON object describing how to decompress the integer coordinates of the geometries to obtain real-world coordinates. See § 4 Transform Object for details. -
must have one member with the name
"CityObjects"
. The value of this member is a collection of key-value pairs, where the key is the ID of the object, and the value is one City Object. The ID of a City Object should be unique (within one CityJSON Object). See § 2 The different City Objects for details. -
must have one member with the name
"vertices"
. The value is an array representing the coordinates of each vertex of the city model. See § 3.1 Coordinates of the vertices. -
may have one member with the name
"metadata"
. The value may be a JSON object describing the coordinate reference system used, the extent of the dataset, its creator, etc. See § 5 Metadata for details. -
may have one member with the name
"extensions"
, which is used if there are Extensions used in the file. See § 8 Extensions for details. -
may have one member with the name
"appearance"
. The value may contain JSON objects representing the textures and/or materials of surfaces. See § 6 Appearance Object for details. -
may have one member with the name
"geometry-templates"
, the value is a JSON object containing the templates that can be reused by different City Objects (usually for trees). This is equivalent to the concept of "implicit geometries" in CityGML. See § 3.4 Geometry templates for details. -
may have other members, and their value is not prescribed. Because these are not standard members in CityJSON, they might be ignored by parsers.
'.city.json'
The minimal valid CityJSON object is:
{ "type" : "CityJSON" , "version" : "1.1" , "transform" : { "scale" : [ 1.0 , 1.0 , 1.0 ], "translate" : [ 0.0 , 0.0 , 0.0 ] }, "CityObjects" : {}, "vertices" : [] }
An "empty" but complete CityJSON object will look like this:
{ "type" : "CityJSON" , "version" : "1.1" , "extensions" : {}, "transform" : { "scale" : [ 1.0 , 1.0 , 1.0 ], "translate" : [ 0.0 , 0.0 , 0.0 ] }, "metadata" : {}, "CityObjects" : {}, "vertices" : [], "appearance" : {}, "geometry-templates" : {} }
2. The different City Objects
-
1st-level: City Objects that can "exist by themselves".
-
2nd-level: City Objects that need to have a
"parents"
to exist.
This is because the schema of CityGML has been flattened.
For example, a "BuildingInstallation"
cannot be present in a dataset without being the "children"
of a "Building"
, but a "Building"
can be present by itself.
A City Object:
-
must have one member
"type"
. The value is one of the possibilities in the figure above (of type string). If an Extension is used, then the type can be any string starting with a"+"
, as explained in § 8 Extensions. -
may have one member with the name
"geometry"
. The value is an array containing 0 or more Geometry Objects. More than one Geometry Object is used to represent several different levels-of-detail (LoDs) for the same object. However, the different Geometry Objects of a given City Object do not have to be of different LoDs. -
may have one member with the name
"attributes"
. The value is an object where the attributes of the City Object are listed. -
may have one member with the name
"geographicalExtent"
(the axis-aligned bounding box of the City Object). The value is an array with 6 values:[minx, miny, minz, maxx, maxy, maxz]
-
may have one member
"children"
. The value is an array of the IDs (of type string) of the 2nd-level City Objects that are part of the 1st-level City Object. Only the direct children of the City Object are listed, not the grandchildren. Also, a City Object can have different types of City Objects as children, eg a"Building"
can have both as children"BuildingPart"
and"BuildingInstallation"
. The order of the children in the array is not relevant.
A City Object of type 2nd-level:
-
must have one member
"parents"
. The value is an array of the IDs (of type string) of the City Objects that are its parents. For the City Objects in the CityJSON core module, this array will always be of size 1 (only one parent). New City Objects defined in extensions can have more than one parents. -
may have one member
"children"
, and the"children"
array only references the City Objects that are one level below the current one in the hierarchy. For instance a"BuildingPart"
that contains a"BuildingInstallation"
.
"CityObjects" : { "id-1" : { "type" : "Building" , "geographicalExtent" : [ 84710.1 , 446846.0 , -5.3 , 84757.1 , 446944.0 , 40.9 ], "attributes" : { "measuredHeight" : 22.3 , "roofType" : "gable" , "owner" : "Elvis Presley" }, "children" : [ "id-2" ], "geometry" : [{ ...}] }, "id-2" : { "type" : "BuildingPart" , "parents" : [ "id-1" ], "children" : [ "id-3" ], ...}, "id-3" : { "type" : "BuildingInstallation" , "parents" : [ "id-2" ], ...}, "id-4" : { "type" : "LandUse" , ...} }
An example of a minimal valid City Object is:
{ "type" : "Building" }
The above example is for a "Building"
City Object, but any 1st-level City Object can be encoded the same way.
An example of a minimal 2nd-level valid City Object is:
{ "type" : "BuildingPart" , "parents" : [ "id-parent" ] }
The above example is for a "BuildingPart"
, but any 2nd-level City Object can be encoded this way.
2.1. Attributes for all City Objects
The attributes for a given City Object are not prescribed (unlike in CityGML).
This means that the "attributes"
is a JSON object and its content is a JSON key-value pair ("owner" in the example above is one such attribute).
Note that any valid JSON value (including an array and/or object) is a valid attribute value.
"CityObjects" : { "id-1" : { "type" : "LandUse" , "attributes" : { "function" : "Industry and Business" , "area-parcel" : { "value" : 437 , "uom" : "m2" }, }, "geometry" : [{ ...}] }, "id-2" : { "type" : "WaterBody" , "attributes" : { "name" : "Lake Black" , "some-list" : [ "a" , "b" , "c" ] }, "geometry" : [{ ...}] } }
2.2. Bridge
Six City Objects are related to bridges:
-
"Bridge"
-
"BridgePart"
-
"BridgeInstallation"
-
"BridgeConstructiveElement"
-
"BridgeRoom"
-
"BridgeFurniture"
The geometry of both "Bridge"
and "BridgePart"
can only be represented with these Geometry Objects: (1) "Solid"
, (2) "CompositeSolid"
, (3) "MultiSurface"
, (4) "CompositeSurface"
.
The geometry of the four other objects can be represented with any of the Geometry Objects.
A City Object of type "Bridge"
or "BridgePart"
may have a member "address"
, whose value is an array of JSON objects listing the potentially several addresses of that bridge .
The properties of an address JSON object are free, to accommodate the different ways addresses are structured in different countries.
"CityObjects" : { "LondonTower" : { "type" : "Bridge" , "address" : [ { "City" : "London" , "Country" : "UK" } ], "children" : [ "Bext1" , "Bext2" , "Inst-2017-11-14" ], "geometry" : [{ "type" : "MultiSurface" , "lod" : "2" , "boundaries" : [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]], [[ 1 , 2 , 6 , 5 ]], [[ 2 , 3 , 7 , 6 ]], [[ 3 , 0 , 4 , 7 ]] ] }] } }
2.3. Building
Eight City Objects are related to buildings:
-
"Building"
-
"BuildingPart"
-
"BuildingInstallation"
-
"BuildingConstructiveElement"
-
"BuildingFurniture"
-
"BuildingStorey"
-
"BuildingRoom"
-
"BuildingUnit"
The geometry of "Building"
, "BuildingPart"
, "BuildingStorey"
, "BuildingRoom"
,
and "BuildingUnit"
can only be represented with these Geometry Objects: (1) "Solid"
, (2) "CompositeSolid"
, (3) "MultiSurface"
, (4) "CompositeSurface"
.
All eight City Objects, except "Building"
, must have a "parents"
property.
The installations, furnitures, and subdivisions can have as parents a "Building"
, a "BuildingPart"
, or a "BuildingRoom"
.
The geometry of "BuildingInstallation"
, "BuildingConstructiveElement"
, or "BuildingFurniture"
objects can be represented with any of the Geometry Objects.
A City Object of type "Building"
, "BuildingPart"
or "BuildingUnit"
may have a member "address"
, consisting of an array of JSON objects listing one or more addresses of that building (an apartment building could contain several for instance).
The properties of an address JSON object are free format, to accommodate the different ways addresses are described in different countries.
If a location is necessary (eg to locate the position of the front door) then a property "location"
should be used, and it should contain a "MultiPoint"
geometry.
"CityObjects" : { "id-1" : { "type" : "Building" , "attributes" : { "roofType" : "gabled roof" }, "geographicalExtent" : [ 84710.1 , 446846.0 , -5.3 , 84757.1 , 446944.0 , 40.9 ], "children" : [ "id-56" , "id-832" , "mybalcony" ] }, "id-56" : { "type" : "BuildingPart" , "parents" : [ "id-1" ], ...}, "mybalcony" : { "type" : "BuildingInstallation" , "parents" : [ "id-1" ], ...} ...}
"myroom" : { "type" : "BuildingRoom" , "attributes" : { "usage" : "living room" }, "parents" : [ "id-1" ], "geometry" : [{ "type" : "Solid" , "lod" : "2" , "boundaries" : [ [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]], ...] ] }] }
{ "type" : "Building" , "address" : [ { "Country" : "Canada" , "Locality" : "Chibougamau" , "ThoroughfareNumber" : "1" , "ThoroughfareName" : "rue de la Patate" , "Postcode" : "H0H 0H0" , "location" : { "type" : "MultiPoint" , "lod" : "1" , "boundaries" : [ 231 ] } } ] }
2.4. CityFurniture
The geometry of a City Object of type "CityFurniture"
can be any Geometry Object.
"mystopsign" : { "type" : "CityFurniture" , "attributes" : { "function" : "bus stop" }, "geometry" : [{ "type" : "MultiSurface" , "lod" : "2" , "boundaries" : [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]] ] }] }
2.5. CityObjectGroup
The CityGML concept of groups, where City Objects are aggregated based on certain criteria (think of a neighbourhood in a city for instance), is possible in CityJSON. The group is a City Object, and it can contain, if needed, a geometry (the polygon representing the neighbourhood for instance).
Since a "CityObjectGroup"
is also a City Object, it can be part of another group.
A City Object of type "CityObjectGroup"
:
-
must have a member
"children"
. The value is an array of the IDs of the City Objects that the group contains. As for other City Objects, the City Objects must have the ID of the group in"parents"
. -
may have a member
"children_roles"
, whose value is an array of strings describing the role of each City Object in the group. This member must be of the same length as that of"children"
. -
may have a member
"attributes"
. -
may have a member
"geometry"
. Notice that since the"CityObjectGroup"
is a container of different City Objects, the concept of Level of Detail does not apply to it. Nevertheless, the"lod"
property is still used for enforcing uniformity with all the other geometries.
"CityObjects" : { "my-neighbourhood" : { "type" : "CityObjectGroup" , "children" : [ "building1" , "building2" , "building666" ] } }
"CityObjects" : { "my-neighbourhood" : { "type" : "CityObjectGroup" , "attributes" : { "location" : "Chibougamau Sud" }, "children" : [ "building1" , "building666" ], "children_roles" : [ "residential building" , "voting location" ], "geometry" : [{ "type" : "MultiSurface" , "lod" : "2" , "boundaries" : [ [[ 2 , 41 , 5 , 77 ]] ] }] } }
2.6. LandUse
The geometry of a City Object of type "LandUse"
can be of type "MultiSurface"
or "CompositeSurface"
.
"oneparcel" : { "type" : "LandUse" , "geometry" : [{ "type" : "MultiSurface" , "lod" : "1" , "boundaries" : [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]] ] }] }
2.7. OtherConstruction
This is used for constructions that are not buildings, bridges, or tunnels. Examples are:
-
electricity pylon
-
fence
-
permanent water tank
-
pontoon
-
railway platform
-
shed
-
windmill
The geometry of a City Object of type "OtherConstruction"
can be any Geometry Object.
"mypylon" : { "type" : "OtherConstruction" , "attributes" : { "class" : "windmill" , "conditionOfConstruction" : "underConstruction" }, "geometry" : [{ "type" : "MultiSurface" , "lod" : "2" , "boundaries" : [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]], ...] }] }
2.8. PlantCover
The geometry of a City Object of type "PlantCover"
can be of type: (1) "Solid"
, (2) "CompositeSolid"
, (3) "MultiSolid"
, (4) "MultiSurface"
, (5) "CompositeSurface"
.
"myplants" : { "type" : "PlantCover" , "attributes" : { "averageHeight" : 11.05 }, "geometry" : [{ "type" : "MultiSolid" , "lod" : "2" , "boundaries" : [ [ [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]], [[ 10 , 13 , 22 , 31 ]] ] ], [ [ [[ 5 , 34 , 31 , 12 ]], [[ 44 , 54 , 62 , 74 ]], [[ 111 , 123 , 922 , 66 ]] ] ] ] }] }
2.9. SolitaryVegetationObject
The geometry of a City Object of type "SolitaryVegetationObject"
can be any Geometry Object.
"onebigtree" : { "type" : "SolitaryVegetationObject" , "attributes" : { "trunkDiameter" : 5.3 , "crownDiameter" : 11.0 }, "geometry" : [{ "type" : "MultiPoint" , "lod" : "1" , "boundaries" : [ 1 ] }] }
2.10. TINRelief
The geometry of a City Object of type "TINRelief"
can only be of type "CompositeSurface"
.
CityJSON does not define a specific Geometry Object for a TIN (triangulated irregular network), and is simply a CompositeSurface for which every surface is a triangle (thus a polygon having 3 vertices, and no interior ring).
Notice that in practice any "CompositeSurface"
is allowed for encoding a terrain, and that arbitrary polygons could also be used (not just triangles).
"myterrain01" : { "type" : "TINRelief" , "geographicalExtent" : [ 84710.1 , 446846.0 , -5.3 , 84757.1 , 446944.0 , 40.9 ], "geometry" : [{ "type" : "CompositeSurface" , "lod" : "1" , "boundaries" : [ [[ 0 , 3 , 2 ]], [[ 4 , 5 , 6 ]], [[ 1 , 2 , 6 ]], [[ 2 , 3 , 7 ]], [[ 3 , 0 , 4 ]] ] }] }
2.11. Transportation
Four City Objects are related to transportation:
-
"Road"
-
"Railway"
-
"Waterway"
-
"TransportSquare"
(to model for instance parking lots and squares)
Observe that the "Section", "Intersection", and "Track" classes from CityGML are omitted because they can be easily specified using specific attributes.
"ma_rue" : { "type" : "Road" , "attributes" : { "class" : "backwards" , "clearanceSpace" : 2.23 , "clearanceSpaceUnit" : "meter" }, "children" : [ "sect1" , "sect2" ], "geometry" : [ ...] } "sect1" : { "type" : "Road" , "attributes" : { "class" : "section" }, "parents" : [ "ma_rue" ], "geometry" : [ ...], }
Similarly, the CityGML classes "TrafficArea", "AuxiliaryTrafficArea", "Marking", and "Hole" are implemented as semantic surface (see § 3.3 Semantics of geometric primitives).
That is, the surface representing a road should be split into sub-surfaces (therefore forming a "MultiSurface"
or a "CompositeSurface"
) in which each of the sub-surfaces has semantics.
"ma_rue" : { "type" : "Road" , "geometry" : [{ "type" : "MultiSurface" , "lod" : "2" , "boundaries" : [ [[ 0 , 3 , 2 , 1 , 4 ]], [[ 4 , 5 , 6 , 666 , 12 ]], [[ 0 , 1 , 5 ]], [[ 20 , 21 , 75 ]] ] }], "semantics" : { "surfaces" : [ { "type" : "TrafficArea" , "surfaceMaterial" : [ "asphalt" ], "function" : "road" }, { "type" : "AuxiliaryTrafficArea" , "function" : "green areas" }, { "type" : "TrafficArea" , "surfaceMaterial" : [ "dirt" ], "function" : "road" } ], "values" : [ 0 , 1 , null , 2 ] } }
2.12. Tunnel
Six City Objects are related to tunnels:
-
"Tunnel"
-
"TunnelPart"
-
"TunnelInstallation"
-
"TunnelConstructiveElement"
-
"TunnelHollowSpace"
-
"TunnelFurniture"
The geometry of both "Tunnel"
and "TunnelPart"
can only be represented with these Geometry Objects: (1) "Solid"
, (2) "CompositeSolid"
, (3) "MultiSurface"
, (4) "CompositeSurface"
.
The geometry of the other four objects can be represented with any of the Geometry Objects.
"CityObjects" : { "Lærdalstunnelen" : { "type" : "Tunnel" , "attributes" : { "yearOfConstruction" : 2000 , "length" : "24.5km" }, "children" : [ "stoparea1" ], "geometry" : [{ "type" : "Solid" , "lod" : "2" , "boundaries" : [ [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]] ] ] }] } }
2.13. WaterBody
The geometry of a City Object of type "WaterBody"
can be of types: "MultiLineString"
, "MultiSurface"
, "CompositeSurface"
, "Solid"
, or "CompositeSolid"
.
"mygreatlake" : { "type" : "WaterBody" , "attributes" : { "usage" : "leisure" , }, "geometry" : [{ "type" : "Solid" , "lod" : "2" , "boundaries" : [ [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]] ] ] }] }
3. Geometry Objects
CityJSON defines the following 3D geometric primitives, all of which are embedded in 3D space (and therefore their vertices have (x, y, z) coordinates). The indexing mechanism of the format Wavefront OBJ is reused, that is a geometry does not store the locations of its vertices, but points to a vertex in a list (property "vertices"
in the CityJSON Object).
As is the case in CityGML, only linear and planar primitives are allowed. No curves or parametric surfaces can be represented.
A Geometry object is a JSON object for which the type member’s value is one of the following:
-
"MultiPoint"
-
"MultiLineString"
-
"MultiSurface"
-
"CompositeSurface"
-
"Solid"
-
"MultiSolid"
-
"CompositeSolid"
-
"GeometryInstance"
(this is another type with different properties, see § 3.4 Geometry templates)
A Geometry object:
-
must have one member with the name
"type"
. The value must be a string with one of the 8 allowed Geometry types, as defined above. -
must have one member with the name
"lod"
. The value must be a string with the LoD identifying the level-of-detail (LoD) of the geometry. This can be either a single digit (following the CityGML standards), or "X.Y"-formatted if the improved LoDs by TU Delft are used. -
must have one member with the name
"boundaries"
. The value is a hierarchy of arrays (the depth depends on the Geometry object) with integers. An integer refers to the index in the"vertices"
array of the CityJSON object, and it is 0-based (ie the first element in the array has the index "0", the second one "1", etc.). -
may have one member
"semantics"
. The value is a JSON Object, as defined below. -
may have one member
"material"
. The value is a JSON Object, as defined below. -
may have one member
"texture"
. The value is a JSON Object, as defined below.
"geometry"
member of a CityObject, the different geometries may be enumerated in the array (all with the same value for the member "lod"
). 3.1. Coordinates of the vertices
A CityJSON must have one member named "vertices"
. The value is an array of array of integers representing the coordinates of each vertex of the city model.
The position of a vertex in this array (0-based) is used to represent the "boundaries"
of Geometry Objects.
-
one vertex must be an array with exactly 3 integers, representing the (x,y,z) location of the vertex before it is transformed to its real-world coordinates (with § 4 Transform Object).
-
the array of vertices may be empty.
-
vertices may be repeated.
"vertices" : [ [ 102 , 103 , 1 ], [ 11 , 910 , 43 ], [ 25 , 744 , 22 ], ...[ 23 , 88 , 5 ], [ 8523 , 487 , 22 ] ]
3.2. Arrays to represent boundaries
The depth of the hierarchy of arrays depends on the Geometry object, and is as follows.
-
A
"MultiPoint"
has an array with the indices of the vertices; this array can be empty. -
A
"MultiLineString"
has an array of arrays, each containing the indices of a LineString. -
A
"MultiSurface"
, or a"CompositeSurface"
, has an array containing surfaces, each surface is modelled by an array of array, the first array being the exterior boundary of the surface, and the others the interior boundaries. -
A
"Solid"
has an array of shells, the first array being the exterior shell of the solid, and the others the interior shells. Each shell has an array of surfaces, modelled in the exact same way as a MultiSurface/CompositeSurface. -
A
"MultiSolid"
, or a"CompositeSolid"
, has an array containing solids, each solid is modelled as above.
//-- my comments
) are only to explain the cases, and should be removed. { "type" : "MultiPoint" , "lod" : "1" , "boundaries" : [ 2 , 44 , 0 , 7 ] }
{ "type" : "MultiLineString" , "lod" : "1" , "boundaries" : [ [ 2 , 3 , 5 ], [ 77 , 55 , 212 ] ] }
{ "type" : "MultiSurface" , "lod" : "2" , "boundaries" : [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]] ] }
{ "type" : "Solid" , "lod" : "2" , "boundaries" : [ //-- exter ior shell[ [[ 0 , 3 , 2 , 1 , 22 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]], [[ 1 , 2 , 6 , 5 ]] ], //-- inter ior shell[ [[ 240 , 243 , 124 ]], [[ 244 , 246 , 724 ]], [[ 34 , 414 , 45 ]], [[ 111 , 246 , 5 ]] ] ] }
{ "type" : "CompositeSolid" , "lod" : "3" , "boundaries" : [ [ //-- 1 st Solid[ [[ 0 , 3 , 2 , 1 , 22 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]], [[ 1 , 2 , 6 , 5 ]] ], [ [[ 240 , 243 , 124 ]], [[ 244 , 246 , 724 ]], [[ 34 , 414 , 45 ]], [[ 111 , 246 , 5 ]] ] ], [ //-- 2 n d Solid[ [[ 666 , 667 , 668 ]], [[ 74 , 75 , 76 ]], [[ 880 , 881 , 885 ]], [[ 111 , 122 , 226 ]] ] ] ] }
3.3. Semantics of geometric primitives
A Semantic Object is a JSON object representing the semantics of a primitive of a geometry (e.g. a surface of a building).
A Semantic Object may also represent other attributes of the primitive (e.g. the slope of the roof, or the solar potential).
For surface and volumetric geometries (e.g. MultiSurface
, Solid
and MultiSolid
), a primitive is a surface.
If a geometry is a MultiPoint
or a MultiLineString
, then the primitives are its respective sub-parts: points and linestrings.
A Semantic Object:
-
must have one member with the name
"type"
. The value is one of the allowed value. These depend on the City Object (see below). -
may have an attribute
"parent"
. The value is an integer pointing to another Semantic Object of the same geometry (index of it, 0-based). This is used to explicitly represent to which wall or roof a window or door belongs to; there can be only one parent. -
may have an attribute
"children"
. The value is an array of integers pointing to other Semantic Objects of the same geometry (index of it, 0-based). This is used to explicitly represent the openings (windows and doors) of walls and roofs. -
may have other attributes in the form of a JSON key-value pair, where the value must not be a JSON object (but a string/number/integer/boolean).
{ "type" : "RoofSurface" , "slope" : 16.4 , "children" : [ 2 , 37 ], "solar-potential" : 5 } { "type" : "Window" , "parent" : 2 , "type-glass" : "HR++" }
"Building"
, "BuildingPart"
, "BuildingRoom"
, "BuildingStorey"
, "BuildingUnit"
, and "BuildingInstallation"
can have the following semantics:
-
"RoofSurface"
-
"GroundSurface"
-
"WallSurface"
-
"ClosureSurface"
-
"OuterCeilingSurface"
-
"OuterFloorSurface"
-
"Window"
-
"Door"
-
"InteriorWallSurface"
-
"CeilingSurface"
-
"FloorSurface"
For "WaterBody"
:
-
"WaterSurface"
-
"WaterGroundSurface"
-
"WaterClosureSurface"
For Transportation ("Road"
, "Railway"
, "TransportSquare"
):
-
"TrafficArea"
-
"AuxiliaryTrafficArea"
-
"TransportationMarking"
-
"TransportationHole"
It is possible to define and use other semantics, but these have to start with a "+"
, inline with the rules defined in the § 8 Extensions.
{ "type" : "+SupportingWall" }
Because in a given City Object (say a "Building"
) several primitives can have the same semantics (think of a complex building that has been triangulated, there can be dozens of triangles used to model the same surface), a Semantic Object must be declared once, and each of the primitives that are represented by it points to it. This is achieved by first declaring all the Semantic Objects in an array, and then having an array where each primitive links to Semantic Objects (position in the array).
If a Geometry object has semantics, then the Geometry object:
-
must have one member with the name
"semantics"
, whose values are two properties:"surfaces"
and"values"
. Both must be present.
Also:
-
the value of
"surfaces"
is an array of Semantic Objects. -
the value of
"values"
is a hierarchy of arrays with integers. The depth depends on the Geometry object: forMultiPoint
andMultiLineString
this is a simple array of integers; for any other geometry type it is two less than the array"boundaries"
. An integer refers to the index in the"surfaces"
array of the same geometry, and it is 0-based. If one surface has no semantics, a value ofnull
must be used.
"surfaces"
to name the array of Semantic Object. Nevertheless, this property is used for points and linestrings of MultiPoints
and MultiLineStrings
, as well. { "type" : "MultiSurface" , "lod" : "2" , "boundaries" : [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]], [[ 0 , 2 , 3 , 8 ]], [[ 10 , 12 , 23 , 48 ]] ], "semantics" : { "surfaces" : [ { "type" : "WallSurface" , "slope" : 33.4 , "children" : [ 2 ] }, { "type" : "RoofSurface" , "slope" : 66.6 }, { "type" : "+PatioDoor" , "parent" : 0 , "colour" : "blue" } ], "values" : [ 0 , 0 , null , 1 , 2 ] } }
{ "type" : "CompositeSolid" , "lod" : "2.2" , "boundaries" : [ [ //-- 1 st Solid[ [[ 0 , 3 , 2 , 1 , 22 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]], [[ 1 , 2 , 6 , 5 ]] ] ], [ //-- 2 n d Solid[ [[ 666 , 667 , 668 ]], [[ 74 , 75 , 76 ]], [[ 880 , 881 , 885 ]] ] ] ], "semantics" : { "surfaces" : [ { "type" : "RoofSurface" }, { "type" : "WallSurface" } ], "values" : [ [ //-- 1 st Solid[ 0 , 1 , 1 , null ] ], [ //-- 2 n d Solid get allnull values[ null , null , null ] ] ] } }
3.4. Geometry templates
CityGML’s "ImplicitGeometries", better known in computer graphics as templates, are one method to compress files since the geometries (such as benches, lamp posts, and trees), need only be defined once. In CityJSON, they are implemented differently from what is specified in CityGML: they are defined separately in the file, and each template can be reused. By contrast, in CityGML, the geometry used for a given City Object is reused by other City Objects, there is thus no central location where all templates are stored.
The Geometry Templates are defined as a JSON object that:
-
must have one member with the name
"templates"
. The value is an array of Geometry Objects. -
must have one member with the name
"vertices-templates"
. The value is an array of coordinates of each vertex of the templates (0-based indexing). The reason the vertices index are not global is to ensure that operations on the vertices (eg for CRS transformation, for § 4 Transform Object, or calculating the bounding box of a dataset) will not be affected by the templates (since they will often be defined locally, and translated/rotated/scaled to their final position).
"geometry-templates" : { "templates" : [ { "type" : "MultiSurface" , "lod" : "2.1" , "boundaries" : [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]] ] }, { "type" : "MultiSurface" , "lod" : "1.3" , "boundaries" : [ [[ 1 , 2 , 6 , 5 ]], [[ 2 , 3 , 7 , 6 ]], [[ 3 , 0 , 4 , 7 ]] ] } ], "vertices-templates" : [ [ 0.0 , 0.5 , 0.0 ], ...[ 1.0 , 1.0 , 0.0 ], [ 0.0 , 1.0 , 0.0 ] ] }
A given template can be used as the geometry (or as one of the geometries) of a City Object.
A new JSON object of type "GeometryInstance"
is defined, and it:
-
must have one member with the name
"template"
, whose value is the position of the template in the"geometry-templates"
(0-indexing). -
must have one member with the name
"boundaries"
, whose value is an array containing only one vertex index, which refers to one vertex in the"vertices"
property of a CityJSON file. (This is the reference point from which the transformations are applied, it is the "referencePoint" in CityGML.) -
must have one member with the name
"transformationMatrix"
, whose value is a 4x4 matrix (thus 16 values in an array) defining the rotation/translation/scaling of the template. Note that these 16 values are ordered row-by-row, as the example below shows.
{ "type" : "SolitaryVegetationObject" , "geometry" : [ { "type" : "GeometryInstance" , "template" : 0 , "boundaries" : [ 372 ], "transformationMatrix" : [ 2.0 , 0.0 , 0.0 , 0.0 , 0.0 , 2.0 , 0.0 , 0.0 , 0.0 , 0.0 , 2.0 , 0.0 , 0.0 , 0.0 , 0.0 , 1.0 ] } ] }
4. Transform Object
To reduce the size of a CityJSON object (and thus the size of files) and to ensure that only a fixed number of digits is stored for the coordinates of the geometries, the coordinates of the vertices of the geometries are represented integer values. We therefore need to store the scale factor and the translation needed to obtain the original coordinates (stored with floats/doubles).
A CityJSON object must therefore have one member "transform"
, whose values are 2 mandatory JSON objects ("scale"
and "translate"
), both arrays with 3 values.
The scheme of TopoJSON (called quantization) is reused, and here we simply add a third coordinate because our vertices are embedded in 3D space.
It should be noticed that only the "vertices"
at the root of the CityJSON object are affected by the transformation, the vertices for the Geometric templates and textures are not.
To obtain the real position of a given vertex v, we must take the 3 values vi listed in the "vertices"
member and:
v[0] = (vi[0] * ["transform"]["scale"][0]) + ["transform"]["translate"][0] v[1] = (vi[1] * ["transform"]["scale"][1]) + ["transform"]["translate"][1] v[2] = (vi[2] * ["transform"]["scale"][2]) + ["transform"]["translate"][2]
The following "transform"
means that 2 important digits are kept (thus millimetre level if meters are the units of the CRS), and the "translate"
usually matches with the minimum values of the axis-aligned bounding box (but does not need to).
"transform" : { "scale" : [ 0.001 , 0.001 , 0.001 ], "translate" : [ 442464.879 , 5482614.692 , 310.19 ] }
5. Metadata
The core of CityJSON supports the following six properties, these are compliant with the international standard ISO19115.
"metadata" : { "geographicalExtent" : [ 84710.1 , 446846.0 , -5.3 , 84757.1 , 446944.0 , 40.9 ], "identifier" : "eaeceeaa-3f66-429a-b81d-bbc6140b8c1c" , "pointOfContact" : { "contactName" : "3D geoinformation group, Delft University of Technology" , "contactType" : "organization" , "role" : "owner" , "phone" : "+31-6666666666" , "emailAddress"<EMAIL_ADDRESS>, "website" : "https://3d.bk.tudelft.nl" , "address" : "Julianalaan 134, Delft 2628BL, the Netherlands" }, "referenceDate" : "1977-02-28" , "referenceSystem" : "https://www.opengis.net/def/crs/EPSG/0/2355" , "title" : "Buildings in LoD2.3 of Chibougamau, Québec" }
5.1. geographicalExtent (bbox)
While the geographical extent can be computed from the dataset itself, it is often useful to store it.
It may be stored as an array with 6 values: [minx, miny, minz, maxx, maxy, maxz]
.
Notice that these are in the real coordinates of the dataset (based on § 5.5 referenceSystem (CRS)) and not after the coordinates have been compressed with the "transform"
property (§ 4 Transform Object).
"metadata" : { "geographicalExtent" : [ 84710.1 , 446846.0 , -5.3 , 84757.1 , 446944.0 , 40.9 ] }
5.2. identifier
A unique identifier for the dataset. It is recommend to use universally unique identifier, but this is not necessary.
"metadata" : { "identifier" : "44574905-d2d2-4f40-8e96-d39e1ae45f70" }
5.3. pointOfContact
The point of contact for the dataset. This is a JSON object that
-
must have one member with the name
"contactName"
. The value is the name of the contact. -
must have one member with the name
"emailAddress"
. The value is a string with the email. -
may have one member with the name
"role"
. The value describes the role that contact person/organisation has, it is one of the following:"resourceProvider"
,"custodian"
,"owner"
,"user"
,"distributor"
,"originator"
,"pointOfContact"
,"principalInvestigator"
,"processor"
,"publisher"
,"author"
,"sponsor"
,"co-author"
,"collaborator"
,"editor"
,"mediator"
,"rightsHolder"
,"contributor"
,"funder"
,"stakeholder"
. -
may have one member with the name
"website"
. The value is the URL of point of contact. -
may have one member with the name
"contactType"
. The value is a string which is either"individual"
or"organization"
. For an"organization"
, the"website"
can also be given. -
may have one member with the name
"address"
. The value is a string with the full address. -
may have one member with the name
"phone"
. The value is a string with the phone number. -
may have one member with the name
"organization"
. The value is the name of the organisation, to be used if the"contactName"
is the name of a person.
"pointOfContact" : { "contactName" : "Justin Trudeau" , "emailAddress"<EMAIL_ADDRESS>, "phone" : "+1-613-992-4211" , "address" : "24 Sussex Drive, Ottawa, Canada" , "contactType" : "individual" , "role" : "pointOfContact" }
5.4. referenceDate
The date when the dataset was compiled, without the time of the day, only a "full-date"
as defined in RFC 3339, Section 5.6 should be used.
"metadata" : { "referenceDate" : "1977-02-28" }
"full-date"
(thus "1977-07-11"
as a string), and should be used for the metadata above.
Other attributes in a CityJSON object can also have a date with a time, and such an attribute is specified as a "full-time"
. For example "1985-04-12T23:20:50.52Z"
(stored as a string).
5.5. referenceSystem (CRS)
The coordinate reference system (CRS) is given as a URL formatted according to the OGC Name Type Specification:
http://www.opengis.net/def/crs/{authority}/{version}/{code}
where {authority}
designates the authority responsible for the definition of this CRS (usually "EPSG" or "OGC"), and where {version}
designates the specific version of the CRS ("0" (zero) is used if there is no version).
For instance, the Dutch national CRS in 3D:
"metadata" : { "referenceSystem" : "https://www.opengis.net/def/crs/EPSG/0/7415" }
Be aware that the CRS should be a three-dimensional one, ie the elevation/height values should be with respect to a specific datum.
5.6. title
A string describing the dataset.
"metadata" : { "title" : "3D city model of Chibougamau, Canada" }
6. Appearance Object
Both textures and materials are supported in CityJSON, and the same mechanisms used in CityGML are reused, so the conversion back-and-forth is easy. The material is represented with the X3D specifications, as is the case for CityGML. For the texture, the COLLADA standard is reused, as is the case for CityGML. However:
-
the CityGML class
GeoreferencedTexture
is not supported. -
the CityGML class
TexCoordGen
is not supported, ie one must specify the UV coordinates in the texture files. -
the major difference is that in CityGML each Material/Texture object keeps a list of the primitives using it, while in CityJSON it is the opposite: if a primitive has a Material/Texture then it is stated with the primitive (with a link to it).
An Appearance Object is a JSON object that
-
may have one member with the name
"materials"
, whose value is an array of Material Objects. -
may have one member with the name
"textures"
, whose value is an array of Texture Objects. -
may have both
"materials"
and"textures"
. -
may have one member with the name
"vertices-texture"
, whose value is an array of coordinates of each so-called UV vertex of the city model. -
may have one member with the name
"default-theme-texture"
, whose value is the name of the default theme for the appearance (a string). This can be used if geometries have more than one textures, so that a viewer displays the default one. -
may have one member with the name
"default-theme-material"
, whose value is the name of the default theme for the material (a string). This can be used if geometries have more than one textures, so that a viewer displays the default one.
"appearance" : { "materials" : [], "textures" :[], "vertices-texture" : [], "default-theme-texture" : "myDefaultTheme1" , "default-theme-material" : "myDefaultTheme2" }
6.1. Geometry Object having material(s)
Each surface in a Geometry Object can have one or more materials assigned to it. To store the material of a surface, a Geometry Object may have a member "material"
, the value of this member is a collection of key-value pairs, where the key is the theme of the material, and the value is one JSON object that must contain either:
-
one member
"values"
. The value is a hierarchy of arrays with integers. Each integer refers to the position (0-based) in the"materials"
member of the"appearance"
member of the CityJSON object. If a surface has no material, thennull
should be used in the array. The depth of the array depends on the Geometry object, and is equal to the depth of the"boundary"
array minus 2, because each surface ([[]]
) gets one material. -
one member
"value"
. The value is one integer referring to the position (0-based) in the"materials"
member of the"appearance"
member of the CityJSON object. This is used because often the materials are used to colour full objects, and repetition of materials is not necessary.
In the following, the Solid has 4 surfaces, and there are 2 themes ("irradiation" and "irradiation-2"). These could represent, for instance, the different colours based on different scenarios of an solar irradiation analysis. Notice that the last surface gets no material (for both themes), thus null
is used.
{ "type" : "Solid" , "lod" : "2.1" , "boundaries" : [ [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]], [[ 1 , 2 , 6 , 5 ]] ] ], "material" : { "irradiation" : { "values" : [[ 0 , 0 , 1 , null ]] }, "irradiation-2" : { "values" : [[ 2 , 2 , 1 , null ]] } } }
6.2. Geometry Object having texture(s)
To store the texture(s) of a surface, a Geometry Object may have a member with the value "texture"
, its value is a collection of key-value pairs, where the key is the theme of the textures, and the value is one JSON object that must contain one member "values"
, which is a hierarchy of arrays with integers. For each ring of each surface, the first value refers to the position (0-based) in the "textures"
member of the "appearance"
member of the CityJSON object. The other indices refer to the UV positions of the corresponding vertices (as listed in the "boundaries"
member of the geometry). Each array representing a ring therefore has one more value than that to store its vertices.
The depth of the array depends on the Geometry object, and is equal to the depth of the "boundary"
array.
In the following, the Solid has 4 surfaces, and there are 2 themes: "winter-textures" and "summer-textures" could for instance represent the textures during winter and summer.. Notice that the last 2 surfaces of the first theme gets no material, thus the value null
is used.
{ "type" : "Solid" , "lod" : "2.2" , "boundaries" : [ [ [[ 0 , 3 , 2 , 1 ]], [[ 4 , 5 , 6 , 7 ]], [[ 0 , 1 , 5 , 4 ]], [[ 1 , 2 , 6 , 5 ]] ] ], "texture" : { "winter-textures" : { "values" : [ [ [[ 0 , 10 , 23 , 22 , 21 ]], [[ 0 , 1 , 2 , 6 , 5 ]], [[ null ]], [[ null ]] ] ] }, "summer-textures" : { "values" : [ [ [[ 1 , 10 , 23 , 22 , 21 ]], [[ 1 , 1 , 2 , 6 , 5 ]], [[ 1 , 66 , 12 , 64 , 5 ]], [[ 2 , 99 , 21 , 16 , 25 ]] ] ] } } }
6.3. Material Object
A Material Object:
-
must have one member with the name
"name"
, whose value is a string identifying the material. -
may have the following members (their meaning is explained there):
-
"ambientIntensity"
. The value is a number between 0.0 and 1.0. -
"diffuseColor"
. The value is an array with 3 numbers between 0.0 and 1.0 (RGB colour). -
"emissiveColor"
. The value is an array with 3 numbers between 0.0 and 1.0 (RGB colour). -
"specularColor"
. The value is an array with 3 numbers between 0.0 and 1.0 (RGB colour). -
"shininess"
. The whose value is a number between 0.0 and 1.0. -
"transparency"
. The value is a number between 0.0 and 1.0 (1.0 being completely transparent). -
"isSmooth"
. The value is a Boolean value, is defined in CityGML as a hint for normal interpolation. If this boolean flag is set to true, vertex normals should be used for shading (Gouraud shading). Otherwise, normals should be constant for a surface patch (flat shading).
-
"name"
is defined for the Material Object, then it is up to the application that reads the CityJSON file to attach a material definition to the "name"
.
This might not always be possible.
Therefore, it is advised to define as many from the optional members as needed for fully displaying the material. "materials" : [ { "name" : "roofandground" , "ambientIntensity" : 0.2000 , "diffuseColor" : [ 0.9000 , 0.1000 , 0.7500 ], "emissiveColor" : [ 0.9000 , 0.1000 , 0.7500 ], "specularColor" : [ 0.9000 , 0.1000 , 0.7500 ], "shininess" : 0.2 , "transparency" : 0.5 , "isSmooth" : false }, { "name" : "wall" , "ambientIntensity" : 0.4000 , "diffuseColor" : [ 0.1000 , 0.1000 , 0.9000 ], "emissiveColor" : [ 0.1000 , 0.1000 , 0.9000 ], "specularColor" : [ 0.9000 , 0.1000 , 0.7500 ], "shininess" : 0.0 , "transparency" : 0.5 , "isSmooth" : true } ]
6.4. Texture Object
A Texture Object:
-
must have one member with the name
"type"
. The value is a string with either "PNG" or "JPG" as value. -
must have one member with the name
"image"
. The value is a string with the name of the file. This file can be a URL (eg"http://www.someurl.org/filename.jpg"
), a relative path (eg"appearances/myroof.jpg"
), or an absolute path (eg"/home/elvis/mycityjson/appearances/myroof.jpg"
). -
may have one member with the name
"wrapMode"
. The value can be any of the following:"none"
,"wrap"
,"mirror"
,"clamp"
, or"border"
. -
may have one member with the name
"textureType"
. The value can be any of the following:"unknown"
,"specific"
, or"typical"
. -
may have one member with the name
"borderColor"
. The value is an array with 4 numbers between 0.0 and 1.0 (RGBA colour).
"textures" : [ { "type" : "PNG" , "image" : "http://www.someurl.org/filename.jpg" }, { "type" : "JPG" , "image" : "appearances/myroof.jpg" , "wrapMode" : "wrap" , "textureType" : "unknown" , "borderColor" : [ 0.0 , 0.1 , 0.2 , 1.0 ] } ]
6.5. Vertices-texture Object
An Appearance Object may have one member named "vertices-texture"
. The value is an array of the (u,v) coordinates of the vertices used for texturing surfaces.
Their position in this array (0-based) is used by the "texture"
member of the Geometry Objects.
-
the array of vertices may be empty.
-
one vertex must be an array with exactly 2 values, representing the (u,v) coordinates.
-
The value of u and v must be between 0.0 and 1.0.
-
vertices may be repeated
"vertices-texture" : [ [ 0.0 , 0.5 ], [ 1.0 , 0.0 ], [ 1.0 , 1.0 ], [ 0.0 , 1.0 ] ]
7. Handling large files
Because CityJSON aims at being easy-to-use and developers friendly, it is advised to keep the size of CityJSON files small. Files of several hundreds of megabytes are bad practice, and should be avoided since users will have great difficulties visualising and manipulating them.
7.1. Decomposing an area into parts/tiles
One solution to handle a large dataset is to subdivide it into tiles or regions, and ensure that each part has a reasonable size. Each part becomes a CityJSON file.
7.2. Text sequences and streaming with CityJSONFeature
Another solution is to decompose a CityJSON object into its features (the City Objects), create several JSON objects, and store them in a JSON Lines text (also called Newline Delimited JSON). This is a format to store several JSON objects in a single file, and allows the processing of each object one at a time.
A CityJSON Feature Object allows storage of one feature, for instance a "Building"
with eventually its children "BuildingPart"
and/or "BuildingInstallation"
.
Unlike a CityJSON Object, all the vertices and appearances of the object are local.
A CityJSON Feature Object:
-
is a JSON object.
-
must have one member with the name
"type"
. The value must be"CityJSONFeature"
. -
must have one member with the name
"id"
. The value must be a string representing the identifier of the City Object Feature, this is used to clearly identify which of the CityObjects is the parent. -
must have one member with the name
"CityObjects"
. The value of this member is a collection of key-value pairs, where the key is the ID of the object, and the value is one City Object. The ID of a City Object should be unique (within one"CityJSONFeature"
), and all the children of the"CityJSONFeature"
must be included (and the children of the children (recursively), if there are any). -
must have one member with the name
"vertices"
. The value is an array of coordinates of each vertex of the current City Object Feature (stored with integers). Their position in this array (0-based) is used as an index to be referenced by the Geometry Objects for the JSON object (warning: the vertices are local to the JSON object). -
may have one member with the name
"appearance"
. The value may contain JSON objects representing the textures and/or materials of surfaces. See § 6 Appearance Object for details. -
must not have other members.
{ "type" : "CityJSONFeature" , "id" : "myid" , "CityObjects" : {}, "vertices" : [], "appearance" : {} }
{ "type" : "CityJSONFeature" , "id" : "id-1" , "CityObjects" : { "id-1" : { "type" : "Building" , "attributes" : { "roofType" : "gabled roof" }, "children" : [ "mypart" ], "geometry" : [ ...] }, "mypart" : { "type" : "BuildingPart" , "parents" : [ "id-1" ], "children" : [ "mybalcony" ], "geometry" : [ ...] }, "mybalcony" : { "type" : "BuildingInstallation" , "parents" : [ "mypart" ], "geometry" : [ ...] } }, "vertices" : [ ...] }
The following root property of a CityJSON Object are not allowed in a CityJSONFeature Object:
-
"transform"
-
"version"
-
"metadata"
-
"geometry-templates"
: these should be resolved/dereferenced -
"extensions"
: these should be in the metadata or collection
Note that a CityJSON Feature Object does not contain all the information that is required for parsing the feature. Most commonly, the transformation properties (the Transform Object) and CRS need to be known by the client in order to correctly georeference the City Objects. These properties may be known by the client upfront, or they may be accessible in a CityJSON Object, which is sent as the first object in a JSON Lines text stream, or in other ways not described here.
In case the properties are stored in a CityJSON Object, this object needs to be a valid CityJSON Object.
This implies that the CityJSON object must contain all the required properties, including "CityObjects"
and "vertices"
, even though they are empty, because this information is stored in the subsequent CityJSON Features.
Below is an example of a CityJSONFeature stream (or a JSON Lines text file), with a CityJSON Object storing the metadata and transformation properties:
{ "type" : "CityJSON" , "version" : "1.1" , "transform" :{ ...}, "CityObjects" :{}, "metadata" :{ ...}, "vertices" :[]} { "type" : "CityJSONFeature" , "id" : "a" , "CityObjects" :{ ...}, "vertices" :[ ...]} { "type" : "CityJSONFeature" , "id" : "b" , "CityObjects" :{ ...}, "vertices" :[ ...]} { "type" : "CityJSONFeature" , "id" : "c" , "CityObjects" :{ ...}, "vertices" :[ ...]}
"CityJSON"
and "CityJSONFeature"
objects may be stored in a file with the extension '.city.jsonl'
"CityJSON"
and "CityJSONFeature"
objects should be defined. 8. Extensions
CityJSON uses JSON Schemas to document and validate its data model, including its Extensions. Schemas offer a way to validate the syntax of a JSON document, and thus the possibility to require certain JSON members. Therefore, for writing more complex Extensions, a basic familiarity with JSON Schemas is advised.
A CityJSON Extension is a JSON file that documents how the core data model of CityJSON is extended, and is also used for validating the CityJSON files. This is conceptually akin to the Application Domain Extensions (ADEs) in CityGML.
A CityJSON Extension can extend the core data model in four ways:
-
Defining new properties at the root of a document
-
Defining attributes on existing City Objects
-
Defining a new Semantic Object
-
Defining a new City Object, or "extending" one of the existing City Objects
There is ongoing work to use the ADE schemas to automatically do this, but this currently is not supported by most software. Viewers might not be affected by ADEs because the geometries are usually not changed by an ADE (although they can!). However, software parsing the XML to extract attributes and features might not work directly (and thus specific code would need to be written).
CityJSON Extensions are designed such that they can be read and processed by standard CityJSON software, often no changes in the parsing code is required. This is achieved by enforcing a set of 6 simple rules (see § 8.7 Rules to follow to define new City Objects) when adding new City Objects. If these are followed, then a CityJSON file containing Extensions will be seen as a "standard" CityJSON file.
One of the philosophies of JSON is "schema-less", which means that one is allowed to define new properties for the JSON objects without documenting them in a JSON schema (watch out: this does not mean that JSON does not have schemas!). While this is in contrast to CityGML (and GML as a whole) where the schemas are central, the schemas of CityJSON are (partly) following that philosophy.
If one wants to document the parcel area in square-meters for a "Building"
("area-parcel": {"value": 437, "uom": "m2"}
), the easiest way is just to add a new property to the City Object attributes:
{ "type" : "Building" , "attributes" : { "storeysAboveGround" : 2 , "area-parcel" : { "value" : 437 , "uom" : "m2" } }, "geometry" : [ ...] }
However, a regular attribute (without the "+"
prefix) cannot be made mandatory in the core CityJSON schema.
Only with an Extension can an attribute be made mandatory (see § 8.4 Case 2: Defining attributes on existing City Objects).
Therefore, an Extension is used for enforcing certain properties, attributes, or City Object types in CityJSON objects. An Extension makes sense if it is expected that different data producers and consumers in the target domain need to exchange data, or if an additional City Object or Semantic type is required for accurately modelling the data.
8.1. Using an Extension in a CityJSON file
An Extension should be given a name (eg "Noise") and the URL of the Extension file should be defined, including the version of the Extension that is used for this file. It is expected that the Extension is publicly available at the URL, and can be downloaded.
Several Extensions can be used in a single CityJSON Object, each one is indexed by its name in the "extensions"
JSON object.
In the example below we have two Extensions: one named "Noise" and one named "Solar_Potential".
{ "type" : "CityJSON" , "version" : "1.1" , "extensions" : { "Noise" : { "url" : "https://someurl.org/noise.json" , "version" : "2.0" }, "Solar_Potential" : { "url" : "https://someurl.org/solar.json" , "version" : "0.8" } }, "CityObjects" : {}, "vertices" : [] }
8.2. The Extension file
A CityJSON Extension is a JSON object, and it must have the following 8 members:
-
one member with the name
"type"
. The value must be"CityJSONExtension"
. -
one member with the name
"name"
. The value must be a string identifying the extension. -
one member with the name
"url"
. The value must be a string with the HTTP URL of the location of the schema where the JSON object is located. -
one member with the name
"version"
. The value must be a string identifying the version of the Extension. -
one member with the name
"versionCityJSON"
. The value must be a string (X.Y) identifying the version of CityJSON that uses the Extension. -
one member with the name
"extraRootProperties"
. The value must be a JSON object. Its content is part of a JSON schema (explained below), or an empty object. -
one member with the name
"extraAttributes"
. The value must be a JSON object. Its content is part of a JSON schema (explained below), or an empty object. -
one member with the name
"extraCityObjects"
. The value must be a JSON object. Its content is part of a JSON schema (explained below), or an empty object.
{ "type" : "CityJSONExtension" , "name" : "Noise" , "description" : "Extension to model the noise" , "url" : "https://someurl.org/noise.ext.json" , "version" : "0.5" , "versionCityJSON" : "1.1" , "extraRootProperties" : {}, "extraAttributes" : {}, "extraCityObjects" : {} }
"items" : { "oneOf" : [ { "$ref" : "geomprimitives.json#/Solid" } ] }
8.3. Case 1: Adding new properties at the root of a document
It is allowed to add a new property at the root of a CityJSON file, but if one wants to document it in a schema, then this property must start with a "+"
.
Imagine we wanted to store some census data for a given neighbourhood for which we have a CityJSON file, then we could define the extra root property "+census"
as follows:
"extraRootProperties" : { "+census" : { "type" : "object" , "properties" : { "percent_men" : { "type" : "number" , "minimum" : 0.0 , "maximum" : 100.0 }, "percent_women" : { "type" : "number" , "minimum" : 0.0 , "maximum" : 100.0 } } } }
And a CityJSON file would look like this:
{ "type" : "CityJSON" , "version" : "1.1" , "extensions" : { "Census" : { "url" : "https://someurl.org/census.ext.json" , "version" : "0.7" } }, "CityObjects" : { ...}, "vertices" : [ ...], "+census" : { "percent_men" : 49.5 , "percent_women" : 51.5 } }
8.4. Case 2: Defining attributes on existing City Objects
It is also possible to add, and document in a schema, specific attributes, for example if we wanted to have the colour of the buildings as a RGBA value (red-green-blue-alpha):
{ "type" : "Building" , "attributes" : { "storeysAboveGround" : 2 , "+colour" : { "rgba" : [ 255 , 255 , 255 , 1 ] } }, "geometry" : [ ...] }
Another example would be to store the area of the parcel of a building, and also to document the unit of measurement (UoM):
{ "type" : "Building" , "attributes" : { "storeysAboveGround" : 2 , "+area-parcel" : { "value" : 437 , "uom" : "m2" } }, "geometry" : [ ...] }
For these two cases, the CityJSON Extension object would look like the snippet below.
Notice that "extraAttributes"
may have several properties (the types of the City Objects are the possibilities) and then each of these has as properties the new attributes (there can be several).
An extra attribute must start with a "+"
; it is good practice to prepend the attribute with the name of the Extension, to avoid that 2 attributes from 2 different Extensions have the same name.
The value of the property is a JSON schema, this schema can reference and reuse JSON objects already defined in the CityJSON schemas.
Thus, the keywords of the property values are defined by the JSON Schema specification.
For instance, "additionalProperties"
is a JSON-schema keyword stating that one is not allowed to add properties to this JSON object, beyond the ones defined in the schema (eg "value", "uom"
).
"extraAttributes" : { "Building" : { "+colour" : { "type" : "object" , "properties" : { "rgba" : { "type" : "array" , "items" : { "type" : "number" }, "minItems" : 4 , "maxItems" : 4 } }, "required" : [ "rgba" ], "additionalProperties" : false }, "+area-parcel" : { "type" : "object" , "properties" : { "value" : { "type" : "number" }, "uom" : { "type" : "string" , "enum" : [ "m2" , "feet2" ] } }, "required" : [ "value" , "uom" ], "additionalProperties" : false } } }
8.5. Case 3: Defining a new Semantic Object
To define a new semantic surface (besides the ones prescribed, see § 3.3 Semantics of geometric primitives), a "+"
must be prepended to its name, eg "+ThermalSurface"
.
{ "type" : "+ThermalSurface" }
8.6. Case 4: Creating and/or extending new City Objects
The creation of a new City Object is done by defining it in the CityJSON Extension object in the "extraCityObjects"
property:
"extraCityObjects" : { "+NoiseBuilding" : { "allOf" : [ { "$ref" : "cityobjects.json#/_AbstractBuilding" }, { "properties" : { "type" : { "enum" : [ "+NoiseBuilding" ] }, "attributes" : { "properties" : { "buildingLDenMin" : { "type" : "number" } } } }, "required" : [ "type" ] } ] } }
"extraCityObjects" : { "+NoiseBuildingPart" : { "allOf" : [ { "$ref" : "cityobjects.json#/_AbstractBuilding" }, { "properties" : { "type" : { "enum" : [ "+NoiseBuildingPart" ] }, "attributes" : { "properties" : { "buildingLDenMin" : { "type" : "number" } } } }, "required" : [ "type" , "parents" ] } ] } }
Since all City Objects are documented in the schemas of CityJSON (in cityobjects.schema.json
), it is basically a matter of copying the parts needed in a new file and modifying its content.
A new name for the City Object must be given and it must begin with a "+"
.
Because City Objects can be of different levels (1st-level ones can exist by themselves; 2nd-level ones need to have a parent), we need to explicitly define that "parents"
is mandatory for 2nd-level objects.
Please note that since JSON schemas do not allow inheritance, the only way to extend a City Object is to define an entirely new one (with a new name, eg "+NoiseBuilding"
).
This is done by copying the schema of the parent City Object and extending it.
8.7. Rules to follow to define new City Objects
The challenge when creating Extensions to the core model is that we do not want to break the software packages (viewers, spatial analysis, etc) that already read and process CityJSON files. While one could define a new City Object and document it, if this new object does not follow the rules below then it will mean that new specific software needs to be built for it (and this would go against the fundamental ideas behind CityJSON).
-
The name of a new City Object must begin with a
"+"
, eg"+NoiseBuilding"
. -
A new City Object must conform to the rules of CityJSON, ie it must contain a property
"type"
. -
Existing City Objects cannot be extended and have new types as children, eg it is not allowed to add a new City Object
"+Balcony"
to a"Building"
. Instead, a new type, eg"+FancyBuilding"
, should be created and it can have a"+Balcony"
as a potential children. -
All the geometries must be in the property
"geometry"
, and cannot be located somewhere else deep in a hierarchy of a new property. -
The Geometry object’s boundary must be one of the eight types described in § 3 Geometry Objects. Similarly, the geometry appearances and templates must follow the core specification. This ensures that all the code written to process, manipulate, and view CityJSON files will be working without modifications.
-
The reuse of types defined in CityJSON, eg
"Solid"
or semantic surfaces, is allowed.
9. CityJSON Schemas
The JSON schemas of the specifications are publicly available at https://cityjson.org/schemas/.
10. CityGML v3.0 conformance
CityJSON v1.1 is conformant with the CityGML v3.0 data model, although not all extension modules have been implemented.
The details of which modules are supported (and where the so-called null mapping are applied, see CityGML Modularization), are available at https://www.cityjson.org/conformance/v30/


The box is the simplest of components, it is more for illustrative purposes than anything. The classname is .box and any other element of component can go inside of it. This is styled with a border mostly so it can be seen.