-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Save Atlas to ProtobufAtlas similar to TextAtlas #99
Changes from 1 commit
bb7706a
1890bc8
a03cade
4e05e34
18611a3
f382466
fd9af27
fbdaacc
c9720fe
bc15496
a804b72
40437f7
70abe50
1eba0c9
d08f1a8
5aa04a8
539337e
0bfec87
5ce39d5
6359a6f
ba3b136
6db5ee7
a7266a6
27aa4e2
4cd48d0
4a06a5d
cd9fb95
f8db3ff
307b015
0e19a0b
2678b77
bc6f404
fe1e9a1
3918bb8
ee43801
eeeb127
0d4e3f0
9657bac
79e7450
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
…it test.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,11 +13,15 @@ | |
import org.openstreetmap.atlas.geography.atlas.Atlas; | ||
import org.openstreetmap.atlas.geography.atlas.AtlasMetaData; | ||
import org.openstreetmap.atlas.geography.atlas.builder.AtlasSize; | ||
import org.openstreetmap.atlas.geography.atlas.builder.RelationBean; | ||
import org.openstreetmap.atlas.geography.atlas.items.Area; | ||
import org.openstreetmap.atlas.geography.atlas.items.Edge; | ||
import org.openstreetmap.atlas.geography.atlas.items.ItemType; | ||
import org.openstreetmap.atlas.geography.atlas.items.Line; | ||
import org.openstreetmap.atlas.geography.atlas.items.Node; | ||
import org.openstreetmap.atlas.geography.atlas.items.Point; | ||
import org.openstreetmap.atlas.geography.atlas.items.Relation; | ||
import org.openstreetmap.atlas.geography.atlas.items.RelationMember; | ||
import org.openstreetmap.atlas.geography.atlas.packed.PackedAtlas; | ||
import org.openstreetmap.atlas.geography.atlas.packed.PackedAtlasBuilder; | ||
import org.openstreetmap.atlas.geography.converters.proto.ProtoLocationConverter; | ||
|
@@ -30,6 +34,7 @@ | |
import org.openstreetmap.atlas.proto.ProtoLocation; | ||
import org.openstreetmap.atlas.proto.ProtoNode; | ||
import org.openstreetmap.atlas.proto.ProtoPoint; | ||
import org.openstreetmap.atlas.proto.ProtoRelation; | ||
import org.openstreetmap.atlas.streaming.resource.Resource; | ||
import org.openstreetmap.atlas.streaming.resource.WritableResource; | ||
import org.openstreetmap.atlas.utilities.collections.Maps; | ||
|
@@ -74,14 +79,10 @@ public PackedAtlas read(final Resource resource) | |
} | ||
|
||
// initialize atlas metadata | ||
final long numberOfPoints = protoAtlasContainer.getNumberOfPoints(); | ||
final long numberOfLines = protoAtlasContainer.getNumberOfLines(); | ||
final long numberOfAreas = protoAtlasContainer.getNumberOfAreas(); | ||
final long numberOfNodes = protoAtlasContainer.getNumberOfNodes(); | ||
final long numberOfEdges = protoAtlasContainer.getNumberOfEdges(); | ||
final long numberOfRelations = 0; | ||
final AtlasSize atlasSize = new AtlasSize(numberOfEdges, numberOfNodes, numberOfAreas, | ||
numberOfLines, numberOfPoints, numberOfRelations); | ||
final AtlasSize atlasSize = new AtlasSize(protoAtlasContainer.getNumberOfEdges(), | ||
protoAtlasContainer.getNumberOfNodes(), protoAtlasContainer.getNumberOfAreas(), | ||
protoAtlasContainer.getNumberOfLines(), protoAtlasContainer.getNumberOfPoints(), | ||
protoAtlasContainer.getNumberOfRelations()); | ||
// TODO it would be nice to programmatically determine which protobuf version is in use | ||
final AtlasMetaData atlasMetaData = new AtlasMetaData(atlasSize, true, "unknown", | ||
"ProtoAtlas", "unknown", "unknown", Maps.hashMap()); | ||
|
@@ -94,6 +95,7 @@ public PackedAtlas read(final Resource resource) | |
parseAreas(builder, protoAtlasContainer.getAreasList()); | ||
parseNodes(builder, protoAtlasContainer.getNodesList()); | ||
parseEdges(builder, protoAtlasContainer.getEdgesList()); | ||
parseRelations(builder, protoAtlasContainer.getRelationsList()); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there no relations being added to the new packed Atlas or am I missing something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're getting there. It's still in development :) |
||
return (PackedAtlas) builder.get(); | ||
} | ||
|
@@ -110,12 +112,13 @@ public void write(final Atlas atlas, final WritableResource resource) | |
{ | ||
final ProtoAtlasContainer.Builder protoAtlasBuilder = ProtoAtlasContainer.newBuilder(); | ||
|
||
// get the Atlas features into the ProtoAtlasBuilder | ||
// put the Atlas features into the ProtoAtlasBuilder | ||
writePointsToBuilder(atlas, protoAtlasBuilder); | ||
writeLinesToBuilder(atlas, protoAtlasBuilder); | ||
writeAreasToBuilder(atlas, protoAtlasBuilder); | ||
writeNodesToBuilder(atlas, protoAtlasBuilder); | ||
writeEdgesToBuilder(atlas, protoAtlasBuilder); | ||
writeRelationsToBuilder(atlas, protoAtlasBuilder); | ||
|
||
final ProtoAtlasContainer protoAtlas = protoAtlasBuilder.build(); | ||
resource.writeAndClose(protoAtlas.toByteArray()); | ||
|
@@ -199,6 +202,37 @@ private void parsePoints(final PackedAtlasBuilder builder, final List<ProtoPoint | |
}); | ||
} | ||
|
||
private RelationBean parseRelationBean(final ProtoRelation protoRelation) | ||
{ | ||
final RelationBean bean = new RelationBean(); | ||
|
||
protoRelation.getBeansList().forEach(protoRelationBean -> | ||
{ | ||
final long memberId = protoRelationBean.getMemberId(); | ||
final String memberRole = protoRelationBean.getMemberRole(); | ||
final ItemType memberType = ItemType | ||
.forValue(protoRelationBean.getMemberType().getNumber()); | ||
bean.addItem(memberId, memberRole, memberType); | ||
}); | ||
|
||
return bean; | ||
} | ||
|
||
private void parseRelations(final PackedAtlasBuilder builder, | ||
final List<ProtoRelation> relations) | ||
{ | ||
final ProtoTagListConverter protoTagListConverter = new ProtoTagListConverter(); | ||
relations.forEach(protoRelation -> | ||
{ | ||
final long identifier = protoRelation.getId(); | ||
final RelationBean bean = parseRelationBean(protoRelation); | ||
final Map<String, String> tags = protoTagListConverter | ||
.convert(protoRelation.getTagsList()); | ||
// TODO should identifier and OSMIdentifier be the same? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They shouldn't be the same, one is the Atlas identifier, and one is the OSM identifier. Atlas identifier is padded with the country-slicing and way-sectioning digits. We should make a design decision on which one is passed in. This is somewhat tricky - since atlas identifier must be unique per type of entity (a Relation and an Edge can have the same atlas identifier, but no two Relations can have the same atlas identifier). So if this is a true representation of an Atlas, they should pass in the Atlas Identifier and we can leverage our existing factories to figure out the OSM Identifier based on the atlas identifier (remove the 6 digit padding). Let me know if that made sense! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm I see. I guess my question is, what should I be passing in for that second parameter? Will I need to have some additional code right here in this function to calculate the correct OSM id? Is there a reason the other builder 'add' methods for Node, Edge, Point, Line, etc. do not have an OSM id parameter? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check out ReverseIdentifierFactory - it can return the OSM identifier given an Atlas identifier. There is currently an issue for the other "add" methods to be consistent with this one. Sent you a pointer offline. |
||
builder.addRelation(identifier, identifier, bean, tags); | ||
}); | ||
} | ||
|
||
private void writeAreasToBuilder(final Atlas atlas, final Builder protoAtlasBuilder) | ||
{ | ||
long numberOfAreas = 0; | ||
|
@@ -318,4 +352,34 @@ private void writePointsToBuilder(final Atlas atlas, | |
} | ||
protoAtlasBuilder.setNumberOfPoints(numberOfPoints); | ||
} | ||
|
||
private void writeRelationsToBuilder(final Atlas atlas, final Builder protoAtlasBuilder) | ||
{ | ||
long numberOfRelations = 0; | ||
final ProtoTagListConverter protoTagListConverter = new ProtoTagListConverter(); | ||
|
||
for (final Relation relation : atlas.relations()) | ||
{ | ||
final ProtoRelation.Builder protoRelationBuilder = ProtoRelation.newBuilder(); | ||
protoRelationBuilder.setId(relation.getIdentifier()); | ||
for (final RelationMember member : relation.members()) | ||
{ | ||
final ProtoRelation.RelationBean.Builder beanBuilder = ProtoRelation.RelationBean | ||
.newBuilder(); | ||
beanBuilder.setMemberId(member.getRelationIdentifier()); | ||
beanBuilder.setMemberRole(member.getRole()); | ||
final ItemType type = ItemType.forEntity(member.getEntity()); | ||
beanBuilder.setMemberType(ProtoRelation.ProtoItemType.valueOf(type.getValue())); | ||
|
||
// TODO there may be a problem here if there are more relations in this atlas than | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doubt we will have 2 billion relations in an atlas. I would be more concerned with number of edges (due to way-sectioning and bi-directionality) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm. This would be a problem as well, since the ProtoAtlasContainer, when deserialized into an object, stores each of the feature types in an ArrayList - this is built into protobuf. So in memory you have a List of Nodes, Points, Lines, Edges, etc. I would imagine you would never have 2 billion features in one of those categories in a single atlas. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's hope not, but theoretically this could happen! This is worth noting and identifying as a limitation of the current proto implementation. |
||
// possible int32 values. This is because protobuf internally stores the protobeans | ||
// list as an ArrayList | ||
protoRelationBuilder.addBeans(beanBuilder.build()); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: extra line |
||
} | ||
numberOfRelations++; | ||
protoAtlasBuilder.addRelations(protoRelationBuilder.build()); | ||
} | ||
protoAtlasBuilder.setNumberOfRelations(numberOfRelations); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
syntax = "proto2"; | ||
|
||
option java_multiple_files = true; | ||
option java_outer_classname = "ProtoRelationWrapper"; | ||
|
||
package org.openstreetmap.atlas.proto; | ||
|
||
import "Tag.proto"; | ||
|
||
message ProtoRelation { | ||
optional int64 id = 1; | ||
repeated ProtoTag tags = 2; | ||
|
||
enum ProtoItemType { | ||
NODE = 0; | ||
EDGE = 1; | ||
AREA = 2; | ||
LINE = 3; | ||
POINT = 4; | ||
RELATION = 5; | ||
} | ||
|
||
message RelationBean { | ||
optional int64 memberId = 1; | ||
optional string memberRole = 2; | ||
optional ProtoItemType memberType = 3; | ||
} | ||
|
||
repeated RelationBean beans = 3; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wondering if we should have any kind of tag to specify this atlas was built from Proto?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll take a look at that class and see if there's something I can add.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I just mean add an entry into the Metadata tags saying source=proto and proto_version=xx (not sure if you can read that dynamically, but assuming yes).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok yeah can do. Did you have some fancy method in mind or should I just write code that greps build.gradle?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought there might be an easier way! If there's not, I wouldn't worry about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll mark it as TODO and if some simple way presents itself I'll be sure to implement it.