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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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" ) ) )
|
||||
{
|
||||
// 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. */
|
||||
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
|
||||
if ( NewBuilding.BuildingLevels == 0 )
|
||||
{
|
||||
NewBuilding.BuildingLevels = rand() % 5 + 1;
|
||||
NewBuilding.BuildingLevels = rand() % 10 + 3;
|
||||
}
|
||||
NewBuilding.Amenity = OSMWay.Amenity;
|
||||
NewBuilding.Building = OSMWay.Building;
|
||||
|
|
@ -316,6 +316,207 @@ bool UStreetMapFactory::LoadFromOpenStreetMapXMLFile( UStreetMap* StreetMap, FSt
|
|||
|
||||
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.
|
||||
|
|
@ -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
|
||||
{
|
||||
int32 RoadIndex = INDEX_NONE;
|
||||
|
|
|
|||
|
|
@ -99,20 +99,32 @@ public:
|
|||
/** Buildings border vertical offset */
|
||||
UPROPERTY(Category = StreetMap, EditAnywhere, meta = (ClampMin = "0", UIMin = "0"))
|
||||
float BuildingBorderZ;
|
||||
|
||||
|
||||
/** Water vertex color */
|
||||
UPROPERTY(Category = StreetMap, EditAnywhere)
|
||||
FLinearColor WaterColor;
|
||||
|
||||
/** Park vertex color */
|
||||
UPROPERTY(Category = StreetMap, EditAnywhere)
|
||||
FLinearColor ParkColor;
|
||||
|
||||
|
||||
FStreetMapMeshBuildSettings() :
|
||||
RoadOffesetZ(0.0f),
|
||||
bWant3DBuildings(true),
|
||||
bWantLitBuildings(true),
|
||||
StreetThickness(800.0f),
|
||||
StreetColor(0.05f, 0.75f, 0.05f),
|
||||
StreetColor(0.93f, 0.90f, 0.87f),
|
||||
MajorRoadThickness(1000.0f),
|
||||
MajorRoadColor(0.15f, 0.85f, 0.15f),
|
||||
MajorRoadColor(0.92f, 0.91f, 0.88f),
|
||||
HighwayThickness(1400.0f),
|
||||
HighwayColor(FLinearColor(0.25f, 0.95f, 0.25f)),
|
||||
HighwayColor(FLinearColor(0.91f, 0.90f, 0.87f)),
|
||||
BuildingBorderThickness(20.0f),
|
||||
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 */
|
||||
UCLASS(Blueprintable, BlueprintType)
|
||||
class STREETMAPRUNTIME_API UStreetMap : public UObject
|
||||
|
|
@ -361,6 +424,32 @@ public:
|
|||
{
|
||||
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 */
|
||||
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 */
|
||||
UPROPERTY( Category=StreetMap, VisibleAnywhere )
|
||||
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 */
|
||||
UPROPERTY( Category=StreetMap, EditAnywhere, BlueprintReadWrite)
|
||||
|
|
|
|||
|
|
@ -232,6 +232,10 @@ void UStreetMapComponent::GenerateMesh()
|
|||
const float BuildingBorderZ = MeshBuildSettings.BuildingBorderZ;
|
||||
const FColor BuildingBorderColor( BuildingBorderLinearColor.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& Nodes = StreetMap->GetNodes();
|
||||
const auto& Buildings = StreetMap->GetBuildings();
|
||||
const auto& Waters = StreetMap->GetWaters();
|
||||
const auto& Parks = StreetMap->GetParks();
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue