Last week I started to put together a small geometry NuGet package featuring simple types and operations. The goal is to keep it lightweight and performant, even if it's written in C# as opposed to C++. The reason for keeping it in C# is that I may one day want to make the tools available in a more explicit format for uses in industries where programming proficiency is not so pervasive, hence opting for the more readable format.
Nonetheless, I need to optimize it where I can. This is the first in a series of gists on the matter.
1
In the RemoveVertices
and RemoveVerticesAtIndex
methods, it's better to remove items from the end of the list to the start. This is because removing an item from a list involves shifting all the subsequent items down. If you remove items from the start of the list first, you'll end up shifting the same items multiple times.
Code Before
/// <summary>
/// Removes multiple vertices from the polygon.
/// </summary>
/// <param name="points">
/// The array of points representing the vertices to be removed.
/// </param>
public void RemoveVertices( Point[] points ) {
for ( int i = 0; i < points.Length; i++ ) {
RemoveVertex( points[ i ] );
}
}
/// <summary>
/// Removes vertices at the specified indices.
/// </summary>
/// <param name="indices"> The indices of the vertices to remove. </param>
public void RemoveVerticesAtIndex( int[] indices ) {
for ( int i = 0; i < indices.Length; i++ ) {
RemoveVertexAtIndex( indices[ i ] );
}
}
Code After
/// <summary>
/// Removes multiple vertices from the polygon.
/// </summary>
/// <param name="points">
/// The array of points representing the vertices to be removed.
/// </param>
public void RemoveVertices( Point[] points ) {
foreach (var point in points) {
Vertices.Remove(point);
}
}
/// <summary>
/// Removes vertices at the specified indices.
/// </summary>
/// <param name="indices"> The indices of the vertices to remove. </param>
public void RemoveVerticesAtIndex( int[] indices ) {
Array.Sort(indices, (a, b) => b.CompareTo(a)); // sort in descending order
foreach (var index in indices) {
Vertices.RemoveAt(index);
}
}
2
In the FromCircle
method, you can move the calculation of (2 * Math.PI / numberOfVertices) outside the loop because it's a constant for a given numberOfVertices.
Code Before
/// <summary>
/// Creates a polygon by approximating a circle using the specified number of
/// vertices.
/// </summary>
/// <param name="circle"> The circle to approximate. </param>
/// <param name="numberOfVertices">
/// The number of vertices to use for the approximation. Default is 32.
/// </param>
/// <returns> The created polygon. </returns>
public Polygon FromCircle( Circle circle, double numberOfVertices = 32 ) {
Vertices = new List<Point>( );
for ( int i = 0; i < numberOfVertices; i++ ) {
double angle = i * ( 2 * Math.PI / numberOfVertices );
double x = circle.Center.X + circle.Radius * Math.Cos( angle );
double y = circle.Center.Y + circle.Radius * Math.Sin( angle );
Vertices.Add( new Point( x, y ) );
}
return this;
}
Code After
/// <summary>
/// Creates a polygon by approximating a circle using the specified number of
/// vertices.
/// </summary>
/// <param name="circle"> The circle to approximate. </param>
/// <param name="numberOfVertices">
/// The number of vertices to use for the approximation. Default is 32.
/// </param>
/// <returns> The created polygon. </returns>
public Polygon FromCircle( Circle circle, double numberOfVertices = 32 ) {
Vertices = new List<Point>( );
double angleIncrement = 2 * Math.PI / numberOfVertices;
for ( int i = 0; i < numberOfVertices; i++ ) {
double angle = i * angleIncrement;
double x = circle.Center.X + circle.Radius * Math.Cos(angle);
double y = circle.Center.Y + circle.Radius * Math.Sin(angle);
Vertices.Add( new Point( x, y ) );
}
return this;
}