GeometryHelper.ArrangeAlgorithms
4.0.0
merge project
dotnet add package GeometryHelper.ArrangeAlgorithms --version 4.0.0
NuGet\Install-Package GeometryHelper.ArrangeAlgorithms -Version 4.0.0
<PackageReference Include="GeometryHelper.ArrangeAlgorithms" Version="4.0.0" />
<PackageVersion Include="GeometryHelper.ArrangeAlgorithms" Version="4.0.0" />
<PackageReference Include="GeometryHelper.ArrangeAlgorithms" />
paket add GeometryHelper.ArrangeAlgorithms --version 4.0.0
#r "nuget: GeometryHelper.ArrangeAlgorithms, 4.0.0"
#:package GeometryHelper.ArrangeAlgorithms@4.0.0
#addin nuget:?package=GeometryHelper.ArrangeAlgorithms&version=4.0.0
#tool nuget:?package=GeometryHelper.ArrangeAlgorithms&version=4.0.0
GeometryHelper.ArrangeAlgorithms
2D label placement for engineering drawings: given a set of labels, each associated with a guide segment and surrounding blocked regions, the library calculates translation vectors that keep labels from overlapping each other and from encroaching on the blocked regions.
It depends on AutoCAD and Tekla for nothing. The geometry it works in comes from GeometryHelper.PlaneGeometry, which comes with this package as a dependency.
Installation
dotnet add package GeometryHelper.ArrangeAlgorithms
GeometryHelper.PlaneGeometry and GeometryHelper.CommonGeometry come with it as dependencies.
Visual Examples
AutoCAD Integration
Here are some examples of labels arranged inside AutoCAD to avoid overlaps and blocked regions:
| Greedy | Force Directed |
|---|---|
![]() |
![]() |
Tekla Structures Integration
Here is an example of reinforcement marks before and after arrangement:
| Before Arrangement | After Arrangement |
|---|---|
![]() |
![]() |
| Arranged Marks Avoiding Dimension Obstacles |
|---|
![]() |
Quick Start
var leader = new GeoLine2(0.0, 0.0, 2000.0, 0.0);
var arranges = new List<Arrange>
{
new Arrange
{
// Label bounding box: center, width, height, rotation angle (radians, counter-clockwise)
GeoRectangle2 = new GeoRectangle2(new GeoPoint2(1000.0, 0.0), 2000.0, 1000.0),
// Guide segment: its midpoint is the origin for candidate positions expansion
GeoLine2 = leader,
// Minimum perpendicular offset between label edge and guide segment, specific to this label (default 50)
MarkOffsetFromLine = 50.0,
// Blocked regions the label must not overlap
BlockPolygons = new List<GeoPolygon2>(),
BlockLines = new List<GeoLine2>()
}
};
// Returns translation vector for each label, in the exact input order.
// Each Arrange object is also automatically updated: arranges[i].TranslationVector contains the same vector.
List<GeoVector2> moves = Arrange.Run(arranges);
for (int i = 0; i < arranges.Count; i++)
{
// You can use the returned 'moves[i]' or read the property directly:
GeoVector2 move = arranges[i].TranslationVector;
GeoPoint2 newPosition = arranges[i].GeoRectangle2.Center + move;
bool isPlaced = arranges[i].Placed; // false = forced to fallback, still has overlap
}
To change the algorithm or fine-tune parameters, pass ArrangeOptions:
var options = new ArrangeOptions
{
Algorithm = ArrangeAlgorithmType.BoundedBacktracking,
RowGap = 20.0,
PerpendicularLevels = 3
};
List<GeoVector2> moves = Arrange.Run(arranges, options);
ArrangeOptions is the shared configuration for the entire list. MarkOffsetFromLine is set per Arrange because each label may require a different offset:
var smallTextLabel = new Arrange
{
GeoRectangle2 = new GeoRectangle2(new GeoPoint2(1000.0, 0.0), 2000.0, 1000.0),
GeoLine2 = leader,
MarkOffsetFromLine = 50.0 // small text, closely sticks to guide segment
};
var largeTextLabel = new Arrange
{
GeoRectangle2 = new GeoRectangle2(new GeoPoint2(1000.0, 0.0), 4000.0, 2000.0),
GeoLine2 = leader,
MarkOffsetFromLine = 200.0 // large text, must move further away
};
List<GeoVector2> moves = Arrange.Run(new List<Arrange> { smallTextLabel, largeTextLabel }, options);
Candidate Positions Generation
All 5 algorithms share the same set of discrete candidate positions, expanding from the midpoint of the guide segment:
- Perpendicular Translation — each level in
PerpendicularLevelscreates a row of labels, symmetric on both sides of the guide segment. The first level is placed at half the label height plus the label's ownMarkOffsetFromLine. Each subsequent level adds the label height plusRowGap. - Longitudinal Sliding — in each row, the label slides parallel to the guide segment in both directions, up to a maximum of half the guide segment length plus
LongitudinalOvershootRatiotimes the label width.
The algorithms only differ in how they select from this candidate set.
Five Algorithms
ArrangeAlgorithmType |
Selection Strategy | Trade-off |
|---|---|---|
Greedy (default) |
Sequentially places labels, prioritizing the most constrained ones; selects the most open spot in the first group of free candidates | Fastest, reproducible results, but prone to local optima |
BoundedBacktracking |
Same as Greedy, but backtracks when subsequent labels are stuck, bounded by MaxBacktrackSteps |
Higher clean placement rate, slower on crowded drawings |
SimulatedAnnealing |
Global optimization based on a collision-penalty energy function, gradually cooling down | Best for extremely crowded drawings, CPU-heavy |
ForceDirected |
Simulates spring and repulsive forces, then maps to the nearest discrete candidate | Distributes labels evenly and naturally |
ConstraintSatisfaction |
CSP with MRV heuristic and forward checking | Most rigorous, potential combinatorial explosion with large number of labels |
BoundedBacktracking and ConstraintSatisfaction automatically fallback to Greedy if no collision-free solution is found, ensuring every label always has a display position.
SimulatedAnnealing uses a fixed seed, so its results are reproducible between runs.
Parameters for each Arrange
| Parameter | Default | Meaning |
|---|---|---|
GeoRectangle2 |
— | Label bounding box, the geometry that will be translated |
GeoLine2 |
— | Guide segment; its midpoint is the origin for candidate positions expansion |
MarkOffsetFromLine |
50.0 | Minimum perpendicular offset between label edge and guide segment |
BlockPolygons |
— | Blocked polygons that the label must not overlap |
BlockLines |
— | Blocked line segments that the label must not overlap |
Main Parameters of ArrangeOptions
| Parameter | Default | Meaning |
|---|---|---|
Algorithm |
Greedy |
Algorithm to use |
RowGap |
20.0 | Clearance between two consecutive rows of labels |
PerpendicularLevels |
3 | Number of perpendicular fallback levels to test on each side |
LongitudinalOvershootRatio |
0.75 | Ratio of label width allowed to overshoot beyond the two endpoints of the guide segment |
MinimumBoxSize |
10.0 | Labels smaller than this size are ignored |
MinimumMoveDistance |
0.1 | Translations smaller than this threshold are rounded to zero |
NeighbourMargin |
50.0 | Expanded margin when filtering nearby obstacles |
PlaceMostConstrainedFirst |
true | Place labels with fewer options first |
PlaceFromInsideOut |
true | Prioritize labels close to the area centroid |
LookAheadCandidates |
3 | Number of free positions considered before selection |
MaxBacktrackSteps |
1000 | Cap on the number of backtracking steps |
AnnealingInitialTemperature |
100.0 | Initial temperature for the Simulated Annealing algorithm |
AnnealingCoolingRate |
0.95 | Cooling rate for the Simulated Annealing algorithm |
ForceIterations |
100 | Number of force simulation iterations for the Force-Directed algorithm |
Tolerance |
Tolerance.Global |
Tolerance for geometric comparisons |
Default values are in millimeters, matching conventional structural drawings.
Running inside AutoCAD
GeometryHelper.ArrangeAlgorithms.CadTest builds a DLL file to be loaded into AutoCAD:
dotnet build Samples/GeometryHelper.ArrangeAlgorithms.CadTest/GeometryHelper.ArrangeAlgorithms.CadTest.csproj
The output is located at Samples/GeometryHelper.ArrangeAlgorithms.CadTest/bin/Debug/net48/GeometryHelper.ArrangeAlgorithms.CadTest.dll. Load this file into AutoCAD using the NETLOAD command, then run one of the following commands: T1_Greedy, T1_BoundedBacktracking, T1_SimulatedAnnealing, T1_ForceDirected, T1_ConstraintSatisfaction. Select LINE or LWPOLYLINE objects, and the plugin will draw the label box before and after arrangement, along with statistics.
The project compiles against three AutoCAD assemblies — accoremgd, acdbmgd, acmgd — committed under Libraries/GeometryHelper.CadConvert/Lib and referenced from there by relative path, so no AutoCAD installation is needed to build. Loading the result still needs AutoCAD, which supplies those assemblies at run time.
Running inside Tekla Structures
GeometryHelper.ArrangeAlgorithms.TeklaTest is a console application that connects to the active Tekla Structures model and drawing to arrange reinforcement marks.
To build and run:
- Open Tekla Structures and open a drawing with some reinforcement marks and dimensions selected.
- Build the project:
dotnet build Samples/GeometryHelper.ArrangeAlgorithms.TeklaTest/GeometryHelper.ArrangeAlgorithms.TeklaTest.csproj - Run the compiled executable:
Samples/GeometryHelper.ArrangeAlgorithms.TeklaTest/bin/Debug/net48/GeometryHelper.ArrangeAlgorithms.TeklaTest.exe
Licence
MIT.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- GeometryHelper.PlaneGeometry (>= 4.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|
2D label placement for engineering drawings. Given labels that each carry a guide segment and a
set of blocked regions, the library returns the translation vectors that keep the labels off each
other and off the blocked regions.
- Five algorithms behind one entry point, chosen through ArrangeOptions.Algorithm: Greedy,
Bounded Backtracking, Simulated Annealing, Force-Directed and Constraint Satisfaction.
- Arrange.Run fills in a translation for every label; a label that cannot be improved keeps a
zero vector rather than being dropped from the result.
- Blocked regions accept both polygons and lines, so dimensions and the rebar centrelines a mark
must not cross are expressed the same way.
- Offsets, spacing, iteration counts and the tolerance are all set through ArrangeOptions, whose
defaults are in millimetres to match conventional structural drawings.
- It depends on AutoCAD and Tekla for nothing. The geometry comes from
GeometryHelper.PlaneGeometry, which arrives as a dependency along with
GeometryHelper.CommonGeometry.




