Moved packing algorithms, spatial partitioning system and serialization helpers from Nuclex.Support to Nuclex.Game; minor improvements in documentation; AbortedException no longer derives from ApplicationException; added document that gives an overview of several R-Tree splitting techniques I found on the 'net
git-svn-id: file:///srv/devel/repo-conversion/nusu@86 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
parent
fd2f072c2d
commit
86d915f9f0
|
@ -1,86 +1,47 @@
|
|||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{9118C4C7-DC1E-4BFB-A99D-2A22B7590D7F}</ProjectGuid>
|
||||
<ProjectTypeGuids>{6D335F3A-9D43-41b4-9D22-F6F17C4BE596};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>9.0.21022</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{9118C4C7-DC1E-4BFB-A99D-2A22B7590D7F}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Nuclex.Support</RootNamespace>
|
||||
<AssemblyName>Nuclex.Support</AssemblyName>
|
||||
<TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
|
||||
<XnaFrameworkVersion>v3.0</XnaFrameworkVersion>
|
||||
<XnaPlatform>Windows</XnaPlatform>
|
||||
<XnaCrossPlatformGroupID>83ebf0bc-f29b-41fa-a770-ba1f1ad89a46</XnaCrossPlatformGroupID>
|
||||
<FileUpgradeFlags>
|
||||
</FileUpgradeFlags>
|
||||
<OldToolsVersion>2.0</OldToolsVersion>
|
||||
<UpgradeBackupLocation>
|
||||
</UpgradeBackupLocation>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\x86\Debug</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;WINDOWS;UNITTEST</DefineConstants>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>TRACE;DEBUG;UNITTEST</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<NoStdLib>true</NoStdLib>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DocumentationFile>Documents\Nuclex.Support.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\x86\Release</OutputPath>
|
||||
<DefineConstants>TRACE;WINDOWS;UNITTEST</DefineConstants>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;UNITTEST</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<NoStdLib>true</NoStdLib>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DocumentationFile>Documents\Nuclex.Support.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.Xna.Framework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=x86">
|
||||
<Private>False</Private>
|
||||
<SpecificVersion>True</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Xna.Framework.Game, Version=3.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
<SpecificVersion>True</SpecificVersion>
|
||||
</Reference>
|
||||
<Reference Include="mscorlib">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="NMock2, Version=1.0.2657.18750, Culture=neutral, processorArchitecture=MSIL">
|
||||
<Reference Include="NMock2, Version=2.0.0.44, Culture=neutral, PublicKeyToken=37d3be0adc87c2b7, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\References\nmock\net-2.0\NMock2.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="nunit.framework, Version=2.4.3.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
|
||||
<Reference Include="nunit.framework, Version=2.4.6.0, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\References\nunit\net-2.0\nunit.framework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System">
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
|
@ -126,23 +87,6 @@
|
|||
<Compile Include="Source\Licensing\LicenseKey.Test.cs">
|
||||
<DependentUpon>LicenseKey.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Packing\ArevaloRectanglePacker.cs" />
|
||||
<Compile Include="Source\Packing\ArevaloRectanglePacker.Test.cs">
|
||||
<DependentUpon>ArevaloRectanglePacker.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Packing\CygonRectanglePacker.cs" />
|
||||
<Compile Include="Source\Packing\CygonRectanglePacker.Test.cs">
|
||||
<DependentUpon>CygonRectanglePacker.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Packing\OutOfSpaceException.cs" />
|
||||
<Compile Include="Source\Packing\RectanglePacker.cs" />
|
||||
<Compile Include="Source\Packing\RectanglePacker.Test.cs">
|
||||
<DependentUpon>RectanglePacker.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Packing\SimpleRectanglePacker.cs" />
|
||||
<Compile Include="Source\Packing\SimpleRectanglePacker.Test.cs">
|
||||
<DependentUpon>SimpleRectanglePacker.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Parsing\CommandLineParser.cs" />
|
||||
<Compile Include="Source\Parsing\CommandLineParser.Test.cs">
|
||||
<DependentUpon>CommandLineParser.cs</DependentUpon>
|
||||
|
@ -167,16 +111,6 @@
|
|||
</Compile>
|
||||
<Compile Include="Source\Scheduling\ThreadCallbackOperation.cs" />
|
||||
<Compile Include="Source\Scheduling\ThreadOperation.cs" />
|
||||
<Compile Include="Source\Serialization\BinarySerializer.cs" />
|
||||
<Compile Include="Source\Serialization\BinarySerializer.Test.cs">
|
||||
<DependentUpon>BinarySerializer.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Source\Serialization\IBinarySerializable.cs" />
|
||||
<Compile Include="Source\SpatialPartitioning\BoundingRectangle.cs" />
|
||||
<Compile Include="Source\SpatialPartitioning\RTree2.cs" />
|
||||
<Compile Include="Source\SpatialPartitioning\RTreeLeaf2.cs" />
|
||||
<Compile Include="Source\SpatialPartitioning\RTreeNode2.cs" />
|
||||
<Compile Include="Source\SpatialPartitioning\SpatialIndex2.cs" />
|
||||
<Compile Include="Source\StringHelper.cs" />
|
||||
<Compile Include="Source\StringHelper.Test.cs">
|
||||
<DependentUpon>StringHelper.cs</DependentUpon>
|
||||
|
@ -202,41 +136,11 @@
|
|||
<Compile Include="Source\Tracking\WeightedWaitable.cs" />
|
||||
<Compile Include="Source\WeakReference.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<NestedContentProject Include="Content\Content.contentproj">
|
||||
<Project>c57cb055-80d7-4b9d-a1cb-22f52f73972f</Project>
|
||||
<Visible>False</Visible>
|
||||
</NestedContentProject>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 2.0 %28x86%29</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.0 %28x86%29</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 3.1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Documents\Nuclex.Support.txt" />
|
||||
<Content Include="Documents\Request Framework.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v3.0\Microsoft.Xna.GameStudio.Common.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v3.0\Microsoft.Xna.GameStudio.NestedContent.targets" />
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
|
@ -1,60 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Nuclex.Support.Packing {
|
||||
|
||||
/// <summary>Unit test for the arevalo rectangle packer class</summary>
|
||||
[TestFixture]
|
||||
public class ArevaloRectanglePackerTest : RectanglePackerTest {
|
||||
|
||||
/// <summary>Tests the packer's efficiency using a deterministic benchmark</summary>
|
||||
[Test]
|
||||
public void TestSpaceEfficiency() {
|
||||
float efficiency = CalculateEfficiency(new ArevaloRectanglePacker(70, 70));
|
||||
|
||||
Assert.GreaterOrEqual(efficiency, 0.75f, "Packer achieves 75% efficiency");
|
||||
}
|
||||
|
||||
/// <summary>Tests the packer's stability by running a complete benchmark</summary>
|
||||
[Test]
|
||||
public void TestStability() {
|
||||
float score = Benchmark(
|
||||
delegate() { return new ArevaloRectanglePacker(1024, 1024); }
|
||||
);
|
||||
|
||||
// This is mainly a stability and performance test. It fails when the
|
||||
// packer crashes on its own and is otherwise only there to tell how long
|
||||
// it takes to complete the benchmark.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Packing
|
||||
|
||||
#endif // UNITTEST
|
|
@ -1,391 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Nuclex.Support.Packing {
|
||||
|
||||
/// <summary>Rectangle packer using an algorithm by Javier Arevalo</summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Original code by Javier Arevalo (jare at iguanademos dot com). Rewritten
|
||||
/// to C# / .NET by Markus Ewald (cygon at nuclex dot org).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// You have a bunch of rectangular pieces. You need to arrange them in a
|
||||
/// rectangular surface so that they don't overlap, keeping the total area of the
|
||||
/// rectangle as small as possible. This is fairly common when arranging characters
|
||||
/// in a bitmapped font, lightmaps for a 3D engine, and I guess other situations as
|
||||
/// well.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The idea of this algorithm is that, as we add rectangles, we can pre-select
|
||||
/// "interesting" places where we can try to add the next rectangles. For optimal
|
||||
/// results, the rectangles should be added in order. I initially tried using area
|
||||
/// as a sorting criteria, but it didn't work well with very tall or very flat
|
||||
/// rectangles. I then tried using the longest dimension as a selector, and it
|
||||
/// worked much better. So much for intuition...
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// These "interesting" places are just to the right and just below the currently
|
||||
/// added rectangle. The first rectangle, obviously, goes at the top left, the next
|
||||
/// one would go either to the right or below this one, and so on. It is a weird way
|
||||
/// to do it, but it seems to work very nicely.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The way we search here is fairly brute-force, the fact being that for most off-
|
||||
/// line purposes the performance seems more than adequate. I have generated a
|
||||
/// japanese font with around 8500 characters and all the time was spent generating
|
||||
/// the bitmaps.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Also, for all we care, we could grow the parent rectangle in a different way
|
||||
/// than power of two. It just happens that power of 2 is very convenient for
|
||||
/// graphics hardware textures.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// I'd be interested in hearing of other approaches to this problem. Make sure
|
||||
/// to post them on http://www.flipcode.com
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class ArevaloRectanglePacker : RectanglePacker {
|
||||
|
||||
#region class AnchorRankComparer
|
||||
|
||||
/// <summary>Compares the 'rank' of anchoring points</summary>
|
||||
/// <remarks>
|
||||
/// Anchoring points are potential locations for the placement of new rectangles.
|
||||
/// Each time a rectangle is inserted, an anchor point is generated on its upper
|
||||
/// right end and another one at its lower left end. The anchor points are kept
|
||||
/// in a list that is ordered by their closeness to the upper left corner of the
|
||||
/// packing area (their 'rank') so the packer favors positions that are closer to
|
||||
/// the upper left for new rectangles.
|
||||
/// </remarks>
|
||||
private class AnchorRankComparer : IComparer<Point> {
|
||||
|
||||
/// <summary>Provides a default instance for the anchor rank comparer</summary>
|
||||
public static AnchorRankComparer Default = new AnchorRankComparer();
|
||||
|
||||
/// <summary>Compares the rank of two anchors against each other</summary>
|
||||
/// <param name="left">Left anchor point that will be compared</param>
|
||||
/// <param name="right">Right anchor point that will be compared</param>
|
||||
/// <returns>The relation of the two anchor point's ranks to each other</returns>
|
||||
public int Compare(Point left, Point right) {
|
||||
//return Math.Min(left.X, left.Y) - Math.Min(right.X, right.Y);
|
||||
return (left.X + left.Y) - (right.X + right.Y);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>Initializes a new rectangle packer</summary>
|
||||
/// <param name="packingAreaWidth">Maximum width of the packing area</param>
|
||||
/// <param name="packingAreaHeight">Maximum height of the packing area</param>
|
||||
public ArevaloRectanglePacker(int packingAreaWidth, int packingAreaHeight)
|
||||
: base(packingAreaWidth, packingAreaHeight) {
|
||||
|
||||
this.packedRectangles = new List<Rectangle>();
|
||||
this.anchors = new List<Point>();
|
||||
this.anchors.Add(new Point(0, 0));
|
||||
|
||||
this.actualPackingAreaWidth = 1;
|
||||
this.actualPackingAreaHeight = 1;
|
||||
}
|
||||
|
||||
/// <summary>Tries to allocate space for a rectangle in the packing area</summary>
|
||||
/// <param name="rectangleWidth">Width of the rectangle to allocate</param>
|
||||
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
||||
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
||||
/// <returns>True if space for the rectangle could be allocated</returns>
|
||||
public override bool TryPack(
|
||||
int rectangleWidth, int rectangleHeight, out Point placement
|
||||
) {
|
||||
|
||||
// Try to find an anchor where the rectangle fits in, enlarging the packing
|
||||
// area and repeating the search recursively until it fits or the
|
||||
// maximum allowed size is exceeded.
|
||||
int anchorIndex = selectAnchorRecursive(
|
||||
rectangleWidth, rectangleHeight,
|
||||
this.actualPackingAreaWidth, this.actualPackingAreaHeight
|
||||
);
|
||||
|
||||
// No anchor could be found at which the rectangle did fit in
|
||||
if(anchorIndex == -1) {
|
||||
placement = Point.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
placement = this.anchors[anchorIndex];
|
||||
|
||||
// Move the rectangle either to the left or to the top until it collides with
|
||||
// a neightbouring rectangle. This is done to combat the effect of lining up
|
||||
// rectangles with gaps to the left or top of them because the anchor that
|
||||
// would allow placement there has been blocked by another rectangle
|
||||
optimizePlacement(ref placement, rectangleWidth, rectangleHeight);
|
||||
|
||||
// Remove the used anchor and add new anchors at the upper right and lower left
|
||||
// positions of the new rectangle
|
||||
{
|
||||
// The anchor is only removed if the placement optimization didn't
|
||||
// move the rectangle so far that the anchor isn't blocked anymore
|
||||
bool blocksAnchor =
|
||||
((placement.X + rectangleWidth) > this.anchors[anchorIndex].X) &&
|
||||
((placement.Y + rectangleHeight) > this.anchors[anchorIndex].Y);
|
||||
|
||||
if(blocksAnchor)
|
||||
this.anchors.RemoveAt(anchorIndex);
|
||||
|
||||
// Add new anchors at the upper right and lower left coordinates of the rectangle
|
||||
this.anchors.Add(new Point(placement.X + rectangleWidth, placement.Y));
|
||||
this.anchors.Add(new Point(placement.X, placement.Y + rectangleHeight));
|
||||
}
|
||||
|
||||
// Finally, we can add the rectangle to our packed rectangles list
|
||||
this.packedRectangles.Add(
|
||||
new Rectangle(placement.X, placement.Y, rectangleWidth, rectangleHeight)
|
||||
);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Optimizes the rectangle's placement by moving it either left or up to fill
|
||||
/// any gaps resulting from rectangles blocking the anchors of the most optimal
|
||||
/// placements.
|
||||
/// </summary>
|
||||
/// <param name="placement">Placement to be optimized</param>
|
||||
/// <param name="rectangleWidth">Width of the rectangle to be optimized</param>
|
||||
/// <param name="rectangleHeight">Height of the rectangle to be optimized</param>
|
||||
private void optimizePlacement(
|
||||
ref Point placement, int rectangleWidth, int rectangleHeight
|
||||
) {
|
||||
Rectangle rectangle = new Rectangle(
|
||||
placement.X, placement.Y, rectangleWidth, rectangleHeight
|
||||
);
|
||||
|
||||
// Try to move the rectangle to the left as far as possible
|
||||
int leftMost = placement.X;
|
||||
while(isFree(ref rectangle, PackingAreaWidth, PackingAreaHeight)) {
|
||||
leftMost = rectangle.X;
|
||||
--rectangle.X;
|
||||
}
|
||||
|
||||
// Reset rectangle to original position
|
||||
rectangle.X = placement.X;
|
||||
|
||||
// Try to move the rectangle upwards as far as possible
|
||||
int topMost = placement.Y;
|
||||
while(isFree(ref rectangle, PackingAreaWidth, PackingAreaHeight)) {
|
||||
topMost = rectangle.Y;
|
||||
--rectangle.Y;
|
||||
}
|
||||
|
||||
// Use the dimension in which the rectangle could be moved farther
|
||||
if((leftMost - placement.X) > (topMost - placement.Y))
|
||||
placement.X = leftMost;
|
||||
else
|
||||
placement.Y = topMost;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches for a free anchor and recursively enlarges the packing area
|
||||
/// if none can be found.
|
||||
/// </summary>
|
||||
/// <param name="rectangleWidth">Width of the rectangle to be placed</param>
|
||||
/// <param name="rectangleHeight">Height of the rectangle to be placed</param>
|
||||
/// <param name="testedPackingAreaWidth">Width of the tested packing area</param>
|
||||
/// <param name="testedPackingAreaHeight">Height of the tested packing area</param>
|
||||
/// <returns>
|
||||
/// Index of the anchor the rectangle is to be placed at or -1 if the rectangle
|
||||
/// does not fit in the packing area anymore.
|
||||
/// </returns>
|
||||
private int selectAnchorRecursive(
|
||||
int rectangleWidth, int rectangleHeight,
|
||||
int testedPackingAreaWidth, int testedPackingAreaHeight
|
||||
) {
|
||||
|
||||
// Try to locate an anchor point where the rectangle fits in
|
||||
int freeAnchorIndex = findFirstFreeAnchor(
|
||||
rectangleWidth, rectangleHeight, testedPackingAreaWidth, testedPackingAreaHeight
|
||||
);
|
||||
|
||||
// If a the rectangle fits without resizing packing area (any further in case
|
||||
// of a recursive call), take over the new packing area size and return the
|
||||
// anchor at which the rectangle can be placed.
|
||||
if(freeAnchorIndex != -1) {
|
||||
this.actualPackingAreaWidth = testedPackingAreaWidth;
|
||||
this.actualPackingAreaHeight = testedPackingAreaHeight;
|
||||
|
||||
return freeAnchorIndex;
|
||||
}
|
||||
|
||||
//
|
||||
// If we reach this point, the rectangle did not fit in the current packing
|
||||
// area and our only choice is to try and enlarge the packing area.
|
||||
//
|
||||
|
||||
// For readability, determine whether the packing area can be enlarged
|
||||
// any further in its width and in its height
|
||||
bool canEnlargeWidth = (testedPackingAreaWidth < PackingAreaWidth);
|
||||
bool canEnlargeHeight = (testedPackingAreaHeight < PackingAreaHeight);
|
||||
|
||||
// Try to enlarge the smaller of the two dimensions first (unless the smaller
|
||||
// dimension is already at its maximum size)
|
||||
if(
|
||||
canEnlargeHeight && (
|
||||
(testedPackingAreaHeight < testedPackingAreaWidth) || !canEnlargeWidth
|
||||
)
|
||||
) {
|
||||
|
||||
// Try to double the height of the packing area
|
||||
return selectAnchorRecursive(
|
||||
rectangleWidth, rectangleHeight,
|
||||
testedPackingAreaWidth, Math.Min(testedPackingAreaHeight * 2, PackingAreaHeight)
|
||||
);
|
||||
|
||||
} else if(canEnlargeWidth) {
|
||||
|
||||
// Try to double the width of the packing area
|
||||
return selectAnchorRecursive(
|
||||
rectangleWidth, rectangleHeight,
|
||||
Math.Min(testedPackingAreaWidth * 2, PackingAreaWidth), testedPackingAreaHeight
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
// Both dimensions are at the maximum sizes and the rectangle still
|
||||
// didn't fit. We give up!
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Locates the first free anchor at which the rectangle fits</summary>
|
||||
/// <param name="rectangleWidth">Width of the rectangle to be placed</param>
|
||||
/// <param name="rectangleHeight">Height of the rectangle to be placed</param>
|
||||
/// <param name="testedPackingAreaWidth">Total width of the packing area</param>
|
||||
/// <param name="testedPackingAreaHeight">Total height of the packing area</param>
|
||||
/// <returns>The index of the first free anchor or -1 if none is found</returns>
|
||||
private int findFirstFreeAnchor(
|
||||
int rectangleWidth, int rectangleHeight,
|
||||
int testedPackingAreaWidth, int testedPackingAreaHeight
|
||||
) {
|
||||
Rectangle potentialLocation = new Rectangle(
|
||||
0, 0, rectangleWidth, rectangleHeight
|
||||
);
|
||||
|
||||
// Walk over all anchors (which are ordered by their distance to the
|
||||
// upper left corner of the packing area) until one is discovered that
|
||||
// can house the new rectangle.
|
||||
for(int index = 0; index < this.anchors.Count; ++index) {
|
||||
potentialLocation.X = this.anchors[index].X;
|
||||
potentialLocation.Y = this.anchors[index].Y;
|
||||
|
||||
// See if the rectangle would fit in at this anchor point
|
||||
if(isFree(ref potentialLocation, testedPackingAreaWidth, testedPackingAreaHeight))
|
||||
return index;
|
||||
}
|
||||
|
||||
// No anchor points were found where the rectangle would fit in
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the rectangle can be placed in the packing area
|
||||
/// at its current location.
|
||||
/// </summary>
|
||||
/// <param name="rectangle">Rectangle whose position to check</param>
|
||||
/// <param name="testedPackingAreaWidth">Total width of the packing area</param>
|
||||
/// <param name="testedPackingAreaHeight">Total height of the packing area</param>
|
||||
/// <returns>True if the rectangle can be placed at its current position</returns>
|
||||
private bool isFree(
|
||||
ref Rectangle rectangle, int testedPackingAreaWidth, int testedPackingAreaHeight
|
||||
) {
|
||||
|
||||
// If the rectangle is partially or completely outside of the packing
|
||||
// area, it can't be placed at its current location
|
||||
bool leavesPackingArea =
|
||||
(rectangle.X < 0) ||
|
||||
(rectangle.Y < 0) ||
|
||||
(rectangle.Right >= testedPackingAreaWidth) ||
|
||||
(rectangle.Bottom >= testedPackingAreaHeight);
|
||||
|
||||
if(leavesPackingArea)
|
||||
return false;
|
||||
|
||||
// Brute-force search whether the rectangle touches any of the other
|
||||
// rectangles already in the packing area
|
||||
for(int index = 0; index < this.packedRectangles.Count; ++index) {
|
||||
|
||||
if(this.packedRectangles[index].Intersects(rectangle))
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Success! The rectangle is inside the packing area and doesn't overlap
|
||||
// with any other rectangles that have already been packed.
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Inserts a new anchor point into the anchor list</summary>
|
||||
/// <param name="anchor">Anchor point that will be inserted</param>
|
||||
/// <remarks>
|
||||
/// This method tries to keep the anchor list ordered by ranking the anchors
|
||||
/// depending on the distance from the top left corner in the packing area.
|
||||
/// </remarks>
|
||||
private void insertAnchor(ref Point anchor) {
|
||||
|
||||
// Find out where to insert the new anchor based on its rank (which is
|
||||
// calculated based on the anchor's distance to the top left corner of
|
||||
// the packing area).
|
||||
//
|
||||
// From MSDN on BinarySearch():
|
||||
// "If the List does not contain the specified value, the method returns
|
||||
// a negative integer. You can apply the bitwise complement operation (~) to
|
||||
// this negative integer to get the index of the first element that is
|
||||
// larger than the search value."
|
||||
int insertIndex = this.anchors.BinarySearch(anchor, AnchorRankComparer.Default);
|
||||
if(insertIndex < 0)
|
||||
insertIndex = ~insertIndex;
|
||||
|
||||
// Insert the anchor at the index matching its rank
|
||||
this.anchors.Insert(insertIndex, anchor);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Current width of the packing area</summary>
|
||||
private int actualPackingAreaWidth;
|
||||
/// <summary>Current height of the packing area</summary>
|
||||
private int actualPackingAreaHeight;
|
||||
/// <summary>Rectangles contained in the packing area</summary>
|
||||
private List<Rectangle> packedRectangles;
|
||||
/// <summary>Anchoring points where new rectangles can potentially be placed</summary>
|
||||
private List<Point> anchors;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Packing
|
|
@ -1,60 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Nuclex.Support.Packing {
|
||||
|
||||
/// <summary>Unit test for the cygon rectangle packer class</summary>
|
||||
[TestFixture]
|
||||
public class CygonRectanglePackerTest : RectanglePackerTest {
|
||||
|
||||
/// <summary>Tests the packer's efficiency using a deterministic benchmark</summary>
|
||||
[Test]
|
||||
public void TestSpaceEfficiency() {
|
||||
float efficiency = CalculateEfficiency(new CygonRectanglePacker(70, 70));
|
||||
|
||||
Assert.GreaterOrEqual(efficiency, 0.75f, "Packer achieves 75% efficiency");
|
||||
}
|
||||
|
||||
/// <summary>Tests the packer's stability by running a complete benchmark</summary>
|
||||
[Test]
|
||||
public void TestStability() {
|
||||
float score = Benchmark(
|
||||
delegate() { return new CygonRectanglePacker(1024, 1024); }
|
||||
);
|
||||
|
||||
// This is mainly a stability and performance test. It fails when the
|
||||
// packer crashes on its own and is otherwise only there to tell how long
|
||||
// it takes to complete the benchmark.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Packing
|
||||
|
||||
#endif // UNITTEST
|
|
@ -1,283 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Nuclex.Support.Packing {
|
||||
|
||||
/// <summary>Packer using a custom algorithm by Markus 'Cygon' Ewald</summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Algorithm conceived by Markus Ewald (cygon at nuclex dot org), though
|
||||
/// I'm quite sure I'm not the first one to come up with it :)
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The algorithm always places rectangles as low as possible in the packing
|
||||
/// area. So, for any new rectangle that is to be added, the packer has to
|
||||
/// determine the X coordinate at which the rectangle can have the lowest
|
||||
/// overall height without intersecting any other rectangles.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// To quickly discover these locations, the packer uses a sophisticated
|
||||
/// data structure that stores the upper silhouette of the packing area. When
|
||||
/// a new rectangle needs to be added, only the silouette edges need to be
|
||||
/// analyzed to find the position where the rectangle would achieve the lowest
|
||||
/// placement possible in the packing area.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public class CygonRectanglePacker : RectanglePacker {
|
||||
|
||||
#region class SliceStartComparer
|
||||
|
||||
/// <summary>Compares the starting position of height slices</summary>
|
||||
private class SliceStartComparer : IComparer<Point> {
|
||||
|
||||
/// <summary>Provides a default instance for the anchor rank comparer</summary>
|
||||
public static SliceStartComparer Default = new SliceStartComparer();
|
||||
|
||||
/// <summary>Compares the starting position of two height slices</summary>
|
||||
/// <param name="left">Left slice start that will be compared</param>
|
||||
/// <param name="right">Right slice start that will be compared</param>
|
||||
/// <returns>The relation of the two slice starts ranks to each other</returns>
|
||||
public int Compare(Point left, Point right) {
|
||||
return left.X - right.X;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>Initializes a new rectangle packer</summary>
|
||||
/// <param name="packingAreaWidth">Maximum width of the packing area</param>
|
||||
/// <param name="packingAreaHeight">Maximum height of the packing area</param>
|
||||
public CygonRectanglePacker(int packingAreaWidth, int packingAreaHeight)
|
||||
: base(packingAreaWidth, packingAreaHeight) {
|
||||
|
||||
this.heightSlices = new List<Point>();
|
||||
|
||||
// At the beginning, the packing area is a single slice of height 0
|
||||
this.heightSlices.Add(new Point(0, 0));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Tries to allocate space for a rectangle in the packing area</summary>
|
||||
/// <param name="rectangleWidth">Width of the rectangle to allocate</param>
|
||||
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
||||
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
||||
/// <returns>True if space for the rectangle could be allocated</returns>
|
||||
public override bool TryPack(
|
||||
int rectangleWidth, int rectangleHeight, out Point placement
|
||||
) {
|
||||
// If the rectangle is larger than the packing area in any dimension,
|
||||
// it will never fit!
|
||||
if(
|
||||
(rectangleWidth > PackingAreaWidth) || (rectangleHeight > PackingAreaHeight)
|
||||
) {
|
||||
placement = Point.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine the placement for the new rectangle
|
||||
bool fits = tryFindBestPlacement(rectangleWidth, rectangleHeight, out placement);
|
||||
|
||||
// If a place for the rectangle could be found, update the height slice table to
|
||||
// mark the region of the rectangle as being taken.
|
||||
if(fits)
|
||||
integrateRectangle(placement.X, rectangleWidth, placement.Y + rectangleHeight);
|
||||
|
||||
return fits;
|
||||
}
|
||||
|
||||
/// <summary>Finds the best position for a rectangle of the given dimensions</summary>
|
||||
/// <param name="rectangleWidth">Width of the rectangle to find a position for</param>
|
||||
/// <param name="rectangleHeight">Height of the rectangle to find a position for</param>
|
||||
/// <param name="placement">Receives the best placement found for the rectangle</param>
|
||||
/// <returns>True if a valid placement for the rectangle could be found</returns>
|
||||
private bool tryFindBestPlacement(
|
||||
int rectangleWidth, int rectangleHeight, out Point placement
|
||||
) {
|
||||
|
||||
// Slice index, vertical position and score of the best placement we could find
|
||||
int bestSliceIndex = -1; // Slice index where the best placement was found
|
||||
int bestSliceY = 0; // Y position of the best placement found
|
||||
int bestScore = PackingAreaWidth * PackingAreaHeight; // lower == better!
|
||||
|
||||
// This is the counter for the currently checked position. The search works by
|
||||
// skipping from slice to slice, determining the suitability of the location for the
|
||||
// placement of the rectangle.
|
||||
int leftSliceIndex = 0;
|
||||
|
||||
// Determine the slice in which the right end of the rectangle is located
|
||||
int rightSliceIndex = this.heightSlices.BinarySearch(
|
||||
new Point(rectangleWidth, 0), SliceStartComparer.Default
|
||||
);
|
||||
if(rightSliceIndex < 0)
|
||||
rightSliceIndex = ~rightSliceIndex;
|
||||
|
||||
while(rightSliceIndex <= this.heightSlices.Count) {
|
||||
|
||||
// Determine the highest slice within the slices covered by the rectangle at
|
||||
// its current placement. We cannot put the rectangle any lower than this without
|
||||
// overlapping the other rectangles.
|
||||
int highest = this.heightSlices[leftSliceIndex].Y;
|
||||
for(int index = leftSliceIndex + 1; index < rightSliceIndex; ++index)
|
||||
if(this.heightSlices[index].Y > highest)
|
||||
highest = this.heightSlices[index].Y;
|
||||
|
||||
// Only process this position if it doesn't leave the packing area
|
||||
if((highest + rectangleHeight < PackingAreaHeight)) {
|
||||
int score = highest;
|
||||
|
||||
if(score < bestScore) {
|
||||
bestSliceIndex = leftSliceIndex;
|
||||
bestSliceY = highest;
|
||||
bestScore = score;
|
||||
}
|
||||
}
|
||||
|
||||
// Advance the starting slice to the next slice start
|
||||
++leftSliceIndex;
|
||||
if(leftSliceIndex >= this.heightSlices.Count)
|
||||
break;
|
||||
|
||||
// Advance the ending slice until we're on the proper slice again, given the new
|
||||
// starting position of the rectangle.
|
||||
int rightRectangleEnd = this.heightSlices[leftSliceIndex].X + rectangleWidth;
|
||||
for(; rightSliceIndex <= this.heightSlices.Count; ++rightSliceIndex) {
|
||||
int rightSliceStart;
|
||||
if(rightSliceIndex == this.heightSlices.Count)
|
||||
rightSliceStart = PackingAreaWidth;
|
||||
else
|
||||
rightSliceStart = this.heightSlices[rightSliceIndex].X;
|
||||
|
||||
// Is this the slice we're looking for?
|
||||
if(rightSliceStart > rightRectangleEnd)
|
||||
break;
|
||||
}
|
||||
|
||||
// If we crossed the end of the slice array, the rectangle's right end has left
|
||||
// the packing area, and thus, our search ends.
|
||||
if(rightSliceIndex > this.heightSlices.Count)
|
||||
break;
|
||||
|
||||
} // while rightSliceIndex <= this.heightSlices.Count
|
||||
|
||||
// Return the best placement we found for this rectangle. If the rectangle
|
||||
// didn't fit anywhere, the slice index will still have its initialization value
|
||||
// of -1 and we can report that no placement could be found.
|
||||
if(bestSliceIndex == -1) {
|
||||
placement = Point.Zero;
|
||||
return false;
|
||||
} else {
|
||||
placement = new Point(this.heightSlices[bestSliceIndex].X, bestSliceY);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Integrates a new rectangle into the height slice table</summary>
|
||||
/// <param name="left">Position of the rectangle's left side</param>
|
||||
/// <param name="width">Width of the rectangle</param>
|
||||
/// <param name="bottom">Position of the rectangle's lower side</param>
|
||||
private void integrateRectangle(int left, int width, int bottom) {
|
||||
|
||||
// Find the first slice that is touched by the rectangle
|
||||
int startSlice = this.heightSlices.BinarySearch(
|
||||
new Point(left, 0), SliceStartComparer.Default
|
||||
);
|
||||
int firstSliceOriginalHeight;
|
||||
|
||||
// Did we score a direct hit on an existing slice start?
|
||||
if(startSlice >= 0) {
|
||||
|
||||
// We scored a direct hit, so we can replace the slice we have hit
|
||||
firstSliceOriginalHeight = this.heightSlices[startSlice].Y;
|
||||
this.heightSlices[startSlice] = new Point(left, bottom);
|
||||
|
||||
} else { // No direct hit, slice starts inside another slice
|
||||
|
||||
// Add a new slice after the slice in which we start
|
||||
startSlice = ~startSlice;
|
||||
firstSliceOriginalHeight = this.heightSlices[startSlice - 1].Y;
|
||||
this.heightSlices.Insert(startSlice, new Point(left, bottom));
|
||||
|
||||
}
|
||||
|
||||
int right = left + width;
|
||||
++startSlice;
|
||||
|
||||
// Special case, the rectangle started on the last slice, so we cannot
|
||||
// use the start slice + 1 for the binary search and the possibly already
|
||||
// modified start slice height now only remains in our temporary
|
||||
// firstSliceOriginalHeight variable
|
||||
if(startSlice >= this.heightSlices.Count) {
|
||||
|
||||
// If the slice ends within the last slice (usual case, unless it has the
|
||||
// exact same width the packing area has), add another slice to return to
|
||||
// the original height at the end of the rectangle.
|
||||
if(right < PackingAreaWidth)
|
||||
this.heightSlices.Add(new Point(right, firstSliceOriginalHeight));
|
||||
|
||||
} else { // The rectangle doesn't start on the last slice
|
||||
|
||||
int endSlice = this.heightSlices.BinarySearch(
|
||||
startSlice, this.heightSlices.Count - startSlice,
|
||||
new Point(right, 0), SliceStartComparer.Default
|
||||
);
|
||||
|
||||
// Another direct hit on the final slice's end?
|
||||
if(endSlice > 0) {
|
||||
|
||||
this.heightSlices.RemoveRange(startSlice, endSlice - startSlice);
|
||||
|
||||
} else { // No direct hit, rectangle ends inside another slice
|
||||
|
||||
// Make index from negative BinarySearch() result
|
||||
endSlice = ~endSlice;
|
||||
|
||||
// Find out to which height we need to return at the right end of
|
||||
// the rectangle
|
||||
int returnHeight;
|
||||
if(endSlice == startSlice)
|
||||
returnHeight = firstSliceOriginalHeight;
|
||||
else
|
||||
returnHeight = this.heightSlices[endSlice - 1].Y;
|
||||
|
||||
// Remove all slices covered by the rectangle and begin a new slice at its end
|
||||
// to return back to the height of the slice on which the rectangle ends.
|
||||
this.heightSlices.RemoveRange(startSlice, endSlice - startSlice);
|
||||
if(right < PackingAreaWidth)
|
||||
this.heightSlices.Insert(startSlice, new Point(right, returnHeight));
|
||||
|
||||
} // if endSlice > 0
|
||||
|
||||
} // if startSlice >= this.heightSlices.Count
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Stores the height silhouette of the rectangles</summary>
|
||||
private List<Point> heightSlices;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Packing
|
|
@ -1,58 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nuclex.Support.Packing {
|
||||
|
||||
/// <summary>Insufficient space left in packing area to contain a given object</summary>
|
||||
/// <remarks>
|
||||
/// An exception being sent to you from deep space. Erm, no, wait, it's an exception
|
||||
/// that occurs when a packing algorithm runs out of space and is unable to fit
|
||||
/// the object you tried to pack into the remaining packing area.
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
public class OutOfSpaceException : Exception {
|
||||
|
||||
/// <summary>Initializes the exception</summary>
|
||||
public OutOfSpaceException() { }
|
||||
|
||||
/// <summary>Initializes the exception with an error message</summary>
|
||||
/// <param name="message">Error message describing the cause of the exception</param>
|
||||
public OutOfSpaceException(string message) : base(message) { }
|
||||
|
||||
/// <summary>Initializes the exception as a followup exception</summary>
|
||||
/// <param name="message">Error message describing the cause of the exception</param>
|
||||
/// <param name="inner">Preceding exception that has caused this exception</param>
|
||||
public OutOfSpaceException(string message, Exception inner) : base(message, inner) { }
|
||||
|
||||
/// <summary>Initializes the exception from its serialized state</summary>
|
||||
/// <param name="info">Contains the serialized fields of the exception</param>
|
||||
/// <param name="context">Additional environmental informations</param>
|
||||
protected OutOfSpaceException(
|
||||
System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context
|
||||
)
|
||||
: base(info, context) { }
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Packing
|
|
@ -1,102 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Nuclex.Support.Packing {
|
||||
|
||||
/// <summary>Base class for unit testing the rectangle packers</summary>
|
||||
public abstract class RectanglePackerTest {
|
||||
|
||||
/// <summary>Delegate for a Rectangle Packer factory method</summary>
|
||||
/// <returns>A new rectangle packer</returns>
|
||||
protected delegate RectanglePacker RectanglePackerBuilder();
|
||||
|
||||
/// <summary>Determines the efficiency of a packer with a packing area of 70x70</summary>
|
||||
/// <param name="packer">Packer with a packing area of 70x70 units</param>
|
||||
/// <returns>The efficiency factor of the packer</returns>
|
||||
/// <remarks>
|
||||
/// A perfect packer would achieve an efficiency rating of 1.0. This is
|
||||
/// impossible however since the 24 squares cannot all be packed into
|
||||
/// the 70x70 square with no overlap (Bitner & Reingold 1975). The closer
|
||||
/// the efficiency rating is to 1.0, the better, with 0.99 being the
|
||||
/// mathematically best rating achievable.
|
||||
/// </remarks>
|
||||
protected float CalculateEfficiency(RectanglePacker packer) {
|
||||
// If we take a 1x1 square, a 2x2 square, etc. up to a 24x24 square,
|
||||
// the sum of the areas of these squares is 4900, which is 70². This
|
||||
// is the only nontrivial sum of consecutive squares starting with
|
||||
// one which is a perfect square (Watson 1918).
|
||||
int areaCovered = 0;
|
||||
|
||||
for(int size = 24; size >= 1; --size) {
|
||||
Point placement;
|
||||
|
||||
if(packer.TryPack(size, size, out placement))
|
||||
areaCovered += size * size;
|
||||
}
|
||||
|
||||
return (float)areaCovered / 4900.0f;
|
||||
}
|
||||
|
||||
/// <summary>Benchmarks the provided rectangle packer using random data</summary>
|
||||
/// <param name="buildPacker">
|
||||
/// Rectangle packer build method returning new rectangle packers
|
||||
/// with an area of 1024 x 1024
|
||||
/// </param>
|
||||
/// <returns>The achieved benchmark score</returns>
|
||||
protected float Benchmark(RectanglePackerBuilder buildPacker) {
|
||||
// How many runs to perform for getting a stable average
|
||||
const int averagingRuns = 1;
|
||||
|
||||
// Generates the random number seeds. This is used so that each run produces
|
||||
// the same number sequences and makes the comparison of different algorithms
|
||||
// a little bit more stable.
|
||||
Random seedGenerator = new Random(12345);
|
||||
int rectanglesPacked = 0;
|
||||
|
||||
// Perform a number of runs to get a semi-stable average score
|
||||
for(int averagingRun = 0; averagingRun < averagingRuns; ++averagingRun) {
|
||||
Random dimensionGenerator = new Random(seedGenerator.Next());
|
||||
RectanglePacker packer = buildPacker();
|
||||
|
||||
// Try to cramp as many rectangles into the packing area as possible
|
||||
for(; ; ++rectanglesPacked) {
|
||||
Point placement;
|
||||
|
||||
int width = dimensionGenerator.Next(16, 64);
|
||||
int height = dimensionGenerator.Next(16, 64);
|
||||
|
||||
// As soon as the packer rejects the first rectangle, the run is over
|
||||
if(!packer.TryPack(width, height, out placement))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the average score achieved by the packer
|
||||
return (float)rectanglesPacked / (float)averagingRuns;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Packing
|
|
@ -1,89 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Nuclex.Support.Packing {
|
||||
|
||||
/// <summary>Base class for rectangle packing algorithms</summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// By uniting all rectangle packers under this common base class, you can
|
||||
/// easily switch between different algorithms to find the most efficient or
|
||||
/// performant one for a given job.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// An almost exhaustive list of packing algorithms can be found here:
|
||||
/// http://www.csc.liv.ac.uk/~epa/surveyhtml.html
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public abstract class RectanglePacker {
|
||||
|
||||
/// <summary>Initializes a new rectangle packer</summary>
|
||||
/// <param name="packingAreaWidth">Width of the packing area</param>
|
||||
/// <param name="packingAreaHeight">Height of the packing area</param>
|
||||
protected RectanglePacker(int packingAreaWidth, int packingAreaHeight) {
|
||||
this.packingAreaWidth = packingAreaWidth;
|
||||
this.packingAreaHeight = packingAreaHeight;
|
||||
}
|
||||
|
||||
/// <summary>Allocates space for a rectangle in the packing area</summary>
|
||||
/// <param name="rectangleWidth">Width of the rectangle to allocate</param>
|
||||
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
||||
/// <returns>The location at which the rectangle has been placed</returns>
|
||||
public virtual Point Pack(int rectangleWidth, int rectangleHeight) {
|
||||
Point point;
|
||||
|
||||
if(!TryPack(rectangleWidth, rectangleHeight, out point))
|
||||
throw new OutOfSpaceException("Rectangle does not fit in packing area");
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
/// <summary>Tries to allocate space for a rectangle in the packing area</summary>
|
||||
/// <param name="rectangleWidth">Width of the rectangle to allocate</param>
|
||||
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
||||
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
||||
/// <returns>True if space for the rectangle could be allocated</returns>
|
||||
public abstract bool TryPack(
|
||||
int rectangleWidth, int rectangleHeight, out Point placement
|
||||
);
|
||||
|
||||
/// <summary>Maximum width the packing area is allowed to have</summary>
|
||||
protected int PackingAreaWidth {
|
||||
get { return this.packingAreaWidth; }
|
||||
}
|
||||
|
||||
/// <summary>Maximum height the packing area is allowed to have</summary>
|
||||
protected int PackingAreaHeight {
|
||||
get { return this.packingAreaHeight; }
|
||||
}
|
||||
|
||||
/// <summary>Maximum allowed width of the packing area</summary>
|
||||
private int packingAreaWidth;
|
||||
/// <summary>Maximum allowed height of the packing area</summary>
|
||||
private int packingAreaHeight;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Packing
|
|
@ -1,60 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Nuclex.Support.Packing {
|
||||
|
||||
/// <summary>Unit test for the simple rectangle packer class</summary>
|
||||
[TestFixture]
|
||||
public class SimpleRectanglePackerTest : RectanglePackerTest {
|
||||
|
||||
/// <summary>Tests the packer's efficiency using a deterministic benchmark</summary>
|
||||
[Test]
|
||||
public void TestSpaceEfficiency() {
|
||||
float efficiency = CalculateEfficiency(new SimpleRectanglePacker(70, 70));
|
||||
|
||||
Assert.GreaterOrEqual(efficiency, 0.75f, "Packer achieves 75% efficiency");
|
||||
}
|
||||
|
||||
/// <summary>Tests the packer's stability by running a complete benchmark</summary>
|
||||
[Test]
|
||||
public void TestStability() {
|
||||
float score = Benchmark(
|
||||
delegate() { return new SimpleRectanglePacker(1024, 1024); }
|
||||
);
|
||||
|
||||
// This is mainly a stability and performance test. It fails when the
|
||||
// packer crashes on its own and is otherwise only there to tell how long
|
||||
// it takes to complete the benchmark.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Packing
|
||||
|
||||
#endif // UNITTEST
|
|
@ -1,94 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Nuclex.Support.Packing {
|
||||
|
||||
/// <summary>Simplified packer for rectangles which don't vary greatly in size</summary>
|
||||
/// <remarks>
|
||||
/// This is a highly performant packer that sacrifices space efficiency for
|
||||
/// low memory usage and runtime performance. It achieves good results with
|
||||
/// near-uniform sized rectangles but will waste lots of space with rectangles
|
||||
/// of varying dimensions.
|
||||
/// </remarks>
|
||||
public class SimpleRectanglePacker : RectanglePacker {
|
||||
|
||||
/// <summary>Initializes a new rectangle packer</summary>
|
||||
/// <param name="packingAreaWidth">Maximum width of the packing area</param>
|
||||
/// <param name="packingAreaHeight">Maximum height of the packing area</param>
|
||||
public SimpleRectanglePacker(int packingAreaWidth, int packingAreaHeight)
|
||||
: base(packingAreaWidth, packingAreaHeight) { }
|
||||
|
||||
/// <summary>Tries to allocate space for a rectangle in the packing area</summary>
|
||||
/// <param name="rectangleWidth">Width of the rectangle to allocate</param>
|
||||
/// <param name="rectangleHeight">Height of the rectangle to allocate</param>
|
||||
/// <param name="placement">Output parameter receiving the rectangle's placement</param>
|
||||
/// <returns>True if space for the rectangle could be allocated</returns>
|
||||
public override bool TryPack(
|
||||
int rectangleWidth, int rectangleHeight, out Point placement
|
||||
) {
|
||||
|
||||
// If the rectangle is larger than the packing area in any dimension,
|
||||
// it will never fit!
|
||||
if(
|
||||
(rectangleWidth > PackingAreaWidth) || (rectangleHeight > PackingAreaHeight)
|
||||
) {
|
||||
placement = Point.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do we have to start a new line ?
|
||||
if(this.column + rectangleWidth > PackingAreaWidth) {
|
||||
this.currentLine += this.lineHeight;
|
||||
this.lineHeight = 0;
|
||||
this.column = 0;
|
||||
}
|
||||
|
||||
// If it doesn't fit vertically now, the packing area is considered full
|
||||
if(this.currentLine + rectangleHeight > PackingAreaHeight) {
|
||||
placement = Point.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
// The rectangle appears to fit at the current location
|
||||
placement = new Point(this.column, this.currentLine);
|
||||
|
||||
this.column += rectangleWidth; // Can be larger than cache width till next run
|
||||
if(rectangleHeight > this.lineHeight)
|
||||
this.lineHeight = rectangleHeight;
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Current packing line</summary>
|
||||
private int currentLine;
|
||||
/// <summary>Height of the current packing line</summary>
|
||||
private int lineHeight;
|
||||
/// <summary>Current column in the current packing line</summary>
|
||||
private int column;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Packing
|
|
@ -29,7 +29,7 @@ namespace Nuclex.Support.Scheduling {
|
|||
/// background process.
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
public class AbortedException : ApplicationException {
|
||||
public class AbortedException : Exception {
|
||||
|
||||
/// <summary>Initializes the exception</summary>
|
||||
public AbortedException() { }
|
||||
|
|
|
@ -1,82 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
#if UNITTEST
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Nuclex.Support.Serialization {
|
||||
|
||||
/// <summary>Ensures that the binary serializer is working correctly</summary>
|
||||
[TestFixture]
|
||||
public class BinarySerializerTest {
|
||||
|
||||
private class TestSerializable : IBinarySerializable {
|
||||
public void Load(BinaryReader reader) { this.Dummy = reader.ReadInt32(); }
|
||||
public void Save(BinaryWriter writer) { writer.Write(this.Dummy); }
|
||||
public int Dummy;
|
||||
}
|
||||
|
||||
/// <summary>Prepares some test data for the unit test methods</summary>
|
||||
[TestFixtureSetUp]
|
||||
public void Setup() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests wether a simple collection can be successfully saved and loaded again
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestSimpleCollection() {
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
|
||||
// Fill and save
|
||||
{
|
||||
List<TestSerializable> serializables = new List<TestSerializable>();
|
||||
|
||||
serializables.Add(new TestSerializable());
|
||||
serializables.Add(new TestSerializable());
|
||||
serializables[0].Dummy = 123;
|
||||
serializables[1].Dummy = 456;
|
||||
|
||||
BinarySerializer.Save(new BinaryWriter(buffer), serializables);
|
||||
buffer.Position = 0;
|
||||
}
|
||||
|
||||
// Load and validate
|
||||
{
|
||||
List<TestSerializable> serializables = new List<TestSerializable>();
|
||||
|
||||
BinarySerializer.Load(new BinaryReader(buffer), serializables);
|
||||
|
||||
Assert.AreEqual(2, serializables.Count);
|
||||
Assert.AreEqual(123, serializables[0].Dummy);
|
||||
Assert.AreEqual(456, serializables[1].Dummy);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Serialization
|
||||
|
||||
#endif // UNITTEST
|
|
@ -1,286 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Nuclex.Support.Serialization {
|
||||
|
||||
/// <summary>Utility class for serializating objects into binary data</summary>
|
||||
public static class BinarySerializer {
|
||||
|
||||
#region System.Collections.Generic.ICollection
|
||||
|
||||
/// <summary>Loads a collection from its serialized representation</summary>
|
||||
/// <param name="reader">Reader to use for reading the collection</param>
|
||||
/// <param name="collection">Collection to be deserialized into</param>
|
||||
public static void Load<BinarySerializableType>(
|
||||
BinaryReader reader, ICollection<BinarySerializableType> collection
|
||||
) where BinarySerializableType : IBinarySerializable {
|
||||
|
||||
// Read and verify the version of the file format this was saved in
|
||||
int version = reader.ReadInt32();
|
||||
if(version > 1)
|
||||
throw new InvalidOperationException("File format mismatch");
|
||||
|
||||
// Read all the serialized blueprints
|
||||
int count = reader.ReadInt32();
|
||||
for(int index = 0; index < count; ++index) {
|
||||
|
||||
// Try to create an instance from the serialized type name
|
||||
BinarySerializableType item = (BinarySerializableType)Activator.CreateInstance(
|
||||
Type.GetType(reader.ReadString())
|
||||
);
|
||||
|
||||
// Let the blueprint load its own data and add it to the collection
|
||||
(item as IBinarySerializable).Load(reader);
|
||||
collection.Add(item);
|
||||
|
||||
} // for
|
||||
|
||||
}
|
||||
|
||||
/// <summary>Serializes a collection of binary serializable objects</summary>
|
||||
/// <param name="writer">BinaryWriter to serialize the collection into</param>
|
||||
/// <param name="collection">Collection to be serialized</param>
|
||||
public static void Save<BinarySerializableType>(
|
||||
BinaryWriter writer, ICollection<BinarySerializableType> collection
|
||||
) where BinarySerializableType : IBinarySerializable {
|
||||
|
||||
// Save the file format version so the loading routine can detect
|
||||
// which version of the file format has to be loaded
|
||||
writer.Write((int)1);
|
||||
|
||||
// Serialize all the blueprints in the collection
|
||||
writer.Write((int)collection.Count);
|
||||
foreach(BinarySerializableType item in collection) {
|
||||
|
||||
// Save the type name of the object so we can recreate it later
|
||||
writer.Write(item.GetType().AssemblyQualifiedName);
|
||||
|
||||
// Let the object save its own data
|
||||
((IBinarySerializable)item).Save(writer);
|
||||
|
||||
} // foreach
|
||||
|
||||
}
|
||||
|
||||
#endregion // System.Collections.Generic.ICollection
|
||||
|
||||
#region Microsoft.Xna.Framework.Matrix
|
||||
|
||||
/// <summary>Loads a matrix from its serialized representation</summary>
|
||||
/// <param name="reader">Reader to use for reading the matrix</param>
|
||||
/// <param name="matrix">Matrix to be deserialized</param>
|
||||
public static void Load(BinaryReader reader, out Matrix matrix) {
|
||||
matrix.M11 = reader.ReadSingle();
|
||||
matrix.M12 = reader.ReadSingle();
|
||||
matrix.M13 = reader.ReadSingle();
|
||||
matrix.M14 = reader.ReadSingle();
|
||||
|
||||
matrix.M21 = reader.ReadSingle();
|
||||
matrix.M22 = reader.ReadSingle();
|
||||
matrix.M23 = reader.ReadSingle();
|
||||
matrix.M24 = reader.ReadSingle();
|
||||
|
||||
matrix.M31 = reader.ReadSingle();
|
||||
matrix.M32 = reader.ReadSingle();
|
||||
matrix.M33 = reader.ReadSingle();
|
||||
matrix.M34 = reader.ReadSingle();
|
||||
|
||||
matrix.M41 = reader.ReadSingle();
|
||||
matrix.M42 = reader.ReadSingle();
|
||||
matrix.M43 = reader.ReadSingle();
|
||||
matrix.M44 = reader.ReadSingle();
|
||||
}
|
||||
|
||||
/// <summary>Serializes a matrix into a binary data stream</summary>
|
||||
/// <param name="writer">BinaryWriter to serialize the matrix into</param>
|
||||
/// <param name="matrix">Matrix to be serialized</param>
|
||||
public static void Save(BinaryWriter writer, ref Matrix matrix) {
|
||||
writer.Write(matrix.M11);
|
||||
writer.Write(matrix.M12);
|
||||
writer.Write(matrix.M13);
|
||||
writer.Write(matrix.M14);
|
||||
|
||||
writer.Write(matrix.M21);
|
||||
writer.Write(matrix.M22);
|
||||
writer.Write(matrix.M23);
|
||||
writer.Write(matrix.M24);
|
||||
|
||||
writer.Write(matrix.M31);
|
||||
writer.Write(matrix.M32);
|
||||
writer.Write(matrix.M33);
|
||||
writer.Write(matrix.M34);
|
||||
|
||||
writer.Write(matrix.M41);
|
||||
writer.Write(matrix.M42);
|
||||
writer.Write(matrix.M43);
|
||||
writer.Write(matrix.M44);
|
||||
}
|
||||
|
||||
#endregion // Microsoft.Xna.Framework.Matrix
|
||||
|
||||
#region Microsoft.Xna.Framework.Vector2
|
||||
|
||||
/// <summary>Loads a vector from its serialized representation</summary>
|
||||
/// <param name="reader">Reader to use for reading the vector</param>
|
||||
/// <param name="vector">Vector to be deserialized</param>
|
||||
public static void Load(BinaryReader reader, out Vector2 vector) {
|
||||
vector.X = reader.ReadSingle();
|
||||
vector.Y = reader.ReadSingle();
|
||||
}
|
||||
|
||||
/// <summary>Serializes a vector into a binary data stream</summary>
|
||||
/// <param name="writer">BinaryWriter to serialize the vector into</param>
|
||||
/// <param name="vector">Vector to be serialized</param>
|
||||
public static void Save(BinaryWriter writer, ref Vector2 vector) {
|
||||
writer.Write(vector.X);
|
||||
writer.Write(vector.Y);
|
||||
}
|
||||
|
||||
#endregion // Microsoft.Xna.Framework.Vector2
|
||||
|
||||
#region Microsoft.Xna.Framework.Vector3
|
||||
|
||||
/// <summary>Loads a vector from its serialized representation</summary>
|
||||
/// <param name="reader">Reader to use for reading the vector</param>
|
||||
/// <param name="vector">Vector to be deserialized</param>
|
||||
public static void Load(BinaryReader reader, out Vector3 vector) {
|
||||
vector.X = reader.ReadSingle();
|
||||
vector.Y = reader.ReadSingle();
|
||||
vector.Z = reader.ReadSingle();
|
||||
}
|
||||
|
||||
/// <summary>Serializes a vector into a binary data stream</summary>
|
||||
/// <param name="writer">BinaryWriter to serialize the vector into</param>
|
||||
/// <param name="vector">Vector to be serialized</param>
|
||||
public static void Save(BinaryWriter writer, ref Vector3 vector) {
|
||||
writer.Write(vector.X);
|
||||
writer.Write(vector.Y);
|
||||
writer.Write(vector.Z);
|
||||
}
|
||||
|
||||
#endregion // Microsoft.Xna.Framework.Vector3
|
||||
|
||||
#region Microsoft.Xna.Framework.Vector4
|
||||
|
||||
/// <summary>Loads a vector from its serialized representation</summary>
|
||||
/// <param name="reader">Reader to use for reading the vector</param>
|
||||
/// <param name="vector">Vector to be deserialized</param>
|
||||
public static void Load(BinaryReader reader, out Vector4 vector) {
|
||||
vector.X = reader.ReadSingle();
|
||||
vector.Y = reader.ReadSingle();
|
||||
vector.Z = reader.ReadSingle();
|
||||
vector.W = reader.ReadSingle();
|
||||
}
|
||||
|
||||
/// <summary>Serializes a vector into a binary data stream</summary>
|
||||
/// <param name="writer">BinaryWriter to serialize the vector into</param>
|
||||
/// <param name="vector">Vector to be serialized</param>
|
||||
public static void Save(BinaryWriter writer, ref Vector4 vector) {
|
||||
writer.Write(vector.X);
|
||||
writer.Write(vector.Y);
|
||||
writer.Write(vector.Z);
|
||||
writer.Write(vector.W);
|
||||
}
|
||||
|
||||
#endregion // Microsoft.Xna.Framework.Vector4
|
||||
|
||||
#region Microsoft.Xna.Framework.Quaternion
|
||||
|
||||
/// <summary>Loads a quaternion from its serialized representation</summary>
|
||||
/// <param name="reader">Reader to use for reading the quaternion</param>
|
||||
/// <param name="quaternion">Quaternion to be deserialized</param>
|
||||
public static void Load(BinaryReader reader, out Quaternion quaternion) {
|
||||
quaternion.X = reader.ReadSingle();
|
||||
quaternion.Y = reader.ReadSingle();
|
||||
quaternion.Z = reader.ReadSingle();
|
||||
quaternion.W = reader.ReadSingle();
|
||||
}
|
||||
|
||||
/// <summary>Serializes a quaternion into a binary data stream</summary>
|
||||
/// <param name="writer">BinaryWriter to serialize the quaternion into</param>
|
||||
/// <param name="quaternion">Quaternion to be serialized</param>
|
||||
public static void Save(BinaryWriter writer, ref Quaternion quaternion) {
|
||||
writer.Write(quaternion.X);
|
||||
writer.Write(quaternion.Y);
|
||||
writer.Write(quaternion.Z);
|
||||
writer.Write(quaternion.W);
|
||||
}
|
||||
|
||||
#endregion // Microsoft.Xna.Framework.Quaternion
|
||||
|
||||
#region Microsoft.Xna.Framework.Curve
|
||||
|
||||
/// <summary>Loads a curve from its serialized representation</summary>
|
||||
/// <param name="reader">Reader to use for reading the curve</param>
|
||||
/// <param name="curve">Curve to be deserialized</param>
|
||||
public static void Load(BinaryReader reader, Curve curve) {
|
||||
curve.Keys.Clear();
|
||||
|
||||
// Load the curve's loop settings
|
||||
curve.PreLoop = (CurveLoopType)reader.ReadByte();
|
||||
curve.PostLoop = (CurveLoopType)reader.ReadByte();
|
||||
|
||||
// Load the key frames defined for the curve
|
||||
int keyCount = reader.ReadInt32();
|
||||
for(int keyIndex = 0; keyIndex < curve.Keys.Count; ++keyIndex) {
|
||||
float position = reader.ReadSingle();
|
||||
float value = reader.ReadSingle();
|
||||
float tangentIn = reader.ReadSingle();
|
||||
float tangentOut = reader.ReadSingle();
|
||||
CurveContinuity continuity = (CurveContinuity)reader.ReadByte();
|
||||
|
||||
curve.Keys.Add(new CurveKey(position, value, tangentIn, tangentOut, continuity));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Serializes a curve into a binary data stream</summary>
|
||||
/// <param name="writer">BinaryWriter to serialize the curve into</param>
|
||||
/// <param name="curve">Curve to be serialized</param>
|
||||
public static void Save(BinaryWriter writer, Curve curve) {
|
||||
|
||||
// Save the curve's loop settings
|
||||
writer.Write((byte)curve.PreLoop);
|
||||
writer.Write((byte)curve.PostLoop);
|
||||
|
||||
// Save the key frames contained in the curve
|
||||
writer.Write(curve.Keys.Count);
|
||||
for(int keyIndex = 0; keyIndex < curve.Keys.Count; ++keyIndex) {
|
||||
CurveKey key = curve.Keys[keyIndex];
|
||||
|
||||
writer.Write(key.Position);
|
||||
writer.Write(key.Value);
|
||||
writer.Write(key.TangentIn);
|
||||
writer.Write(key.TangentOut);
|
||||
writer.Write((byte)key.Continuity);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion // Microsoft.Xna.Framework.Curve
|
||||
|
||||
} // class BinarySerializer
|
||||
|
||||
} // namespace Nuclex.Support.Serialization
|
|
@ -1,47 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Nuclex.Support.Serialization {
|
||||
|
||||
/// <summary>Interface for objects able to serialize themselfes into a binary format</summary>
|
||||
/// <remarks>
|
||||
/// Sometimes, the limitations of XML serialization are too strict, especially
|
||||
/// in the context of a game where you might need to serialize larger chunks of
|
||||
/// binary data or in cases where you do not wish to expose a default constructor
|
||||
/// in your classes. This interface defines two simple methods that can be
|
||||
/// used to load and save an object's state in a simple manner.
|
||||
/// </remarks>
|
||||
public interface IBinarySerializable {
|
||||
|
||||
/// <summary>Loads the object's state from its serialized representation</summary>
|
||||
/// <param name="reader">Reader to use for reading the object's state</param>
|
||||
void Load(BinaryReader reader);
|
||||
|
||||
/// <summary>Saves the object's state into a serialized representation</summary>
|
||||
/// <param name="writer">Writer to use for writing the object's state</param>
|
||||
void Save(BinaryWriter writer);
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.Serialization
|
|
@ -1,78 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Nuclex.Support.SpatialPartitioning {
|
||||
|
||||
/// <summary>Two-dimensional bounding rectangle</summary>
|
||||
internal struct BoundingRectangle {
|
||||
|
||||
/// <summary>Initializes a new two-dimensional bounding rectangle</summary>
|
||||
/// <param name="min">Lesser coordinates of the bounding rectangle</param>
|
||||
/// <param name="max">Greater coordinates of the bounding rectangle</param>
|
||||
public BoundingRectangle(Vector2 min, Vector2 max) {
|
||||
this.Min = min;
|
||||
this.Max = max;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the smallest bounding rectangle that contains the two
|
||||
/// specified bounding rectangle.
|
||||
/// </summary>
|
||||
/// <param name="original">One of the bounding rectangles to contain</param>
|
||||
/// <param name="additional">One of the bounding rectangles to contain</param>
|
||||
/// <returns>The resulting merged bounding rectangle</returns>
|
||||
public static BoundingRectangle CreateMerged(
|
||||
BoundingRectangle original, BoundingRectangle additional
|
||||
) {
|
||||
BoundingRectangle result;
|
||||
CreateMerged(ref original, ref additional, out result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds the smallest bounding rectangle that contains the two
|
||||
/// specified bounding rectangle.
|
||||
/// </summary>
|
||||
/// <param name="original">One of the bounding rectangles to contain</param>
|
||||
/// <param name="additional">One of the bounding rectangles to contain</param>
|
||||
/// <param name="result">The resulting merged bounding rectangle</param>
|
||||
public static void CreateMerged(
|
||||
ref BoundingRectangle original, ref BoundingRectangle additional,
|
||||
out BoundingRectangle result
|
||||
) {
|
||||
result = new BoundingRectangle();
|
||||
result.Min = Vector2.Min(original.Min, additional.Min);
|
||||
result.Max = Vector2.Max(original.Max, additional.Max);
|
||||
}
|
||||
|
||||
/// <summary>Coordinates of the lesser side of the bounding rectangle</summary>
|
||||
public Vector2 Min;
|
||||
|
||||
/// <summary>Coordinates of the greater side of the bounding rectangle</summary>
|
||||
public Vector2 Max;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.SpatialPartitioning
|
|
@ -1,96 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Nuclex.Support.SpatialPartitioning {
|
||||
|
||||
/// <summary>R-Tree for two-dimensional data</summary>
|
||||
/// <remarks>
|
||||
/// R-Trees essentially fullfill the same role that is traditionally
|
||||
/// assigned to quadtrees in games. But unlike a quadtree, an R-Tree does not
|
||||
/// require knowledge of the total area that is to be covered by the objects
|
||||
/// that will populate the tree.
|
||||
/// </remarks>
|
||||
public partial class RTree2<ItemType> : SpatialIndex2 {
|
||||
|
||||
/// <summary>Variants of R-Tree behaviors this implementation can assume</summary>
|
||||
public enum Variants {
|
||||
|
||||
/// <summary>
|
||||
/// Insertions and deletions take linear time at the cost of degrading the
|
||||
/// tree's overall performance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Finds the two bounding boxes with the greatest normalized separation
|
||||
/// along both axes, and split along this axis. The remaining bounding boxes
|
||||
/// in the node are assigned to the nodes whose covering bounding box is
|
||||
/// increased the least by the addition [Gutt84]. This method takes linear time.
|
||||
/// </remarks>
|
||||
Linear,
|
||||
|
||||
/// <summary>
|
||||
/// Insertions and deletions take quadratic time while keeping the tree's
|
||||
/// overall performance at a reasonable level.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Examines all the children of the overflowing node and find the pair of
|
||||
/// bounding boxes that would waste the most area were they to be inserted
|
||||
/// in the same node. This is determined by subtracting the sum of the areas
|
||||
/// of the two bounding boxes from the area of the covering bounding box.
|
||||
/// These two bounding boxes are placed in separate nodes, say j and k.
|
||||
/// The set of remaining bounding boxes are examined and the bounding box i
|
||||
/// whose addition maximizes the difference in coverage between the bounding
|
||||
/// boxes associated with j and k is added to the node whose coverage
|
||||
/// is minimized by the addition. This process is reapplied to the
|
||||
/// remaining bounding boxes [Gutt84]. This method takes quadratic time.
|
||||
/// </remarks>
|
||||
Quadratic,
|
||||
|
||||
/// <summary>
|
||||
/// Insertions and deletions vary in performance but the tree's overall
|
||||
/// performance is kept high.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The R*-tree [Beck90c] is a name given to a variant of the R-tree which
|
||||
/// makes use of the most complex of the node splitting algorithms. The
|
||||
/// algorithm differs from the other algorithms as it attempts to reduce
|
||||
/// both overlap and coverage. In particular, the primary focus is on
|
||||
/// reducing overlap with ties broken by favoring the splits that reduce
|
||||
/// the coverage by using the splits that minimize the perimeter of the
|
||||
/// bounding boxes of the resulting nodes. In addition, when a node 'a'
|
||||
/// overflows, instead of immediately splitting 'a', an attempt is made
|
||||
/// first to see if some of the objects in 'a' could possibly be more suited
|
||||
/// to being in another node. This is achieved by reinserting a fraction
|
||||
/// (30% has been found to yield good performance [Beck90c]) of these
|
||||
/// objects in the tree (termed 'forced reinsertion'). The node is only split
|
||||
/// if it has been found to overflow after reinsertion has taken place.
|
||||
/// This method is quite complex.
|
||||
/// </remarks>
|
||||
RStar
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Geometry.SpatialPartitioning
|
|
@ -1,36 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Nuclex.Support.SpatialPartitioning {
|
||||
|
||||
/// <summary>Leaf of an R-Tree</summary>
|
||||
internal class RTreeLeaf2<ItemType> {
|
||||
|
||||
public BoundingRectangle BoundingRectangle;
|
||||
public ItemType Item;
|
||||
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.SpatialPartitioning
|
|
@ -1,67 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Nuclex.Support.SpatialPartitioning {
|
||||
|
||||
/// <summary>Node in a two-dimensional R-Tree</summary>
|
||||
/// <typeparam name="ItemType">Type of items that the R-Tree manages</typeparam>
|
||||
internal class RTreeNode2<ItemType> {
|
||||
|
||||
/// <summary>Initializes a new R-Tree node</summary>
|
||||
/// <param name="capacity">Number of items that can fit in the node</param>
|
||||
public RTreeNode2(int capacity) {
|
||||
this.leafs = new RTreeLeaf2<ItemType>[capacity];
|
||||
this.leafCount = 0;
|
||||
}
|
||||
|
||||
/// <summary>Inserts an item into this node</summary>
|
||||
/// <param name="item">Item to be inserted</param>
|
||||
/// <param name="boundingRectangle">Bounding rectangle of the item</param>
|
||||
private void insertEntry(ItemType item, BoundingRectangle boundingRectangle) {
|
||||
Debug.Assert(leafCount < this.leafs.Length);
|
||||
|
||||
this.leafs[this.leafCount].Item = item;
|
||||
this.leafs[this.leafCount].BoundingRectangle = boundingRectangle;
|
||||
|
||||
BoundingRectangle.CreateMerged(
|
||||
ref this.boundingRectangle, ref boundingRectangle,
|
||||
out this.boundingRectangle
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>The node's minimum bounding rectangle</summary>
|
||||
/// <remarks>
|
||||
/// This bounding rectangle is just large enough to contain all the items
|
||||
/// belonging to this node and recursively all of its child nodes.
|
||||
/// </remarks>
|
||||
private BoundingRectangle boundingRectangle;
|
||||
|
||||
/// <summary>Leafs of this node</summary>
|
||||
private RTreeLeaf2<ItemType>[] leafs;
|
||||
/// <summary>Number of leafes in use</summary>
|
||||
private int leafCount;
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.SpatialPartitioning
|
|
@ -1,31 +0,0 @@
|
|||
#region CPL License
|
||||
/*
|
||||
Nuclex Framework
|
||||
Copyright (C) 2002-2008 Nuclex Development Labs
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the IBM Common Public License as
|
||||
published by the IBM Corporation; either version 1.0 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
IBM Common Public License for more details.
|
||||
|
||||
You should have received a copy of the IBM Common Public
|
||||
License along with this library
|
||||
*/
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nuclex.Support.SpatialPartitioning {
|
||||
|
||||
/// <summary>Interface for a 2D geometrical database</summary>
|
||||
public abstract class SpatialIndex2 {
|
||||
|
||||
}
|
||||
|
||||
} // namespace Nuclex.Support.SpatialPartitioning
|
|
@ -74,7 +74,7 @@ namespace Nuclex.Support {
|
|||
/// object.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// null if the object referenced by the current System.WeakReference object
|
||||
/// Is null if the object referenced by the current System.WeakReference object
|
||||
/// has been garbage collected; otherwise, a reference to the object referenced
|
||||
/// by the current System.WeakReference object.
|
||||
/// </remarks>
|
||||
|
|
Loading…
Reference in New Issue
Block a user