using System;
using System.Collections.Generic;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
#pragma warning disable 0618
[assembly: CommandClass(typeof(Rivilis.TestPolygon))]
namespace Rivilis
{
public class TestPolygon
{
[CommandMethod("TP", CommandFlags.Modal | CommandFlags.UsePickSet)]
public void MyCommand()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
if (doc == null) return;
Editor ed = doc.Editor;
Database db = doc.Database;
PromptSelectionOptions pso = new PromptSelectionOptions();
pso.MessageForAdding = "\nВыберите полилинии: ";
pso.MessageForRemoval = "\nУдалите полилинии: ";
TypedValue[] filList = new TypedValue[1] {
new TypedValue((int)DxfCode.Start, "*POLYLINE")
};
SelectionFilter sf = new SelectionFilter(filList);
PromptSelectionResult psr = ed.GetSelection(pso, sf);
if (psr.Status == PromptStatus.OK) {
foreach (ObjectId id in psr.Value.GetObjectIds()) {
var inds = GetVertexiesDesc(id);
int i = 0; // Считаем количество выпуклых углов
foreach (var ind in inds) if (ind.Value) i++;
ed.WriteMessage("\nВ полилинии {0} выпуклых углов {1}",
id.Handle.ToString(), i);
}
}
}
/// <summary>
/// Получаем коллекцию пар (номер вершины) - (флаг выпуклости вершины)
/// </summary>
/// <param name="id">ObjectId полилинии.</param>
/// <returns></returns>
public static Dictionary<int, bool> GetVertexiesDesc(ObjectId id)
{
var inds = new Dictionary<int, bool>();
using (Curve poly = id.Open(OpenMode.ForRead) as Curve) {
Vector3d norm = Vector3d.ZAxis;
try { norm = poly.GetPlane().Normal; } catch { }
// Количество вершин полилинии. Если полилиния незамкнутая, то
// к EndParam нужно добавить 1.
int nVerts = (int)(poly.EndParam + (poly.Closed ? 0 : 1) + 1e-6);
// Полный угол со знаком для определения направления:
// обход по часовой или против часовой стрелки.
double angle = 0;
// Коллекция углов в каждой из вершин
List<double> angles = new List<double>(nVerts);
for (int i = 0; i < nVerts; i++) {
Point3d p1 = poly.GetPointAtParameter((i) % nVerts);
Point3d p2 = poly.GetPointAtParameter((i+1) % nVerts);
Point3d p3 = poly.GetPointAtParameter((i+2) % nVerts);
double ang = signedAngle(p1, p2, p3, norm);
angles.Add(ang); angle += ang;
}
for (int i = 0; i < angles.Count; i++) {
inds.Add(i, angle * angles[i] > 0);
}
}
return inds;
}
/// <summary>
/// Функция получает угол со знаком между указанными векторами, заданными точками,
/// относительно плоскости заданной нормалью
/// </summary>
public static double signedAngle(Point3d p1, Point3d p2, Point3d p3, Vector3d norm)
{
return signedAngle(p2 - p1, p3 - p2, norm);
}
/// <summary>
/// Функция получает угол со знаком между указанными векторами,
/// относительно плоскости заданной нормалью
/// </summary>
public static double signedAngle(Vector3d v1, Vector3d v2, Vector3d norm)
{
Vector3d v3 = v1.CrossProduct(v2);
double angle = Math.Acos(v1.GetNormal().DotProduct(v2.GetNormal()));
return angle * Math.Sign(v3.DotProduct(norm));
}
}
}