WhatsNew for Tektosyne 5.6.2
This file contains the version history for the Tektosyne Library for the .NET Framework. Please refer to the separate ReadMe file for general information.
Version 5.6.2 (released 2012-04-18)
- Class Reference: Updated to Sandcastle Help File Builder version 1.9.4.0 which fixed the missing GetEnumerator overloads in two dictionary classes.
- MutableTuple & ValueTuple: Added missing type parameter documentation.
- Fixed various references in XML comments.
Version 5.6.1 (released 2012-02-29)
AssemblyExtensions: Fixed version number retrieval.
- As it turns out, AssemblyVersionAttribute is not actually stored as a custom attribute. This version number is available only through AssemblyName.Version, and there’s no way to determine whether that property has a user-defined value or its default value.
- Version: Fixed to return AssemblyName.Version, which also changed the default value from “1.0.0.0” to “0.0.0.0”, i.e. that property’s default value.
- FileVersion & InformationalVersion: Changed default values from “1.0.0.0” to Version if there is no AssemblyFile/InformationalVersionAttribute. This is the same fallback used by .NET internally.
Version 5.6.0 (released 2012-02-26)
Added multithreaded drawing within a single WPF Window.
- Windows:
- Added class VisualSource that manages cross-thread marshalling for a Visual running on a background thread, as described by Dwayne Need.
- Added class ConcurrentVisualHost that combines the functionality of ContainerVisualHost, VisualSource, and a Dispatcher background thread to concurrently draw an arbitrary Visual.
- Tektosyne.GuiTest: Added dialog “Concurrent Drawing Test” that demonstrates four ConcurrentVisualHost instances running in parallel.
- Updated User’s Guide with a section on ConcurrentVisualHost & VisualSource.
Miscellaneous changes.
- Collections.QuadTree<TValue>:
- ContainsKey/Value: Added overloads that take a QuadTreeNode<TValue> to examine before conducting a full tree search, and that return the result of FindNode/ByValue in the same parameter.
- FindNodeByValue: Corrected documentation to estimate this method as an O(Count) operation, not an O(Nodes) operation.
- Windows.TreeHelper: Added methods GetLogical/VisualChildren<T> that return all children of a given type in a logical or visual tree, respectively.
- Xml.XmlUtility.ReadTextElement: Now accepts CDATA blocks and sequences of adjacent simple text and CDATA blocks, emulating the behavior of System.Xml.XmlReader.ReadElementString.
- Tektosyne.UnitTest: Updated NUnit version to 2.6.0.
Version 5.5.6 (released 2012-01-09)
Revised and enhanced assembly helper methods.
- Tektosyne.Core: Added static class AssemblyExtensions with extension methods to retrieve an assembly’s informational attributes and public key token.
- Tektosyne.Windows: WindowsUtility.Copyright & PublicKeyToken: Moved to new class AssemblyExtensions. Both properties only need System.Reflection, so they were out of place in Tektosyne.Windows. Please note that Copyright now returns an empty string if the corresponding attribute is not found, whereas WindowsUtility.Copyright returned the literal string “Copyright”.
- Tektosyne.GuiTest: Replaced dialog “Public Key Token” with “Assembly Information”, showing all information extracted by AssemblyExtensions methods from the GuiTest executable.
- Updated User’s Guide with the above changes.
Various minor changes.
- Strings.resx: Renamed ErrorUnknown/Xml/XmlSchema to Unknown/Xml/XmlSchemaError for consistency with general naming scheme. Also added XmlContentNotEmpty & XmlDocumentError.
- StringUtility: Added static method ValidOrNull that returns a null reference unless a specified string has valid content, i.e. roughly the opposite of the Validate methods.
Version 5.5.5 (released 2011-10-22)
Geometry.Angle:
- Added methods DistanceDegrees & DistanceRadians that compute the shortest distance between two angles specified as normalized degrees or radians, respectively. The distance is signed to indicate its rotational direction.
Version 5.5.4 (released 2011-09-12)
Collections.QuadTreeNode<TValue>.FindNode(PointD):
- Added mathematically redundant check against node bounds during depth probe. This was necessary due to floating-point inaccuracies which could otherwise cause search failures.
Version 5.5.3 (released 2011-07-03)
Collections.QuadTreeNode<TValue>.Capacity:
- Moved to QuadTree<TValue>, changed from constant to read-only field, added constructor overload to set field, and changed default value from 16 to 128.
- Capacity defines the number of elements that are stored in a leaf node’s hashtable. Raising this value always speeds up all operations, except for range searches which eventually become more expensive as they require linear searches through larger hashtables.
- Range searches are the reason why we use a quadrant tree in the first place, rather than just one giant hashtable, so we try to optimize for them. In the Tektosyne.GuiTest benchmark, a capacity of 128 yielded the best results, accelerating range searches by 40% compared to the previous capacity of 16. Other tested operations showed a similar speedup.
- However, the optimal capacity may depend on the actual element distribution, so this parameter is now configurable during construction of the QuadTree<TValue>.
Version 5.5.2 (released 2011-06-24)
- Collections.QuadTree<TValue>:
- Added method Move that changes an element’s key. Unlike a normal Remove/Add sequence, Move is an O(log m) or even O(1) operation for nearby keys and short movements.
- FindRange: Added overload that searches a circular range with a given center and radius.
- Geometry:
- RectD/F: Added overloaded method ContainsOpen that excludes Right & Bottom coordinates, simulating RectI behavior.
- RectI: Added overloaded method ContainsClosed that includes Right & Bottom coordinates, simulating RectD/F behavior.
- Graph.IGraph2D<T>.GetDistance: Documented another invariant required by A* pathfinding. The sum of the distances between all successive nodes within a sequence is never less than the distance between any two nodes from the same sequence.
- Updated User’s Guide with the above changes, fixed link to Tektosyne home page, and changed all URL domains from kynosarges.de to kynosarges.org.
Version 5.5.1 (released 2011-05-31)
Added Tektosyne User’s Guide.
- The guide is now available for download at the Tektosyne home page.
- Added project
Tektosyne.Diagrams.xml for Class Diagrammer which was used to create all UML diagrams in the guide.
Fixed a variety of minor issues that surfaced while writing the guide.
- Collections.IKeyedValue<TKey>: Key does not have to be unique within a collection, although that is usually the case. Fixed XML comments accordingly.
- Geometry:
- RegularPolygon.AngleToCompass: Replaced with new method Angle.DegreesToCompass which maps zero degrees to North rather than East, for consistency with Compass values.
- Graph:
- Added class NodeArc that stores the source distance, tangential arc, and visible fraction for any graph node visited by the Visibility<T> algorithm.
- Visibility<T>:
- Added property NodeArcs that holds the NodeArc instances for all visited graph nodes. This data was being computed anyway, so I figured I might as well expose a read-only view to interested clients.
- Improved performance on graphs with many opaque nodes by skipping redundant calculations on opaque nodes that are completely obscured.
- Geometry, Graph & Tektosyne.GuiTest: Changed generic term “pathfinding algorithms” in XML comments and GUI labels to “graph algorithms”. Only two of the four Tektosyne.Graph algorithms are actually concerned with pathfinding, but all operate on IGraph2D<T> instances.
Version 5.5.0 (released 2011-04-20)
Split Tektosyne Library in two assemblies: Tektosyne.Core and Tektosyne.Windows.
- Please refer to the Tektosyne home page and the ReadMe file for a description of the new library structure. Here we list only type removals and changes within types.
- Removed BooleanFlag and derived classes which provided too little value, compared to simple properties.
- DetailException:
- Added constructors that explicitly set the Detail property, with or without an inner exception.
- Detail: Changed to read-only, as usual with exception properties.
- ThrowHelper:
- ThrowDetailException(WithFormat): Added overloads for the two new constructors.
- ThrowMapiException: Moved to static class Net.MapiMail in assembly Tektosyne.Windows, as nothing else throws this exception anyway.
- Geometry:
- Gdi/WpfConversion: Renamed to Gdi/WpfConversions (plural) which appears to be the usual convention. This should not affect users since all members were extension methods anyway.
- IPointComparer & PointComparerX/Y: Renamed to IPointDComparer & PointDComparerX/Y since all three types operate only on PointD instances.
- PolygonGrid.Draw & DrawOptimized, RegularPolygon.Draw & ToFigure: Moved as extension methods to static class PolygonExtensions in assembly Tektosyne.Windows. Accordingly, the PathFigure returned by ToFigure is no longer cached with its RegularPolygon.
- PolygonGrid.Figures: Replaced with extension method PolygonExtensions.ToFigures in assembly Tektosyne.Windows. Accordingly, the returned PathFigureCollection is no longer cached with its PolygonGrid.
- Subdivision.GetEdge/Face & GetNearestEdge/Vertex: Renamed to FindEdge/Face & FindNearestEdge/Vertex since all these operations are non-trivial.
- SubdivisionFace.GetNearestEdge: Renamed to FindNearestEdge, for the same reason.
- Windows.WindowsUtility:
- Removed method CreateLineFigure which provided too little value.
- Split off all Find… extension methods as new static class TreeHelper.
- Split off all other extension methods as new static class WindowsExtensions.
- Xml:
- Removed interface IXmlSerializable which provided too little value. You can still find a copy in assembly Hexkit.Global of the Hexkit project.
- XmlUtility: Moved generic methods AttributeAsEnum<T>, Deserialize<T> & Serialize<T> to new static class XmlSerialization in assembly Tektosyne.Windows, as they require non-core assemblies.
Tektosyne.UnitTest: Updated NUnit version to 2.5.10.
Version 5.4.6 (released 2011-04-13)
Redesigned Visibility algorithm.
- Completely rewritten to produce correct results even for (almost) arbitrary graphs, without requiring a special VisibilityGraph with full nearest-neighbor connectivity.
- The old implementation proceeded by generations of neighbor connections from the source node. The angles obscured by each node generation were accumulated in a 360-degree bit flag array which allowed very efficient testing. However, obscuration was determined by neighbor generations, i.e. step distances, rather than world distances. That limited correct results to graphs with connections of roughly equal length between all nearest neighbors, i.e. PolygonGrid with hexagons or with corner-connected squares.
- The new implementation performs two passes over all nodes within a given maximum world range. First, we calculate the visibility angles of all nodes within range, and also store those opaque nodes that are not fully obscured by another opaque node. A second pass then determines visible nodes by comparing all nodes within range to the opaque subset.
- The new implementation only moderately increases the number of angle calculations if opaque nodes are rare, and does not require equal-length nearest-neighbor connections. Specifying a maximum search range does require that all nodes are reachable by paths with monotonically increasing world distances, but that’s a much weaker condition.
- To support arbitrary Subdivision graphs, nodes are now associated with a polygonal world region, not just a radius around their world location. A node’s visibility angle spans the arc between the extreme vertices of its region polygon, as seen from a given source location.
- As in the old implementation, a node is considered visible while a certain fraction (1/3) of its visibility angle remains unobscured. This can cause odd results when nodes that are obviously in the line of sight are considered obscured, but that’s a necessary compromise when determining visibility on the basis of entire regions rather than individual points.
Tektosyne.Geometry:
- PolygonGrid & Subdivision: Updated IGraph2D<2D> members to reflect interface changes (see below).
- PolygonGrid: Fixed various methods calling the wrong overload of GridToDisplay, for a slight performance improvement.
- RectD/F.Intersect: Added overload that implements the Sutherland–Hodgman polygon clipping algorithm for a given PointD/F array, representing the vertices of an arbitrary polygon.
- Subdivision: Added property VertexRegions that allows clients to determine which polygonal region GetWorldRegion should return for a given graph node, i.e. Subdivision vertex.
- VoronoiResults.ToDelaunaySubdivision:
- Added optional Boolean parameter to determine whether all pairs of GeneratorSites and VoronoiRegions are automatically added to the VertexRegions collection of the new Subdivision.
- Added overload that takes a RectD parameter to automatically invoke ClipDelaunayEdges before the new Subdivision is created, and to clip all added VertexRegions to the same bounds.
Tektosyne.Graph:
- IGraph2D<T>:
- Added property NodeCount that returns the total number of graph nodes.
- Added property Nodes that returns an IEnumerable<T> for all graph nodes.
- Removed obsolete property VisibilityGraph which is no longer required by the new Visibility algorithm.
- Added method GetNearestNode that returns the graph node nearest to the given world coordinates.
- GetWorldCenter: Renamed to GetWorldLocation since a graph node’s world location is no longer necessarily the center of its world region.
- GetWorldRadius: Replaced with GetWorldRegion which returns the exact polygonal region covered by the graph node.
- Visibility:
- Graph field always equals the supplied IGraph2D<T>, as in other pathfinding algorithms.
- Removed obsolete field SkipOpaqueNeighbors which no longer applies to the new non-generational algorithm.
- FindVisible: Replaced Int32 argument for maximum recursion depth with optional Double argument for maximum world distance, measured from the source node to the nearest world region vertex of any found node.
Tektosyne.GuiTest: Pathfinding:
- Graph: Removed “(8 neighbors)” variants of square grids, and added Vertex Neighbors checkbox instead. You can now toggle this flag without creating a new graph, and observe how the pathfinding results change.
- Algorithm: The Visibility algorithm has been revised (see above), and Voronoi regions are now clipped to the bounds of the output panel which may also affect its output.
- Added button Random Source that re-runs the current algorithm on the current graph with a new random source node. A* always finds a path from the top left to the bottom right node, however.
Version 5.4.5 (released 2011-03-31)
Tektosyne.GuiTest: Pathfinding: Fixed A* on Delaunay triangulation
- A* could find suboptimal paths because I had forgotten that IGraph2D<T>.GetDistance cannot be less than IGraphAgent<T>.GetStepCost for any two graph nodes. Subdivision.GetDistance returns world distances rather than step distances, like PolygonGrid.GetDistance. World distances are much greater than step distances, so Subdivision.GetStepCost must scale up accordingly.
- One option is to multiply assigned step costs by the world distance between the current source and target. This means that world distances strongly influence effective step costs, which would be an appropriate choice for planar subdivisions based on real-world terrain.
- Another option is to multiply assigned step costs by some value that equals or exceeds any possible world distance in the graph. This means that world distances are effectively eliminated from step cost considerations, as in a PolygonGrid.
- I chose the second option for the dialog, for conformance with the various PolygonGrid choices. See the comments in Tektosyne.GuiTest.GraphDialog.SubdivisionGraph.GetStepCost for an implementation of the first option.
Version 5.4.4 (released 2011-03-30)
Geometry:
- GeoAlgorithms: Added overloaded method RandomPoints that creates a given number of random PointD coordinates within a given area, optionally observing a pairwise minimum distance.
- LineD: Added static method FromIndexPoints that converts an array of PointD coordinates and an array of index pairs into an equivalent array of LineD instances.
- Added interface IPointComparer that extends IComparer<PointD> and IComparer with the lexicographic epsilon comparison already implemented by PointComparerX/Y.
- PointComparerX/Y: Now implement interface IPointComparer to allow polymorphic Epsilon control and invocation of FindNearest.
- PointD/F: Added method Move that moves the PointD/F a given distance in a given direction.
- RectD/F/I:
- Intersect: Changed return type from RectD/F/I to Boolean and added out parameter for the actual intersection, if any.
- RectD/F.Intersect & IntersectsWith: Added overloads that implement the Liang-Barsky line clipping algorithm for a given LineD/F.
- Voronoi:
- FindAll: Slightly reduced memory consumption, as the Delaunay triangulation is no longer stored separately when the Voronoi diagram is computed.
- FindAll(PointD[], RectD): Empty clipping bounds are now permitted and have the same effect as calling the basic FindAll(PointD[]) overload.
- VoronoiResults:
- DelaunayEdges: Changed from stored GeneratorSites index array to computed LineD array. The GeneratorSites indices for all Delaunay edges are already present as the Site1/2 indices of the VoronoiEdges array, so there’s no need to store them separately.
- Added method ClipDelaunayEdges that returns only those DelaunayEdges which fall into the given clipping bounds, and which connect two Voronoi regions whose shared border also falls within the clipping bounds.
Tektosyne.GuiTest: Pathfinding:
- Replaced menu with a single Pathfinding dialog that offers all available IGraph2D<T> implementations and pathfinding algorithms.
- The newly available IGraph2D<T> implementations include grids of squares with and without vertex neighbors, as well as a random Delaunay triangulation (with nodes represented by the corresponding Voronoi regions).
Version 5.4.3 (released 2011-02-26)
- Collections.CollectionsUtility: Added generic method AnyRandom that tests a given predicate on one randomly selected list element, repeating the attempt for every remaining element until the predicate succeeds or the list is exhausted.
- Geometry.Subdivision:
- Added overloaded method AddEdge that creates a new edge between two given coordinates, which may coincide with existing vertices. A new face is also created if necessary.
- Added method RemoveVertex that removes a given vertex with exactly two incident edges, joining their two twin half-edges into a new half-edge pair.
- RemoveEdge: Now uses the current Epsilon rather than exact comparisons for cycle identification. I got test failures when attempting to use exact comparisons for this purpose during Subdivision construction, and while RemoveEdge did not (yet) exhibit similar errors I decided to play it safe.
- Geometry.SubdivisionEdge.GetOtherCycleEdge: Lowered visibility to internal. This helper method is really of no use to external clients and should never have been public in the first place.
- Tektosyne.GuiTest: Geometry: Subdivision: Added radio buttons Add Edge, Connect Vertex & Remove Vertex that demonstrate the new Subdivision methods AddEdge & RemoveVertex.
Version 5.4.2 (released 2011-02-21)
Geometry:
- LineIntersection: Added Boolean property ExistsBetween that checks whether the two line segments properly intersect one another, i.e. at least one segment registers a Between hit.
- Subdivision:
- Added method MoveVertex that moves a given vertex to new coordinates, provided this change does not create any new edge intersections.
- Added method SplitEdge that splits a given edge in half by creating a new vertex in the middle of the edge.
- Added methods RenumberEdges & RenumberFaces that renumber all Edges & Faces, respectively, to remove any gaps between consecutive keys. The element order is unchanged.
- Intersection & RemoveEdge: Now correctly force the Connectivity property to re-scan all vertices to determine the new maximum vertex degree.
- SubdivisionEdge & SubdivisionFace:
- Both classes now implement IKeyedValue<Int32> with their Key properties.
- Key: Changed to property with mutable backing field. This field is changed only by the new Subdivision.RenumberEdges/Faces methods, however.
- SubdivisionEdge:
- Added property OriginEdges that returns an IEnumerable<SubdivisionEdge> for all half-edges with the same Origin.
- GetOtherFaceEdge: Renamed to GetOtherCycleEdge, in accordance with the revised naming of Cycle… properties.
- SubdivisionFace.AllEdges: Renamed to AllCycleEdges for conformance with SubdivisionEdge.CycleEdges.
Tektosyne.GuiTest: Geometry: Subdivision:
- Moving the mouse cursor now also highlights the nearest vertex, in addition to the nearest half-edge.
- Added radio buttons Remove Edge, Split Edge & Move Vertex to select the action performed by clicking near a highlighted element, corresponding to the eponymous Subdivision methods.
- Added buttons Renumber Edges & Renumber Faces that demonstrate the eponymous new Subdivision methods.
Version 5.4.1 (released 2011-02-15)
Geometry:
- Subdivision: Added method GetZeroAreaCycles that efficiently finds all half-edge cycles for which IsCycleAreaZero succeeds.
- Subdivision.Validate & SubdivisionSearch.Validate: Removed attribute Conditional("DEBUG") and replaced Debug.Assert calls with ThrowHelper.Assert calls. This allows structural validation with programmatic failure handling in release code.
- SubdivisionEdge:
- Replaced method ForEach with property CycleEdges that returns an IEnumerable<SubdivisionEdge> for all half-edges in the same cycle.
- Renamed FaceArea/Centroid/Polygon & IsFaceAreaZero to CycleArea/Centroid/Polygon & IsCycleAreaZero since the incident half-edge cycle does not necessarily constitute a SubdivisionFace (namely if it encloses no area).
- SubdivisionFace: Added property AllEdges that returns an IEnumerable<SubdivisionEdge> for all half-edges on all OuterEdge and InnerEdges cycles.
- SubdivisionSearch, PolygonGrid.SubdivisionMap & VoronoiResults.SubdivisionMap: Added missing attribute Serializable to all three classes.
Other Changes:
- Added class AssertionException which is merely a renamed Exception class for use with the new ThrowHelper.Assert method.
- ThrowHelper:
- Added overloaded method Assert that checks a condition and calls ThrowAssertionException on failure. Unlike Debug/Trace.Assert, this method does not depend on the DEBUG/TRACE symbols and does not attempt to produce any output.
- Added overloaded method ThrowAssertionException that corresponds to the three public constructors of the new AssertionException class.
Version 5.4.0 (released 2011-02-12)
Subdivision Search
- Added class SubdivisionSearch that performs fast point location in planar subdivisions. The search structure is based on a trapezoidal map of the subdivision, using randomized incremental construction according to Computational Geometry by de Berg et al.
- The SubdivisionSearch algorithm performs point location in logarithmic time but requires superlinear construction time and linear space, relative to the number of edges in the subdivision. Use the new Subdivision.Find method for slower one-off searches without such overhead.
- Added structure SubdivisionElement and enumeration SubdivisionElementType to efficiently represent either a half-edge, face, or vertex within a Subdivision. This is the result type for both new point location algorithms.
Geometry.PointComparer:
- Renamed to PointComparerY to indicate that the lexicographic sorting order prefers y-coordinates.
- Added class PointComparerX which is equivalent to PointComparerY but prefers x-coordinates.
- LexiCompare: Renamed exact & epsilon overload to CompareExact & CompareEpsilon, respectively. The Lexi… prefix was meaningless and misleading since all comparisons performed by both classes are lexicographic.
Geometry.Subdivision:
- Added method Find that performs a brute-force search for a given point, returning the same SubdivisionElement for the same input as the new SubdivisionSearch algorithm. Find does not require a dedicated search structure, at the expense of linear (or worse) search performance.
- Fixed yet another bug that occasionally corrupted the cycle structure.
- Edge cycles that enclose no area are always inner cycles. However, if the cycle’s pivot vertex was not the tip of a single-edge protrusion, and the neighboring vertices happened to be oriented in the wrong direction, cycle search would mistakenly assume an outer cycle.
- This possibility was not covered by de Berg et al. in Computational Geometry, and never occurred to me either. Cycle search now performs an extra test to determine whether a cycle encloses any area at all, and immediately assumes an inner cycle on failure.
- The runtime overhead is low since cycle search iterates over all half-edges in a cycle anyway. We identify zero-area cycles by checking if the twins of all half-edges belong to the same cycle, similar to the new property SubdivisionEdge.IsFaceAreaZero.
- Intersection: Fixed face mapping to produce better results and avoid exceptions.
- Face mapping used collinearity testing of connected edges that were split by the edge intersection algorithm. Unfortunately, this proved very unreliable since a correct epsilon for the involved floating-point comparisons is impossible to establish in the general case.
- Edge intersection now directly tracks the incident faces of all half-edges in both original subdivisions, indexed by the keys of the corresponding half-edges in the combined subdivision. A final pass through the combined subdivision’s half-edges then determines the face mapping.
- This requires some extra memory but does not impact the speed of the algorithm. More importantly, the new method is guaranteed to be correct and cannot throw exceptions.
Other Changes:
- Collections.CollectionsUtility:
- Added method IndexArray that creates an Int32 array whose elements equal their index positions.
- Added generic method Randomize that creates a random permutation of the element order in a given IList<T>.
- Geometry:
- GeoAlgorithms: Added method ConnectPoints that returns the LineD instances connecting a given set of PointD coordinates.
- LineD/F/I.Locate & LocateCollinear: Testing for Between now precedes testing for Before/After. This allows epsilon overloads to correctly register approximate Between hits on (nearly) horizontal or vertical line segments.
- SubdivisionEdge: Added property IsFaceAreaZero that determines whether the boundary of the incident Face encloses no area, by checking whether the Twins of all half-edges in the cycle bound the same Face (and therefore also belong to the same cycle). This is faster and more reliable than computing FaceArea since no floating-point calculations are involved.
Tektosyne.GuiTest:
- Benchmark:
- Added Subdivision Search test that compares the new Find algorithms: brute force, ordered and randomized SubdivisionSearch structure.
- Subdivision Intersection: Removed warning notice regarding exceptions as the intersection algorithm now appears to be stable, even for random line sets.
- Geometry: Subdivision Intersection:
- Intersect: Renamed to Rectangle and added Diamond button which intersects a diamond inscribed in the specified rectangle.
- Added display to show face mapping, i.e. previous & intersecting face keys for the current face key under the mouse cursor.
Version 5.3.1 (released 2011-01-10)
- Geometry:
- LineD/F/I.Locate: Moved Start/End comparisons to beginning of methods, as in LocateCollinear. This is somewhat slower when the query point does not match Start/End, but much faster and more reliable when it does.
- LineIntersection.Find: Commented out expensive Debug.Assert calls that were intended merely as documentation, not as actual tests.
- LineLocation: Clarified that Left & Right are always viewed from the line segment’s start point to its end point.
- VoronoiResults: Fixed open Voronoi regions that include two corners of the clipping bounds sometimes claiming the opposite border of the clipping bounds, rather than the adjacent one.
Version 5.3.0 (released 2011-01-02)
Geometry.LineIntersection.Find:
- Added intersection checking based on cross-products between end points, as described by Thomas H. Cormen et al., Introduction to Algorithms (3rd ed.), The MIT Press 2009, p.1018. The combination of the new algorithm with the existing algorithm (based on line equation parameters) is somewhat slower but much more resilient against floating-point inaccuracies.
- In the exact overload, cross-product and denominator comparisons now use a default epsilon of 1e-10 to further increase numerical stability, with a negligible performance impact.
- In the epsilon overload, heuristic epsilon fudging was replaced with explicit epsilon comparisons of any computed intersection between divergent lines against their end points. Together with the other changes, this is not only faster but also much more accurate, and mirrors the point comparisons performed in other branches of the algorithm.
- In both overloads, any line equation parameters are checked against the initial cross-product results, and contradictions force a recursive Find call with a doubled epsilon. This is of course very slow but should happen quite rarely.
- In the epsilon overload, the specified epsilon is always raised to a minimum of 1e-10, i.e. the default epsilon used by the exact overload. Smaller epsilons are pointless as they merely trigger multiple recursions with greater epsilons.
Geometry.Subdivision:
- Added factory method Intersection that intersects two planar subdivisions. The algorithm differs from the one outlined by de Berg et al. in Computational Geometry as follows:
- To determine intersections, we don’t use a plane sweep over the combined set of edges from both subdivisions to determine intersections. Instead, we exploit the fact that all edge intersections within a subdivision are already known, and perform a brute-force intersection of all the edges in the first subdivision with those in the second. This is quite fast, especially if one subdivision is much smaller than the other.
- To determine face mappings, we don’t examine the vertices of the combined subdivision during the face-building plane sweep. Instead, we later match all edges in the two original subdivisions with the (collinear combinations of) identical edges in the combined subdivision.
- FromLines & FromPolygons: Changed to return empty subdivisions for empty input collections, rather than throw an exception.
- Fixed half-edges on inner cycles sometimes not receiving Face pointers, due to incorrect chaining of inner cycles during cycle detection.
Other Changes:
- MathUtility: Added overloaded method Equals that determines whether two Double or Single numbers are equal, given a specified epsilon.
- Geometry:
- MultiLineIntersection: Added method Split that splits a given set of line segments on the intersection points found by the Find & FindSimple methods. This allows creating subdivisions from random line sets, which is not otherwise possible since the lines might intersect.
- MultiLinePoint.Shared: Fixed XML comment erroneously claiming that the Shared coordinates were always copied from the first Lines element whose Locations value equals Start or End, if any. The intersection algorithms make no such guarantee, and the Shared coordinates may in fact be computed even when one or more Locations equal Start or End.
- PointD/F.Equals & IsCollinear, RectD/F.Equals, SizeD/F.Equals: Inlined all epsilon comparisons for better performance.
Tektosyne.GuiTest:
- Benchmark:
- Added Subdivision Intersection test for the eponymous new algorithm.
- Geometry Algorithms test:
- Raised test epsilon from Double.Epsilon to 1e-10.
- The old value was the worst case for epsilon algorithms, producing the same results as exact algorithms but with additional cost.
- The new value is more realistic and dramatically speeds up epsilon algorithms since 1e-10 is big enough to abbreviate calculations on near-zero values.
- Changed iterations from 1 to 10 million and output format from µsec to nsec, compensating for the much better performance of the epsilon cases.
- Geometry:
- Added dialog Subdivision Intersection that tests the eponymous new algorithm. Note that you can copy & paste Voronoi-based subdivisions from the existing Planar Subdivision dialog.
- Line Intersection dialog:
- Added Split button that splits all lines on the detected intersection points. If the Split and FindSimple algorithms both work correctly, the number of lines should increase but the number of detected intersection points should stay the same.
- Increasing the comparison epsilon should no longer produce nonsensical intersection points, thanks to the improved numerical stability of the LineIntersection.Find algorithm.
Version 5.2.2 (released 2010-12-15)
- Geometry:
- Subdivision:
- Added property IsEmpty that indicates whether the subdivision is empty.
- Clone:
- Fixed Epsilon property not being copied.
- Fixed SubdivisionEdge.Face references of copied half-edges still referring to original faces.
- RemoveEdge: Fixed Vertices collection still referring to removed half-edges.
- Added method Validate that performs Debug.Assert tests on all structural invariants.
- SubdivisionFace: Added read-only field Owner that holds the containing Subdivision. Since all half-edges have an incident face, their containing Subdivision is now available with one dereferencing step as well.
- Tektosyne.UnitTest:
- Updated NUnit version to 2.5.9.
- Geometry: All Subdivision tests call Validate on every created Subdivision when DEBUG is defined.
Version 5.2.1 (released 2010-11-24)
- Geometry.Subdivision.RemoveEdge:
- Added overload that returns the keys of the changed and removed faces, if any.
- Fixed data corruption when new inner cycle contains the face’s previous OuterEdge.
Version 5.2.0 (released 2010-11-19)
- Collections:
- Added class Int32HashSet that provides an Int32Dictionary<TValue> without values, i.e. a dynamic hashtable optimized for Int32 keys. Int32HashSet is similar to the standard class HashSet<T> but does not implement the complex ISet<T> interface.
- JIT improvements have somewhat eroded the speedup achieved by Int32Dictionary<TValue> and Int32HashSet, but key searches are still a respectable 50-60% faster (in optimized x64 builds) than Dictionary<Int32, TValue> and HashSet<Int32>, respectively.
- Geometry:
- LineD/F/I:
- Added method DistanceSquared that computes the squared distance from a given point to the nearest point in the line segment.
- Intersect: Added PointD/F/I overload that determines the intersection of the perpendicular dropped from a given point on the line or its infinite extension.
- Subdivision:
- Faces: Now always contains the unbounded face at index position zero and with a Key of zero, even for a newly constructed Subdivision.
- GetFace: Added PointD overload that finds the smallest face which contains a given point, using a linear search through all Faces.
- Added method GetNearestEdge that finds the half-edge that is nearest to and facing a given point, using GetFace(PointD) and SubdivisionFace.GetNearestEdge.
- Added method RemoveEdge that removes a half-edge from the subdivision, adjusting half-edge links and removing any eliminated faces and vertices.
- SubdivisionEdge:
- Added method ForEach that executes an arbitrary Action<SubdivisionEdge> on each half-edge within the same cycle.
- Added method GetOtherFaceEdge that attempts to find a half-edge within the same cycle that differs from the specified half-edge.
- SubdivisionFace: Added method GetNearestEdge that finds the incident half-edge, on any outer or inner boundary, that is nearest to and facing a given point.
- Tektosyne.GuiTest:
- Benchmark: Added Collections test suite that compares the standard HashSet<Int32> and the new Int32HashSet.
- Geometry: Added Planar Subdivision dialog that shows a subdivision created from a random Voronoi diagram. Use the mouse cursor to highlight nearest half-edges and remove edges.
- Tektosyne.UnitTest:
- Updated NUnit version to 2.5.8.
- LineTest: Fixed test diagonals always using LineD type rather than LineD/F/I. Fortunately, all affected tests succeeded anyway!
Version 5.1.5 (released 2010-09-28)
- Changed “Company” attribute of all assemblies from “Christoph Nahr” to “Kynosarges”, in accordance with the new Class Diagrammer release.
- Windows.WindowsUtility: Added method FindContextMenuTarget to find the PlacementTarget of the ContextMenu that contains a given object (typically a clicked MenuItem).
Version 5.1.4 (released 2010-09-02)
- Collections.EqualityComparerAdapter<T>: Added optional hash function parameter to support both methods of the IEqualityComparer & IEqualityComparer<T> interfaces.
- XmlUtility.AttributeAsEnum<T>: Fixed nonfunctional method. The specified attribute name was ignored because I had somehow managed to put quotes around it.
Version 5.1.3 (released 2010-08-26)
Mutable Tuples for WPF Data Binding
- Existing tuple types such as KeyValuePair<TKey, TValue>, Tuple<T1, …>, and ValueTuple<T1, …> all represent immutable tuples. This is usually desirable but prevents their use when mutability is required, e.g. two-way data binding with the items of WPF list controls.
- This release therefore adds a set of mutable tuples. They are implemented as classes with public properties so as to facilitate their use with collections and WPF controls.
- Added classes MutableTuple<T1, T2>, MutableTuple<T1, T2, T3>, and MutableTuple<T1, T2, T3, T4> that represent mutable tuples with 2–4 components.
- Added static class MutableTuple with Create methods that can infer the required generic type arguments.
Other Changes
- ThrowHelper:
- Added method ThrowTypeLoadExceptionWithFormat.
- ThrowArgumentExceptionWithFormat: Added overload with two formatting parameters.
- Collections: Added generic class EqualityComparerAdapter<T> that wraps an equality predicate in the IEqualityComparer & IEqualityComparer<T> interfaces, similar to ComparerAdapter<T>.
- Windows.WindowsUtility:
- Added generic methods FindLogicalChild<T> and FindLogicalParent<T> that search a logical tree for the nearest child or parent, respectively, of the specified type.
- Added generic method FindVisualChild<T> that searches a visual tree for the nearest child of the specified type, i.e. the inverse of FindVisualParent<T>.
- FindVisualParent<T>: Fixed exception when encountering a parent that is not a Visual or Visual3D. Surprisingly, this can actually happen (e.g. Run containing text) and when it does, VisualTreeHelper throws an exception rather than returning a null reference.
- XmlUtility: Added generic method AttributeAsEnum<T> that parses an XElement attribute as an enumeration value. As with ReadAttributeAsEnum<T>, the enumeration may have the Flags attribute.
- Tektosyne.UnitTest: Updated NUnit version to 2.5.7.
Version 5.1.2 (released 2010-07-14)
Tektosyne.Geometry: Subdivisions & Voronoi Diagrams
- ISubdivisionMap<T>: Added property Target holding an optional untyped object that defines all mapped values.
- PolygonGrid.ToSubdivision:
- Changed return type to public nested class PolygonGrid.SubvisionMap which provides more specific comments and a strongly-typed Target property.
- Stored the generating PolygonGrid in the Target property of the returned SubdivisionMap.
- Voronoi:
- Fixed slightly incorrect clipping bounds calculation that could later lead to Debug.Assert failures when VoronoiResults attempted to compute VoronoiRegions.
- That was because RectD.Right & Bottom coordinates are computed, not stored, so when the RectD containing the final clipping bounds is created from LTRB coordinates, these properties may differ slightly from the original values. Unfortunately the Voronoi class used the original LTRB coordinates before they were converted into a RectD, while the VoronoiResults class used the LTRB coordinates extracted from that RectD. The slight difference between the respective Right & Bottom values would cause comparison failures.
- Now the Voronoi class immediately converts the final clipping bounds into a RectD and re-extracts all LTRB coordinates before they are used to construct the Voronoi diagram, eliminating this difference.
- VoronoiEdge: Replaced PointI fields Site & Vertex with equivalent Int32 fields Site1, Site2, Vertex1 & Vertex2. This is somewhat clearer as there is no X/Y relationship between these values.
- VoronoiResults:
- Added method ToDelaunySubdivision that converts all DelaunayEdges to a planar Subdivision.
- Added method ToVoronoiSubdivision that converts all VoronoiRegions to an ISubdivisionMap<Int32> which associates all bounded faces with GeneratorSites indices.
- Added method ClearVoronoiRegions that resets the VoronoiRegions property to a null reference. The new method ToVoronoiSubdivision always creates VoronoiRegions, and retaining them may be undesirable.
Version 5.1.1 (released 2010-07-08)
Tektosyne.Geometry: Subdivision Epsilon Locked
- Subdivision accepts a comparison epsilon for the comparer that sorts its Vertices collection. Previously, this epsilon would be set to a positive value during construction if requested, and then reset to zero. This turned out to be a very bad idea.
- Because vertices are sorted lexicographically by comparing coordinates individually, changing the comparison epsilon can change the ordering of vertices even when they are far apart in terms of absolute distance, just as long as they are close on one axis. This would cause any algorithm that relied on vertex comparisons to crash and burn. The only option was to lock in the epsilon used during construction.
- Subdivision:
- Replaced property VertexComparer with property Epsilon which sets the Epsilon of the PointComparer used by the Vertices collection, but also checks that the Vertices collection is empty and caches the new epsilon for internal use.
- FromLines & FromPolygons:
- All comparisons now use the Subdivision’s current Epsilon. Cycle search previously used exact comparisons regardless of the specified comparison epsilon, which could cause errors when that epsilon was positive.
- Fixed incorrect edge link detection when decreasing angle wrapped around from positive to greater positive value, or increasing angle wrapped around from negative to smaller negative value.
- GetEdge & GetFace: Removed epsilon parameters. The methods now always use the Subdivision’s current Epsilon to ensure correct search results.
- GetFace: Fixed flow control bug triggered by boundary verification.
Tektosyne.Geometry: SubdivisionFace Mapping
- Added interface ISubdivisionMap<T> that maps the faces of a Subdivision to arbitrary objects, and vice versa. This allows correlating a subdivision with data such as map regions or coordinates in a different system.
- PolygonGrid:
- Added method GetElementVertices which returns the polygon vertices of a grid element, shifted to the specified grid location.
- Added method ToSubdivision which creates a Subdivision whose faces equal all grid elements, and a mapping between faces and grid locations. This is actually not particularly useful since using the PolygonGrid directly is much more efficient, but it makes for great test cases (which uncovered the epsilon issue and other bugs fixed in this release).
Tektosyne.Geometry: Other Changes
- GeoAlgorithms:
- Added method NearestPoint that performs a brute-force search for given coordinates in an unsorted PointD collection.
- Added method PolygonArea that computes the area of an arbitrary polygon, with the sign indicating the orientation of its vertices.
- Added method PolygonCentroid that computes the centroid (“center of gravity”) of an arbitrary polygon.
- ConvexHull: Added params keyword to polygon parameter, allowing comma-separated coordinates.
- PointComparer:
- Added method CompareEpsilon that is identical with Compare but always uses the current Epsilon, and therefore provides a faster Comparison<PointD> instance if Epsilon is known to be positive.
- Added method FindNearest that searches a lexicographically sorted PointD collection for given coordinates, using a heuristic approximation followed by a radius-limited search.
- Subdivision: Added method GetNearestVertex that runs FindNearest on the Vertices collection.
- SubdivisionEdge:
- Added property FacePolygon that returns the (inner or outer) boundary of the incident Face which contains the SubdivisionEdge.
- Added properties FaceArea & FaceCentroid that compute the PolygonArea & PolygonCentroid, respectively, for the FacePolygon.
- SubdivisionFace:
- Removed redundant methods GetInnerPolygon & GetOuterPolygon – use the new property FacePolygon on InnerEdges & OuterEdge instead.
- Moved methods Locate & LocateEpsilon to class SubdivisionEdge. These methods also operate only on edge cycles, without regard to the containing face.
- Collections.QuadTree: Renamed compilation constant USE_BITMASK to QUADTREE_BITMASK.
- Tektosyne.GuiTest: Benchmark:
- Changed test suite selection from buttons to drop-down box, as there were too many buttons.
- Added Nearest Point Search which compares the new methods NearestPoint & FindNearest.
Version 5.1.0 (released 2010-06-14)
Tektosyne.Geometry: Doubly-Connected Edge List
- The doubly-connected edge list is a powerful and flexible representation of a planar subdivision, i.e. any arbitrary collection of edges and faces, such as the vector map of a landscape. This release adds a C# implementation of the DCEL described by Mark de Berg et al. in Computational Geometry.
- The current version is a preliminary implementation. You can create DCELs from collections of lines or polygons, but you cannot modify the created DCELs, and essential algorithms such as mutual intersection and point location are still missing. I decided to release this version anyway since the existing code should be stable, and I wanted to publish the necessary changes to the Graph interfaces (described below).
- Added class Subdivision that represents a planar subdivision as a doubly-connected edge list. The class implements IGraph2D<T> with vertex coordinates as graph nodes.
- Added classes SubdivisionEdge & SubdivisionFace that represent one half-edge and one face of a planar subdivision, respectively.
Tektosyne.Graph: Arbitrary Distance Measure
- Graph types used a concept of distances (i.e. IGraph2D.GetDistance) that was defined as the minimum number of movement steps between graph nodes. This was a historical artifact of the original PolygonGrid implementation of the IGraph2D interface, but it is actually unnecessary for pathfinding and impossible to implement efficiently by non-gridlike graphs, such as Subdivision.
- Therefore, the distance measure is now changed to an arbitrary floating-point value. PolygonGrid continues to count movement steps, but Subdivision uses the Euclidean distance between vertices. Path costs were likewise changed since they are estimated by distances. The invariant still holds that the cost for moving from one node to another cannot be less than the distance between the two nodes.
- Changed types of distances and path costs from Int32 to Double throughout the Graph namespace.
- IGraph2D<T>: Removed GetDistance overload that takes a distance argument. Calculating this node set is difficult and also unnecessary in the general case. PolygonGrid retains this overload since it can offer an efficient and useful implementation.
- Visibility<T>: Renamed parameter maxRange to maxDepth, as it actually limits the recursion depth while scanning for direct neighbors, rather than the distance from the source node. A future release will provide an improved Visibility algorithm with a proper distance limit, and hopefully without the old VisibilityGraph kludge.
Other Changes:
- OrdinalString & NaturalString: Removed useless null comparisons from comparison operators that were apparently left over from a version when these structures had been classes.
- StringUtility: Added generic method ValidateCollection that outputs the string representations for all elements in a collection, or “(null)” and “(empty)” for null references and empty strings, respectively.
- Collections.Int32Dictionary<TValue>: Added methods GetAny, GetAnyKey & GetAnyValue which return one arbitrary element while any are left. This allows using the dictionary as an unordered schedule – a non-prioritized priority queue, if you will.
- Geometry:
- LineD/F/I:
- Added properties Slope & InverseSlope that compute the slope or inverse slope of the line, if possible.
- Added methods FindX & FindY that compute the x- or y-coordinate for a given y- or x-coordinate, respectively, on the line or its infinite extension.
- Fixed inadvertent use of double-precision constants in several LineF/I methods that would cause unnecessary precision elevation of intermediate results.
- PointD/F/I: Added overloaded method AngleBetween that computes the angle between two vectors.
- PolygonGrid:
- Changed to to reflect new IGraph2D<T> semantics.
- GetDistance: Renamed to GetStepDistance, and added new method GetDistance which returns the GetStepDistance result converted to Double.
- Tektosyne.GuiTest: Pathfinding:
- Added overdue test for Flood Fill algorithm.
- Added short description to all tests.
- Added New button to all tests that runs the algorithm on a new random hexagon grid.
Version 5.0.2 (released 2010-05-09)
Graph classes now take a generic type argument for the node type.
- Changed graph nodes from PointI coordinates to arbitrary generic type T, allowing node types that cannot easily be mapped to PointI coordinates.
- Removed conversion of graph nodes to unique indices, and changed internal node storage from indexed arrays to hashtables, allowing node types that cannot easily be mapped to unique indices.
- Graph:
- IPlanarGraph: Renamed to IGraph2D since we break everything anyway!
- IPlanarAgent & IPlanarPath: Renamed to IGraphAgent & IGraphPath, respectively, since these interfaces never reference IGraph2D’s two-dimensional world coordinates.
- Change term “Location” to “Node” in all method & property names that refer to IGraph2D nodes.
- IGraph2D<T>:
- Removed obsolete members Locations & IndexOfLocation.
- Contains: Replaced all overloads with the single method Contains(T).
- GetNeighbors: Changed return type from List<PointI> to IList<T>.
- GraphToWorld: Renamed to GetWorldCenter.
- WorldNodeRadius: Changed to method GetWorldRadius that takes a node argument.
- AStar, Coverage, FloodFill, Visibility:
- Changed internal node collections from indexed arrays to hashtables. These are somewhat slower, but also reduce memory consumption since we no longer pre-allocate arrays for the entire graph.
- Other internal collections are likewise no longer pre-allocated to maximum capacity, so as to maximize memory savings with the transition to hashtables.
- Geometry:
- PolygonGrid:
- Now implements IGraph2D<PointI> with graph nodes that represent grid coordinates, just as before. The public interface is nearly unchanged, except as noted below.
- Changed GraphToWorld & WorldNodeRadius to GetWorldCenter & GetWorldRadius, respectively, and removed Locations & IndexOfLocation, in conformance with new IGraph2D<T> interface.
Version 5.0.1 (released 2010-05-02)
- Geometry:
- GeoUtility.AreCollinear & Area2: Moved to PointD/F/I as instance methods IsCollinear & CrossProductLength.
- PointD/F/I.CrossProductLength: Added overload that takes a single PointD parameter and assumes that the two vectors share the origin.
- LineD:
- Contains: Moved to LineIntersection for use with new Find method.
- Intersect: Now forwards to new method LineIntersection.Find.
- LineF/I: Added methods Intersect, Locate & LocateCollinear which were already present in LineD.
- LineIntersection:
- Added static overloaded method Find which implements LineD.Intersect but takes four explicit PointD parameters for the line segments. Since the algorithm operates on start & end points anyway, this allows efficient forwarding from all three Line structures.
- Added static overloaded method LocateCollinear which is identical to LineD.LocateCollinear but takes two explicit PointD parameters for the line segment, for efficient use with Find.
Version 5.0.0 (released 2010-04-30)
Upgraded solution to Microsoft .NET Framework 4.0 Client Profile and Microsoft Visual Studio 2010. This involved the following changes:
- Removed assembly-level declarative security attributes, as .NET 4.0 has obsoleted this CAS feature.
- Fixed many parameter tags in XML comments, as the C# 4 compiler checks them much more thoroughly.
- Pair<T1, T2> & Triplet<T1, T2, T3>:
- Redesigned as an equivalent but lightweight alternative to the new System.Tuple class.
- Renamed to ValueTuple<T1, T2> & ValueTuple<T1, T2, T3>, and added structure ValueTuple<T1, T2, T3, T4>.
- First, Second & Third: Changed to public read-only fields Item1, Item2 & Item3.
- ToString: Simplified output to “(Item1, Item2, Item3, Item4)”.
- Added static class ValueTuple with Create methods that can infer the required generic type arguments.
- StringUtility.Join: Removed both overloads, which are obsoleted by equivalent String.Join overloads.
- Windows.TaskEvents.RestartTimer: Removed parameterless overload, which is obsoleted by Stopwatch.Restart.
Tektosyne.Geometry: Geometric Primitives
- Points, sizes, and rectangles used to be represented as a hodge-podge of BCL types from the System.Drawing & System.Windows namespaces, with
using directives smoothing over their inconsistent naming.
- For all purposes not directly related to GDI or WPF output, these types have now been replaced by a set of immutable structures with consistent naming, functionality, and convertibility.
- The naming scheme follows the one established by the
using directives in previous releases, except that double-precision variants receive a “D” suffix, both for consistency and to avoid a naming clash with the equivalent System.Windows types.
- Added structures PointD/F/I, SizeD/F/I, and RectD/F/I that represent points, sizes, and rectangles based on Double, Single, and Int32 components, respectively.
- LineD/F/I:
- Renamed structure Line to LineD in conformance with new naming scheme.
- ToLineI & LineI(LineD/F): Changed to truncating cast in conformance with BCL types.
- Added method Round that rounds coordinates to nearest Int32 values.
- Added property LengthSquared that computes the squared absolute length, avoiding the final Math.Sqrt operation of the Length property if you only need the squared value anyway.
- Removed redundant property Degrees. Use the new Angle class to convert from radians.
- PointD/F/I combine the functionality of the WPF Point and Vector types. The WPF Vector type contains exactly the same data as the WPF Point type, and serves no apparent purpose except to annoy developers who cannot simply add two Points without converting one to a Vector first.
- PointD/F/I and SizeD/F/I each offer addition & subtraction with other instances of the same type only. I believe these operations should be symmetrical, and I never found much use for the Point-Size operations defined by the GDI types.
- RectD/F use the same geometric inclusion model as the WPF Rect type, i.e. Right/Bottom are considered part of the rectangle. RectI uses the same index inclusion model as the GDI Rectangle type, i.e. Right/Bottom are not considered part of the rectangle. Unifying the inclusion models would have been nice, but too much existing code expects that Int32-based rectangles follow the GDI Rectangle behavior.
- Added static classes GdiConversion & WpfConversion that convert between the new geometric primitives and the equivalent BCL structures in System.Drawing & System.Windows, respectively.
- Removed static class GeoUtility. The conversion methods were moved to GdiConversion & WpfConversion, and the other methods to the corresponding geometric primitives.
Other Changes:
- Changed more properties to public fields where the property wrapper was obviously pointless.
- Change GetHashCode algorithms from (x * 37 + y) to (x ^ y), using bit shifts if necessary, and inlined GetHashCode calls for geometric primitives.
- Replaced unhelpful descriptions of construction parameters (“The initial value for the Foo property”) with more helpful semantic descriptions.
- ThrowHelper: Marked all methods as [MethodImpl(MethodImplOptions.NoInlining)] to aid JIT compiler inlining.
- Collections: Documented the fact that all SyncRoot properties return the same object for a read-only wrapper as for the underlying writable collection. This is actually the reason why SyncRoot is public in the first place, but I had forgotten to state it explicitly.
- Geometry:
- Moved all graph-related classes & interfaces to new namespace Tektosyne.Graph. This includes AStar, Coverage, FloodFill, PathNode, Visibility, IPlanarAgent, IPlanarGraph, and IPlanarPath.
- Added static class Angle with constants & methods to manipulate angles in radians and degrees.
- MultiLinePoint, VoronoiEdge & VoronoiResult: Lowered constructor visibility to internal.
- Windows.WindowsUtility.ScrollStep: Added overload that takes separate width & height parameters instead of a Size instance.
- Tektosyne.GuiTest: Benchmark:
- The x64 JIT compiler’s optimizations have changed in .NET 4.0, and usually for the better.
- The standard class SortedDictionary<TKey, TValue> (= binary search tree with red-black balancing) is nearly twice as fast as in .NET 3.5 SP1.
- Collections.Sorting: Performance of all custom sorting algorithms is greatly improved, and QuickSort is now nearly as fast as the standard Array.Sort.
- Sorting test: Changed item count from 10–120 to 20–240 in steps of 20, compensating for better performance.
- Geometry & Intersection tests: Increased maximum item count from 100 to 120, compensating for better performance.
- Dictionary test: Increased item count from 40,000 to 60,000 and iterations from 20 to 100. This required removing SortedList from the test cases, as this class is far slower than the others.
- Range Tree test: Increased item count from 40,000 to 60,000 so that results remain comparable with Dictionary test.
- Tektosyne.UnitTest: Updated NUnit version to 2.5.5.
Version 4.5.0 (released 2010-04-12)
Global Optimizations:
- The following observations apply to x64 code generated by .NET 3.5 SP1. The x86 JIT compiler and other .NET versions have different performance profiles.
- Popular wisdom claims that trivial property accessors perform as well as fields, thanks to JIT inlining, but benchmarking showed that search speed in BraidedTree<TValue> and Int32Dictionary<TValue> nearly doubled when trivial properties were replaced with fields. The reason is not quite clear. Possibly the JIT compiler stops inlining even trivial accessors under certain conditions, or possibly it can apply more aggressive optimizations when not distracted by inlining. Either way, this speedup is too big to ignore, so I rolled back property use throughout the library.
- Among other optimizations, I also manually inlined trivial error checking methods. This resulted in another significant speedup for collection classes, and here the blame falls squarely on JIT inlining failure.
- Resulting performance gains over previous release: BraidedTree<Int32, TValue> 40-95%; MultiLineIntersection.Find 40-50% for constant and linear output and 15% for quadratic output, FindSimple 20% for quadratic output; minor gains elsewhere.
- Replaced all performance-sensitive public read-only instance properties that are only set during construction with public read-only fields. Note that read-only static members were already implemented as public read-only fields, even in the BCL, so it’s not a big stretch.
- Replaced all automatic properties with field-backed properties, raised all performance-sensitive backing fields to internal visibility, and changed internal property accesses to field accesses where possible.
- Manually inlined all parameterless CheckWritable & CheckDictionary methods, and inline-checked all values against IKeyedValue<TKey> before calling CollectionsUtility.ValidateKey.
- Added attribute [StructLayout(LayoutKind.Auto)] to complex structures that are not intended for interoperation with unmanaged code. C# forces sequential layout by default which is quite useless in managed code, and might hurt performance.
- Changed all uses of Object.Equals with generic type arguments to EqualityComparer<T>.Default.Equals which is much faster for value types. This affects Pair<T1, T2>, Triplet<T1, T2, T3>, BraidedTree<TKey, TValue>’s value search, and various CollectionsUtility methods.
Other Changes:
- Class Reference: Suppressed documentation of internal types & members, as there were too many of them lately.
- Removed [NonSerialized] attribute from static fields (such as Empty) since those never get serialized anyway.
- MathUtility: Added overloaded method IsPrime that determines whether a given Int32 or UInt32 number is prime.
- Collections:
- Added static class ComparerCache<T> which caches the Comparer<T>.Default & EqualityComparer<T>.Default properties for the generic type argument. These properties already provide their own caching, but their getters are still very slow.
- Added class Int32Dictionary<TValue> that provides a specialized DictionaryEx<TKey, TValue> for Int32 keys, increasing key search speed by 60-90%.
- Changed property IsSynchronized to explicit interface implementation on all collection classes. This particular property is so useless that it should remain hidden.
- ArrayEx<T>.CopyFrom: Added missing check for IsReadOnly.
- BraidedTree<TKey, TValue>, KeyValueList<TKey, TValue> & QuadTree<TValue>: Revised CopyTo methods. The previous implementations were correct, but stylistically terrible due to mindless copying & pasting…
- DictionaryEx<TKey, TValue>:
- Clone & Copy: Clarified that the enumeration order is not preserved, as elements may be inserted in a different order.
- Equals: Changed to test for identical elements regardless of enumeration order, as hashtables do not define any fixed ordering.
- KeyValueList<TKey, TValue>:
- Documentation now correctly states that IsUnique checks for unique key-and-value pair, not unique keys.
- Add: Added missing check for null key and validation against IKeyedValue<TKey>.
- QuadTree<TValue>.Nodes: Changed type from DictionaryEx<TKey, TValue> to Int32Dictionary<TValue> for a rather minor speedup.
- QuadTreeNode<TValue>.Signature: Changed type from UInt32 to Int32. The value itself is still unsigned, but this change makes the class CLS-compliant.
- Geometry:
- Added [Serializable] attribute to all remaining types where it makes sense.
- AStar, Coverage, FloodFill & Visibility: Locations properties now return a read-only ListEx<PointI>.
- Line/F/I:
- Changed to immutable structures, i.e. Start & End are now read-only fields.
- Added methods ToLineF/I that convert a Line/F to a LineF/I, just like the explicit conversion operators.
- Removed conversions to & from equivalent Rect/F/I strucures. While lossless, these conversions were also useless since any Line coordinate might end up in any of the four corners of a Rect…
- Size: Renamed to Vector and changed type to Point/F/I instead of SizeF/I or System.Windows.Vector. Tektosyne no longer uses the latter type except for WPF output.
- PathNode: Lowered visibility of constructor and writable fields to internal, and entirely removed public access to Next pointer.
- Xml.XmlUtility: Added generic methods Serialize<T> & Deserialize<T> that convert a serializable object to & from its formatted XML representation, using the NetDataContractSerializer class.
- Tektosyne.GuiTest: Benchmark:
- Dictionary test: Added column for new class Int32Dictionary<TValue>.
- Tektosyne.UnitTest:
- Greatly improved coverage of error cases for collection classes.
- ArrayExTest & ListExTest: Integrated read-only & unique element test suites with regular test suites.
- Replaced most methods carrying the [ExpectedException] attribute with inlined Assert.Throws<T> calls.
Version 4.4.3 (released 2010-04-04)
- Collections.QuadTree<TValue>:
- Added constant ProbeLevel that determines when FindNode(Point) switches to the depth probe algorithm.
- MaxDepth: Renamed to MaxLevel which more accurately reflects its semantics.
- FindNode(Point): Clarified that depth probe starts at level log4 m, where m is Nodes.Count, when m reaches 4^ProbeLevel.
- Tektosyne.GuiTest: Benchmark:
- Range Tree test: Range search covers a greater range and shows iteration count & relative range.
Version 4.4.2 (released 2010-04-02)
- Collections:
- Added generic class ComparerAdapter<T> that wraps a given Comparison<T> method in the IComparer & IComparer<T> interfaces, for compatibility with those annoying old BCL classes that use object-oriented instead of functional composition.
- Added generic classes QuadTree<TValue> & QuadTreeNode<TValue> that provide a quadrant tree with Point keys and multiple elements per node. Searching & enumeration are accelerated by an additional hashtable that finds nodes by their position within the tree structure.
- BraidedTree<TKey, TValue>:
- Now implements non-generic interface ICollection instead of IDictionary. The latter wouldn’t actually work as there was no IDictionaryEnumerator implementation. This is a weird old .NET 1.0 artifact that is incompatible with IEnumerator and cannot be implemented with C# yield statements.
- Added overloaded method FindRange that returns all elements whose keys fall within a specified range, and that optionally meet an additional condition.
- FindNodeOrPrevious: Fixed documentation to correctly state that the result is RootNode rather than a null reference if there is no node before the specified key.
- KeyValueList<TKey, TValue>: Now implements generic interface IDictionary<TKey, TValue> (but not the non-generic IDictionary interface, see above).
- Sorting:
- Added overloaded method BinarySearch<T> that performs a binary search over an arbitrary sorted IList<T>, with or without a custom Comparison<T> method.
- Added overloaded method BestBinarySearch<T> that calls the BinarySearch<T> method of the Array or List(Ex)<T> classes for such arguments, and the new BinarySearch<T> method otherwise.
- When the search value is not found, the new methods don’t simply return -1, but rather the bitwise complement of the collection index of the first element that is greater than the search value, just like the Array and List(Ex)<T> methods. This allows efficient range searching in IList<T> collections.
- Tektosyne.GuiTest: Benchmark:
- Added Range Tree test that compares the new QuadTree<TValue> class to a BraidedTree<TKey, TValue> with Point keys.
- Changed Dictionary test from 100 x 10,000 keys to 10 x 40,000 keys so that the results can be directly compared with the Range Tree test.
Version 4.4.1 (released 2010-03-20)
- MersenneTwister.Default: Added warning that static instance is not thread-safe because any Next call changes its internal state.
- Collections:
- BraidedTree<TKey, TValue>:
- FindNode(TValue): Renamed to FindNodeByValue to avoid ambiguity when TKey and TValue are the same type.
- RemoveNode: Throws an exception if the specified node belongs to a different tree structure, or to none at all. Null references or the current RootNode still result in silent failure.
- BraidedTreeNode<TKey, TValue>:
- Constructors: Added BraidedTree<TKey, TValue> parameter that initializes the new Tree property.
- Removed unnecessary constructor that took a key but no value.
- Added Tree property that stores the containing BraidedTree<TKey, TValue>. This property is set upon construction and remains unchanged until the node is removed from its tree, at which point it is permanently reset to a null reference.
- Geometry:
- Added static class MultiLineIntersection that provides two algorithms for calculating all intersections between a given set of line segments: a brute force algorithm and Bentley & Ottmann’s sweep line algorithm. Both variants are necessary because the sweep line algorithm’s worst case is much slower than the brute force algorithm. Moreover, only the brute force algorithm supports epsilon comparisons.
- Added structure MultiLinePoint that holds one intersection point found by either MultiLineIntersection algorithm.
- Line:
- Intersect:
- Changed to return the lexicographically first intersection point, according to PointComparer, if the two line segments partially or entirely overlap. This ensures deterministic results for any two line segments, regardless of their orientation.
- Adjusted epsilon overload so that intersection detection and collinear classification no longer depends on Line lengths, as long as the two line segments are of roughly equal length.
- Locate: Adjusted epsilon overload so that collinear classification no longer depends on Line length.
- Locate & LocateCollinear: Replaced Vector arithmetic with double variables for a slight speedup.
- Tektosyne.GuiTest:
- Benchmark: Added Intersection test that compares the brute force and sweep line algorithms of the new MultiLineIntersection class.
- Geometry: Added Intersection dialog to demonstrate the brute force algorithm of the new MultiLineIntersection class with a variable comparison epsilon.
Version 4.4.0 (released 2010-03-04)
- Collections:
- Added generic classes BraidedTree<TKey, TValue> and BraidedTreeNode<TKey, TValue> that provide a “braided” search tree, i.e. a binary search tree whose nodes are connected with a doubly linked list along the sorting order.
- MathUtility & Geometry.GeoUtility:
- Removed epsilon checks from all Compare & Equals overloads.
- Removed all CompareUnchecked & EqualsUnchecked overloads, as they are now obsolete.
- Checking epsilons in basic comparison methods was one of those well-intentioned ideas that didn’t work out too well. The unchecked versions are much faster, so you’d only ever call a checked version once at the start of a complex algorithm. Well, it’s easier to just test for a positive epsilon directly…
- Geometry:
- Added class PointComparer that establishes a lexicographic ordering for Point instances, either with exact or epsilon comparisons. The actual comparison methods are static, so instantiating the PointComparer is optional.
- GeoAlgorithms.Compare: Moved to new class PointComparer and renamed to LexiCompare, due to name clash with interface methods.
- Tektosyne.GuiTest: Benchmark:
- Added Dictionary test for adding, iterating, searching & removing elements in BraidedTree<TKey, TValue> and several BCL classes: Dictionary<TKey, TValue> (= hashtable), SortedDictionary<TKey, TValue> (= red-black tree), and SortedList<TKey, TValue>.
- Geometry: Fixed times reported for Line Intersection & Point in Polygon. As it turns out, the high-precision timer is too imprecise to measure individual calls to these methods. Rounding errors accumulated in each iteration, resulting in times that were far too high. The tests now measure entire loop bodies and then divide results by iteration counts.
- Geometry & Sorting: Input arrays now start with 10 elements. Smaller sizes were meaningless due to timer rounding errors. Sorting times now include copying the test array, as the required time is negligible at the measured array sizes.
Version 4.3.3 (released 2010-02-23)
- Geometry:
- GeoAlgorithms: Added overloaded method Compare that establishes a lexicographic ordering for Point instances, either with exact or epsilon comparisons.
- GeoUtility:
- Added Equals & EqualsUnchecked overloads for Line, LineF, Rect, RectF, Size & SizeF.
- Equals(Point) & Equals(PointF): Replaced second MathUtility.Compare call with CompareUnchecked for a slight speedup.
- Line:
- Added static method Contains that tests a specified LineLocation value for Start, Between, or End.
- Added overloaded methods Locate & LocateCollinear that determine the location of a specified point relative to the Line, either with exact or epsilon comparisons.
- Removed overloaded methods Contains, ContainsUnchecked, IsLeft & IsLeftOrOn which are now special cases of Locate.
- LineLocation: Added enumeration values Left & Right to cover non-collinear points detected by Line.Locate.
Version 4.3.2 (released 2010-02-17)
- Geometry:
- Added enumerations LineLocation & LineRelation for new LineIntersection structure.
- LineIntersection: Changed to structure that holds all results for revised Line.Intersect method.
- Line.Intersect: Revised to return LineIntersection instance with additional result data, including the external intersection point of lines that do not touch, as in the original O’Rourke implementation.
- Line, LineF & LineI: Added method Reverse that reverses the Start & End points.
Version 4.3.1 (released 2010-02-12)
- Geometry:
- Added enumeration LineIntersection that specifies the possible types of intersection between two lines.
- GeoAlgorithms:
- Added method Area2 that calculates twice the area of a specified triangle.
- Added overloaded method AreCollinear that determines whether three specified points are collinear, either with exact or epsilon comparisons.
- Added methods RandomLine & RandomPoint that create a random Line or Point, respectively, within a specified area.
- CreateRandomPolygon: Shortened name to RandomPolygon since GeoAlgorithms generally don’t use verb prefixes.
- Line, LineF & LineI: Clarified that these structures represent (finite) line segments rather than (infinite) lines.
- Line:
- Added methods Contains & ContainsUnchecked that determine whether the Line contains a specified point.
- Added methods IsLeft & IsLeftOrOn that determine whether a specified point is to the left of, or directly on, the infinite extension of the Line.
- Added method Intersect that determines if and where two Line instances intersect.
- All new methods are overloaded for exact and epsilon comparisons.
Version 4.3.0 (released 2010-02-04)
- MathUtility:
- Compare: Added missing overload description to Class Reference.
- Added overloaded method CompareUnchecked which is identical to Compare but does not check the specified epsilon.
- Geometry:
- GeometryUtility:
- Shortened class name to GeoUtility.
- Moved methods CreateRandomPolygon & PointInPolygon to new static class GeoAlgorithms.
- Added overloaded methods Equals & EqualsUnchecked that compare two Point or PointF instances, given a specified epsilon.
- GeoAlgorithms:
- Added method ConvexHull that determines the convex hull for a given set of points, using Graham’s scan.
- Changed PointInPolygon overload with epsilon comparisons to use CompareUnchecked, for a speedup of about 50%.
- Changed PointInPolygon overload with exact comparisons to separate implementation, for a further speedup of 200%.
- Added class Voronoi that finds Voronoi diagrams and Delaunay triangulations, using Fortune’s sweep line algorithm.
- Added class VoronoiResults and structure VoronoiEdge that hold the results of the Voronoi algorithm.
- Tektosyne.GuiTest:
- File: Added Benchmark Tests dialog to test running time of sorting & geometric algorithms.
- Geometry:
- Added Convex Hull dialog to test the ConvexHull algorithm with random point sets.
- Addec Voronoi & Delaunay dialog to test the Voronoi algorithm with random point sets.
- Both dialogs feature Copy & Paste buttons to copy the current point set to the Windows clipboard (in XML format) and to process the point set currently stored in the clipboard, respectively.
- Tektosyne.UnitTest: Updated NUnit version to 2.5.3.
Version 4.2.0 (released 2009-12-12)
- MathUtility: Removed Compare overloads without specified epsilons. The assumed values were Double.Epsilon or Single.Epsilon, respectively, but since those are the smallest representable differences, the result was simply an exact comparison. We can already do that much more efficiently without utility methods, so both overloads were redundant.
- MersenneTwister: Added static read-only field Default containing a default-constructed instance. Applications that use MersenneTwister typically create such a shared instance anyway.
- Geometry:
- Added enumeration PolygonLocation that specifies the location of a point relative to an arbitrary polygon.
- GeometryUtility:
- Added method CreateRandomPolygon that creates a random arbitrary simple polygon within a specified area.
- Added method PointInPolygon that determines the PolygonLocation for a given point and polygon.
- Polygon: Renamed to RegularPolygon since new Geometry methods operate on arbitrary polygons which don’t use this class.
- Tektosyne.GuiTest: Geometry:
- Added Point in Polygon dialog to test the PointInPolygon algorithm with random polygons.
- Polygon: Renamed to Regular Polygon, and fixed non-inflated polygon not being drawn.
Version 4.1.9 (released 2009-08-30)
- Windows.MessageDialog: Automatically resizes to primary message, like a standard MessageBox, but not to secondary message. This required some tricky coding since WPF normally resizes a window either to all its contents, or not at all.
Version 4.1.8 (released 2009-07-16)
- StringUtility.PackSpace: Changed to use static Regex.Replace method instead of Regex instance.
- Xml.XmlUtility.ReadAttributeAsEnum<T>:
- Removed obsolete non-generic overload.
- Multiple constant names for bit field enumerations may be separated merely by whitespace, without the preceding comma required by Enum.Parse. This allows reading bit field enums that were serialized to the XML Schema type xsd:list.
- Tektosyne.UnitTest: Updated NUnit version to 2.5.1.
Version 4.1.7 (released 2009-06-27)
- Windows.BitmapUtility.Read & Win32Api.SafeMemoryHandle.Get/SetMemory: Changed to unsafe and fixed arithmetic overflows on 64-bit systems. These methods had cast IntPtr addresses to Int32 values which caused occasional overflows on 64-bit systems. The fix was to cast the addresses to byte* instead, which is always the correct size but requires that the methods are marked as unsafe.
Version 4.1.6 (released 2009-06-21)
- Fortran: Added Int16 overloads for methods Min, Max, and Sum (but not for Modulo because its intermediate calculations produce Int32 values).
- MathUtility: Added extension method Restrict that restricts a number to a specified range, with overloads for all common numeric types.
- Windows:
- Added immutable structure ColorVector that represents a displacement in sRGB color space.
- BitmapUtility: Added methods Shift & ShiftPbgra32 that shift the color channels of a locked WriteableBitmap or PBGRA32 color value, respectively.
- Xml.XmlUtility: Added overloads ReadAttributeAsInt16 & ReadAttributeAsInt64.
Version 4.1.5 (released 2009-05-25)
- Class Reference: Updated to Sandcastle Help File Builder version 1.8.0.1 which fixed the missing
this qualifier for extension methods.
- Collections:
- Added generic class ArrayEx<T> that provides an array with arbitrary rank, one-dimensional indexing regardless of rank, and a read-only wrapper of the same public type.
- Replaced protected backer fields ReadOnlyFlag & UniqueFlag with protected property setters in all applicable classes.
- Geometry.PolygonGrid:
- Added generic method CreateArrayEx<T> that returns an ArrayEx<T> instead of a standard Array.
- CreateArray: Accepts generic type parameter instead of explicit Type object, and returns typed two-dimensional array instead of untyped Array object.
- Removed obsolete method CreateBooleanArray – use new method CreateArray<T> instead.
Version 4.1.4 (released 2009-05-17)
- Publish.proj: Changed archiver for distribution package from Info-ZIP to 7-Zip.
- Tektosyne.UnitTest: Updated NUnit version to 2.4.8.
Version 4.1.3 (released 2009-02-13)
- Changed AssemblyVersion back to AssemblyFileVersion since WPF cannot handle auto-incremented build numbers. XAML requires two compilation passes between which an auto-incremented build number may increase, resulting in version mismatches and .NET load errors for signed assemblies.
- Removed all unspecific thread safety warnings on static classes, as they were self-evident and not consistently applied.
- Marked all static Empty fields of serializable types as non-serialized.
- Collections: Changed all static Empty properties to static read-only fields, which are fully thread-safe due to static initialization.
- Windows.WindowsUtility.SelectItem: Renamed to SelectAndShow, changed to accept null items, and added overload that accepts item index.
Version 4.1.2 (released 2009-02-08)
- Windows: Removed class AnimationWorker which was merely an elaborate hack, now superseded by the much simpler WindowsUtility.DoEvents hack for the same purpose.
Version 4.1.1 (released 2009-01-17)
- Windows.WindowsUtility:
- Added generic method FindVisualParent<T> that searches a visual tree for the nearest parent of the specified type.
- FindListItem: Renamed to FindParentListItem. The functionality is unchanged but the method now simply forwards to FindVisualParent<ListBoxItem>.
Version 4.1.0 (released 2009-01-11)
- Added explicit CultureInfo.CurrentCulture argument to all String.Format and ToString calls that generate display output.
- Changed all named XAML elements to private visibility, reducing the number of undesired entries in the Class Reference. Contrary to the MSDN Library documentation, “private” is actually a valid value for the
x:FieldModifier attribute.
- Added static class ThrowHelper for throwing common exceptions.
- Explicit
throw statements translate into ca. 30-60 extra bytes of machine code that are never needed during normal execution, reducing general throughput and discouraging inlining by the JIT compiler. ThrowHelper puts throw statements into separate methods, thus pooling their code in one remote place where it can do no harm.
- Added several Throw… methods for all common exception types and parameters.
- Changed
throw statements throughout the library to ThrowHelper calls where appropriate.
- Collections:
- CollectionsUtility:
- Added extension method Swap that swaps the elements at two specified IList<T> indices.
- Added extension method ConditionalSwap that compares the elements at two specified IList<T> indices, and swaps them only if they are out of order.
- Moved method InsertionSort to new static class Sorting.
- Added static class Sorting containing sorting algorithms that operate on IList<T> collections.
- Added methods HeapSort, QuickSort & ShellSort for the eponymous standard sorting algorithms. ShellSort is stable like InsertionSort but much faster. QuickSort works on any IList<T>, unlike the BCL Sort method. HeapSort is unstable and slow, and was added only for completeness.
- Added method BestQuickSort that runs the fastest available QuickSort implementation, depending on the concrete type of the IList<T> collection. For Array and List(Ex)<T> collections, this is the BCL Sort method which is still faster than the new QuickSort method.
- All algorithms check for less than two elements, and the complex unstable algorithms also check for exactly two or three elements.
Version 4.0.5 (released 2008-12-24)
- BooleanFlag.ValueChanged & ValueSet: Guarded raising of events against asynchronous removal of last event handler.
- Geometry.PolygonGrid.DisplayToGridCore: Guarded debug assertions with comparison epsilons. Since coordinates were changed from float to double, these assertions would get incorrectly triggered by discrepancies in floating-point rounding when running in debug mode.
- Windows:
- BitmapUtility: Added Read overload that accepts two additional flags to request horizontal and/or vertical mirroring of the source bitmap. This lets you perform simple bitmap transformations without the inevitable blurring caused by WPF drawing.
- TaskEvents: Guarded raising of all events against asynchronous removal of last event handler.
- WindowsUtility: Added method DoEvents that processes all queued WPF messages with the risk of reentrancy, just like the eponymous Windows Forms method. As with the AnimationWorker class, I use this method only because WPF does not offer any better options for synchronous display updates.
Version 4.0.4 (released 2008-12-08)
- Added structures NaturalString & OrdinalString that implicitly sort a wrapped string with StringUtility.CompareNatural, i.e. using a natural rather than lexical sorting order. The sorting rules are CurrentCulture and Ordinal, respectively.
- StringUtility:
- CompareNatural, IsRichText, IsValidEmail & PackSpace: Changed to extension methods.
- Added extension method CompareOrdinal that calls CompareNatural with Ordinal sorting rules.
- Validate: Added generic overload that accepts a specified replacement text.
- Geometry:
- Polygon.ToFigure: Froze returned PathFigure to improve performance and prevent changes to the cached object.
- PolygonGrid: Added method DrawOptimized that eliminates duplicate lines. This roughly halves the total number of lines drawn, with corresponding savings in memory consumption and rendering time.
- PolygonGrid.Figures: Froze returned PathFigureCollection to improve performance and prevent changes to the cached object. Since Figures no longer attempts to modify an existing PathFigureCollection that might have been created by another thread, multiple threads may now modify the same PolygonGrid instance without causing a Dispatcher exception.
- Windows:
- Added class AnimationWorker that synchronizes arbitrary operations with WPF rendering updates. This works like the Windows Forms DoEvents call and carries the same risk of reentrancy, but WPF does not appear to offer a better solution to this problem.
- BitmapBuffer & BitmapUtility: Added Overlay overloads that perform color substitution during alpha blending.
- WindowsUtility:
- Added method FindListItem that finds the ListBoxItem (or derived type, i.e. ListViewItem or ComboBoxItem) which contains a specified DependencyObject. Use this method to determine the list item for an embedded control that received an input event.
- Added extension method GetTypeface that creates a WPF control’s current Typeface from its Font properties.
- Tektosyne.GuiTest: Bitmap Overlay Test: Added Color Substitution button to demonstrate the new Overlay overloads.
Version 4.0.3 (released 2008-11-08)
- Added static read-only Empty fields that contain a default-initialized instance to all structs (Pair & Triplet, Geometry.Line/LineF/LineI, Net.MapiAddress).
- Win32Api:
- Added structure MemoryStatusEx for new method Kernel.GlobalMemoryStatusEx.
- Kernel:
- Added method GlobalMemoryStatusEx that returns valid values on 64-bit operating systems, unlike GlobalMemoryStatus.
- Added method MoveMemory (translated to RtlMoveMemory) for fast copying of memory blocks.
- User: Added method GetCursorPos that determines the current screen position of the mouse cursor, unlike System.Windows.Input.Mouse.GetPosition which only determines positions relative to WPF input elements.
- Windows:
- Added class HwndWrapper that wraps a Win32 window handle (HWND) in a Windows Forms IWin32Window interface. This allows using a WPF Window’s handle with a Windows Forms method that expects a Windows Forms IWin32Window instance.
- CustomColorDialog: Added Show overload that takes a WPF Window & Color instead of a Windows Forms IWin32Window & GDI+ Color.
- StackTextBlock:
- Added default constructor to allow use in XAML pages.
- DefaultText: Setting this property correctly sets the Text property when the message stack is empty.
- WindowsUtility:
- Added extension methods ToGdiColor & ToWpfColor that convert between GDI+ and WPF Color values.
- Added method GetVisualDpi that returns the dpi resolution at which a Visual has been rendered.
- Added property ScreenDpi that returns the dpi resolution of the primary desktop.
- Changed method GetMemoryStatus to use GlobalMemoryStatusEx for 64-bit compatibility.
Version 4.0.2 (released 2008-09-15)
- StringUtility.Validate<T>: Added missing <typeparam> tag to XML comment.
- Collections.CollectionsUtility:
- Added missing <typeparam> tags to XML comments of all generic methods.
- Renamed Equals methods to SequenceEqual for conformance with System.Linq.Enumerable.
- Renamed non-generic MoveItem and SequenceEqual overloads to MoveItemUntyped and SequenceEqualUntyped, respectively, since C# cannot resolve overloads for generic and non-generic collections if both types are in scope.
- SequenceEqual(Untyped) overloads for ICollection & ICollection<T> dispose of any created enumerators before returning.
- Added SequenceEqual(Untyped) overloads for IList & IList<T> that use indexers instead of enumerators for element comparison.
- Changed all MoveItem(Untyped) and SequenceEqual(Untyped) overloads to extension methods.
- Geometry.GeometryUtility:
- Added extension methods ToInt32Rect & ToRectI that convert integer-based rectangles between their Int32Rect and RectI representations.
- Added ToRect overload that takes an Int32Rect argument. Amazingly, Microsoft failed to provide a conversion even between these two types that both reside in System.Windows.
- Windows:
- Added enumeration ScrollDirection that had already been part of Tektosyne 3.x.
- BitmapBuffer & BitmapUtility: Changed all Int32Rect arguments to RectI for conformance with our geometric type system.
- WindowsUtility:
- Added method CreateLineFigure that converts a Point array to a PathFigure of connected lines.
- Added extension method ScrollStep that scrolls a ScrollViewer by an arbitrary step size.
Version 4.0.1 (released 2008-09-03)
- Geometry:
- GeometryUtility:
- Added extension method Round with three overloads that convert double-based Point, Size & Rect structures to their integer-based equivalents.
- Added extension methods ToPoint, ToSize & ToRect that convert integer-based Point, Size & Rect structures to their double-based equivalents.
- Polygon.ToFigure: Changed optional offset argument from Point to Vector.
- Windows:
- BitmapBuffer & BitmapUtility: Added method MakeTransparent that changes all opaque pixels of a specified color to transparent black.
- BitmapUtility:
- Added method ColorToOpaquePbgra32 that converts a Color value to its PBGRA32 representation, assuming full opacity.
- Added Grow overload that takes a RenderTargetBitmap instead of a WriteableBitmap.
Version 4.0.0 (released 2008-08-24)
Upgraded solution to Microsoft .NET Framework 3.5 SP1 and Windows Presentation Foundation. This triggered a namespace reorganization:
- Added namespace Geometry for types & algorithms related to geometry and pathfinding.
- Added namespace Windows for types & algorithms related to WPF, including Windows Forms interoperation.
- Removed obsolete namespaces Drawing, Mathematics & WinForms. Drawing and WinForms were focused on the obsolete GDI+ and Windows Forms technologies, respectively, while Mathematics did not reflect a standard namespace and contained too few types after reorganization.
- Moved classes Fortran, MathUtility & MersenneTwister from obsolete namespace Mathematics to namespace Tektosyne.
- Moved abstract geometric types & algorithms from obsolete namespaces Drawing & Mathematics to new namespace Geometry.
- Moved GUI-specific types & algorithms from obsolete namespaces Drawing & WinForms to new namespace Windows.
- Renamed namespace NetMail to Net for conformance with general naming scheme.
Tektosyne:
- Removed obsolete delegate Combination. Use the more versatile System.Func<…> delegates instead.
- Collections:
- Removed obsolete static class Apply. Use the extension methods in class System.Linq.Enumerable instead.
- CollectionsUtility:
- Removed obsolete method CreateList. Use the new collection initializer syntax of C# 3 instead.
- Removed obsolete method ToArray. Use the eponymous extension method in class System.Linq.Enumerable instead.
- Equals: Unchanged. Theoretically obsoleted by System.Linq.Enumerable.SequenceEqual, but that method does not compare the number of elements in each sequence before comparing individual elements. This severely impacts performance when comparing sequences with different sizes but long identical prefixes. See Microsoft Connect Feedback.
- InsertionSort: Changed to extension method of interface IList<T>.
- Added unit tests for Equals<T> and InsertionSort<T>.
- Geometry:
- Please refer to section Geometric Primitives in the ReadMe file regarding our workaround for Microsoft’s chaotic dispersal of geometric types across the BCL.
- Changed all floating-point coordinates to Double or corresponding WPF types (Point, Rect, Size).
- Added class GeometryUtility containing several Circumscribe overloads based on the old Drawing.DrawingUtility.CoverRectangle method.
- Line: Renamed to LineI and added new structure Line using Double coordinates.
- Polygon: Added Draw and ToFigure methods for easy generation of WPF drawings.
- PolygonGrid: Added Draw method and Figures property for easy generation of WPF drawings.
- Windows:
- Added adapter class ContainerVisualHost for hosting a single ContainerVisual (typically DrawingVisual) within a FrameworkElement.
- Added enumeration DefaultTheme and static class DefaultThemeSetter to select a specific WPF default theme at the start of a WPF application.
- FormattingPanel: Changed to class FormatTextBlock (derived from TextBlock) and removed SetWidth methods since WPF controls automatically resize to the required width.
- StatusBarMessagePanel: Changed to class StackTextBlock (derived from TextBlock) and removed visual customization which is now handled in XAML code.
- Added class WindowsUtility containing relevant methods & properties of the old WinForms classes Application & WinFormsUtility.
- Added a superset of the bitmap manipulation functionality offered by the old Drawing.DrawingUtility class.
- Added class BitmapBuffer that caches a bitmap’s pixel data. Prior to .NET 3.5 SP1, the WPF WriteableBitmap class only allowed reading & writing entire pixel blocks. BitmapBuffer exposes a secondary pixel buffer with various helper methods that simplify pixel manipulation.
- Added class BitmapUtility with helper methods for the WPF WriteableBitmap class. This includes manipulating PBGRA32 color values as well as accessing a bitmap’s BackBuffer, a feature that was added by .NET 3.5 SP1. You may use either BitmapBuffer or BitmapUtility for pixel manipulation, depending on whether you want a separate buffer.
- Added several classes intended for Windows Forms interoperation.
- Added Windows Forms class ComponentControl which hosts non-Control components such as ErrorProvider, HelpProvider, and ToolTip.
- Added Windows Forms class NumericUpDownHost (derived from ComponentControl) which hosts one NumericUpDownEx control and forwards all relevant properties. Use this control for hosting NumericUpDown controls in WPF WindowsFormsHost elements.
- Added class WindowsFormsHostEx that shifts input focus to the hosted Windows Forms control, allowing you to reliably activate Windows Forms controls using the keyboard shortcuts of WPF labels.
- Xml.XmlUtility:
- Changed all Move… and Read… methods to extension methods of class XmlReader.
- Renamed all ReadXAttribute methods to ReadAttributeAsX for conformance with the Read(Element)ContentAsX methods of class XmlReader.
Tektosyne.GuiTest:
- Can now run from a shared network drive since .NET 3.5 SP1 extends “Full Trust” permissions to local network shares.
- Removed test dialogs for the obsolete ControlBuilder and RichTextDialog classes.
- Added test dialogs for MapiMail class and for new BitmapBuffer class.
Version 3.4.6 (released 2008-08-21)
- Pair & Triplet: Changed unit tests to match new GetHashCode implementations.
- Collections:
- CollectionsUtility.InsertionSort:
- Allowed null reference for the Comparison<T> argument. This requests the Comparer<T>Default.Compare method.
- Added second overload that implicitly specifies a null reference for the Comparison<T> argument.
- ListEx: Added two remaining overloads of standard method List<T>.CopyTo.
Version 3.4.5 (released 2008-08-08)
- Pair & Triplet: Changed GetHashCode to take all properties into account.
- IO.RootedPath: Changed GetHashCode to take both RootFolder and AbsolutePath into account.
- NetMail:
- Added structure MapiAddress holding the display name and e-mail address of the sender or recipient of a Simple MAPI message.
- MapiMail: Changed all KeyValuePair<String, String> arguments to the new MapiAddress structure.
Version 3.4.4 (released 2008-07-25)
- Added immutable generic structures Pair & Triplet to store two or three arbitrary values, respectively.
- StringUtility: Added generic Validate overload for culture-invariant formatting of arbitrary objects.
- WinForms.NumericUpDownEx: Added protected method OnLostFocus that correctly resets to Minimum when focus is lost while entry field does not contain a valid Decimal number.
Version 3.4.3 (released 2008-06-10)
Upgraded source code to Visual Studio 2008. The binaries still target .NET 2.0.
- Replaced NAnt.build with Publish.proj for MSBuild. This script only builds the distribution package; use MSBuild on Tektosyne.sln or Tektosyne.csproj to perform unsigned builds from the command line.
- Tektosyne.csproj: Removed SearchReplace.cs and corresponding pre-build event since VS2008 can generate resource properties with public access level.
- Tektosyne.GuiTest:
- Replaced separate application manifest file with embedded “app.manifest” standard file.
- Replaced Common Controls dependency in manifest file with Application.EnableVisualStyles call.
- Tektosyne.UnitTest:
- Updated NUnit version to 2.4.7.
- Changed NUnit output file when run within VS2008 to TestResult.xml in the Tektosyne root directory.
Version 3.4.2 (released 2008-06-02)
- Tektosyne.csproj: Added missing quotes around command name and first argument in prebuild event. This should finally allow Tektosyne to compile in directories containing spaces, including folders under “My Documents”. Thanks to Pat O’Hara for solving this mystery!
- Collections: Added static property Empty to all collections that provide a read-only wrapper, returning an empty immutable collection that is created on access and cached for repeated access. Clients can use these collections instead of null references to indicate an empty result set.
Version 3.4.1 (released 2008-04-28)
- Strings: Added several new error messages.
- DetailException.Message: Changed default value to system-supplied localized description.
- WinForms.MessageDialog.Show: When showing exception data, the secondary message area now displays the exception’s Message text, then its Detail text if any, and then its full string representation.
Version 3.4.0 (released 2008-03-21)
- Added attribute [DebuggerStepThrough] to all trivial property getters & setters to simplify debugging.
- StringUtility: Added method CompareNatural that performs a “natural” string comparison. This method breaks strings into sequences of decimal digits and other characters, and sorts the former by their numeric values.
- Drawing.PolygonGrid:
- Added properties VisibilityGraph and WorldNodeRadius required by IPlanarGraph interface. VisibilityGraph is backed by a new InstanceData field which is only recreated when the Element property changes.
- Removed properties AStar and Coverage. Pathfinding algorithms don’t logically belong in this class, and things got too complicated with the two new algorithms.
- Mathematics:
- Added class FloodFill that determines all adjacent locations in an IPlanarGraph for which a specified predicate succeeds. This is essentially a simpler version of the Coverage algorithm that ignores path costs and does not require the caller to supply an IPlanarAgent.
- Added class Visibility that determines all locations in an IPlanarGraph which are visible from a specified location, using a specified predicate for opacity. This is a line-of-sight algorithm based on trigonometric calculations that consider the world coordinates of each location.
- AStar & Coverage: Added implicit support for moving agents that distinguish between temporary and permanent occupation of a graph node. AStar support for such agents is not perfect – please see the Class Reference for details.
- IPlanarAgent: Breaking Semantic Changes
- CanMakeStep: Should only test for temporary residence (during a movement) and never call CanOccupy.
- CanOccupy: Should only test for permanent residence (at the end of a movement) and return true by default.
- Removed obsolete property PartialOccupation. The distinction between temporary and permanent residence is now implicit by having CanOccupy return false under certain conditions.
- IPlanarGraph:
- Added property VisibilityGraph to provide a graph variant that is guaranteed to work with line-of-sight algorithms, regardless of the original graph’s concept of neighboring locations.
- Added property WorldNodeRadius to allow line-of-sight algorithms to determine which locations might obscure each other.
- WinForms.MessageDialog & RichTextDialog: Changed to resizable dialog border when a text box is created. The dialog’s minimum size is its creation size, and the text box grows as the dialog is resized.
- WinForms.ListViewColumnSorter:
- Added boolean property NaturalSort that requests StringUtility.CompareNatural instead of String.Compare for lexical sorting.
- Added enumeration property StringComparison that specifies options for lexical sorting, whether standard or natural.
- WinForms.NumericUpDownEx:
- FormatValue: Fixed crash when attempting to use Hexadecimal format.
- IsTextValid: Changed implementation to use TryParse instead of exceptions.
- Tektosyne.GuiTest:
- Added “trustInfo” element to manifest file. Supposedly this makes Vista happy if you have UAC enabled (I don’t).
- Added menu item Mathematics: Visibility to test the new Visibility algorithm on a random graph. Black hexagons are considered opaque, all others transparent. Squares indicate the hexagons visible from the central hexagon.
- Drawing: Save & Print Grid: Fixed Print Grid button not working on 64-bit Windows. Turned out that the Windows Forms class PrintDialog has a property called UseEXDialog that must be manually set to
true, or else the dialog won’t work at all!
Version 3.3.3 (released 2007-08-19)
- Collections: Fixed XML documentation of all Keys/Values properties.
- Drawing.Line/LineF: Fixed format error in ToString methods.
- WinForms: Fixed XML documentation of Application.MemoryStatus and MenuItemEx.IsEnabled properties.
Version 3.3.2a (released 2007-05-25)
Compatibility fixes only, no functional changes.
- Tektosyne appears to work fine on Windows Vista. The ReadMe file was updated accordingly.
- Changed manifest file for
Tektosyne.GuiTest to reference the 64-bit version of the Common Controls library when running on 64-bit Windows. Previously, trying to run this application on 64-bit Windows would generate a meaningless error message.
- Added notes regarding very long path names and Visual C# Express to the ReadMe file. Janis Bridges originally reported these issues for Hexkit, but I figured they might affect Tektosyne users as well. (Update: The problem wasn’t very long paths but paths containing spaces, see version 3.4.2)
Version 3.3.2 (released 2007-04-30)
- Updated NAnt.build for NAnt 0.85 final.
- Updated Visual Studio solution and NAnt.build for NUnit 2.4.0 final.
- Added NUnit assembly
nunit.framework.dll to the Tektosyne distribution since this is apparently the only way to reliably reference this assembly.
Version 3.3.1 (released 2007-04-05)
- Collections.DictionaryEx/SortedDictionaryEx/SortedListEx:
- Added AddRange method, as in List/ListEx and derived classes.
- Constructors that take an IDictionary argument check for key mismatches on IKeyedValue values.
- Drawing.PolygonGrid.DisplayToGridClipped: Added final check for valid grid coordinates. This catches invalid return values for grids that are one element wide and/or high.
- WinForms.BitmapPanel: Fixed nonfunctional scrollbars by hacking around a bug in .NET 2.0.
Version 3.3.0 (released 2006-11-05)
- Prefixed all Utility classes with their enclosing namespace for disambiguation.
- Mathematics: Added new A* option to eliminate zero-cost oscillations.
- AStar: Added pathfinding option UseWorldDistance that prefers path nodes with a minimal world distance from the target location, given equal path costs.
- IPlanarGraph and Drawing.PolygonGrid: Added method GraphToWorld as a generalized wrapper for PolygonGrid.GridToDisplay.
- WinForms: Automated the creation of standard components.
- ContainerForm: Added properties ErrorProvider, HelpProvider, and ToolTip with on-demand creation and automatic disposal of these components.
- NumericUpDownEx: Added method UpdateToolTip to manually refresh the tool tip message when the Minimum or Maximum values change after a ToolTip component has been assigned.
- Templates.FormTemplate: CreateControl returns a ContainerForm instead of a Form.
- Templates.NumericUpDownTemplate: SetProperties automatically sets ErrorProvider and ToolTip to the corresponding components of the nearest ContainerForm parent.
- Xml.XmlUtility: Added typesafe generic overload for ReadEnumAttribute.
Version 3.2.2 (released 2006-10-08)
- Drawing.PolygonGrid:
- Added static method AreCompatible to check a given Polygon and PolygonGridShift value for compatibility within the same PolygonGrid.
- Element: Setting this property only resets GridShift to a default value if the new Element is incompatible with the current GridShift.
Version 3.2.1 (released 2006-08-28)
- Collections: Added missing ArgumentNullException checks to AsReadOnly constructors.
- Drawing:
- Added enumeration Compass defining the eight major compass directions.
- Added structure LineF representing a directed line with floating-point coordinates.
- Line.TransformAngle: Replaced with Degrees, a simple conversion without the special offset that I mistakenly believed necessary for transformation matrices.
- Drawing.Polygon:
- Added property HasTopIndex to determine whether Connectivity index zero corresponds to a topmost edge or vertex.
- Added methods AngleToCompass, CompassToIndex, and IndexToCompass to convert between Compass directions and angles or Connectivity indices, respectively.
- Added method Resize to create a new Polygon with a new Length and otherwise identical property values.
- AngleToIndex, IndexToAngle: Added missing half-segment shift when HasTopIndex is false.
- Circumscribe, Inflate, Inscribe: Copied missing VertexNeighbors value to new instance.
- Drawing.PolygonGrid:
- Added method AsReadOnly with property IsReadOnly to create a read-only wrapper around a given PolygonGrid. Attempting to change the read-only view throws an exception. Changes to the original instance are reflected in the read-only view.
- Added overloaded method DisplayToGridClipped that clips invalid display coordinates to the nearest valid grid coordinates.
- Added overloaded method GetElementBounds that returns the bounding rectangle for a grid element or a region of adjacent grid elements.
- Drawing.Utility: Added method CoverRectangle that converts a RectangleF into a Rectangle that entirely covers the source rectangle.
- WinForms:
- Templates.FormTemplate & Tektosyne.Controls.xsd: Added field ShowIcon and replaced obsolete fields Closed/Closing with FormClosed/FormClosing.
- Templates.DialogTemplate: ShowIcon is set to false, and HelpButton is set to true if a valid event host and HelpRequested handler are specified.
- Utility.InitializeDialog: ShowIcon is set to false, and HelpButton remains unchanged.
- Xml.Utility: Added method overloads ReadDoubleAttribute and ReadSingleAttribute.
Version 3.2.0 (released 2006-06-27)
- Drawing: Many changes to support arbitrary polygons.
- Added class Polygon and enumeration PolygonOrientation. Polygon represents a regular polygon with an arbitrary side count and length, and one of the orientations defined by PolygonOrientation.
- Added class PolygonGrid and enumeration PolygonGridShift. PolygonGrid represents a rectangular grid based on a four-sided or six-sided Polygon, and with shifted rows or columns as defined by PolygonGridShift.
- Removed obsolete types Hexagon, HexagonEdge, and HexagonRectangle.
- Drawing.Utility: Added method GetBounds with two overloads to determine the minimum bounding rectangle for a set of Point or PointF coordinates.
- Mathematics.Fortran:
- Added overloaded method Modulo. The so-called “modulus” operator % actually calculates the remainder, which is different from the true modulus function for negative values.
- Min, Max, Sum: Added Int64 overloads.
- WinForms.Templates.ControlTemplate & Tektosyne.Controls.xsd: Added fields MinimumHeight, MinimumWidth, Paint, and Resize.
- WinForms.Utility.CreateButtons: All created buttons are anchored to the bottom of the hosting dialog. This allows CreateButtons to be used with resizable dialogs.
- Tektosyne.GuiTest: Added Drawing menu.
- Polygon & Polygon Grid: Show test dialogs for classes Polygon and PolygonGrid.
- Save & Print Grid: Create PNG file or printed page for arbitrary PolygonGrid. This dialog supersedes the package
MakeHexMap.zip that was available as a separate download.
Version 3.1.0 (released 2006-05-08)
- Class Reference: Added general thread safety statements, and specific notes on classes whose static methods may require manual synchronization.
- Strings.resx: Updated to Microsoft ResX Schema 2.0 and added auto-generated Strings class with strongly-typed resource properties. A build-time hack elevates the default visibility of this class, as described in the ReadMe file.
- Renamed all System.Drawing.Graphics variables from “paint” to “graphics”, for conformance with other variable names.
- Application: Renamed to WinForms.Application and removed properties Company, Directory, Product, and Version which are duplicated in System.Windows.Forms.Application.
- BooleanFlag, IO.RootedPath: Changed null comparisons with object casts to Object.ReferenceEquals calls. The method call is more readable and gets compiled to the same optimized code.
- Collections.Utility: Added generic method InsertionSort, providing a stable sort algorithm which the BCL lacks.
- Drawing.Utility: Changed DialogFont value to SystemFonts.MessageBoxFont which reflects the user’s system font size selection, unlike the old value of SystemFonts.DialogFont.
- Global: Replaced method GetMemoryStatus with property WinForms.Application.MemoryStatus and deleted empty class.
- WinForms.Utility: Added method GetButtonText which translates DialogResult values into localized button labels.
Version 3.0.1 (released 2005-12-08)
- Unsealed all public classes outside of namespace Win32Api
- BooleanFlag.GetHashCode: Changed to Int32 equivalent of Value
- WinForms.Templates: Renamed class TemplateBase to Template
Version 3.0.0 (released 2005-10-30)
- Upgraded solution to Microsoft .NET Framework 2.0
- Moved project Tektosyne to eponymous subdirectory
- Renamed project Tektosyne.Test to Tektosyne.GuiTest
- Added project Tektosyne.UnitTest for NUnit 2.2.2
- Changes due to introduction of generics:
- All classes with reflective Equals method implement IEquatable<T>
- Added generic class EventArgs for the transmission of a single value
- Replaced all custom EventArgs and EventHandler classes with generic classes
- Replaced all CodeSmith-generated collections with generic collections (see below)
- Removed obsolete classes and members:
- PrecisionTimer obsoleted by System.Diagnostics.Stopwatch
- StringUtility.IsEmpty/IsNotEmpty obsoleted by System.String.IsNullOrEmpty
- StringUtility.NotNull obsoleted by new ?? operator
- StringUtility.Split obsoleted by new System.String.Split overload
- StringUtility.StartsWith obsoleted by new System.String.StartsWith overload
- WinForms.MenuItemEx.Name obsoleted by System.Windows.Forms.Menu.Name
- Added generic delegate Combination for aggregating values
- Added ctor with inner exception parameter to all exception classes
- StringUtility (formerly Strings.Utility): Added method IsValidEmail
- Booleans:
- Renamed SetOnlyFlag to BooleanSetFlag and placed in BooleanFlag file
- Renamed SetClearFlag to BooleanSetClearFlag and placed in BooleanFlag file
- Moved BooleanFlag to Tektosyne.BooleanFlag, along with derived classes
- Removed empty Booleans namespace
- Collections:
- Added classes Apply and KeyMismatchException
- Added generic collection classes DictionaryEx, ListEx, KeyedList, MultiKeyedList, QueueEx, SortedDictionaryEx, SortedListEx, StackEx
- Replaced class DictionaryList with generic class KeyValueList
- Replaced interface IDictionaryValue with IKeyedValue and IMutableKeyedValue
- Collections.Utility:
- Changed methods to use generics and IMutableKeyedValue
- Added generic methods CreateList, Equals, MoveItem, ToArray, ValidateKey
- IO:
- Added class RootedPath
- Renamed class Path to PathEx
- Utility.CopyAndReplace: Revised parameter naming
- IO.PathEx (formerly Path):
- Added methods AddDirectorySeparator, NormalizeDirectorySeparator, and RemoveDirectorySeparator
- Equals: Null references and empty strings are equivalent
- Equals: Removes trailing directory separators before comparison
- Shorten: Never returns a null reference
- Mathematics.Utility:
- Added overloaded method Compare for epsilon comparisons
- Strings:
- Renamed class Utility to Tektosyne.StringUtility
- Removed ValidString and empty Strings namespace
- WebMail:
- Renamed namespace WebMail to NetMail, mirroring .NET 2.0 change
- Address: User cancellation generates empty result instead of exception
- ResolveName: Changed out parameters to returned key-and-value pair
- Address, ResolveName, SendMail:
- Current working directory is saved & restored
- Unmanaged memory is protected by SafeGlobalHandle and SafeMapiHandle
- Win32Api:
- Added classes SafeMemoryHandle, SafeGlobalHandle, SafeMapiHandle for unmanaged memory
- Mapi: Changed IntPtr output parameters to SafeMapiHandle
- MapiFlags: Changed to base type Int32 for CLS compliance
- MapiMessage: Changed IntPtr fields to SafeGlobalHandle and implemented IDisposable
- WinForms.TaskEvents:
- Changed property Timer to class Stopwatch
- Added methods RestartTimer() and RestartTimer(Int64)
- WinForms.Utility:
- Added method IsControlRightToLeft
- Replaced DefaultFont with Drawing.Utility.DialogFont
- WinForms.Templates.MessageBoxTemplate:
- Added parameter DefaultButton
- Checks for right-to-left fonts
- Xml.Utility: Added methods CreateReaderSettings and CreateWriterSettings
Version 2.8.0 (released 2005-06-03)
- AssemblyVersion includes build date in Major.Minor.Build.Revision:
- Build equals the number of days since 1 January 2000 local time
- Revision equals half the number of seconds since midnight local time
- Reflowed all XML comments to a line width of 100 characters
- Source code lines may extend to 100 characters or more
- WinForms:
- Added delegate ExceptionEventHandler with ExceptionEventArgs
- Added delegate MessageEventHandler with MessageEventArgs
- Added delegate ProgressEventHandler with ProgressEventArgs
- Added class TaskEvents, replacing class StatusMessage
- Renamed class MessagePanel to StatusBarMessagePanel
- WinForms.ListViewColumnSorter:
- Changed number parsing from Double.Parse to Double.TryParse
- Numbers may contain currency symbols, parentheses, and trailing signs
- WinForms.MessageDialog: Increased size of details box
- WinForms.Templates: Added classes ProgressBar/Splitter/TrackBarTemplate
- Xml.Utility: Added methods ReadBoolean/Byte/Enum/Int32/StringAttribute
Version 2.7.4 (released 2005-03-06)
- Reordered class members to conform to MSDN sequence
- Strings.Utility.PackSpace: Removed RegexOptions.Compiled
Version 2.7.3 (released 2005-02-28)
- WinForms.Templates:
- MessageDialogTemplate: Added missing ShowDialog overload
- RichTextDialogTemplate: Added missing ShowDialog overload
Version 2.7.2 (released 2005-02-20)
- IO.Utility:
- Added method SearchDirectory
- Renamed SearchTree to SearchDirectoryTree
- Both methods now accept nonexistent directories
Version 2.7.1 (released 2005-01-21)
- Class Reference no longer lists .NET Framework internals
- Added class PropertyValueException for invalid property values
- DetailException: Base class changed to Exception, as per FxCop
- Strings.InvalidStringArgumentException:
- Renamed to Tektosyne.ArgumentNullOrEmptyException
- Intended for use with any kind of composite object
- Base class changed to ArgumentException
- ctor() and ctor(String) set localized error message
- Strings.Utility:
- Added Join overload for object arrays
- Join overloads use ToString rather than type conversion
- WebMail.MapiException:
- Base class changed to Exception, as per FxCop
- ctor() sets Message property according to Code
Version 2.7.0 (released 2004-12-29)
- Reformatted WhatsNew file for clarity
- Class Reference now compiled with NDoc 1.3
- Drawing.Collections: Added class StringPointDictionary
- Mathematics.AStar and Coverage:
- Added properties Agent and Graph, removed property Strict
- Updated to use new IPlanarAgent members
- Mathematics.IPlanarAgent:
- Added property PartialOccupation and method CanOccupy
- Added property RelaxedRange, replacing Strict properties
- WebMail.MapiException: ctor(MapiError) sets Message property according to Code
- WebMail.MapiMail: Added method GetErrorStringAndCode
- WinForms.ControlBuilder: Added support for modal message dialogs
- WinForms.StatusMessage: Show updates the status bar’s parent control
- WinForms.Templates:
- Added classes MessageBoxTemplate,MessageDialogTemplate, RichTextDialogTemplate
- Moved common XML attribute Name to class TemplateBase
- WinForms.Utility: Added method GetSystemIcon
- Xml.Utility: Added method ReadTextElement
Version 2.6.5 (released 2004-10-09)
- PrecisionTimer: Removed unreliable method GetTimeSlice
- IO.Path: Added method GetTempFileName
- Mathematics.AStar: Changed range testing to IsNearTarget call
- Mathematics.IPlanarAgent: Added method IsNearTarget
- WinForms.NumericUpDownEx: Fixed number formatting in tool tips
- WinForms.StatusMessage: Added property Timer
Version 2.6.4 (released 2004-09-12)
- Drawing.Hexagon: Added static method GetOpposingEdge
- Drawing.HexagonRectangle:
- Added static method GetNeighborEdge
- Changed methods GetNeighbor, IsLeftRow, IsRightRow to static
- Fixed evil bug in method IndexOfLocation
- Mathematics.AStar:
- Changed Absolute/RelativeLimit to search radius limits
- Fixed suboptimal results for complex paths
- Mathematics.Coverage: Optimized path calculations some more
Version 2.6.3 (released 2004-08-30)
- Changed all loops over collections from foreach to for
- Collections.DictionaryList.Equals: Added identity check
- Mathematics.AStar:
- Added properties AbsoluteLimit and RelativeLimit
- Greatly increased performance thanks to list lookup tables
- WinForms: Added class StatusMessage
- WinForms.FormattingPanel: Revised checks for null arguments
Version 2.6.2 (released 2004-08-08)
- Application: Added property PublicKeyToken
- Drawing.Utility: Added method BlendRectangle with alpha blending
- Drawing.Utility.CopyRectangle: Added parameter for alpha threshold
- Strings: Added class InvalidStringArgumentException
- Strings.Utility.Join: Rewritten for better performance
- WinForms.ControlBuilder: Added ScrollBar, HScrollBar, VScrollBar
Version 2.6.1 (released 2004-07-12)
- Removed security attributes with SecurityAction.RequestOptional
- Collections.DictionaryList:
- Added read-only wrapper, removed synchronized wrapper
- Enumerators allow modifications to collection elements
- Drawing.Collections: Added strongly-typed StringBrushDictionary
- Mathematics.Collections: Added strongly-typed Int32 collections
- Strings: Added namespace Collections
- Strings.Utility: Changed Split to return string array
Version 2.6.0 (released 2004-07-01)
- Initial release of renamed Tektosyne library
- Signed precompiled assemblies with a strong name
- Added CLSCompliant, ComVisible, and security attributes
- Added XML schemas Tektosyne.Controls.xsd and Tektosyne.Menus.xsd
- Moved classes in General and Reflection to top-level namespace
- Moved classes MathTbx.Hexagon… to namespace Drawing
- Renamed namespace BooleanTbx to Booleans, StringTbx to Strings, MathTbx to Mathematics, WinApi to Win32Api
- Booleans.BooleanFlag hierarchy: Changed for full CLS compliance
- Booleans.SetClearFlag: Replaced SetValue with Value setter
- Collections.DictionaryList:
- Changed all key and value comparisons to Equals calls
- Fixed Capacity setter for synchronized wrapper
- Fixed ICollection.CopyTo method when copying to Object[] array
- Removed invisible Enumerator.Current overload
- Collections.Utility: Added method MoveItem (from WinForms.Utility)
- Drawing.HexagonRectangle: Removed unused CheckBounds overload
- IO: Added class Path for renamed methods Equals and Shorten
- Mathematics.Coverage: Rewrote for vastly improved performance
- Mathematics.Fortran: Added overloaded methods Ceiling and Floor
- Strings.Utility: Added method NotNull
- Strings.ValidString: No longer referenced by Tektosyne library
- WebMail.MapiException: Changed for full CLS compliance
- WebMail.MapiMail: Ensures that unmanaged memory is deallocated
- Win32Api: Changed most MAPI enumerations for CLS compliance
- WinForms: Added namespace Collections
- WinForms: Added class ControlBuilder and namespace Templates
- WinForms: Added classes ListViewEx, MenuItemEx, NumericUpDownEx
- WinForms: Changed class MenuBuilder to match ControlBuilder
- WinForms: Renamed class RicherTextBox to RichTextBoxEx
- WinForms: Renamed class StatusProgressBar to StatusBarEx
- WinForms.Utility: Many changes, please review entire class
Version 2.5.1 (released 2004-05-14)
- Collections.DictionaryList.CopyTo: Accepts empty arrays
- WinForms.MenuTemplate: Changed to derive from MenuItem
- WinForms.MenuBuilder: Changed to reflect new MenuTemplate
Version 2.5.0 (released 2004-05-09)
- Drawing: Added Line structure and LineCollection class
- MathTbx: Added interface IPlanarPath and class Utility
- MathTbx.AStar: Changed to implement IPlanarPath
- MathTbx.Coverage: Changed Strict parameter to property
- MathTbx.HexagonEdge: Fixed enumeration sequence
Version 2.4.2 (released 2004-04-19)
- WinForms: Added ListViewColumnSorter class
- WinForms.Utility: Added SelectListItem method
Version 2.4.1 (released 2004-03-31)
- General.Timer: Renamed to PrecisionTimer, added method GetTimeSlice
- MathTbx.AStar: Added parameter range and method GetLastNode
- MathTbx.HexagonRectangle.Clone: Fixed method and comments
- MathTbx.Coverage: Added strict parameter, further increased speed
- MathTbx.MersenneTwister: Updated home page address
- WinForms.MessagePanel: Added DefaultText property and Clear method
Version 2.4.0 (released 2004-02-24)
- Added ToolboxTest application for convenient testing
- Collections.Utility: Added method Restrict
- MathTbx.AStar, Coverage, IPlanarAgent: Removed state parameters
- MathTbx.AStar.UpdateParents: Fixed cost calculation bug (?)
- MathTbx.Coverage: Greatly increased speed for large regions
- MathTbx.HexagonRectangle: Fixed Bottom/Right handling
- MathTbx.IPlanarGraph: Added Locations and IndexOfLocation
- StringTbx.Utility: Added method IsRichText
- WinForms: Added classes RicherTextBox and RichTextDialog
- WinForms.MessageDialog.Show: Correctly sets Owner property
- WinForms.Utility.KeysToMenuString: Digit keys fixed
Version 2.3.0 (released 2004-01-27)
- Toolbox.NET is now distributed under the MIT license
- Added namespace General with classes Timer and Utility
- Drawing.Utility: Added method GrowBitmap
- MathTbx: Added classes AStar, Coverage, MersenneTwister, and PathNode; and interfaces IPlanarAgent and IPlanarGraph
- MathTbx.Hexagon: Added argument checking to constructor
- MathTbx.HexagonRectangle: Width and Height must be positive
- MathTbx.HexagonRectangle: Implements IPlanarGraph interface
- WinApi.Kernel: Added methods Get/SetSystemTimeAdjustment and QueryPerformanceCounter/Frequency
- WinForms.Utility.GetMemoryStatus: Moved to General.Utility
Version 2.2.2 (released 2003-12-22)
- Collections.DictionaryList: Added InnerKeys/Values to fix AddRange(DictionaryList) and Equals for synchronized wrapper
Version 2.2.1 (released 2003-11-28)
- Moved version history to separate WhatsNew file
- Collections.Utility.ChangeKey: Accepts existing newKey for dictionary
- StringTbx.Utility.Split: Returns empty collection for empty input string
Version 2.2.0 (released 2003-11-14)
- Collections.Utility: Added DeleteKey and ProcessKey methods
- Drawing.Collections: Added strongly typed collection classes
- MathTbx: Added HexagonRectangle and HexagonEdge classes
- MathTbx.Hexagon: Added static method Inflate
- MathTbx.Hexagon.Outline: Fixed inverted sequence of points
- WinForms.MenuBuilder.Shortcuts: Maps to MenuItem objects
- WinForms.Utility: Added static method MenuItemEnabled
Version 2.1.1 (released 2003-09-28)
- BooleanTbx: Added class BooleanEventArgs
- WinForms.Utility.CreateLabel: Returns created label
Version 2.1.0 (released 2003-09-23)
- Added build script for NAnt 0.8.3
- Changed empty string comparisons to zero length tests, as per FxCop 1.21
- Corrected erroneous XML comments throughout the library
- Created individual directories for all sub-namespaces
- Structured all source files with #region directives
- WebMail.MapiMail.SendMail: Accepts multiple recipients
- WinApi: Added enumerations which replace all constant fields
- WinApi.MapiError.GetString: Moved to WebMail.MapiMail.GetErrorString
Version 2.0.3 (released 2003-06-24)
- BooleanTbx.BooleanFlag: Added null checks to all comparisons
- Collections.DictionaryList.AddRange: Fixed premature capacity increase
- StringTbx.ValidString: Added comparison methods and operators
Version 2.0.2 (released 2003-06-13)
- WinForms.Utility.CreateButtons: Returns list of created buttons
Version 2.0.1 (released 2003-06-11)
- Collections.DictionaryList: Fixed null reference exceptions
Version 2.0.0 (released 2003-06-11)
- Changed foreach iterations to use correct item type
- Collections: Removed class UnsortedList (use DictionaryList instead)
- Collections.DictionaryList: Rewritten without CollectionBase
- WinForms: Added class HelpEventConverter
- WinForms.MessageDialog: Adjusted control layout
- WinForms.StatusProgressBar: Added Dispose and fixed OnDrawItem
- WinForms.Utility: Added static method CreateButtons
- WinForms.Utility.ScrollDirection: Moved to namespace scope
Version 1.9.3 (released 2003-05-17)
- Deleted HintPath assembly references to .NET Framework 1.0
- WinForms.Utility.MoveListItem: Removed BeginUpdate/EndUpdate calls to avoid obscure bug with Windows.Forms list controls
Version 1.9.2 (released 2003-05-11)
- Cosmetic changes, released for synchronization with Hexkit only
Version 1.9.1 (released 2003-05-04)
- Class reference now links to .NET Framework 1.1 documentation
- IO.Utility: Added static methods PathEquals and StripDirectory
- StringTbx.Utility: Added static method StartsWith
Version 1.9.0 (released 2003-04-30)
- Project moved to .NET Framework 1.1 and Visual Studio .NET 2003
- Added some argument error strings to resource table
- WebMail.MapiMail: Added static methods Address and ResolveName
- WebMail.MapiMail.Send: Renamed to SendMail for MAPI conformance
- WinApi.Mapi: Added MAPIAddress, MAPIFreeBuffer, MAPIResolveName
- WinApi.Mapi: Moved MapiFlags and MapiError to namespace WinApi
- StringTbx.ValidString: Removed implicit boolean conversion
- IO.Utility: Added argument null checks to public methods
Version 1.8.2 (released 2003-04-04)
- Revised some exception types and messages
- BooleanTbx.SetClearFlag: Added instance method SetValue
- Collections.Utility.CountKey: Removed erroneous null checking
Version 1.8.1 (released 2003-03-29)
- Revised some comments regarding raising and handling events
- Collections.IDictionaryValue: Corrected misleading documentation
- BooleanTbx: Added classes BooleanFlag, SetOnlyFlag, SetClearFlag
- WinForms: Added class CustomColorDialog, extending ColorDialog
Version 1.8.0 (released 2003-03-20)
- Added missing argument checking and exception comments
- WinForms: Added class FormattingPanel, extending StatusBarPanel
- WinForms: Added class StatusProgressBar, extending StatusBar
- WinForms.MessageDialog: Fixed icon sizing and aliasing problems
- WinForms.Utility: Added static method GetStatusPanelWidth
- Xml: Added interface IXmlSerializable to control XML serialization
Version 1.7.0 (released 2003-03-04)
- Added class DetailException, extending ApplicationException
- StringTbx.Utility: Added static methods IsEmpty and IsNotEmpty
- StringTbx.ValidString: Added instance property IsNotEmpty
- WebMail.MapiException: Derived from ApplicationException
- WinForms: Added class MessageDialog for detailed messages
- Xml.Utility: Added static method GetXmlMessage
Version 1.6.1 (released 2003-02-24)
- Collections: Added class DictionaryList
- Collections.Utility.ChangeKey/CountKey: Added IList overloads
- Collections.Utility.ChangeKey(IDictionary): Checks for UnsortedList
Version 1.6.0 (released 2003-02-20)
- Classes extensively renamed and refactored
- MathTbx.Fortran.Sum: Accepts “params” arrays
- WebMail.MapiMail.Send: Accepts multiple attachments
- WinForms.BitmapPanel: Fixed missing background color
- Xml.Utility: Added static method MoveToStartElement
Version 1.5.0 (released 2003-02-01)
- Added class Xml to supplement namespace Xml
- Mail.MailException: Supports serialization
- StringTbx.ValidString: Added equality comparison
Version 1.4.0 (released 2003-01-22)
- Initial separate release of Toolbox library
Version 1.0.0 (released 2002-05-27)