Merge remote-tracking branch 'upstream/master'

Conflicts:
	data/core.yaml
	dist/locales/en.json
This commit is contained in:
popov
2017-01-09 11:15:56 +10:00
53 changed files with 1247 additions and 320 deletions
+8 -2
View File
@@ -11,7 +11,10 @@ html, body {
}
body {
font:normal 12px/1.6667 'Helvetica Neue', Arial, sans-serif;
font: normal 12px/1.6667 -apple-system, BlinkMacSystemFont,
"Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell",
"Fira Sans", "Droid Sans", "Helvetica Neue", "Arial",
sans-serif;
margin:0;
padding:0;
min-width: 768px;
@@ -148,7 +151,10 @@ a:hover {
textarea {
resize: vertical;
font:normal 12px/20px 'Helvetica Neue', Arial, sans-serif;
font:normal 12px/20px -apple-system, BlinkMacSystemFont,
"Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell",
"Fira Sans", "Droid Sans", "Helvetica Neue", "Arial",
sans-serif;
}
textarea,
+8
View File
@@ -38,6 +38,14 @@
{
"countryCodes": ["tw"],
"format": [["postcode", "city", "district"], ["place", "street"], ["housenumber", "floor"]]
},
{
"countryCodes": ["jp"],
"format": [["postcode", "province", "county"], ["city", "suburb", "quarter"], ["neighbourhood", "block_number", "housenumber"]]
},
{
"countryCodes": ["tr"],
"format": [["neighbourhood"], ["street", "housenumber"], ["postcode", "district", "city"]]
}
]
}
+46 -46
View File
@@ -78,24 +78,24 @@ en:
delete:
title: Delete
description:
single: Delete this object permanently.
multiple: Delete these objects permanently.
single: Delete this feature permanently.
multiple: Delete these features permanently.
annotation:
point: Deleted a point.
vertex: Deleted a node from a way.
line: Deleted a line.
area: Deleted an area.
relation: Deleted a relation.
multiple: "Deleted {n} objects."
multiple: "Deleted {n} features."
incomplete_relation:
single: This object can't be deleted because it hasn't been fully downloaded.
multiple: These objects can't be deleted because they haven't been fully downloaded.
single: This feature can't be deleted because it hasn't been fully downloaded.
multiple: These features can't be deleted because they haven't been fully downloaded.
part_of_relation:
single: This object can't be deleted because it is part of a larger relation. You must remove it from the relation first.
multiple: These objects can't be deleted because they are part of larger relations. You must remove them from the relations first.
single: This feature can't be deleted because it is part of a larger relation. You must remove it from the relation first.
multiple: These features can't be deleted because they are part of larger relations. You must remove them from the relations first.
connected_to_hidden:
single: This object can't be deleted because it is connected to a hidden feature.
multiple: These objects can't be deleted because some are connected to hidden features.
single: This feature can't be deleted because it is connected to a hidden feature.
multiple: These features can't be deleted because some are connected to hidden features.
add_member:
annotation: Added a member to a relation.
delete_member:
@@ -127,71 +127,71 @@ en:
move:
title: Move
description:
single: Move this object to a different location.
multiple: Move these objects to a different location.
single: Move this feature to a different location.
multiple: Move these features to a different location.
key: M
annotation:
point: Moved a point.
vertex: Moved a node in a way.
line: Moved a line.
area: Moved an area.
multiple: Moved multiple objects.
multiple: Moved multiple features.
incomplete_relation:
single: This object can't be moved because it hasn't been fully downloaded.
multiple: These objects can't be moved because they haven't been fully downloaded.
single: This feature can't be moved because it hasn't been fully downloaded.
multiple: These features can't be moved because they haven't been fully downloaded.
too_large:
single: This object can't be moved because not enough of it is currently visible.
multiple: These objects can't be moved because not enough of them are currently visible.
single: This feature can't be moved because not enough of it is currently visible.
multiple: These features can't be moved because not enough of them are currently visible.
connected_to_hidden:
single: This object can't be moved because it is connected to a hidden feature.
multiple: These objects can't be moved because some are connected to hidden features.
single: This feature can't be moved because it is connected to a hidden feature.
multiple: These features can't be moved because some are connected to hidden features.
reflect:
title: reflect
description:
long:
single: Reflect this object across its long axis.
multiple: Reflect these objects across their long axis.
single: Reflect this feature across its long axis.
multiple: Reflect these features across their long axis.
short:
single: Reflect this object across its short axis.
multiple: Reflect these objects across their short axis.
single: Reflect this feature across its short axis.
multiple: Reflect these features across their short axis.
key:
long: T
short: Y
annotation:
long:
single: Reflected an object across its long axis.
multiple: Reflected multiple objects across their long axis.
single: Reflected an feature across its long axis.
multiple: Reflected multiple features across their long axis.
short:
single: Reflected an object across its short axis.
multiple: Reflected multiple objects across their short axis.
single: Reflected an feature across its short axis.
multiple: Reflected multiple features across their short axis.
incomplete_relation:
single: This object can't be reflected because it hasn't been fully downloaded.
multiple: These objects can't be reflected because they haven't been fully downloaded.
single: This feature can't be reflected because it hasn't been fully downloaded.
multiple: These features can't be reflected because they haven't been fully downloaded.
too_large:
single: This object can't be reflected because not enough of it is currently visible.
multiple: These objects can't be reflected because not enough of them are currently visible.
single: This feature can't be reflected because not enough of it is currently visible.
multiple: These features can't be reflected because not enough of them are currently visible.
connected_to_hidden:
single: This object can't be reflected because it is connected to a hidden feature.
multiple: These objects can't be reflected because some are connected to hidden features.
single: This feature can't be reflected because it is connected to a hidden feature.
multiple: These features can't be reflected because some are connected to hidden features.
rotate:
title: Rotate
description:
single: Rotate this object around its center point.
multiple: Rotate these objects around their center point.
single: Rotate this feature around its center point.
multiple: Rotate these features around their center point.
key: R
annotation:
line: Rotated a line.
area: Rotated an area.
multiple: Rotated multiple objects.
multiple: Rotated multiple features.
incomplete_relation:
single: This object can't be rotated because it hasn't been fully downloaded.
multiple: These objects can't be rotated because they haven't been fully downloaded.
single: This feature can't be rotated because it hasn't been fully downloaded.
multiple: These features can't be rotated because they haven't been fully downloaded.
too_large:
single: This object can't be rotated because not enough of it is currently visible.
multiple: These objects can't be rotated because not enough of them are currently visible.
single: This feature can't be rotated because not enough of it is currently visible.
multiple: These features can't be rotated because not enough of them are currently visible.
connected_to_hidden:
single: This object can't be rotated because it is connected to a hidden feature.
multiple: These objects can't be rotated because some are connected to hidden features.
single: This feature can't be rotated because it is connected to a hidden feature.
multiple: These features can't be rotated because some are connected to hidden features.
reverse:
title: Reverse
description: Make this line go in the opposite direction.
@@ -310,7 +310,7 @@ en:
back_tooltip: Change feature
remove: Remove
search: Search
multiselect: Selected items
multiselect: Selected features
unknown: Unknown
incomplete: <not downloaded>
feature_list: Search features
@@ -423,12 +423,12 @@ en:
done: "All conflicts resolved!"
help: |
Another user changed some of the same map features you changed.
Click on each item below for more details about the conflict, and choose whether to keep
Click on each feature below for more details about the conflict, and choose whether to keep
your changes or the other user's changes.
merge_remote_changes:
conflict:
deleted: 'This object has been deleted by {user}.'
location: 'This object was moved by both you and {user}.'
deleted: 'This feature has been deleted by {user}.'
location: 'This feature was moved by both you and {user}.'
nodelist: 'Nodes were changed by both you and {user}.'
memberlist: 'Relation members were changed by both you and {user}.'
tags: 'You changed the <b>{tag}</b> tag to "{local}" and {user} changed it to "{remote}".'
@@ -462,7 +462,7 @@ en:
untagged_point: Untagged point
untagged_line: Untagged line
untagged_area: Untagged area
many_deletions: "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org."
many_deletions: "You're deleting {n} features. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org."
tag_suggests_area: "The tag {tag} suggests line should be area, but it is not an area"
untagged_point_tooltip: "Select a feature type that describes what this point is."
untagged_line_tooltip: "Select a feature type that describes what this line is."
+48 -7
View File
@@ -78,20 +78,24 @@ en:
# access=*
label: Access
address:
# 'addr:city=*, addr:conscriptionnumber=*, addr:country=*, addr:district=*, addr:floor=*, addr:hamlet=*, addr:housename=*, addr:housenumber=*, addr:place=*, addr:postcode=*, addr:province=*, addr:state=*, addr:street=*, addr:subdistrict=*, addr:suburb=*'
# 'addr:block_number=*, addr:city=*, addr:conscriptionnumber=*, addr:county=*, addr:country=*, addr:district=*, addr:floor=*, addr:hamlet=*, addr:housename=*, addr:housenumber=*, addr:neighbourhood=*, addr:place=*, addr:postcode=*, addr:province=*, addr:quarter=*, addr:state=*, addr:street=*, addr:subdistrict=*, addr:suburb=*'
label: Address
placeholders:
block_number: Block number
city: City
conscriptionnumber: '123'
country: Country
county: County
district: District
floor: Floor
hamlet: Hamlet
housename: Housename
housenumber: '123'
neighbourhood: Neighbourhood
place: Place
postcode: Postcode
province: Province
quarter: Quarter
state: State
street: Street
subdistrict: Subdistrict
@@ -284,6 +288,9 @@ en:
WNW: West-northwest
# direction=WSW
WSW: West-southwest
castle_type:
# castle_type=*
label: Type
clock_direction:
# direction=*
label: Direction
@@ -431,6 +438,18 @@ en:
fence_type:
# fence_type=*
label: Type
fire_hydrant/position:
# 'fire_hydrant:position=*'
label: Position
options:
# 'fire_hydrant:position=green'
green: Green
# 'fire_hydrant:position=lane'
lane: Lane
# 'fire_hydrant:position=parking_lot'
parking_lot: Parking Lot
# 'fire_hydrant:position=sidewalk'
sidewalk: Sidewalk
fire_hydrant/type:
# 'fire_hydrant:type=*'
label: Type
@@ -1059,11 +1078,12 @@ en:
very_horrible: 'Specialized off-road: tractor, ATV'
# smoothness field placeholder
placeholder: 'Thin Rollers, Wheels, Off-Road...'
social_facility:
# social_facility=*
label: Type
social_facility_for:
# 'social_facility:for=*'
label: People served
# social_facility_for field placeholder
placeholder: 'Homeless, Disabled, Child, etc'
label: People Served
source:
# source=*
label: Source
@@ -1161,6 +1181,9 @@ en:
flush: Flush
# 'toilets:disposal=pitlatrine'
pitlatrine: Pit/Latrine
toll:
# toll=*
label: Toll
tourism:
# tourism=*
label: Type
@@ -1481,10 +1504,8 @@ en:
name: Courthouse
terms: '<translate with synonyms or related terms for ''Courthouse'', separated by commas>'
amenity/coworking_space:
# amenity=coworking_space
# office=coworking
name: Coworking Space
# 'terms: coworking,office'
terms: '<translate with synonyms or related terms for ''Coworking Space'', separated by commas>'
amenity/crematorium:
# amenity=crematorium
name: Crematorium
@@ -1862,6 +1883,10 @@ en:
# barrier=bollard
name: Bollard
terms: '<translate with synonyms or related terms for ''Bollard'', separated by commas>'
barrier/border_control:
# barrier=border_control
name: Border Control
terms: '<translate with synonyms or related terms for ''Border Control'', separated by commas>'
barrier/cattle_grid:
# barrier=cattle_grid
name: Cattle Grid
@@ -2298,6 +2323,7 @@ en:
emergency/fire_hydrant:
# emergency=fire_hydrant
name: Fire Hydrant
# 'terms: fire plug'
terms: '<translate with synonyms or related terms for ''Fire Hydrant'', separated by commas>'
emergency/no:
# emergency=no
@@ -2435,6 +2461,7 @@ en:
highway/motorway:
# highway=motorway
name: Motorway
# 'terms: autobahn,expressway,freeway,highway,interstate,parkway,thruway,turnpike'
terms: '<translate with synonyms or related terms for ''Motorway'', separated by commas>'
highway/motorway_junction:
# highway=motorway_junction
@@ -2841,6 +2868,11 @@ en:
name: Golf Course
# 'terms: links'
terms: '<translate with synonyms or related terms for ''Golf Course'', separated by commas>'
leisure/horse_riding:
# leisure=horse_riding
name: Horseback Riding Facility
# 'terms: equestrian,stable'
terms: '<translate with synonyms or related terms for ''Horseback Riding Facility'', separated by commas>'
leisure/ice_rink:
# leisure=ice_rink
name: Ice Rink
@@ -3231,6 +3263,11 @@ en:
# office=company
name: Company Office
terms: '<translate with synonyms or related terms for ''Company Office'', separated by commas>'
office/coworking:
# office=coworking
name: Coworking Space
# 'terms: coworking,office'
terms: '<translate with synonyms or related terms for ''Coworking Space'', separated by commas>'
office/educational_institution:
# office=educational_institution
name: Educational Institution
@@ -3338,6 +3375,10 @@ en:
name: Neighborhood
# 'terms: neighbourhood'
terms: '<translate with synonyms or related terms for ''Neighborhood'', separated by commas>'
place/square:
# place=square
name: Square
terms: '<translate with synonyms or related terms for ''Square'', separated by commas>'
place/suburb:
# place=suburb
name: Borough
+38 -19
View File
@@ -79,17 +79,21 @@
"address": {
"type": "address",
"keys": [
"addr:block_number",
"addr:city",
"addr:conscriptionnumber",
"addr:county",
"addr:country",
"addr:district",
"addr:floor",
"addr:hamlet",
"addr:housename",
"addr:housenumber",
"addr:neighbourhood",
"addr:place",
"addr:postcode",
"addr:province",
"addr:quarter",
"addr:state",
"addr:street",
"addr:subdistrict",
@@ -103,17 +107,21 @@
"label": "Address",
"strings": {
"placeholders": {
"block_number": "Block number",
"city": "City",
"conscriptionnumber": "123",
"county": "County",
"country": "Country",
"district": "District",
"floor": "Floor",
"hamlet": "Hamlet",
"housename": "Housename",
"housenumber": "123",
"neighbourhood": "Neighbourhood",
"place": "Place",
"postcode": "Postcode",
"province": "Province",
"quarter": "Quarter",
"state": "State",
"street": "Street",
"subdistrict": "Subdistrict",
@@ -364,6 +372,11 @@
}
}
},
"castle_type": {
"key": "castle_type",
"type": "combo",
"label": "Type"
},
"clock_direction": {
"key": "direction",
"type": "combo",
@@ -599,6 +612,19 @@
"type": "combo",
"label": "Type"
},
"fire_hydrant/position": {
"key": "fire_hydrant:position",
"type": "combo",
"label": "Position",
"strings": {
"options": {
"lane": "Lane",
"parking_lot": "Parking Lot",
"sidewalk": "Sidewalk",
"green": "Green"
}
}
},
"fire_hydrant/type": {
"key": "fire_hydrant:type",
"type": "combo",
@@ -1404,25 +1430,13 @@
},
"social_facility_for": {
"key": "social_facility:for",
"type": "radio",
"label": "People served",
"placeholder": "Homeless, Disabled, Child, etc",
"options": [
"abused",
"child",
"disabled",
"diseased",
"drug_addicted",
"homeless",
"juvenile",
"mental_health",
"migrant",
"orphan",
"senior",
"underprivileged",
"unemployed",
"victim"
]
"type": "combo",
"label": "People Served"
},
"social_facility": {
"key": "social_facility",
"type": "combo",
"label": "Type"
},
"source": {
"key": "source",
@@ -1577,6 +1591,11 @@
}
}
},
"toll": {
"key": "toll",
"type": "check",
"label": "Toll"
},
"tourism": {
"key": "tourism",
"type": "typeCombo",
+8
View File
@@ -1,17 +1,21 @@
{
"type": "address",
"keys": [
"addr:block_number",
"addr:city",
"addr:conscriptionnumber",
"addr:county",
"addr:country",
"addr:district",
"addr:floor",
"addr:hamlet",
"addr:housename",
"addr:housenumber",
"addr:neighbourhood",
"addr:place",
"addr:postcode",
"addr:province",
"addr:quarter",
"addr:state",
"addr:street",
"addr:subdistrict",
@@ -23,17 +27,21 @@
"label": "Address",
"strings": {
"placeholders": {
"block_number": "Block number",
"city": "City",
"conscriptionnumber": "123",
"county": "County",
"country": "Country",
"district": "District",
"floor": "Floor",
"hamlet": "Hamlet",
"housename": "Housename",
"housenumber": "123",
"neighbourhood": "Neighbourhood",
"place": "Place",
"postcode": "Postcode",
"province": "Province",
"quarter": "Quarter",
"state": "State",
"street": "Street",
"subdistrict": "Subdistrict",
+5
View File
@@ -0,0 +1,5 @@
{
"key": "castle_type",
"type": "combo",
"label": "Type"
}
@@ -0,0 +1,13 @@
{
"key": "fire_hydrant:position",
"type": "combo",
"label": "Position",
"strings": {
"options": {
"lane": "Lane",
"parking_lot": "Parking Lot",
"sidewalk": "Sidewalk",
"green": "Green"
}
}
}
+5
View File
@@ -0,0 +1,5 @@
{
"key": "social_facility",
"type": "combo",
"label": "Type"
}
+3 -21
View File
@@ -1,23 +1,5 @@
{
"key": "social_facility:for",
"type": "radio",
"label": "People served",
"placeholder": "Homeless, Disabled, Child, etc",
"options": [
"abused",
"child",
"disabled",
"diseased",
"drug_addicted",
"homeless",
"juvenile",
"mental_health",
"migrant",
"orphan",
"senior",
"underprivileged",
"unemployed",
"victim"
]
}
"type": "combo",
"label": "People Served"
}
+5
View File
@@ -0,0 +1,5 @@
{
"key": "toll",
"type": "check",
"label": "Toll"
}
+125 -35
View File
@@ -445,6 +445,26 @@
},
"name": "Airport terminal"
},
"amenity/coworking_space": {
"icon": "commercial",
"fields": [
"address",
"building_area",
"opening_hours",
"internet_access",
"internet_access/fee",
"internet_access/ssid"
],
"geometry": [
"point",
"area"
],
"tags": {
"office": "coworking"
},
"name": "Coworking Space",
"searchable": false
},
"amenity/register_office": {
"icon": "town-hall",
"fields": [
@@ -1015,29 +1035,6 @@
},
"name": "Courthouse"
},
"amenity/coworking_space": {
"icon": "commercial",
"fields": [
"address",
"building_area",
"opening_hours",
"internet_access",
"internet_access/fee",
"internet_access/ssid"
],
"geometry": [
"point",
"area"
],
"terms": [
"coworking",
"office"
],
"tags": {
"amenity": "coworking_space"
},
"name": "Coworking Space"
},
"amenity/crematorium": {
"icon": "cemetery",
"fields": [
@@ -2109,9 +2106,10 @@
"operator",
"address",
"building_area",
"social_facility",
"social_facility_for",
"opening_hours",
"wheelchair",
"social_facility_for"
"wheelchair"
],
"geometry": [
"point",
@@ -2128,8 +2126,9 @@
"operator",
"address",
"building_area",
"opening_hours",
"social_facility_for"
"social_facility",
"social_facility_for",
"opening_hours"
],
"geometry": [
"point",
@@ -2147,9 +2146,10 @@
"operator",
"address",
"building_area",
"social_facility",
"social_facility_for",
"opening_hours",
"wheelchair",
"social_facility_for"
"wheelchair"
],
"geometry": [
"point",
@@ -2172,9 +2172,10 @@
"operator",
"address",
"building_area",
"social_facility",
"social_facility_for",
"opening_hours",
"wheelchair",
"social_facility_for",
"internet_access",
"internet_access/fee",
"internet_access/ssid"
@@ -2729,6 +2730,21 @@
},
"name": "Bollard"
},
"barrier/border_control": {
"icon": "roadblock",
"fields": [
"access",
"building_area"
],
"geometry": [
"vertex",
"area"
],
"tags": {
"barrier": "border_control"
},
"name": "Border Control"
},
"barrier/cattle_grid": {
"icon": "prison",
"geometry": [
@@ -2876,10 +2892,12 @@
"barrier/toll_booth": {
"icon": "roadblock",
"fields": [
"access"
"access",
"building_area"
],
"geometry": [
"vertex"
"vertex",
"area"
],
"tags": {
"barrier": "toll_booth"
@@ -4511,12 +4529,16 @@
"emergency/fire_hydrant": {
"icon": "fire-station",
"fields": [
"fire_hydrant/type"
"fire_hydrant/type",
"fire_hydrant/position"
],
"geometry": [
"point",
"vertex"
],
"terms": [
"fire plug"
],
"tags": {
"emergency": "fire_hydrant"
},
@@ -5013,6 +5035,7 @@
"lanes",
"surface",
"maxheight",
"toll",
"ref"
],
"geometry": [
@@ -5021,7 +5044,16 @@
"tags": {
"highway": "motorway"
},
"terms": [],
"terms": [
"autobahn",
"expressway",
"freeway",
"highway",
"interstate",
"parkway",
"thruway",
"turnpike"
],
"name": "Motorway"
},
"highway/path": {
@@ -5492,12 +5524,12 @@
"highway/track": {
"icon": "highway-track",
"fields": [
"tracktype",
"surface",
"width",
"structure",
"access",
"incline",
"tracktype",
"smoothness",
"mtb/scale",
"mtb/scale/uphill",
@@ -5605,6 +5637,7 @@
"lanes",
"surface",
"maxheight",
"toll",
"ref"
],
"geometry": [
@@ -5699,6 +5732,10 @@
"name": "Boundary Stone"
},
"historic/castle": {
"fields": [
"castle_type",
"building_area"
],
"geometry": [
"point",
"area"
@@ -6697,6 +6734,26 @@
},
"name": "Golf Course"
},
"leisure/horse_riding": {
"fields": [
"access_simple",
"operator",
"address",
"building"
],
"geometry": [
"point",
"area"
],
"terms": [
"equestrian",
"stable"
],
"tags": {
"leisure": "horse_riding"
},
"name": "Horseback Riding Facility"
},
"leisure/ice_rink": {
"icon": "pitch",
"fields": [
@@ -8156,6 +8213,29 @@
"terms": [],
"name": "Company Office"
},
"office/coworking": {
"icon": "commercial",
"fields": [
"address",
"building_area",
"opening_hours",
"internet_access",
"internet_access/fee",
"internet_access/ssid"
],
"geometry": [
"point",
"area"
],
"terms": [
"coworking",
"office"
],
"tags": {
"office": "coworking"
},
"name": "Coworking Space"
},
"office/educational_institution": {
"icon": "commercial",
"fields": [
@@ -8579,6 +8659,16 @@
],
"name": "Neighborhood"
},
"place/square": {
"geometry": [
"point",
"area"
],
"tags": {
"place": "square"
},
"name": "Square"
},
"place/suburb": {
"icon": "triangle-stroked",
"fields": [
@@ -0,0 +1,20 @@
{
"icon": "commercial",
"fields": [
"address",
"building_area",
"opening_hours",
"internet_access",
"internet_access/fee",
"internet_access/ssid"
],
"geometry": [
"point",
"area"
],
"tags": {
"office": "coworking"
},
"name": "Coworking Space",
"searchable": false
}
@@ -5,10 +5,9 @@
"phone",
"opening_hours",
"wheelchair"
],
"geometry": [
"area",
"area",
"point"
],
"tags": {
@@ -16,4 +15,4 @@
},
"terms": ["cemetery","funeral"],
"name": "Crematorium"
}
}
@@ -3,16 +3,16 @@
"operator",
"address",
"building_area",
"social_facility",
"social_facility_for",
"opening_hours",
"wheelchair",
"social_facility_for"
"wheelchair"
],
"geometry": [
"point",
"area"
],
"terms": [
],
"terms": [],
"tags": {
"amenity": "social_facility"
},
@@ -3,8 +3,9 @@
"operator",
"address",
"building_area",
"opening_hours",
"social_facility_for"
"social_facility",
"social_facility_for",
"opening_hours"
],
"geometry": [
"point",
@@ -3,9 +3,10 @@
"operator",
"address",
"building_area",
"social_facility",
"social_facility_for",
"opening_hours",
"wheelchair",
"social_facility_for"
"wheelchair"
],
"geometry": [
"point",
@@ -3,9 +3,10 @@
"operator",
"address",
"building_area",
"social_facility",
"social_facility_for",
"opening_hours",
"wheelchair",
"social_facility_for",
"internet_access",
"internet_access/fee",
"internet_access/ssid"
@@ -0,0 +1,15 @@
{
"icon": "roadblock",
"fields": [
"access",
"building_area"
],
"geometry": [
"vertex",
"area"
],
"tags": {
"barrier": "border_control"
},
"name": "Border Control"
}
+4 -2
View File
@@ -1,10 +1,12 @@
{
"icon": "roadblock",
"fields": [
"access"
"access",
"building_area"
],
"geometry": [
"vertex"
"vertex",
"area"
],
"tags": {
"barrier": "toll_booth"
@@ -1,12 +1,16 @@
{
"icon": "fire-station",
"fields": [
"fire_hydrant/type"
"fire_hydrant/type",
"fire_hydrant/position"
],
"geometry": [
"point",
"vertex"
],
"terms": [
"fire plug"
],
"tags": {
"emergency": "fire_hydrant"
},
+11 -1
View File
@@ -8,6 +8,7 @@
"lanes",
"surface",
"maxheight",
"toll",
"ref"
],
"geometry": [
@@ -16,6 +17,15 @@
"tags": {
"highway": "motorway"
},
"terms": [],
"terms": [
"autobahn",
"expressway",
"freeway",
"highway",
"interstate",
"parkway",
"thruway",
"turnpike"
],
"name": "Motorway"
}
+1 -1
View File
@@ -1,12 +1,12 @@
{
"icon": "highway-track",
"fields": [
"tracktype",
"surface",
"width",
"structure",
"access",
"incline",
"tracktype",
"smoothness",
"mtb/scale",
"mtb/scale/uphill",
+1
View File
@@ -8,6 +8,7 @@
"lanes",
"surface",
"maxheight",
"toll",
"ref"
],
"geometry": [
@@ -1,4 +1,8 @@
{
"fields": [
"castle_type",
"building_area"
],
"geometry": [
"point",
"area"
@@ -0,0 +1,20 @@
{
"fields": [
"access_simple",
"operator",
"address",
"building"
],
"geometry": [
"point",
"area"
],
"terms": [
"equestrian",
"stable"
],
"tags": {
"leisure": "horse_riding"
},
"name": "Horseback Riding Facility"
}
@@ -17,7 +17,7 @@
"office"
],
"tags": {
"amenity": "coworking_space"
"office": "coworking"
},
"name": "Coworking Space"
}
+10
View File
@@ -0,0 +1,10 @@
{
"geometry": [
"point",
"area"
],
"tags": {
"place": "square"
},
"name": "Square"
}
+20 -4
View File
@@ -115,6 +115,10 @@
"key": "aeroway",
"value": "terminal"
},
{
"key": "office",
"value": "coworking"
},
{
"key": "amenity",
"value": "register_office"
@@ -231,10 +235,6 @@
"key": "amenity",
"value": "courthouse"
},
{
"key": "amenity",
"value": "coworking_space"
},
{
"key": "amenity",
"value": "crematorium"
@@ -549,6 +549,10 @@
"key": "barrier",
"value": "bollard"
},
{
"key": "barrier",
"value": "border_control"
},
{
"key": "barrier",
"value": "cattle_grid"
@@ -1447,6 +1451,10 @@
"key": "leisure",
"value": "golf_course"
},
{
"key": "leisure",
"value": "horse_riding"
},
{
"key": "leisure",
"value": "ice_rink"
@@ -1796,6 +1804,10 @@
"key": "office",
"value": "company"
},
{
"key": "office",
"value": "coworking"
},
{
"key": "office",
"value": "educational_institution"
@@ -1891,6 +1903,10 @@
"key": "place",
"value": "neighbourhood"
},
{
"key": "place",
"value": "square"
},
{
"key": "place",
"value": "suburb"
+91 -54
View File
@@ -102,8 +102,8 @@
"delete": {
"title": "Delete",
"description": {
"single": "Delete this object permanently.",
"multiple": "Delete these objects permanently."
"single": "Delete this feature permanently.",
"multiple": "Delete these features permanently."
},
"annotation": {
"point": "Deleted a point.",
@@ -111,19 +111,19 @@
"line": "Deleted a line.",
"area": "Deleted an area.",
"relation": "Deleted a relation.",
"multiple": "Deleted {n} objects."
"multiple": "Deleted {n} features."
},
"incomplete_relation": {
"single": "This object can't be deleted because it hasn't been fully downloaded.",
"multiple": "These objects can't be deleted because they haven't been fully downloaded."
"single": "This feature can't be deleted because it hasn't been fully downloaded.",
"multiple": "These features can't be deleted because they haven't been fully downloaded."
},
"part_of_relation": {
"single": "This object can't be deleted because it is part of a larger relation. You must remove it from the relation first.",
"multiple": "These objects can't be deleted because they are part of larger relations. You must remove them from the relations first."
"single": "This feature can't be deleted because it is part of a larger relation. You must remove it from the relation first.",
"multiple": "These features can't be deleted because they are part of larger relations. You must remove them from the relations first."
},
"connected_to_hidden": {
"single": "This object can't be deleted because it is connected to a hidden feature.",
"multiple": "These objects can't be deleted because some are connected to hidden features."
"single": "This feature can't be deleted because it is connected to a hidden feature.",
"multiple": "These features can't be deleted because some are connected to hidden features."
}
},
"add_member": {
@@ -163,8 +163,8 @@
"move": {
"title": "Move",
"description": {
"single": "Move this object to a different location.",
"multiple": "Move these objects to a different location."
"single": "Move this feature to a different location.",
"multiple": "Move these features to a different location."
},
"key": "M",
"annotation": {
@@ -172,31 +172,31 @@
"vertex": "Moved a node in a way.",
"line": "Moved a line.",
"area": "Moved an area.",
"multiple": "Moved multiple objects."
"multiple": "Moved multiple features."
},
"incomplete_relation": {
"single": "This object can't be moved because it hasn't been fully downloaded.",
"multiple": "These objects can't be moved because they haven't been fully downloaded."
"single": "This feature can't be moved because it hasn't been fully downloaded.",
"multiple": "These features can't be moved because they haven't been fully downloaded."
},
"too_large": {
"single": "This object can't be moved because not enough of it is currently visible.",
"multiple": "These objects can't be moved because not enough of them are currently visible."
"single": "This feature can't be moved because not enough of it is currently visible.",
"multiple": "These features can't be moved because not enough of them are currently visible."
},
"connected_to_hidden": {
"single": "This object can't be moved because it is connected to a hidden feature.",
"multiple": "These objects can't be moved because some are connected to hidden features."
"single": "This feature can't be moved because it is connected to a hidden feature.",
"multiple": "These features can't be moved because some are connected to hidden features."
}
},
"reflect": {
"title": "reflect",
"description": {
"long": {
"single": "Reflect this object across its long axis.",
"multiple": "Reflect these objects across their long axis."
"single": "Reflect this feature across its long axis.",
"multiple": "Reflect these features across their long axis."
},
"short": {
"single": "Reflect this object across its short axis.",
"multiple": "Reflect these objects across their short axis."
"single": "Reflect this feature across its short axis.",
"multiple": "Reflect these features across their short axis."
}
},
"key": {
@@ -205,50 +205,50 @@
},
"annotation": {
"long": {
"single": "Reflected an object across its long axis.",
"multiple": "Reflected multiple objects across their long axis."
"single": "Reflected an feature across its long axis.",
"multiple": "Reflected multiple features across their long axis."
},
"short": {
"single": "Reflected an object across its short axis.",
"multiple": "Reflected multiple objects across their short axis."
"single": "Reflected an feature across its short axis.",
"multiple": "Reflected multiple features across their short axis."
}
},
"incomplete_relation": {
"single": "This object can't be reflected because it hasn't been fully downloaded.",
"multiple": "These objects can't be reflected because they haven't been fully downloaded."
"single": "This feature can't be reflected because it hasn't been fully downloaded.",
"multiple": "These features can't be reflected because they haven't been fully downloaded."
},
"too_large": {
"single": "This object can't be reflected because not enough of it is currently visible.",
"multiple": "These objects can't be reflected because not enough of them are currently visible."
"single": "This feature can't be reflected because not enough of it is currently visible.",
"multiple": "These features can't be reflected because not enough of them are currently visible."
},
"connected_to_hidden": {
"single": "This object can't be reflected because it is connected to a hidden feature.",
"multiple": "These objects can't be reflected because some are connected to hidden features."
"single": "This feature can't be reflected because it is connected to a hidden feature.",
"multiple": "These features can't be reflected because some are connected to hidden features."
}
},
"rotate": {
"title": "Rotate",
"description": {
"single": "Rotate this object around its center point.",
"multiple": "Rotate these objects around their center point."
"single": "Rotate this feature around its center point.",
"multiple": "Rotate these features around their center point."
},
"key": "R",
"annotation": {
"line": "Rotated a line.",
"area": "Rotated an area.",
"multiple": "Rotated multiple objects."
"multiple": "Rotated multiple features."
},
"incomplete_relation": {
"single": "This object can't be rotated because it hasn't been fully downloaded.",
"multiple": "These objects can't be rotated because they haven't been fully downloaded."
"single": "This feature can't be rotated because it hasn't been fully downloaded.",
"multiple": "These features can't be rotated because they haven't been fully downloaded."
},
"too_large": {
"single": "This object can't be rotated because not enough of it is currently visible.",
"multiple": "These objects can't be rotated because not enough of them are currently visible."
"single": "This feature can't be rotated because not enough of it is currently visible.",
"multiple": "These features can't be rotated because not enough of them are currently visible."
},
"connected_to_hidden": {
"single": "This object can't be rotated because it is connected to a hidden feature.",
"multiple": "These objects can't be rotated because some are connected to hidden features."
"single": "This feature can't be rotated because it is connected to a hidden feature.",
"multiple": "These features can't be rotated because some are connected to hidden features."
}
},
"reverse": {
@@ -388,7 +388,7 @@
"back_tooltip": "Change feature",
"remove": "Remove",
"search": "Search",
"multiselect": "Selected items",
"multiselect": "Selected features",
"unknown": "Unknown",
"incomplete": "<not downloaded>",
"feature_list": "Search features",
@@ -522,13 +522,13 @@
"delete": "Leave Deleted",
"download_changes": "Or download your changes.",
"done": "All conflicts resolved!",
"help": "Another user changed some of the same map features you changed.\nClick on each item below for more details about the conflict, and choose whether to keep\nyour changes or the other user's changes.\n"
"help": "Another user changed some of the same map features you changed.\nClick on each feature below for more details about the conflict, and choose whether to keep\nyour changes or the other user's changes.\n"
}
},
"merge_remote_changes": {
"conflict": {
"deleted": "This object has been deleted by {user}.",
"location": "This object was moved by both you and {user}.",
"deleted": "This feature has been deleted by {user}.",
"location": "This feature was moved by both you and {user}.",
"nodelist": "Nodes were changed by both you and {user}.",
"memberlist": "Relation members were changed by both you and {user}.",
"tags": "You changed the <b>{tag}</b> tag to \"{local}\" and {user} changed it to \"{remote}\"."
@@ -569,7 +569,7 @@
"untagged_point": "Untagged point",
"untagged_line": "Untagged line",
"untagged_area": "Untagged area",
"many_deletions": "You're deleting {n} objects. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
"many_deletions": "You're deleting {n} features. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.",
"tag_suggests_area": "The tag {tag} suggests line should be area, but it is not an area",
"untagged_point_tooltip": "Select a feature type that describes what this point is.",
"untagged_line_tooltip": "Select a feature type that describes what this line is.",
@@ -780,17 +780,21 @@
"address": {
"label": "Address",
"placeholders": {
"block_number": "Block number",
"city": "City",
"conscriptionnumber": "123",
"county": "County",
"country": "Country",
"district": "District",
"floor": "Floor",
"hamlet": "Hamlet",
"housename": "Housename",
"housenumber": "123",
"neighbourhood": "Neighbourhood",
"place": "Place",
"postcode": "Postcode",
"province": "Province",
"quarter": "Quarter",
"state": "State",
"street": "Street",
"subdistrict": "Subdistrict",
@@ -954,6 +958,9 @@
"NNW": "North-northwest"
}
},
"castle_type": {
"label": "Type"
},
"clock_direction": {
"label": "Direction",
"options": {
@@ -1095,6 +1102,15 @@
"fence_type": {
"label": "Type"
},
"fire_hydrant/position": {
"label": "Position",
"options": {
"lane": "Lane",
"parking_lot": "Parking Lot",
"sidewalk": "Sidewalk",
"green": "Green"
}
},
"fire_hydrant/type": {
"label": "Type",
"options": {
@@ -1604,8 +1620,10 @@
}
},
"social_facility_for": {
"label": "People served",
"placeholder": "Homeless, Disabled, Child, etc"
"label": "People Served"
},
"social_facility": {
"label": "Type"
},
"source": {
"label": "Source"
@@ -1690,6 +1708,9 @@
"bucket": "Bucket"
}
},
"toll": {
"label": "Toll"
},
"tourism": {
"label": "Type"
},
@@ -1888,6 +1909,10 @@
"name": "Airport terminal",
"terms": "airport,aerodrome"
},
"amenity/coworking_space": {
"name": "Coworking Space",
"terms": ""
},
"amenity/register_office": {
"name": "Register Office",
"terms": ""
@@ -2004,10 +2029,6 @@
"name": "Courthouse",
"terms": ""
},
"amenity/coworking_space": {
"name": "Coworking Space",
"terms": "coworking,office"
},
"amenity/crematorium": {
"name": "Crematorium",
"terms": "cemetery,funeral"
@@ -2324,6 +2345,10 @@
"name": "Bollard",
"terms": ""
},
"barrier/border_control": {
"name": "Border Control",
"terms": ""
},
"barrier/cattle_grid": {
"name": "Cattle Grid",
"terms": ""
@@ -2754,7 +2779,7 @@
},
"emergency/fire_hydrant": {
"name": "Fire Hydrant",
"terms": ""
"terms": "fire plug"
},
"emergency/phone": {
"name": "Emergency Phone",
@@ -2874,7 +2899,7 @@
},
"highway/motorway": {
"name": "Motorway",
"terms": ""
"terms": "autobahn,expressway,freeway,highway,interstate,parkway,thruway,turnpike"
},
"highway/path": {
"name": "Path",
@@ -3228,6 +3253,10 @@
"name": "Golf Course",
"terms": "links"
},
"leisure/horse_riding": {
"name": "Horseback Riding Facility",
"terms": "equestrian,stable"
},
"leisure/ice_rink": {
"name": "Ice Rink",
"terms": "hockey,skating,curling"
@@ -3584,6 +3613,10 @@
"name": "Company Office",
"terms": ""
},
"office/coworking": {
"name": "Coworking Space",
"terms": "coworking,office"
},
"office/educational_institution": {
"name": "Educational Institution",
"terms": ""
@@ -3680,6 +3713,10 @@
"name": "Neighborhood",
"terms": "neighbourhood"
},
"place/square": {
"name": "Square",
"terms": ""
},
"place/suburb": {
"name": "Borough",
"terms": "Boro,Quarter"
+49 -14
View File
@@ -14,8 +14,16 @@ export function actionCircularize(wayId, projection, maxAngle) {
maxAngle = (maxAngle || 20) * Math.PI / 180;
var action = function(graph) {
var way = graph.entity(wayId);
var action = function(graph, t) {
if (t === null || !isFinite(t)) t = 1;
t = Math.min(Math.max(+t, 0), 1);
var way = graph.entity(wayId),
origNodes = {};
graph.childNodes(way).forEach(function(node) {
if (!origNodes[node.id]) origNodes[node.id] = node;
});
if (!way.isConvex(graph)) {
graph = action.makeConvex(graph);
@@ -56,21 +64,27 @@ export function actionCircularize(wayId, projection, maxAngle) {
endNodeIndex = nodes.indexOf(endNode),
numberNewPoints = -1,
indexRange = endNodeIndex - startNodeIndex,
distance, totalAngle, eachAngle, startAngle, endAngle,
angle, loc, node, j,
inBetweenNodes = [];
nearNodes = {},
inBetweenNodes = [],
startAngle, endAngle, totalAngle, eachAngle,
angle, loc, node, origNode, j;
if (indexRange < 0) {
indexRange += nodes.length;
}
// position this key node
distance = geoEuclideanDistance(centroid, keyPoints[i]);
var distance = geoEuclideanDistance(centroid, keyPoints[i]);
if (distance === 0) { distance = 1e-4; }
keyPoints[i] = [
centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius,
centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
graph = graph.replace(keyNodes[i].move(projection.invert(keyPoints[i])));
centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius
];
loc = projection.invert(keyPoints[i]);
node = keyNodes[i];
origNode = origNodes[node.id];
node = node.move(geoInterp(origNode.loc, loc, t));
graph = graph.replace(node);
// figure out the between delta angle we want to match to
startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
@@ -87,14 +101,20 @@ export function actionCircularize(wayId, projection, maxAngle) {
eachAngle = totalAngle / (indexRange + numberNewPoints);
} while (Math.abs(eachAngle) > maxAngle);
// move existing points
// move existing nodes
for (j = 1; j < indexRange; j++) {
angle = startAngle + j * eachAngle;
loc = projection.invert([
centroid[0] + Math.cos(angle)*radius,
centroid[1] + Math.sin(angle)*radius]);
centroid[0] + Math.cos(angle) * radius,
centroid[1] + Math.sin(angle) * radius
]);
node = nodes[(j + startNodeIndex) % nodes.length].move(loc);
node = nodes[(j + startNodeIndex) % nodes.length];
origNode = origNodes[node.id];
nearNodes[node.id] = angle;
node = node.move(geoInterp(origNode.loc, loc, t));
graph = graph.replace(node);
}
@@ -103,9 +123,21 @@ export function actionCircularize(wayId, projection, maxAngle) {
angle = startAngle + (indexRange + j) * eachAngle;
loc = projection.invert([
centroid[0] + Math.cos(angle) * radius,
centroid[1] + Math.sin(angle) * radius]);
centroid[1] + Math.sin(angle) * radius
]);
node = osmNode({loc: loc});
// choose a nearnode to use as the original
var min = Infinity;
for (var nodeId in nearNodes) {
var nearAngle = nearNodes[nodeId],
dist = Math.abs(nearAngle - angle);
if (dist < min) {
dist = min;
origNode = origNodes[nodeId];
}
}
node = osmNode({ loc: geoInterp(origNode.loc, loc, t) });
graph = graph.replace(node);
nodes.splice(endNodeIndex + j, 0, node);
@@ -195,5 +227,8 @@ export function actionCircularize(wayId, projection, maxAngle) {
};
action.transitionable = true;
return action;
}
+22 -3
View File
@@ -17,15 +17,34 @@ export function actionMerge(ids) {
points.forEach(function(point) {
target = target.mergeTags(point.tags);
graph = graph.replace(target);
graph.parentRelations(point).forEach(function(parent) {
graph = graph.replace(parent.replaceMember(point, target));
});
graph = graph.remove(point);
});
var nodes = _.uniq(graph.childNodes(target)),
removeNode = point;
graph = graph.replace(target);
for (var i = 0; i < nodes.length; i++) {
var node = nodes[i];
if (graph.parentWays(node).length > 1 ||
graph.parentRelations(node).length ||
node.hasInterestingTags()) {
continue;
}
// Found an uninteresting child node on the target way.
// Move orig point into its place to preserve point's history. #3683
graph = graph.replace(point.update({ tags: {}, loc: node.loc }));
target = target.replaceNode(node.id, point.id);
graph = graph.replace(target);
removeNode = node;
break;
}
graph = graph.remove(removeNode);
});
return graph;
};
+20 -13
View File
@@ -1,6 +1,6 @@
import _ from 'lodash';
import { actionDeleteNode } from './delete_node';
import { geoEuclideanDistance } from '../geo/index';
import { geoEuclideanDistance, geoInterp } from '../geo/index';
/*
* Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
@@ -11,26 +11,30 @@ export function actionOrthogonalize(wayId, projection) {
upperThreshold = Math.cos(threshold * Math.PI / 180);
var action = function(graph) {
var action = function(graph, t) {
if (t === null || !isFinite(t)) t = 1;
t = Math.min(Math.max(+t, 0), 1);
var way = graph.entity(wayId),
nodes = graph.childNodes(way),
points = _.uniq(nodes).map(function(n) { return projection(n.loc); }),
corner = {i: 0, dotp: 1},
epsilon = 1e-4,
i, j, score, motions;
node, loc, score, motions, i, j;
if (nodes.length === 4) {
if (points.length === 3) { // move only one vertex for right triangle
for (i = 0; i < 1000; i++) {
motions = points.map(calcMotion);
points[corner.i] = addPoints(points[corner.i],motions[corner.i]);
points[corner.i] = addPoints(points[corner.i], motions[corner.i]);
score = corner.dotp;
if (score < epsilon) {
break;
}
}
graph = graph.replace(graph.entity(nodes[corner.i].id)
.move(projection.invert(points[corner.i])));
node = graph.entity(nodes[corner.i].id);
loc = projection.invert(points[corner.i]);
graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
} else {
var best,
@@ -57,25 +61,25 @@ export function actionOrthogonalize(wayId, projection) {
for (i = 0; i < points.length; i++) {
// only move the points that actually moved
if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
graph = graph.replace(graph.entity(nodes[i].id)
.move(projection.invert(points[i])));
loc = projection.invert(points[i]);
node = graph.entity(nodes[i].id);
graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
}
}
// remove empty nodes on straight sections
for (i = 0; i < points.length; i++) {
var node = nodes[i];
for (i = 0; t === 1 && i < points.length; i++) {
node = graph.entity(nodes[i].id);
if (graph.parentWays(node).length > 1 ||
graph.parentRelations(node).length ||
node.hasInterestingTags()) {
continue;
}
var dotp = normalizedDotProduct(i, points);
if (dotp < -1 + epsilon) {
graph = actionDeleteNode(nodes[i].id)(graph);
graph = actionDeleteNode(node.id)(graph);
}
}
}
@@ -182,5 +186,8 @@ export function actionOrthogonalize(wayId, projection) {
};
action.transitionable = true;
return action;
}
+10 -2
View File
@@ -6,6 +6,7 @@ import {
import {
geoEuclideanDistance,
geoExtent,
geoInterp,
geoRotate
} from '../geo';
@@ -52,7 +53,10 @@ export function actionReflect(reflectIds, projection) {
}
var action = function(graph) {
var action = function(graph, t) {
if (t === null || !isFinite(t)) t = 1;
t = Math.min(Math.max(+t, 0), 1);
var nodes = utilGetAllNodes(reflectIds, graph),
ssr = getSmallestSurroundingRectangle(graph, nodes);
@@ -87,7 +91,8 @@ export function actionReflect(reflectIds, projection) {
a * (c[0] - p[0]) + b * (c[1] - p[1]) + p[0],
b * (c[0] - p[0]) - a * (c[1] - p[1]) + p[1]
];
node = node.move(projection.invert(c2));
var loc2 = projection.invert(c2);
node = node.move(geoInterp(node.loc, loc2, t));
graph = graph.replace(node);
}
@@ -102,5 +107,8 @@ export function actionReflect(reflectIds, projection) {
};
action.transitionable = true;
return action;
}
+16 -9
View File
@@ -1,5 +1,5 @@
import { actionDeleteNode } from './delete_node';
import { geoEuclideanDistance } from '../geo/index';
import { geoEuclideanDistance, geoInterp } from '../geo/index';
/*
@@ -8,12 +8,15 @@ import { geoEuclideanDistance } from '../geo/index';
export function actionStraighten(wayId, projection) {
function positionAlongWay(n, s, e) {
return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1]))/
return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1])) /
(Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
}
var action = function(graph) {
var action = function(graph, t) {
if (t === null || !isFinite(t)) t = 1;
t = Math.min(Math.max(+t, 0), 1);
var way = graph.entity(wayId),
nodes = graph.childNodes(way),
points = nodes.map(function(n) { return projection(n.loc); }),
@@ -26,17 +29,18 @@ export function actionStraighten(wayId, projection) {
var node = nodes[i],
point = points[i];
if (graph.parentWays(node).length > 1 ||
if (t < 1 || graph.parentWays(node).length > 1 ||
graph.parentRelations(node).length ||
node.hasInterestingTags()) {
var u = positionAlongWay(point, startPoint, endPoint),
p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]);
p = [
startPoint[0] + u * (endPoint[0] - startPoint[0]),
startPoint[1] + u * (endPoint[1] - startPoint[1])
],
loc2 = projection.invert(p);
graph = graph
.replace(graph.entity(node.id)
.move(projection.invert([p0, p1])));
graph = graph.replace(node.move(geoInterp(node.loc, loc2, t)));
} else {
// safe to delete
@@ -83,5 +87,8 @@ export function actionStraighten(wayId, projection) {
};
action.transitionable = true;
return action;
}
+3 -1
View File
@@ -27,7 +27,9 @@ export function behaviorSelect(context) {
lasso = d3.select('#surface .lasso').node(),
mode = context.mode();
if (!(datum instanceof osmEntity)) {
if (datum.type === 'midpoint') {
// do nothing
} else if (!(datum instanceof osmEntity)) {
if (!d3.event.shiftKey && !lasso && mode.id !== 'browse')
context.enter(modeBrowse(context));
+84 -32
View File
@@ -11,13 +11,15 @@ import { utilRebind } from '../util/rebind';
export function coreHistory(context) {
var stack, index, tree,
imageryUsed = ['Bing'],
var imageryUsed = ['Bing'],
dispatch = d3.dispatch('change', 'undone', 'redone'),
lock = utilSessionMutex('lock');
lock = utilSessionMutex('lock'),
duration = 150,
stack, index, tree;
function perform(actions) {
// internal _act, accepts list of actions and eased time
function _act(actions, t) {
actions = Array.prototype.slice.call(actions);
var annotation;
@@ -31,7 +33,7 @@ export function coreHistory(context) {
var graph = stack[index].graph;
for (var i = 0; i < actions.length; i++) {
graph = actions[i](graph);
graph = actions[i](graph, t);
}
return {
@@ -42,6 +44,40 @@ export function coreHistory(context) {
}
// internal _perform with eased time
function _perform(args, t) {
var previous = stack[index].graph;
stack = stack.slice(0, index + 1);
stack.push(_act(args, t));
index++;
return change(previous);
}
// internal _replace with eased time
function _replace(args, t) {
var previous = stack[index].graph;
// assert(index == stack.length - 1)
stack[index] = _act(args, t);
return change(previous);
}
// internal _overwrite with eased time
function _overwrite(args, t) {
var previous = stack[index].graph;
if (index > 0) {
index--;
stack.pop();
}
stack = stack.slice(0, index + 1);
stack.push(_act(args, t));
index++;
return change(previous);
}
// determine diffrence and dispatch a change event
function change(previous) {
var difference = coreDifference(previous, history.graph());
dispatch.call('change', this, difference);
@@ -76,29 +112,58 @@ export function coreHistory(context) {
perform: function() {
var previous = stack[index].graph;
// complete any transition already in progress
d3.select(document).interrupt('history.perform');
stack = stack.slice(0, index + 1);
stack.push(perform(arguments));
index++;
var transitionable = false,
action0 = arguments[0];
return change(previous);
if (arguments.length === 1 ||
arguments.length === 2 && !_.isFunction(arguments[1])) {
transitionable = !!action0.transitionable;
}
if (transitionable) {
var origArguments = arguments;
d3.select(document)
.transition('history.perform')
.duration(duration)
.ease(d3.easeLinear)
.tween('history.tween', function() {
return function(t) {
if (t < 1) _overwrite([action0], t);
};
})
.on('start', function() {
_perform([action0], 0);
})
.on('end interrupt', function() {
_overwrite(origArguments, 1);
});
} else {
return _perform(arguments);
}
},
replace: function() {
var previous = stack[index].graph;
d3.select(document).interrupt('history.perform');
return _replace(arguments, 1);
},
// assert(index == stack.length - 1)
stack[index] = perform(arguments);
return change(previous);
// Same as calling pop and then perform
overwrite: function() {
d3.select(document).interrupt('history.perform');
return _overwrite(arguments, 1);
},
pop: function() {
var previous = stack[index].graph;
d3.select(document).interrupt('history.perform');
var previous = stack[index].graph;
if (index > 0) {
index--;
stack.pop();
@@ -107,23 +172,9 @@ export function coreHistory(context) {
},
// Same as calling pop and then perform
overwrite: function() {
var previous = stack[index].graph;
if (index > 0) {
index--;
stack.pop();
}
stack = stack.slice(0, index + 1);
stack.push(perform(arguments));
index++;
return change(previous);
},
undo: function() {
d3.select(document).interrupt('history.perform');
var previous = stack[index].graph;
// Pop to the next annotated state.
@@ -138,8 +189,9 @@ export function coreHistory(context) {
redo: function() {
var previous = stack[index].graph;
d3.select(document).interrupt('history.perform');
var previous = stack[index].graph;
while (index < stack.length - 1) {
index++;
if (stack[index].annotation) break;
+9 -4
View File
@@ -235,16 +235,21 @@ export function modeSelect(context, selectedIDs) {
if (datum instanceof osmWay && !target.classed('fill')) {
var choice = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection),
node = osmNode();
var prev = datum.nodes[choice.index - 1],
prev = datum.nodes[choice.index - 1],
next = datum.nodes[choice.index];
context.perform(
actionAddMidpoint({loc: choice.loc, edge: [prev, next]}, node),
actionAddMidpoint({loc: choice.loc, edge: [prev, next]}, osmNode()),
t('operations.add.annotation.vertex')
);
d3.event.preventDefault();
d3.event.stopPropagation();
} else if (datum.type === 'midpoint') {
context.perform(
actionAddMidpoint({loc: datum.loc, edge: datum.edge}, osmNode()),
t('operations.add.annotation.vertex'));
d3.event.preventDefault();
d3.event.stopPropagation();
}
+4 -1
View File
@@ -27,7 +27,10 @@ export function operationMerge(selectedIDs, context) {
}
context.perform(action, annotation);
var ids = selectedIDs.filter(function(id) { return context.hasEntity(id); });
var ids = selectedIDs.filter(function(id) {
var entity = context.hasEntity(id);
return entity && entity.type !== 'node';
});
context.enter(modeSelect(context, ids).suppressMenu(true));
};
+1 -1
View File
@@ -8,7 +8,6 @@ import { osmEntity, osmNode, osmRelation, osmWay } from '../osm/index';
import { utilDetect } from '../util/detect';
import { utilRebind } from '../util/rebind';
var dispatch = d3.dispatch('authLoading', 'authDone', 'change', 'loading', 'loaded'),
useHttps = window.location.protocol === 'https:',
protocol = useHttps ? 'https:' : 'http:',
@@ -70,6 +69,7 @@ function getTags(obj) {
var attrs = elems[i].attributes;
tags[attrs.k.value] = attrs.v.value;
}
return tags;
}
+12 -3
View File
@@ -1,6 +1,7 @@
import * as d3 from 'd3';
import _ from 'lodash';
import rbush from 'rbush';
import {
geoExtent,
geoEuclideanDistance,
@@ -8,9 +9,15 @@ import {
geoPolygonIntersectsPolygon,
geoPathLength
} from '../geo/index';
import { osmEntity } from '../osm/index';
import { utilDetect } from '../util/detect';
import { utilDisplayName, utilEntitySelector } from '../util/index';
import {
utilDisplayName,
utilDisplayNameForPath,
utilEntitySelector
} from '../util/index';
export function svgLabels(projection, context) {
@@ -134,7 +141,7 @@ export function svgLabels(projection, context) {
.data(entities, osmEntity.key)
.attr('startOffset', '50%')
.attr('xlink:href', function(d) { return '#labelpath-' + d.id; })
.text(utilDisplayName);
.text(utilDisplayNameForPath);
}
@@ -313,9 +320,11 @@ export function svgLabels(projection, context) {
entity = labelable[k][i];
geometry = entity.geometry(graph);
var name = utilDisplayName(entity),
var getName = (geometry === 'line') ? utilDisplayNameForPath : utilDisplayName,
name = getName(entity),
width = name && textWidth(name, fontSize),
p;
if (geometry === 'point') {
p = getPointLabel(entity, width, fontSize, geometry);
} else if (geometry === 'vertex' && !lowZoom) {
-1
View File
@@ -13,7 +13,6 @@ import { uiTagReference } from './tag_reference';
import { uiPreset } from './preset';
import { utilRebind } from '../util/rebind';
export function uiEntityEditor(context) {
var dispatch = d3.dispatch('choose'),
state = 'select',
+4 -3
View File
@@ -159,12 +159,13 @@ export function uiFieldAddress(field, context) {
.style('width', function (d) { return d.width * 100 + '%'; });
// Update
// setup dropdowns for common address tags
var addrTags = [
'street', 'city', 'state', 'province', 'district',
'subdistrict', 'suburb', 'place', 'postcode'
'city', 'county', 'country', 'district', 'hamlet',
'neighbourhood', 'place', 'postcode', 'province',
'quarter', 'state', 'street', 'subdistrict', 'suburb'
];
// If fields exist for any of these tags, create dropdowns to pick nearby values..
addrTags.forEach(function(tag) {
var nearValues = (tag === 'street') ? getNearStreets
: (tag === 'city') ? getNearCities
+1
View File
@@ -3,6 +3,7 @@ export { utilEntitySelector } from './util';
export { utilEntityOrMemberSelector } from './util';
export { utilGetAllNodes } from './util';
export { utilDisplayName } from './util';
export { utilDisplayNameForPath } from './util';
export { utilDisplayType } from './util';
export { utilStringQs } from './util';
export { utilQsString } from './util';
+122
View File
@@ -0,0 +1,122 @@
// see https://github.com/openstreetmap/iD/pull/3707
// https://gist.github.com/mapmeld/556b09ddec07a2044c76e1ef45f01c60
var chars = {
// madda above alef
1570: { initial: 'آ‎', isolated: 'ﺁ', medial: 'ﺁ', final: 'ﺂ' },
// hamza above and below alef
1571: { initial: 'أ', isolated: 'ﺃ', medial: '', final: 'ﺄ' },
// 1572 is ؤ
1573: { initial: 'إ', isolated: 'ﺇ', medial: '', final: 'ﺈ' },
// 1574 is ئ
1575: { initial: 'ا', isolated: 'ا', medial: '', final: '' },
1576: { initial: 'ﺑ', isolated: 'ﺏ', medial: 'ﺒ', final: 'ﺐ' },
// 1577 ة
1577: { initial: '', isolated: 'ة', medial: '', final: 'ﺔ' },
1578: { initial: 'ﺗ', isolated: 'ﺕ', medial: 'ﺘ', final: 'ﺖ' },
1579: { initial: 'ﺛ', isolated: 'ﺙ', medial: 'ﺜ', final: 'ﺚ' },
1580: { initial: 'ﺟ', isolated: 'ﺝ', medial: 'ﺠ', final: 'ﺞ' },
1581: { initial: 'ﺣ', isolated: 'ﺡ', medial: 'ﺤ', final: 'ﺢ' },
1582: { initial: 'ﺧ', isolated: 'ﺥ', medial: 'ﺨ', final: 'ﺦ' },
1583: { initial: 'ﺩ', isolated: 'ﺩ', medial: '', final: 'ﺪ' },
1584: { initial: 'ﺫ', isolated: 'ﺫ', medial: '', final: 'ﺬ' },
1585: { initial: 'ﺭ', isolated: 'ﺭ', medial: '', final: 'ﺮ' },
1586: { initial: 'ﺯ', isolated: 'ﺯ', medial: '', final: 'ﺰ' },
1688: { initial: 'ﮊ', isolated: 'ﮊ', medial: '', final: 'ﮋ' },
1587: { initial: 'ﺳ', isolated: 'ﺱ', medial: 'ﺴ', final: 'ﺲ' },
1588: { initial: 'ﺷ', isolated: 'ﺵ', medial: 'ﺸ', final: 'ﺶ' },
1589: { initial: 'ﺻ', isolated: 'ﺹ', medial: 'ﺼ', final: 'ﺺ' },
1590: { initial: 'ﺿ', isolated: 'ﺽ', medial: 'ﻀ', final: 'ﺾ' },
1591: { initial: 'ﻃ', isolated: 'ﻁ', medial: 'ﻄ', final: 'ﻂ' },
1592: { initial: 'ﻇ', isolated: 'ﻅ', medial: 'ﻈ', final: 'ﻆ' },
1593: { initial: 'ﻋ', isolated: 'ﻉ', medial: 'ﻌ', final: 'ﻊ' },
1594: { initial: 'ﻏ', isolated: 'ﻍ', medial: 'ﻐ', final: 'ﻎ' },
// 1595 ػ - may be very rare
1601: { initial: 'ﻓ', isolated: 'ﻑ', medial: 'ﻔ', final: 'ﻒ' },
1602: { initial: 'ﻗ', isolated: 'ﻕ', medial: 'ﻘ', final: 'ﻖ' },
1604: { initial: 'ﻟ', isolated: 'ﻝ', medial: 'ﻠ', final: 'ﻞ' },
1605: { initial: 'ﻣ', isolated: 'ﻡ', medial: 'ﻤ', final: 'ﻢ' },
1606: { initial: 'ﻧ', isolated: 'ﻥ', medial: 'ﻨ', final: 'ﻦ' },
1607: { initial: '', isolated: '', medial: '', final: '' },
1608: { initial: 'ﻭ', isolated: 'ﻭ', medial: '', final: 'ﻮ' },
// 1609 ى
1609: { initial: 'ﯨ', isolated: 'ﻯ', medial: 'ﯩ', final: 'ﻰ' },
// 1610 ي
1610: { initial: 'ﻳ', isolated: 'ﻱ', medial: 'ﻴ', final: 'ﻲ' },
// short vowel sounds / tashkil markings
1662: { initial: 'ﭘ', isolated: 'ﭖ', medial: 'ﭙ', final: 'ﭗ' },
1670: { initial: 'ﭼ', isolated: 'ﭺ', medial: 'ﭽ', final: 'ﭻ' },
1603: { initial: 'ﻛ', isolated: 'ﻙ', medial: 'ﻜ', final: 'ﻚ' },
1705: { initial: 'ﻛ', isolated: 'ﮎ', medial: 'ﻜ', final: 'ﮏ' },
1711: { initial: 'ﮔ', isolated: 'ﮒ', medial: 'ﮕ', final: 'ﮓ' },
1740: { initial: 'ﻳ', isolated: 'ﻯ', medial: 'ﻴ', final: 'ﻰ' },
5000: { initial: 'ﻻ', isolated: 'ﻻ', medial: '', final: 'ﻼ' }
};
export function fixArabicScriptTextForSvg(inputText) {
var context = true;
var ret = '';
var rtlBuffer = [];
for (var i = 0, l = inputText.length; i < l; i++) {
var code = inputText[i].charCodeAt(0);
var nextCode = inputText[i + 1] ? inputText[i + 1].charCodeAt(0) : 0;
if (!chars[code]) {
if (code === 32 && rtlBuffer.length) {
// whitespace
rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
} else {
// non-RTL character
ret += rtlBuffer.reverse().join('') + inputText[i];
rtlBuffer = [];
}
continue;
}
if (context) {
if (i === l - 1 || nextCode === 32) {
rtlBuffer.push(chars[code].isolated);
} else {
// special case for لا
if (code === 1604 && nextCode === 1575) {
rtlBuffer.push(chars[5000].initial);
i++;
context = true;
continue;
}
rtlBuffer.push(chars[code].initial);
}
} else {
if (i === l - 1 || nextCode === 32){
rtlBuffer.push(chars[code].final);
} else {
// special case for ﻼ
if (code === 1604 && nextCode === 1575){
rtlBuffer.push(chars[5000].final);
i++;
context = true;
continue;
}
if (chars[code].medial === ''){
rtlBuffer.push(chars[code].final);
} else {
rtlBuffer.push(chars[code].medial);
}
}
}
context = (chars[code].medial === '') || nextCode === 32;
}
ret += rtlBuffer.reverse().join('');
return ret;
}
+16
View File
@@ -2,6 +2,7 @@ import * as d3 from 'd3';
import { t, textDirection } from './locale';
import { utilDetect } from './detect';
import { remove as removeDiacritics } from 'diacritics';
import { fixArabicScriptTextForSvg } from './svg_paths_arabic_fix';
export function utilTagText(entity) {
@@ -60,12 +61,27 @@ export function utilDisplayName(entity) {
var localizedNameKey = 'name:' + utilDetect().locale.toLowerCase().split('-')[0],
name = entity.tags[localizedNameKey] || entity.tags.name || '',
network = entity.tags.cycle_network || entity.tags.network;
if (!name && entity.tags.ref) {
name = entity.tags.ref;
if (network) {
name = network + ' ' + name;
}
}
return name;
}
export function utilDisplayNameForPath(entity) {
var name = utilDisplayName(entity);
var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
var arabicRegex = /[\u0600-\u06FF]/g;
if (!isFirefox && name && arabicRegex.test(name)) {
name = fixArabicScriptTextForSvg(name);
}
return name;
}
+6 -6
View File
@@ -29,7 +29,7 @@
},
"dependencies": {
"diacritics": "1.2.3",
"lodash": "4.17.2",
"lodash": "4.17.4",
"marked": "0.3.6",
"osm-auth": "1.0.1",
"rbush": "2.0.1",
@@ -40,11 +40,11 @@
"devDependencies": {
"brfs": "1.4.3",
"chai": "~3.5.0",
"d3": "4.4.0",
"d3": "4.4.1",
"ecstatic": "~2.1.0",
"editor-layer-index": "osmlab/editor-layer-index.git#gh-pages",
"gaze": "~1.1.1",
"eslint": "~3.12.0",
"eslint": "~3.13.0",
"glob": "~7.1.0",
"happen": "~0.3.1",
"js-yaml": "~3.7.0",
@@ -56,11 +56,11 @@
"mocha": "~3.2.0",
"mocha-phantomjs-core": "~2.1.0",
"name-suggestion-index": "0.1.1",
"npm-run-all": "~3.1.1",
"npm-run-all": "~4.0.0",
"phantomjs-prebuilt": "~2.1.11",
"request": "~2.79.0",
"rollup": "0.38.0",
"rollup-plugin-commonjs": "6.0.1",
"rollup": "0.41.1",
"rollup-plugin-commonjs": "7.0.0",
"rollup-plugin-json": "2.0.2",
"rollup-plugin-node-resolve": "2.0.0",
"shelljs": "~0.7.5",
+49
View File
@@ -271,4 +271,53 @@ describe('iD.actionCircularize', function () {
expect(isCircular('-', graph)).to.be.ok;
});
describe('transitions', function () {
it('is transitionable', function() {
expect(iD.actionCircularize().transitionable).to.be.true;
});
it('circularize at t = 0', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [2, 0]}),
iD.Node({id: 'c', loc: [2, 2]}),
iD.Node({id: 'd', loc: [0, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionCircularize('-', projection)(graph, 0);
expect(isCircular('-', graph)).to.be.not.ok;
expect(graph.entity('-').nodes).to.have.length(20);
expect(area('-', graph)).to.be.closeTo(-4, 1e-2);
});
it('circularize at t = 0.5', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [2, 0]}),
iD.Node({id: 'c', loc: [2, 2]}),
iD.Node({id: 'd', loc: [0, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionCircularize('-', projection)(graph, 0.5);
expect(isCircular('-', graph)).to.be.not.ok;
expect(graph.entity('-').nodes).to.have.length(20);
expect(area('-', graph)).to.be.closeTo(-4.812, 1e-2);
});
it('circularize at t = 1', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [2, 0]}),
iD.Node({id: 'c', loc: [2, 2]}),
iD.Node({id: 'd', loc: [0, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionCircularize('-', projection)(graph, 1);
expect(isCircular('-', graph)).to.be.ok;
expect(graph.entity('-').nodes).to.have.length(20);
expect(area('-', graph)).to.be.closeTo(-6.168, 1e-2);
});
});
});
+19
View File
@@ -36,4 +36,23 @@ describe('iD.actionMerge', function () {
expect(graph.entity('w').tags).to.eql({a: 'a', b: 'b', area: 'yes'});
expect(graph.entity('r').members).to.eql([{id: 'w', role: 'r', type: 'way'}]);
});
it('preserves original point if possible', function () {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [1, 0], tags: {a: 'a'}}),
iD.Node({id: 'p', loc: [0, 0], tags: {p: 'p'}}),
iD.Node({id: 'q', loc: [0, 1]}),
iD.Way({id: 'w', nodes: ['p', 'q'], tags: {w: 'w'}})
]),
action = iD.actionMerge(['a', 'w']);
graph = action(graph);
expect(graph.hasEntity('a')).to.be.ok;
expect(graph.hasEntity('p')).to.be.ok;
expect(graph.hasEntity('q')).to.be.undefined;
expect(graph.entity('w').tags).to.eql({a: 'a', w: 'w'});
expect(graph.entity('w').nodes).to.eql(['p', 'a']);
expect(graph.entity('a').loc[0]).to.eql(0);
expect(graph.entity('a').loc[1]).to.eql(1);
});
});
+65 -5
View File
@@ -11,7 +11,6 @@ describe('iD.actionOrthogonalize', function () {
]);
graph = iD.actionOrthogonalize('-', projection)(graph);
expect(graph.entity('-').nodes).to.have.length(5);
});
@@ -25,7 +24,6 @@ describe('iD.actionOrthogonalize', function () {
]);
graph = iD.actionOrthogonalize('-', projection)(graph);
expect(graph.entity('-').nodes).to.have.length(5);
});
@@ -38,7 +36,6 @@ describe('iD.actionOrthogonalize', function () {
]);
graph = iD.actionOrthogonalize('-', projection)(graph);
expect(graph.entity('-').nodes).to.have.length(4);
});
@@ -53,7 +50,6 @@ describe('iD.actionOrthogonalize', function () {
]);
graph = iD.actionOrthogonalize('-', projection)(graph);
expect(graph.hasEntity('d')).to.eq(undefined);
});
@@ -68,7 +64,6 @@ describe('iD.actionOrthogonalize', function () {
]);
graph = iD.actionOrthogonalize('-', projection)(graph);
expect(graph.entity('-').nodes).to.have.length(6);
expect(graph.hasEntity('d')).to.not.eq(undefined);
});
@@ -121,4 +116,69 @@ describe('iD.actionOrthogonalize', function () {
expect(Object.keys(diff.changes()).sort()).to.eql(['a', 'b', 'c', 'f']);
});
describe('transitions', function () {
it('is transitionable', function() {
expect(iD.actionOrthogonalize().transitionable).to.be.true;
});
it('orthogonalize at t = 0', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [1, 0.01], tags: {foo: 'bar'}}),
iD.Node({id: 'c', loc: [2, -0.01]}),
iD.Node({id: 'd', loc: [3, 0]}),
iD.Node({id: 'e', loc: [3, 1]}),
iD.Node({id: 'f', loc: [0, 1]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'e', 'f', 'a']})
]);
graph = iD.actionOrthogonalize('-', projection)(graph, 0);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c', 'd', 'e', 'f', 'a']);
expect(graph.entity('b').loc[0]).to.be.closeTo(1, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(0.01, 1e-6);
expect(graph.entity('c').loc[0]).to.be.closeTo(2, 1e-6);
expect(graph.entity('c').loc[1]).to.be.closeTo(-0.01, 1e-6);
});
it('orthogonalize at t = 0.5', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [1, 0.01], tags: {foo: 'bar'}}),
iD.Node({id: 'c', loc: [2, -0.01]}),
iD.Node({id: 'd', loc: [3, 0]}),
iD.Node({id: 'e', loc: [3, 1]}),
iD.Node({id: 'f', loc: [0, 1]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'e', 'f', 'a']})
]);
graph = iD.actionOrthogonalize('-', projection)(graph, 0.5);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c', 'd', 'e', 'f', 'a']);
expect(graph.entity('b').loc[0]).to.be.closeTo(1, 1e-3);
expect(graph.entity('b').loc[1]).to.be.closeTo(0.005, 1e-3);
expect(graph.entity('c').loc[0]).to.be.closeTo(2, 1e-3);
expect(graph.entity('c').loc[1]).to.be.closeTo(-0.005, 1e-3);
});
it('orthogonalize at t = 1', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [1, 0.01], tags: {foo: 'bar'}}),
iD.Node({id: 'c', loc: [2, -0.01]}),
iD.Node({id: 'd', loc: [3, 0]}),
iD.Node({id: 'e', loc: [3, 1]}),
iD.Node({id: 'f', loc: [0, 1]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'e', 'f', 'a']})
]);
graph = iD.actionOrthogonalize('-', projection)(graph, 1);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'd', 'e', 'f', 'a']);
expect(graph.entity('b').loc[0]).to.be.closeTo(1, 2e-3);
expect(graph.entity('b').loc[1]).to.be.closeTo(0, 2e-3);
expect(graph.hasEntity('c')).to.eq(undefined);
});
});
});
+121
View File
@@ -63,4 +63,125 @@ describe('iD.actionReflect', function() {
expect(graph.entity('d').loc[1]).to.be.closeTo(2, 1e-6);
});
describe('transitions', function () {
it('is transitionable', function() {
expect(iD.actionReflect().transitionable).to.be.true;
});
it('reflect long at t = 0', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [4, 0]}),
iD.Node({id: 'c', loc: [4, 2]}),
iD.Node({id: 'd', loc: [1, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionReflect(['-'], projection)(graph, 0);
expect(graph.entity('a').loc[0]).to.be.closeTo(0, 1e-6);
expect(graph.entity('a').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.entity('b').loc[0]).to.be.closeTo(4, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.entity('c').loc[0]).to.be.closeTo(4, 1e-6);
expect(graph.entity('c').loc[1]).to.be.closeTo(2, 1e-6);
expect(graph.entity('d').loc[0]).to.be.closeTo(1, 1e-6);
expect(graph.entity('d').loc[1]).to.be.closeTo(2, 1e-6);
});
it('reflect long at t = 0.5', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [4, 0]}),
iD.Node({id: 'c', loc: [4, 2]}),
iD.Node({id: 'd', loc: [1, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionReflect(['-'], projection)(graph, 0.5);
expect(graph.entity('a').loc[0]).to.be.closeTo(0, 1e-6);
expect(graph.entity('a').loc[1]).to.be.closeTo(1, 1e-6);
expect(graph.entity('b').loc[0]).to.be.closeTo(4, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(1, 1e-6);
expect(graph.entity('c').loc[0]).to.be.closeTo(4, 1e-6);
expect(graph.entity('c').loc[1]).to.be.closeTo(1, 1e-6);
expect(graph.entity('d').loc[0]).to.be.closeTo(1, 1e-6);
expect(graph.entity('d').loc[1]).to.be.closeTo(1, 1e-6);
});
it('reflect long at t = 1', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [4, 0]}),
iD.Node({id: 'c', loc: [4, 2]}),
iD.Node({id: 'd', loc: [1, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionReflect(['-'], projection)(graph, 1);
expect(graph.entity('a').loc[0]).to.be.closeTo(0, 1e-6);
expect(graph.entity('a').loc[1]).to.be.closeTo(2, 1e-6);
expect(graph.entity('b').loc[0]).to.be.closeTo(4, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(2, 1e-6);
expect(graph.entity('c').loc[0]).to.be.closeTo(4, 1e-6);
expect(graph.entity('c').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.entity('d').loc[0]).to.be.closeTo(1, 1e-6);
expect(graph.entity('d').loc[1]).to.be.closeTo(0, 1e-6);
});
it('reflect short at t = 0', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [4, 0]}),
iD.Node({id: 'c', loc: [4, 2]}),
iD.Node({id: 'd', loc: [1, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionReflect(['-'], projection).useLongAxis(false)(graph, 0);
expect(graph.entity('a').loc[0]).to.be.closeTo(0, 1e-6);
expect(graph.entity('a').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.entity('b').loc[0]).to.be.closeTo(4, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.entity('c').loc[0]).to.be.closeTo(4, 1e-6);
expect(graph.entity('c').loc[1]).to.be.closeTo(2, 1e-6);
expect(graph.entity('d').loc[0]).to.be.closeTo(1, 1e-6);
expect(graph.entity('d').loc[1]).to.be.closeTo(2, 1e-6);
});
it('reflect short at t = 0.5', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [4, 0]}),
iD.Node({id: 'c', loc: [4, 2]}),
iD.Node({id: 'd', loc: [1, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionReflect(['-'], projection).useLongAxis(false)(graph, 0.5);
expect(graph.entity('a').loc[0]).to.be.closeTo(2, 1e-6);
expect(graph.entity('a').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.entity('b').loc[0]).to.be.closeTo(2, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.entity('c').loc[0]).to.be.closeTo(2, 1e-6);
expect(graph.entity('c').loc[1]).to.be.closeTo(2, 1e-6);
expect(graph.entity('d').loc[0]).to.be.closeTo(2, 1e-6);
expect(graph.entity('d').loc[1]).to.be.closeTo(2, 1e-6);
});
it('reflect short at t = 1', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [4, 0]}),
iD.Node({id: 'c', loc: [4, 2]}),
iD.Node({id: 'd', loc: [1, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd', 'a']})
]);
graph = iD.actionReflect(['-'], projection).useLongAxis(false)(graph, 1);
expect(graph.entity('a').loc[0]).to.be.closeTo(4, 1e-6);
expect(graph.entity('a').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.entity('b').loc[0]).to.be.closeTo(0, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.entity('c').loc[0]).to.be.closeTo(0, 1e-6);
expect(graph.entity('c').loc[1]).to.be.closeTo(2, 1e-6);
expect(graph.entity('d').loc[0]).to.be.closeTo(3, 1e-6);
expect(graph.entity('d').loc[1]).to.be.closeTo(2, 1e-6);
});
});
});
+73 -16
View File
@@ -5,12 +5,11 @@ describe('iD.actionStraighten', function () {
it('returns falsy for ways with internal nodes near centerline', function () {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [1, 0.1]}),
iD.Node({id: 'b', loc: [1, 0.01]}),
iD.Node({id: 'c', loc: [2, 0]}),
iD.Node({id: 'd', loc: [3, 0]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd']})
]);
expect(iD.actionStraighten('-', projection).disabled(graph)).not.to.be.ok;
});
@@ -22,7 +21,6 @@ describe('iD.actionStraighten', function () {
iD.Node({id: 'd', loc: [3, 0]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd']})
]);
expect(iD.actionStraighten('-', projection).disabled(graph)).to.equal('too_bendy');
});
@@ -34,49 +32,108 @@ describe('iD.actionStraighten', function () {
iD.Node({id: 'd', loc: [0, 0]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd']})
]);
expect(iD.actionStraighten('-', projection).disabled(graph)).to.equal('too_bendy');
});
});
it('deletes empty nodes', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [2, 0], tags: {}}),
iD.Node({id: 'c', loc: [2, 2]}),
iD.Node({id: 'b', loc: [1, 0.01], tags: {}}),
iD.Node({id: 'c', loc: [2, 0]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c']})
]);
graph = iD.actionStraighten('-', projection)(graph);
expect(graph.entity('-').nodes).to.eql(['a', 'c']);
expect(graph.hasEntity('b')).to.eq(undefined);
});
it('does not delete tagged nodes', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [2, 0], tags: {foo: 'bar'}}),
iD.Node({id: 'c', loc: [2, 2]}),
iD.Node({id: 'b', loc: [1, 0.01], tags: {foo: 'bar'}}),
iD.Node({id: 'c', loc: [2, 0]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c']})
]);
graph = iD.actionStraighten('-', projection)(graph);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c']);
expect(graph.entity('b').loc[0]).to.be.closeTo(1, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(0, 1e-6);
});
it('does not delete nodes connected to other ways', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [2, 0]}),
iD.Node({id: 'c', loc: [2, 2]}),
iD.Node({id: 'd', loc: [0, 2]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd']}),
iD.Node({id: 'b', loc: [1, 0.01]}),
iD.Node({id: 'c', loc: [2, 0]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c']}),
iD.Way({id: '=', nodes: ['b']})
]);
graph = iD.actionStraighten('-', projection)(graph);
expect(graph.entity('-').nodes).to.have.length(3);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c']);
expect(graph.entity('b').loc[0]).to.be.closeTo(1, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(0, 1e-6);
});
describe('transitions', function () {
it('is transitionable', function() {
expect(iD.actionStraighten().transitionable).to.be.true;
});
it('straighten at t = 0', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [1, 0.01], tags: {foo: 'bar'}}),
iD.Node({id: 'c', loc: [2, -0.01]}),
iD.Node({id: 'd', loc: [3, 0]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd']})
]);
graph = iD.actionStraighten('-', projection)(graph, 0);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c', 'd']);
expect(graph.entity('b').loc[0]).to.be.closeTo(1, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(0.01, 1e-6);
expect(graph.entity('c').loc[0]).to.be.closeTo(2, 1e-6);
expect(graph.entity('c').loc[1]).to.be.closeTo(-0.01, 1e-6);
});
it('straighten at t = 0.5', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [1, 0.01], tags: {foo: 'bar'}}),
iD.Node({id: 'c', loc: [2, -0.01]}),
iD.Node({id: 'd', loc: [3, 0]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd']})
]);
graph = iD.actionStraighten('-', projection)(graph, 0.5);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c', 'd']);
expect(graph.entity('b').loc[0]).to.be.closeTo(1, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(0.005, 1e-6);
expect(graph.entity('c').loc[0]).to.be.closeTo(2, 1e-6);
expect(graph.entity('c').loc[1]).to.be.closeTo(-0.005, 1e-6);
});
it('straighten at t = 1', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [1, 0.01], tags: {foo: 'bar'}}),
iD.Node({id: 'c', loc: [2, -0.01]}),
iD.Node({id: 'd', loc: [3, 0]}),
iD.Way({id: '-', nodes: ['a', 'b', 'c', 'd']})
]);
graph = iD.actionStraighten('-', projection)(graph, 1);
expect(graph.entity('-').nodes).to.eql(['a', 'b', 'd']);
expect(graph.entity('b').loc[0]).to.be.closeTo(1, 1e-6);
expect(graph.entity('b').loc[1]).to.be.closeTo(0, 1e-6);
expect(graph.hasEntity('c')).to.eq(undefined);
});
});
});
+12
View File
@@ -51,6 +51,7 @@ describe('iD.History', function () {
history.on('change', spy);
var difference = history.perform(action);
expect(spy).to.have.been.calledWith(difference);
expect(spy.callCount).to.eql(1);
});
it('performs multiple actions', function () {
@@ -61,6 +62,17 @@ describe('iD.History', function () {
expect(action2).to.have.been.called;
expect(history.undoAnnotation()).to.equal('annotation');
});
it('performs transitionable actions in a transition', function (done) {
var action1 = function() { return iD.Graph(); };
action1.transitionable = true;
history.on('change', spy);
history.perform(action1);
window.setTimeout(function() {
expect(spy.callCount).to.be.above(2);
done();
}, 300);
});
});
describe('#replace', function () {