11 Dec work
This commit is contained in:
parent
10131860d4
commit
199a62edfe
11 changed files with 494 additions and 5 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -335,6 +335,72 @@ bool FOSMFile::ProcessAttribute( const TCHAR* AttributeName, const TCHAR* Attrib
|
||||||
// Other type that we don't recognize yet. See http://wiki.openstreetmap.org/wiki/Key:building
|
// Other type that we don't recognize yet. See http://wiki.openstreetmap.org/wiki/Key:building
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "natural" ) ) )
|
||||||
|
{
|
||||||
|
if( !FCString::Stricmp( AttributeValue, TEXT( "water" ) ) )
|
||||||
|
{
|
||||||
|
CurrentWayInfo->WayType = EOSMWayType::Water;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Other natural type that we don't recognize yet. See http://wiki.openstreetmap.org/wiki/Key:building
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "waterway" ) ) )
|
||||||
|
{
|
||||||
|
CurrentWayInfo->WayType = EOSMWayType::Water;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "water" ) ) )
|
||||||
|
{
|
||||||
|
CurrentWayInfo->WayType = EOSMWayType::Water;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "landuse" ) ) )
|
||||||
|
{
|
||||||
|
if( !FCString::Stricmp( AttributeValue, TEXT( "basin" ) ) )
|
||||||
|
{
|
||||||
|
CurrentWayInfo->WayType = EOSMWayType::Water;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( !FCString::Stricmp( AttributeValue, TEXT( "reservoir" ) ) )
|
||||||
|
{
|
||||||
|
CurrentWayInfo->WayType = EOSMWayType::Water;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( !FCString::Stricmp( AttributeValue, TEXT( "pond" ) ) )
|
||||||
|
{
|
||||||
|
CurrentWayInfo->WayType = EOSMWayType::Water;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "leisure" ) ) )
|
||||||
|
{
|
||||||
|
if( !FCString::Stricmp( AttributeValue, TEXT( "park" ) ) )
|
||||||
|
{
|
||||||
|
CurrentWayInfo->WayType = EOSMWayType::Park;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( !FCString::Stricmp( AttributeValue, TEXT( "fitness_centre" ) ) )
|
||||||
|
{
|
||||||
|
CurrentWayInfo->WayType = EOSMWayType::Building;
|
||||||
|
CurrentWayInfo->Amenity = AttributeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Other natural type that we don't recognize yet. See http://wiki.openstreetmap.org/wiki/Key:building
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "height" ) ) )
|
else if( !FCString::Stricmp( CurrentWayTagKey, TEXT( "height" ) ) )
|
||||||
{
|
{
|
||||||
// Check to see if there is a space character in the height value. For now, we're looking
|
// Check to see if there is a space character in the height value. For now, we're looking
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,12 @@ public:
|
||||||
|
|
||||||
/** Default type of building. A general catch-all. */
|
/** Default type of building. A general catch-all. */
|
||||||
Building,
|
Building,
|
||||||
|
|
||||||
|
/** Default type of building. A general catch-all. */
|
||||||
|
Water,
|
||||||
|
|
||||||
|
/** Default type of building. A general catch-all. */
|
||||||
|
Park,
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,7 @@ bool UStreetMapFactory::LoadFromOpenStreetMapXMLFile( UStreetMap* StreetMap, FSt
|
||||||
// Vinfamy added
|
// Vinfamy added
|
||||||
if ( NewBuilding.BuildingLevels == 0 )
|
if ( NewBuilding.BuildingLevels == 0 )
|
||||||
{
|
{
|
||||||
NewBuilding.BuildingLevels = rand() % 5 + 1;
|
NewBuilding.BuildingLevels = rand() % 10 + 3;
|
||||||
}
|
}
|
||||||
NewBuilding.Amenity = OSMWay.Amenity;
|
NewBuilding.Amenity = OSMWay.Amenity;
|
||||||
NewBuilding.Building = OSMWay.Building;
|
NewBuilding.Building = OSMWay.Building;
|
||||||
|
|
@ -316,6 +316,207 @@ bool UStreetMapFactory::LoadFromOpenStreetMapXMLFile( UStreetMap* StreetMap, FSt
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Adds a water to the street map using the OpenStreetMap data, flattening the road's coordinates into our map's space
|
||||||
|
auto AddWaterForWay = [ConvertLatLongToMetersRelative, OSMToCentimetersScaleFactor](
|
||||||
|
const FOSMFile& OSMFile,
|
||||||
|
UStreetMap& StreetMapRef,
|
||||||
|
const FOSMFile::FOSMWayInfo& OSMWay ) -> bool
|
||||||
|
{
|
||||||
|
if( OSMWay.WayType == FOSMFile::EOSMWayType::Water )
|
||||||
|
{
|
||||||
|
// Require at least three points so that we don't have degenerate polygon!
|
||||||
|
if( OSMWay.Nodes.Num() > 2 )
|
||||||
|
{
|
||||||
|
// Create a Water for this way
|
||||||
|
FStreetMapWater& NewWater = *new( StreetMapRef.Waters )FStreetMapWater();
|
||||||
|
|
||||||
|
FVector2D BoundsMin( TNumericLimits<float>::Max(), TNumericLimits<float>::Max() );
|
||||||
|
FVector2D BoundsMax( TNumericLimits<float>::Lowest(), TNumericLimits<float>::Lowest() );
|
||||||
|
|
||||||
|
NewWater.WaterPoints.AddUninitialized( OSMWay.Nodes.Num() );
|
||||||
|
int32 CurWaterPoint = 0;
|
||||||
|
|
||||||
|
for( const FOSMFile::FOSMNodeInfo* OSMNodePtr : OSMWay.Nodes )
|
||||||
|
{
|
||||||
|
const FOSMFile::FOSMNodeInfo& OSMNode = *OSMNodePtr;
|
||||||
|
|
||||||
|
// Transform all points relative to the center of the latitude/longitude bounds, so that
|
||||||
|
// we get as much precision as possible.
|
||||||
|
const double RelativeToLatitude = OSMFile.AverageLatitude;
|
||||||
|
const double RelativeToLongitude = OSMFile.AverageLongitude;
|
||||||
|
const FVector2D NodePos = ConvertLatLongToMetersRelative(
|
||||||
|
OSMNode.Latitude,
|
||||||
|
OSMNode.Longitude,
|
||||||
|
RelativeToLatitude,
|
||||||
|
RelativeToLongitude ) * OSMToCentimetersScaleFactor;
|
||||||
|
|
||||||
|
// Update bounding box
|
||||||
|
{
|
||||||
|
if( NodePos.X < BoundsMin.X )
|
||||||
|
{
|
||||||
|
BoundsMin.X = NodePos.X;
|
||||||
|
}
|
||||||
|
if( NodePos.Y < BoundsMin.Y )
|
||||||
|
{
|
||||||
|
BoundsMin.Y = NodePos.Y;
|
||||||
|
}
|
||||||
|
if( NodePos.X > BoundsMax.X )
|
||||||
|
{
|
||||||
|
BoundsMax.X = NodePos.X;
|
||||||
|
}
|
||||||
|
if( NodePos.Y > BoundsMax.Y )
|
||||||
|
{
|
||||||
|
BoundsMax.Y = NodePos.Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in the points
|
||||||
|
NewWater.WaterPoints[ CurWaterPoint++ ] = NodePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the Water ended up with a closed polygon, then remove the final (redundant) point
|
||||||
|
const bool bIsClosed = NewWater.WaterPoints[ 0 ].Equals( NewWater.WaterPoints[ NewWater.WaterPoints.Num() - 1 ], KINDA_SMALL_NUMBER );
|
||||||
|
if( bIsClosed )
|
||||||
|
{
|
||||||
|
// Remove the final redundant point
|
||||||
|
NewWater.WaterPoints.Pop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Wasn't expecting to have an unclosed shape. Our tolerances might be off, or the data was malformed.
|
||||||
|
// Either way, it shouldn't be a problem as we'll close the shape ourselves below.
|
||||||
|
// @todo: Log this for the user as an import warning
|
||||||
|
}
|
||||||
|
|
||||||
|
NewWater.WaterName = OSMWay.Name;
|
||||||
|
if( NewWater.WaterName.IsEmpty() )
|
||||||
|
{
|
||||||
|
NewWater.WaterName = OSMWay.Ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewWater.BoundsMin = BoundsMin;
|
||||||
|
NewWater.BoundsMax = BoundsMax;
|
||||||
|
|
||||||
|
StreetMapRef.BoundsMin.X = FMath::Min( StreetMapRef.BoundsMin.X, BoundsMin.X );
|
||||||
|
StreetMapRef.BoundsMin.Y = FMath::Min( StreetMapRef.BoundsMin.Y, BoundsMin.Y );
|
||||||
|
StreetMapRef.BoundsMax.X = FMath::Max( StreetMapRef.BoundsMax.X, BoundsMax.X );
|
||||||
|
StreetMapRef.BoundsMax.Y = FMath::Max( StreetMapRef.BoundsMax.Y, BoundsMax.Y );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NOTE: Skipped adding Water for way because it has less than 3 points
|
||||||
|
// @todo: Log this for the user as an import warning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Adds a Park to the street map using the OpenStreetMap data, flattening the road's coordinates into our map's space
|
||||||
|
auto AddParkForWay = [ConvertLatLongToMetersRelative, OSMToCentimetersScaleFactor](
|
||||||
|
const FOSMFile& OSMFile,
|
||||||
|
UStreetMap& StreetMapRef,
|
||||||
|
const FOSMFile::FOSMWayInfo& OSMWay ) -> bool
|
||||||
|
{
|
||||||
|
if( OSMWay.WayType == FOSMFile::EOSMWayType::Park )
|
||||||
|
{
|
||||||
|
// Require at least three points so that we don't have degenerate polygon!
|
||||||
|
if( OSMWay.Nodes.Num() > 2 )
|
||||||
|
{
|
||||||
|
// Create a Park for this way
|
||||||
|
FStreetMapPark& NewPark = *new( StreetMapRef.Parks )FStreetMapPark();
|
||||||
|
|
||||||
|
FVector2D BoundsMin( TNumericLimits<float>::Max(), TNumericLimits<float>::Max() );
|
||||||
|
FVector2D BoundsMax( TNumericLimits<float>::Lowest(), TNumericLimits<float>::Lowest() );
|
||||||
|
|
||||||
|
NewPark.ParkPoints.AddUninitialized( OSMWay.Nodes.Num() );
|
||||||
|
int32 CurParkPoint = 0;
|
||||||
|
|
||||||
|
for( const FOSMFile::FOSMNodeInfo* OSMNodePtr : OSMWay.Nodes )
|
||||||
|
{
|
||||||
|
const FOSMFile::FOSMNodeInfo& OSMNode = *OSMNodePtr;
|
||||||
|
|
||||||
|
// Transform all points relative to the center of the latitude/longitude bounds, so that
|
||||||
|
// we get as much precision as possible.
|
||||||
|
const double RelativeToLatitude = OSMFile.AverageLatitude;
|
||||||
|
const double RelativeToLongitude = OSMFile.AverageLongitude;
|
||||||
|
const FVector2D NodePos = ConvertLatLongToMetersRelative(
|
||||||
|
OSMNode.Latitude,
|
||||||
|
OSMNode.Longitude,
|
||||||
|
RelativeToLatitude,
|
||||||
|
RelativeToLongitude ) * OSMToCentimetersScaleFactor;
|
||||||
|
|
||||||
|
// Update bounding box
|
||||||
|
{
|
||||||
|
if( NodePos.X < BoundsMin.X )
|
||||||
|
{
|
||||||
|
BoundsMin.X = NodePos.X;
|
||||||
|
}
|
||||||
|
if( NodePos.Y < BoundsMin.Y )
|
||||||
|
{
|
||||||
|
BoundsMin.Y = NodePos.Y;
|
||||||
|
}
|
||||||
|
if( NodePos.X > BoundsMax.X )
|
||||||
|
{
|
||||||
|
BoundsMax.X = NodePos.X;
|
||||||
|
}
|
||||||
|
if( NodePos.Y > BoundsMax.Y )
|
||||||
|
{
|
||||||
|
BoundsMax.Y = NodePos.Y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill in the points
|
||||||
|
NewPark.ParkPoints[ CurParkPoint++ ] = NodePos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the Park ended up with a closed polygon, then remove the final (redundant) point
|
||||||
|
const bool bIsClosed = NewPark.ParkPoints[ 0 ].Equals( NewPark.ParkPoints[ NewPark.ParkPoints.Num() - 1 ], KINDA_SMALL_NUMBER );
|
||||||
|
if( bIsClosed )
|
||||||
|
{
|
||||||
|
// Remove the final redundant point
|
||||||
|
NewPark.ParkPoints.Pop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Wasn't expecting to have an unclosed shape. Our tolerances might be off, or the data was malformed.
|
||||||
|
// Either way, it shouldn't be a problem as we'll close the shape ourselves below.
|
||||||
|
// @todo: Log this for the user as an import warning
|
||||||
|
}
|
||||||
|
|
||||||
|
NewPark.ParkName = OSMWay.Name;
|
||||||
|
if( NewPark.ParkName.IsEmpty() )
|
||||||
|
{
|
||||||
|
NewPark.ParkName = OSMWay.Ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
NewPark.BoundsMin = BoundsMin;
|
||||||
|
NewPark.BoundsMax = BoundsMax;
|
||||||
|
|
||||||
|
StreetMapRef.BoundsMin.X = FMath::Min( StreetMapRef.BoundsMin.X, BoundsMin.X );
|
||||||
|
StreetMapRef.BoundsMin.Y = FMath::Min( StreetMapRef.BoundsMin.Y, BoundsMin.Y );
|
||||||
|
StreetMapRef.BoundsMax.X = FMath::Max( StreetMapRef.BoundsMax.X, BoundsMax.X );
|
||||||
|
StreetMapRef.BoundsMax.Y = FMath::Max( StreetMapRef.BoundsMax.Y, BoundsMax.Y );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// NOTE: Skipped adding Park for way because it has less than 3 points
|
||||||
|
// @todo: Log this for the user as an import warning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Load up the OSM file. It's in XML format.
|
// Load up the OSM file. It's in XML format.
|
||||||
|
|
@ -349,6 +550,26 @@ bool UStreetMapFactory::LoadFromOpenStreetMapXMLFile( UStreetMap* StreetMap, FSt
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
else if( OSMWay->WayType == FOSMFile::EOSMWayType::Water )
|
||||||
|
{
|
||||||
|
if( AddWaterForWay( OSMFile, *StreetMap, *OSMWay ) )
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if( OSMWay->WayType == FOSMFile::EOSMWayType::Park )
|
||||||
|
{
|
||||||
|
if( AddParkForWay( OSMFile, *StreetMap, *OSMWay ) )
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int32 RoadIndex = INDEX_NONE;
|
int32 RoadIndex = INDEX_NONE;
|
||||||
|
|
|
||||||
|
|
@ -99,20 +99,32 @@ public:
|
||||||
/** Buildings border vertical offset */
|
/** Buildings border vertical offset */
|
||||||
UPROPERTY(Category = StreetMap, EditAnywhere, meta = (ClampMin = "0", UIMin = "0"))
|
UPROPERTY(Category = StreetMap, EditAnywhere, meta = (ClampMin = "0", UIMin = "0"))
|
||||||
float BuildingBorderZ;
|
float BuildingBorderZ;
|
||||||
|
|
||||||
|
|
||||||
|
/** Water vertex color */
|
||||||
|
UPROPERTY(Category = StreetMap, EditAnywhere)
|
||||||
|
FLinearColor WaterColor;
|
||||||
|
|
||||||
|
/** Park vertex color */
|
||||||
|
UPROPERTY(Category = StreetMap, EditAnywhere)
|
||||||
|
FLinearColor ParkColor;
|
||||||
|
|
||||||
|
|
||||||
FStreetMapMeshBuildSettings() :
|
FStreetMapMeshBuildSettings() :
|
||||||
RoadOffesetZ(0.0f),
|
RoadOffesetZ(0.0f),
|
||||||
bWant3DBuildings(true),
|
bWant3DBuildings(true),
|
||||||
bWantLitBuildings(true),
|
bWantLitBuildings(true),
|
||||||
StreetThickness(800.0f),
|
StreetThickness(800.0f),
|
||||||
StreetColor(0.05f, 0.75f, 0.05f),
|
StreetColor(0.93f, 0.90f, 0.87f),
|
||||||
MajorRoadThickness(1000.0f),
|
MajorRoadThickness(1000.0f),
|
||||||
MajorRoadColor(0.15f, 0.85f, 0.15f),
|
MajorRoadColor(0.92f, 0.91f, 0.88f),
|
||||||
HighwayThickness(1400.0f),
|
HighwayThickness(1400.0f),
|
||||||
HighwayColor(FLinearColor(0.25f, 0.95f, 0.25f)),
|
HighwayColor(FLinearColor(0.91f, 0.90f, 0.87f)),
|
||||||
BuildingBorderThickness(20.0f),
|
BuildingBorderThickness(20.0f),
|
||||||
BuildingBorderLinearColor(0.85f, 0.85f, 0.85f),
|
BuildingBorderLinearColor(0.85f, 0.85f, 0.85f),
|
||||||
BuildingBorderZ(10.0f)
|
BuildingBorderZ(10.0f),
|
||||||
|
ParkColor(0.00f, 0.55f, 0.27f),
|
||||||
|
WaterColor(0.26f, 0.75f, 0.98f)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -312,6 +324,57 @@ struct STREETMAPRUNTIME_API FStreetMapBuilding
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Vinfamy added
|
||||||
|
|
||||||
|
USTRUCT( BlueprintType )
|
||||||
|
struct STREETMAPRUNTIME_API FStreetMapWater
|
||||||
|
{
|
||||||
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
|
/** Name of the water */
|
||||||
|
UPROPERTY( Category=StreetMap, EditAnywhere)
|
||||||
|
FString WaterName;
|
||||||
|
|
||||||
|
/** Polygon points that define the perimeter of the water */
|
||||||
|
UPROPERTY( Category=StreetMap, EditAnywhere )
|
||||||
|
TArray<FVector2D> WaterPoints;
|
||||||
|
|
||||||
|
// @todo: Performance: Bounding information could be computed at load time if we want to avoid the memory cost of storing it
|
||||||
|
|
||||||
|
/** 2D bounds (min) of this water's points */
|
||||||
|
UPROPERTY( Category=StreetMap, EditAnywhere )
|
||||||
|
FVector2D BoundsMin;
|
||||||
|
|
||||||
|
/** 2D bounds (max) of this water's points */
|
||||||
|
UPROPERTY( Category=StreetMap, EditAnywhere )
|
||||||
|
FVector2D BoundsMax;
|
||||||
|
};
|
||||||
|
|
||||||
|
USTRUCT( BlueprintType )
|
||||||
|
struct STREETMAPRUNTIME_API FStreetMapPark
|
||||||
|
{
|
||||||
|
GENERATED_USTRUCT_BODY()
|
||||||
|
|
||||||
|
/** Name of the park */
|
||||||
|
UPROPERTY( Category=StreetMap, EditAnywhere)
|
||||||
|
FString ParkName;
|
||||||
|
|
||||||
|
/** Polygon points that define the perimeter of the park */
|
||||||
|
UPROPERTY( Category=StreetMap, EditAnywhere )
|
||||||
|
TArray<FVector2D> ParkPoints;
|
||||||
|
|
||||||
|
// @todo: Performance: Bounding information could be computed at load time if we want to avoid the memory cost of storing it
|
||||||
|
|
||||||
|
/** 2D bounds (min) of this water's points */
|
||||||
|
UPROPERTY( Category=StreetMap, EditAnywhere )
|
||||||
|
FVector2D BoundsMin;
|
||||||
|
|
||||||
|
/** 2D bounds (max) of this water's points */
|
||||||
|
UPROPERTY( Category=StreetMap, EditAnywhere )
|
||||||
|
FVector2D BoundsMax;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/** A loaded street map */
|
/** A loaded street map */
|
||||||
UCLASS(Blueprintable, BlueprintType)
|
UCLASS(Blueprintable, BlueprintType)
|
||||||
class STREETMAPRUNTIME_API UStreetMap : public UObject
|
class STREETMAPRUNTIME_API UStreetMap : public UObject
|
||||||
|
|
@ -361,6 +424,32 @@ public:
|
||||||
{
|
{
|
||||||
return Buildings;
|
return Buildings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** vinfamy Gets all of the waters (read only) */
|
||||||
|
const TArray<FStreetMapWater>& GetWaters() const
|
||||||
|
{
|
||||||
|
return Waters;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets all of the waters */
|
||||||
|
TArray<FStreetMapWater>& GetWaters()
|
||||||
|
{
|
||||||
|
return Waters;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** vinfamy Gets all of the parks (read only) */
|
||||||
|
const TArray<FStreetMapPark>& GetParks() const
|
||||||
|
{
|
||||||
|
return Parks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets all of the parks */
|
||||||
|
TArray<FStreetMapPark>& GetParks()
|
||||||
|
{
|
||||||
|
return Parks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Gets the bounding box of the map */
|
/** Gets the bounding box of the map */
|
||||||
FVector2D GetBoundsMin() const
|
FVector2D GetBoundsMin() const
|
||||||
|
|
@ -397,6 +486,14 @@ protected:
|
||||||
/** List of nodes on this map. Nodes describe interesting points along roads, usually where roads intersect or at the end of a dead-end street */
|
/** List of nodes on this map. Nodes describe interesting points along roads, usually where roads intersect or at the end of a dead-end street */
|
||||||
UPROPERTY( Category=StreetMap, VisibleAnywhere )
|
UPROPERTY( Category=StreetMap, VisibleAnywhere )
|
||||||
TArray<FStreetMapNode> Nodes;
|
TArray<FStreetMapNode> Nodes;
|
||||||
|
|
||||||
|
/** Vinfamy added - List of waters (natural = water) */
|
||||||
|
UPROPERTY( Category=StreetMap, VisibleAnywhere )
|
||||||
|
TArray<FStreetMapWater> Waters;
|
||||||
|
|
||||||
|
/** List of parks (leisure = park) */
|
||||||
|
UPROPERTY( Category=StreetMap, VisibleAnywhere )
|
||||||
|
TArray<FStreetMapPark> Parks;
|
||||||
|
|
||||||
/** List of all buildings on the street map */
|
/** List of all buildings on the street map */
|
||||||
UPROPERTY( Category=StreetMap, EditAnywhere, BlueprintReadWrite)
|
UPROPERTY( Category=StreetMap, EditAnywhere, BlueprintReadWrite)
|
||||||
|
|
|
||||||
|
|
@ -232,6 +232,10 @@ void UStreetMapComponent::GenerateMesh()
|
||||||
const float BuildingBorderZ = MeshBuildSettings.BuildingBorderZ;
|
const float BuildingBorderZ = MeshBuildSettings.BuildingBorderZ;
|
||||||
const FColor BuildingBorderColor( BuildingBorderLinearColor.ToFColor( false ) );
|
const FColor BuildingBorderColor( BuildingBorderLinearColor.ToFColor( false ) );
|
||||||
const FColor BuildingFillColor( FLinearColor( BuildingBorderLinearColor * 0.33f ).CopyWithNewOpacity( 1.0f ).ToFColor( false ) );
|
const FColor BuildingFillColor( FLinearColor( BuildingBorderLinearColor * 0.33f ).CopyWithNewOpacity( 1.0f ).ToFColor( false ) );
|
||||||
|
|
||||||
|
const FColor WaterColor = MeshBuildSettings.WaterColor.ToFColor( false );
|
||||||
|
const FColor ParkColor = MeshBuildSettings.ParkColor.ToFColor( false );
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -247,6 +251,8 @@ void UStreetMapComponent::GenerateMesh()
|
||||||
const auto& Roads = StreetMap->GetRoads();
|
const auto& Roads = StreetMap->GetRoads();
|
||||||
const auto& Nodes = StreetMap->GetNodes();
|
const auto& Nodes = StreetMap->GetNodes();
|
||||||
const auto& Buildings = StreetMap->GetBuildings();
|
const auto& Buildings = StreetMap->GetBuildings();
|
||||||
|
const auto& Waters = StreetMap->GetWaters();
|
||||||
|
const auto& Parks = StreetMap->GetParks();
|
||||||
|
|
||||||
for( const auto& Road : Roads )
|
for( const auto& Road : Roads )
|
||||||
{
|
{
|
||||||
|
|
@ -430,6 +436,99 @@ void UStreetMapComponent::GenerateMesh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Vinfamy added
|
||||||
|
|
||||||
|
TArray< int32 > TempIndicesW;
|
||||||
|
TArray< int32 > TriangulatedVertexIndicesW;
|
||||||
|
TArray< FVector > TempPointsW;
|
||||||
|
for( int32 WaterIndex = 0; WaterIndex < Waters.Num(); ++WaterIndex )
|
||||||
|
{
|
||||||
|
const auto& Water = Waters[ WaterIndex ];
|
||||||
|
|
||||||
|
// Water mesh (or filled area, if the Water has no height)
|
||||||
|
|
||||||
|
// Triangulate this Water
|
||||||
|
// @todo: Performance: Triangulating lots of Water polygons is quite slow. We could easily do this
|
||||||
|
// as part of the import process and store tessellated geometry instead of doing this at load time.
|
||||||
|
bool WindsClockwise;
|
||||||
|
if( FPolygonTools::TriangulatePolygon( Water.WaterPoints, TempIndicesW, /* Out */ TriangulatedVertexIndicesW, /* Out */ WindsClockwise ) )
|
||||||
|
{
|
||||||
|
// @todo: Performance: We could preprocess the Water shapes so that the points always wind
|
||||||
|
// in a consistent direction, so we can skip determining the winding above.
|
||||||
|
|
||||||
|
const int32 FirstTopVertexIndex = this->Vertices.Num();
|
||||||
|
|
||||||
|
// calculate fill Z for Waters
|
||||||
|
// either use the defined height or extrapolate from Water level count
|
||||||
|
float WaterFillZ = 0.0f;
|
||||||
|
|
||||||
|
// Top of Water
|
||||||
|
{
|
||||||
|
TempPointsW.SetNum( Water.WaterPoints.Num(), false );
|
||||||
|
for( int32 PointIndex = 0; PointIndex < Water.WaterPoints.Num(); ++PointIndex )
|
||||||
|
{
|
||||||
|
TempPointsW[ PointIndex ] = FVector( Water.WaterPoints[ ( Water.WaterPoints.Num() - PointIndex ) - 1 ], WaterFillZ );
|
||||||
|
}
|
||||||
|
AddTriangles( TempPointsW, TriangulatedVertexIndicesW, FVector::ForwardVector, FVector::UpVector, WaterColor, MeshBoundingBox );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// @todo: Triangulation failed for some reason, possibly due to degenerate polygons. We can
|
||||||
|
// probably improve the algorithm to avoid this happening.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Water border
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TArray< int32 > TempIndicesP;
|
||||||
|
TArray< int32 > TriangulatedVertexIndicesP;
|
||||||
|
TArray< FVector > TempPointsP;
|
||||||
|
for( int32 ParkIndex = 0; ParkIndex < Parks.Num(); ++ParkIndex )
|
||||||
|
{
|
||||||
|
const auto& Park = Parks[ ParkIndex ];
|
||||||
|
|
||||||
|
// Park mesh (or filled area, if the Park has no height)
|
||||||
|
|
||||||
|
// Triangulate this Park
|
||||||
|
// @todo: Performance: Triangulating lots of Park polygons is quite slow. We could easily do this
|
||||||
|
// as part of the import process and store tessellated geometry instead of doing this at load time.
|
||||||
|
bool WindsClockwise;
|
||||||
|
if( FPolygonTools::TriangulatePolygon( Park.ParkPoints, TempIndicesP, /* Out */ TriangulatedVertexIndicesP, /* Out */ WindsClockwise ) )
|
||||||
|
{
|
||||||
|
// @todo: Performance: We could preprocess the Park shapes so that the points always wind
|
||||||
|
// in a consistent direction, so we can skip determining the winding above.
|
||||||
|
|
||||||
|
const int32 FirstTopVertexIndex = this->Vertices.Num();
|
||||||
|
|
||||||
|
// calculate fill Z for Parks
|
||||||
|
// either use the defined height or extrapolate from Park level count
|
||||||
|
float ParkFillZ = 0.0f;
|
||||||
|
|
||||||
|
// Top of Park
|
||||||
|
{
|
||||||
|
TempPointsP.SetNum( Park.ParkPoints.Num(), false );
|
||||||
|
for( int32 PointIndex = 0; PointIndex < Park.ParkPoints.Num(); ++PointIndex )
|
||||||
|
{
|
||||||
|
TempPointsP[ PointIndex ] = FVector( Park.ParkPoints[ ( Park.ParkPoints.Num() - PointIndex ) - 1 ], ParkFillZ );
|
||||||
|
}
|
||||||
|
AddTriangles( TempPointsP, TriangulatedVertexIndicesP, FVector::ForwardVector, FVector::UpVector, ParkColor, MeshBoundingBox );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// @todo: Triangulation failed for some reason, possibly due to degenerate polygons. We can
|
||||||
|
// probably improve the algorithm to avoid this happening.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Park border
|
||||||
|
}
|
||||||
|
|
||||||
CachedLocalBounds = MeshBoundingBox;
|
CachedLocalBounds = MeshBoundingBox;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue