using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Linq;
namespace Gile.AutoCAD.LispExtension
{
/// <summary>
/// Provides properties an methods to help data exchange between LISP and .NET.
/// Some methods are also used to control the arguments validity and throw exceptions of type LispException.
/// </summary>
static class Lisp
{
#region TypedValue Constants
/// <summary>
/// Gets the value LispDataType.Nil
/// </summary>
public static TypedValue Nil
=> new TypedValue
(5019);
/// <summary>
/// Gets the value LispDataType.T_atom
/// </summary>
public static TypedValue T
=> new TypedValue
(5021);
/// <summary>
/// Gets the value LispDataType.ListBegin
/// </summary>
public static TypedValue ListBegin
=> new TypedValue
(5016);
/// <summary>
/// Gets the value LispDataType.ListEnd
/// </summary>
public static TypedValue ListEnd
=> new TypedValue
(5017);
/// <summary>
/// Gets the value LispDataType.DottedPair
/// </summary>
public static TypedValue DottedPair
=> new TypedValue
(5018);
/// <summary>
/// Gets the value LispDataType.Void
/// </summary>
public static TypedValue
Void => new TypedValue
(5014);
#endregion
#region Type .NET -> TypedValue
/// <summary>
/// Gets the value as a TypedValue.
/// </summary>
/// <param name="i">Instance of Int32 which the method applies to.</param>
/// <returns>The value as TypedValue.</returns>
public static TypedValue ToLispValue
(this int i
) => new TypedValue
(5010, i
);
/// <summary>
/// Gets the value as a TypedValue.
/// </summary>
/// <param name="d">Instance of Double which the method applies to.</param>
/// <returns>The value as TypedValue.</returns>
public static TypedValue ToLispValue
(this double d
) => new TypedValue
(5001, d
);
/// <summary>
/// Gets the value as a TypedValue.
/// </summary>
/// <param name="s">Instance of String which the method applies to.</param>
/// <returns>The value as TypedValue.</returns>
public static TypedValue ToLispValue
(this string s
) => new TypedValue
(5005, s
);
/// <summary>
/// Gets the value as a TypedValue.
/// </summary>
/// <param name="id">Instance of ObjectId which the method applies to.</param>
/// <returns>The value as TypedValue.</returns>
public static TypedValue ToLispValue
(this ObjectId id
) => new TypedValue
(5006, id
);
/// <summary>
/// Gets the value as a TypedValue.
/// </summary>
/// <param name="ss">Instance of SelectionSet which the method applies to.</param>
/// <returns>The value as TypedValue.</returns>
public static TypedValue ToLispValue
(this SelectionSet ss
) => new TypedValue
(5007, ss
);
#endregion
#region TypedValue -> type .NET (type validity control)
/// <summary>
/// Gets the value as Int16.
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>The value as Int16.</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Int16.
/// </exception>
public static short GetAsShort(this TypedValue tv)
{
if (tv.TypeCode == 5003)
{
return (short)tv.Value;
}
else
{
throw new ArgumentTypeException
("shortp", tv
); }
}
/// <summary>
/// Gets the value as Int32.
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>The value as Int32 (Int16 type is converted).</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Int16 or LispDataType.Tnt32.
/// </exception>
public static int GetAsInteger(this TypedValue tv)
{
switch (tv.TypeCode)
{
case 5003:
case 5010:
return Convert.ToInt32(tv.Value);
default:
throw new ArgumentTypeException
("fixnump", tv
); }
}
/// <summary>
/// Gets the value as Double.
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>The value as Double.</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Double, LispDataType.Angle or LispDataType.Orientation.
/// </exception>
public static double GetAsDouble(this TypedValue tv)
{
if (tv.TypeCode == 5001 || tv.TypeCode == 5004 || tv.TypeCode == 5008)
{
return (double)tv.Value;
}
else
{
throw new ArgumentTypeException
("shortp", tv
); }
}
/// <summary>
/// Gets the value as number (accepte tous les types numériques).
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>The value as double (integer inputs are converted).</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Int16, LispDataType.Tnt32,
/// LispDataType.Double, LispDataType.Angle or LispDataType.Orientation.
/// </exception>
public static double GetAsNumber(this TypedValue tv)
{
switch (tv.TypeCode)
{
case 5003:
case 5010:
case 5001:
case 5004:
case 5008:
return Convert.ToDouble(tv.Value);
default:
throw new ArgumentTypeException
("numberp", tv
); }
}
/// <summary>
/// Gets the value as point 2d (the value may represent any list of two numbers).
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>The value as Point2d.</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Point2d.
/// </exception>
public static Point2d GetAsPoint2d(this TypedValue tv)
{
if (tv.TypeCode != 5002)
{
throw new ArgumentTypeException
("point 2D", tv
); }
return (Point2d)tv.Value;
}
/// <summary>
/// Gets the value as Point3d (the value may represent any list of three numbers).
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>The value as Point3d.</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Point3d.
/// </exception>
public static Point3d GetAsPoint3d(this TypedValue tv)
{
if (tv.TypeCode != 5009)
{
throw new ArgumentTypeException
("point 3D", tv
); }
return (Point3d)tv.Value;
}
/// <summary>
/// Gets the value as point (the value may represent any list of two or three numbers).
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>The value as Point3d.</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Point3d or TypeCode.Point2d.
/// </exception>
public static Point3d GetAsPoint(this TypedValue tv)
{
switch (tv.TypeCode)
{
case 5002:
var pt = (Point2d)tv.Value;
return new Point3d
(pt
.X, pt
.Y,
0.0); case 5009:
return (Point3d)tv.Value;
default:
throw new ArgumentTypeException
("point2D/3D", tv
); }
}
/// <summary>
/// Gets the value as String.
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>The value as string</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.Text.
/// </exception>
public static string GetAsString(this TypedValue tv)
{
if (tv.TypeCode != 5005)
{
throw new ArgumentTypeException
("stringp", tv
); }
return (string)tv.Value;
}
/// <summary>
/// Gets the value as ObjectId (la valeur représente un ENAME).
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>The value as ObjectId</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.ObjectId.
/// </exception>
public static ObjectId GetAsObjectId(this TypedValue tv)
{
if (tv.TypeCode != 5006)
{
throw new ArgumentTypeException
("lentityp", tv
); }
return (ObjectId)tv.Value;
}
/// <summary>
/// Gets the value as SelectionSet.
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>The value as SelectionSet</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode is not equal to LispDataType.SelectionSet.
/// </exception>
public static SelectionSet GetAsSelectionSet(this TypedValue tv)
{
if (tv.TypeCode != 5007)
{
throw new ArgumentTypeException
("lselsetp", tv
); }
return (SelectionSet)tv.Value;
}
/// <summary>
/// Evaluates if the value is nil.
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>true, if TypeCode equals LispDataType.Nil ; false, otherwise.</returns>
public static bool IsNil(this TypedValue tv) =>
tv.TypeCode == 5019;
/// <summary>
/// Evaluates if the value is T.
/// </summary>
/// <param name="tv">Instance of TypedValue which the method applies to.</param>
/// <returns>true, if TypeCode equals LispDataType.T_atom ; false, otherwise.</returns>
public static bool IsT(this TypedValue tv) =>
tv.TypeCode == 5021;
#endregion
#region TypedValue -> LISP list (type validity control)
/// <summary>
/// Gets a list contained in a TypedValue array.
/// </summary>
/// <param name="args">TypedValue array the method applies to.</param>
/// <param name="index">Start index of the list (first parenthesis) in the array.</param>
/// <returns>A TypedValue array corresponding to the list contents.</returns>
/// <exception cref="ArgumentTypeException">
/// ArgumentTypeException is thrown if the TypeCode at specified index is not equal to ListDataType.ListBegin or ListDataType.Nil.
/// </exception>
public static TypedValue[] GetListContent(this TypedValue[] args, int index)
{
if (args[index].IsNil())
return new TypedValue
[0];
if (args[index].TypeCode != 5016)
throw new ArgumentTypeException
("listp", args
[index
]);
int cnt = 1;
return args
.Skip(index + 1)
.TakeWhile(tv =>
{
switch (tv.TypeCode)
{
case 5016: cnt++; break;
case 5017: cnt--; break;
default: break;
}
return cnt != 0;
})
.ToArray();
}
#endregion
#region ResultBuffer -> TypedValue[] (items number validity control)
/// <summary>
/// Converts the ResultBuffer into TypedValue array controling the number of items.
/// </summary>
/// <param name="resbuf">Instance of ResultBuffer which the method applies to.</param>
/// <param name="length">Number of items the array is supposed to contain.</param>
/// <returns>Un table de TypedValue.</returns>
/// <exception cref="TooFewArgsException">
/// TooFewArgsException is thrown <paramref name="resbuf"/> is null or if the number of items is lower than <paramref name="length"/>.
/// </exception>
/// <exception cref="TooManyArgsException">
/// TooManyArgsException is thrown if the number of items is greater than <paramref name="length"/>.
/// </exception>
public static TypedValue[] GetAsArray(this ResultBuffer resbuf, int length)
{
return resbuf.GetAsArray(length, length);
}
/// <summary>
/// Converts the ResultBuffer into TypedValue array controling the number of items.
/// </summary>
/// <param name="resbuf">Instance of ResultBuffer which the method applies to.</param>
/// <param name="minLength">Minimum number of items the array is supposed to contain.</param>
/// <param name="maxLength">Maximum number of items the array is supposed to contain.</param>
/// <returns>A TypedValue array.</returns>
/// <exception cref="System.ArgumentOutOfRangeException">
/// ArgumentOutOfRangeException is thrown if <paramref name="minLength"/> is lower than 0.
/// </exception>
/// <exception cref="System.ArgumentOutOfRangeException">
/// ArgumentOutOfRangeException is thrown if <paramref name="maxLength"/> is lower than <paramref name="minLength"/>.
/// </exception>
/// <exception cref="TooFewArgsException">
/// TooFewArgsException is thrown if <paramref name="resbuf"/> is null or if the number of items is lower than <paramref name="minLength"/>.
/// </exception>
/// <exception cref="TooManyArgsException">
/// TooManyArgsException is thrown if the number of items eis greater than <paramref name="length"/>.
/// </exception>
public static TypedValue[] GetAsArray(this ResultBuffer resbuf, int minLength, int maxLength)
{
if (minLength < 0)
{
throw new ArgumentOutOfRangeException
("minLength",
"minLength must be lower than 0"); }
if (maxLength < minLength)
{
throw new ArgumentOutOfRangeException
("maxLength",
"maxLength must be greater than minLength"); }
if (resbuf == null)
{
if (minLength == 0)
{
return new TypedValue
[0]; }
else
{
throw new TooFewArgsException
(); }
}
TypedValue[] args = resbuf.AsArray();
if (args.Length < minLength)
{
throw new TooFewArgsException
(); }
if (args.Length > maxLength)
{
throw new TooManyArgsException
(); }
return args;
}
#endregion
}
}