Offset Polyline
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.DatabaseServices;
namespace OffsetPolylineSample
{
/// <summary>
/// Provides the Offset() extension method for the Polyline type
/// </summary>
public static class PolylineExtension
{
/// <summary>
/// Enumeration of offset side options
/// </summary>
public enum OffsetSide { In, Out, Left, Right, Both }
/// <summary>
/// Offset the source polyline to specified side(s).
/// </summary>
/// <param name="source">The polyline to be offseted.</param>
/// <param name="offsetDist">The offset distance.</param>
/// <param name="side">The offset side(s).</param>
/// <returns>A polyline sequence resulting from the offset of the source polyline.</returns>
public static IEnumerable<Polyline> Offset(this Polyline source, double offsetDist, OffsetSide side)
{
offsetDist = Math.Abs(offsetDist);
IEnumerable<Polyline> offsetRight = source.GetOffsetCurves(offsetDist).Cast<Polyline>();
double areaRight = offsetRight.Select(pline => pline.Area).Sum();
IEnumerable<Polyline> offsetLeft = source.GetOffsetCurves(-offsetDist).Cast<Polyline>();
double areaLeft = offsetLeft.Select(pline => pline.Area).Sum();
switch (side)
{
case OffsetSide.In:
if (areaRight < areaLeft)
{
offsetLeft.Dispose();
return offsetRight;
}
else
{
offsetRight.Dispose();
return offsetLeft;
}
case OffsetSide.Out:
if (areaRight < areaLeft)
{
offsetRight.Dispose();
return offsetLeft;
}
else
{
offsetLeft.Dispose();
return offsetRight;
}
case OffsetSide.Left:
offsetRight.Dispose();
return offsetLeft;
case OffsetSide.Right:
offsetLeft.Dispose();
return offsetRight;
case OffsetSide.Both:
return offsetRight.Concat(offsetLeft);
default:
return null;
}
}
private static void Dispose(this IEnumerable<Polyline> plines)
{
foreach (Polyline pline in plines)
{
pline.Dispose();
}
}
}
}
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
namespace OffsetPolylineSample
{
public class CommandMethods
{
[CommandMethod("Test", CommandFlags.Modal)]
public void Test()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
PromptDistanceOptions pdo =
new PromptDistanceOptions("\nSpecify the offset distance: ");
pdo.AllowZero = false;
PromptDoubleResult pdr = ed.GetDistance(pdo);
if (pdr.Status != PromptStatus.OK) return;
double offsetDist = pdr.Value;
PromptKeywordOptions pko =
new PromptKeywordOptions("\nEnter the offset side [In/Out/Left/Right/Both]", "In Out Left Right Both");
PromptResult pr = ed.GetKeywords(pko);
if (pr.Status != PromptStatus.OK) return;
PolylineExtension.OffsetSide side;
switch (pr.StringResult)
{
case "In": side = PolylineExtension.OffsetSide.In; break;
case "Out": side = PolylineExtension.OffsetSide.Out; break;
case "Left": side = PolylineExtension.OffsetSide.Left; break;
case "Right": side = PolylineExtension.OffsetSide.Right; break;
default: side = PolylineExtension.OffsetSide.Both; break;
}
PromptEntityOptions peo = new PromptEntityOptions("\nSelect a polyline: ");
peo.SetRejectMessage("Only a polyline !");
peo.AddAllowedClass(typeof(Polyline), true);
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
while (true)
{
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK) break;
Polyline pline = (Polyline)tr.GetObject(per.ObjectId, OpenMode.ForRead);
foreach (Polyline pl in pline.Offset(offsetDist, side))
{
btr.AppendEntity(pl);
tr.AddNewlyCreatedDBObject(pl, true);
}
db.TransactionManager.QueueForGraphicsFlush();
}
tr.Commit();
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.DatabaseServices;
namespace OffsetPolylineSample
{
/// <summary>
/// Provides the Offset() extension method for the Polyline type
/// </summary>
public static class PolylineExtension
{
/// <summary>
/// Enumeration of offset side options
/// </summary>
public enum OffsetSide
{
In, Out, Left, Right, Both
}
/// <summary>
/// Offset the source polyline to specified side(s).
/// </summary>
/// <param name="source">The polyline to be offseted.</param>
/// <param name="offsetDist">The offset distance.</param>
/// <param name="side">The offset side(s).</param>
/// <returns>A polyline sequence resulting from the offset of the source polyline.</returns>
public static IEnumerable<Polyline> Offset( this Polyline source, double offsetDist, OffsetSide side )
{
offsetDist = Math.Abs( offsetDist );
using( var plines = new DisposableSet<Polyline>() )
{
IEnumerable<Polyline> offsetRight = source.GetOffsetCurves( offsetDist ).Cast<Polyline>();
plines.AddRange( offsetRight );
IEnumerable<Polyline> offsetLeft = source.GetOffsetCurves( -offsetDist ).Cast<Polyline>();
plines.AddRange( offsetLeft );
double areaRight = offsetRight.Select( pline => pline.Area ).Sum();
double areaLeft = offsetLeft.Select( pline => pline.Area ).Sum();
switch( side )
{
case OffsetSide.In:
if( areaRight < areaLeft )
{
plines.RemoveRange( offsetRight );
return offsetRight;
}
else
{
plines.RemoveRange( offsetLeft );
return offsetLeft;
}
case OffsetSide.Out:
if( areaRight < areaLeft )
{
plines.RemoveRange( offsetLeft );
return offsetLeft;
}
else
{
plines.RemoveRange( offsetRight );
return offsetRight;
}
case OffsetSide.Left:
plines.RemoveRange( offsetLeft );
return offsetLeft;
case OffsetSide.Right:
plines.RemoveRange( offsetRight );
return offsetRight;
case OffsetSide.Both:
plines.Clear();
return offsetRight.Concat( offsetLeft );
default:
return null;
}
}
}
}
public class DisposableSet<T> : HashSet<T>, IDisposable where T: IDisposable
{
public void Dispose()
{
System.Exception last = null;
foreach( T item in this )
{
if( item != null )
{
try
{
item.Dispose();
}
catch( System.Exception ex )
{
last = last ?? ex;
}
}
}
this.Clear();
if( last != null )
throw last;
}
public void AddRange( IEnumerable<T> items )
{
foreach( T item in items )
{
if( item == null )
throw new ArgumentNullException( "element" );
base.Add( item );
}
}
public void RemoveRange( IEnumerable<T> items )
{
foreach( T item in items )
{
if( item != null )
base.Remove( item );
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.AutoCAD.DatabaseServices;
namespace OffsetPolylineSample
{
/// <summary>
/// Provides the Offset() extension method for the Polyline type
/// </summary>
public static class PolylineExtension
{
/// <summary>
/// Enumeration of offset side options
/// </summary>
public enum OffsetSide
{
In, Out, Left, Right, Both
}
/// <summary>
/// Offset the source polyline to specified side(s).
/// </summary>
/// <param name="source">The polyline to be offseted.</param>
/// <param name="offsetDist">The offset distance.</param>
/// <param name="side">The offset side(s).</param>
/// <returns>A polyline sequence resulting from the offset of the source polyline.</returns>
public static IEnumerable<Polyline> Offset( this Polyline source, double offsetDist, OffsetSide side )
{
offsetDist = Math.Abs( offsetDist );
using( var plines = new DisposableSet<Polyline>() )
{
IEnumerable<Polyline> offsetRight = source.GetOffsetCurves( offsetDist ).Cast<Polyline>();
plines.AddRange( offsetRight );
IEnumerable<Polyline> offsetLeft = source.GetOffsetCurves( -offsetDist ).Cast<Polyline>();
plines.AddRange( offsetLeft );
double areaRight = offsetRight.Select( pline => pline.Area ).Sum();
double areaLeft = offsetLeft.Select( pline => pline.Area ).Sum();
switch( side )
{
case OffsetSide.In:
return plines.RemoveRange(
areaRight < areaLeft ? offsetRight : offsetLeft );
case OffsetSide.Out:
return plines.RemoveRange(
areaRight < areaLeft ? offsetLeft : offsetRight );
case OffsetSide.Left:
return plines.RemoveRange( offsetLeft );
case OffsetSide.Right:
return plines.RemoveRange( offsetRight );
case OffsetSide.Both:
plines.Clear();
return offsetRight.Concat( offsetLeft );
default:
return null;
}
}
}
}
public interface IDisposableCollection<T> : ICollection<T>, IDisposable
where T : IDisposable
{
void AddRange( IEnumerable<T> items );
IEnumerable<T> RemoveRange( IEnumerable<T> items );
}
public class DisposableSet<T> : HashSet<T>, IDisposableCollection<T>
where T: IDisposable
{
public DisposableSet()
{
}
public DisposableSet( IEnumerable<T> items )
{
AddRange( items );
}
public void Dispose()
{
if( base.Count > 0 )
{
System.Exception last = null;
var list = this.ToList();
this.Clear();
foreach( T item in list )
{
if( item != null )
{
try
{
item.Dispose();
}
catch( System.Exception ex )
{
last = last ?? ex;
}
}
}
if( last != null )
throw last;
}
}
public void AddRange( IEnumerable<T> items )
{
if( items == null )
throw new ArgumentNullException( "items" );
base.UnionWith( items );
}
public IEnumerable<T> RemoveRange( IEnumerable<T> items )
{
if( items == null )
throw new ArgumentNullException( "items" );
base.ExceptWith( items );
return items;
}
}
}