Скрипт уже написан на C# (см. приложение), но проблема в том, что на C# он выдаёт неверные значения. Насколько мне известно это баг самого API для C#, который признали даже разработчики.
Проверял похожий скрипт на LISP (см. приложение) - там значения верные получались, но этот скрипт немного под другие цели, но если хотите можно допилить его, для меня это китайская грамота.
От скрипта нужно чтобы:
1) Пользователь выбирал объекты.
2) В выбранных объектах для каждой области скрипт находит какими бы были моменты инерции по осям X и Y у области, если её изменить так, что
2а) область уменьшить в 10 раз (перевод из миллиметров в сантиметры)
2б) центр масс станет находиться в начале координат
3) Для каждой из областей скрипт находит имя как содержимое первого попавшегося однострочного текста из выбранных объектов, точка вставки которого лежит в пределах ограничивающей рамки области.
Если текст не найден, то присваивается имя "noname"
4) После получения всей информации нужно вывести в текстовое окно (которое ctrl+F2) информацию в следующем виде:
Наименование\tA\tJx\tWx\tJy\tWy\n
<Имя1>\t<значение A1>\t<значение Jx1>\t<значение Wx1>\t<значение Jy1>\t<значение Wy1>\n
<Имя2>\t<значение A2>\t<значение Jx2>\t<значение Wx2>\t<значение Jy2>\t<значение Wy2>\n
...
<Имяn>\t<значение An>\t<значение Jxn>\t<значение Wxn>\t<значение Jyn>\t<значение Wyn>\n
где: \t - символ табуляции
\n - символ новой строки
<Имя1> - имя полученное по п.3
<значение A1> - значение площади области в сантиметрах
<значение Jx1> - значение момента инерции в сантиметрах (см. п.2)
<значение Wx1> - значение момента сопротивления в сантиметрах, полученное как Jx1 / Макс (Y1, Y2), округлённое до 4 знаков после запятой
где Y1, Y2 - это абсолютные значения расстояний от центра масс до края ограничивающей рамки по оси Y.
Другими словами момент инерции по оси X равен моменту инерции по оси X, делённому на наибольшее расстояние от центра масс до крайнего волокна по оси Y
<значение Jy1> - значение момента инерции в сантиметрах (см. п.2)
<значение Wy1> - значение момента сопротивления в сантиметрах, полученное как Jy1 / Макс (X1, X2)
Общая идея такая, чтобы скриптом получать уже вычисленные значения, копировать их из текстового окна и вставлять в Excel
Во вложении тестовый файл, при отработке скрипта должен получиться следующий результат:
Скрипт на C#:
using System;
using System.Collections.Generic;
using System.Drawing;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using FSImark.Services;
using Region = Autodesk.AutoCAD.DatabaseServices.Region;
namespace FSImark.GetGeometryParameters
{
public class GetGeometryParametersModel
{
public List<Data> Datas { get; set; } = new List<Data>();
public bool IsSearchName { get; set; } = true;
public void Do()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
var types = new List<TypedValue> { new TypedValue((int)DxfCode.Start, "REGION") };
var filter = new SelectionFilter(types.ToArray());
var pso = new PromptSelectionOptions
{
MessageForAdding = $"Выберите области{(IsSearchName ? " и наименования" : "")} для добавления их в набор",
MessageForRemoval = $"Выберите области{(IsSearchName ? " и наименования" : "")}, подлежащие удалению из набора",
SingleOnly = false,
RejectObjectsFromNonCurrentSpace = true,
AllowDuplicates = false
};
var psr = ed.GetSelection(pso, filter);
if (psr.Status != PromptStatus.OK)
{
ed.WriteMessage("Ничего не выбрано. Выполнение команды прервано\n");
return;
}
Datas.Clear();
using (var tr = db.TransactionManager.StartTransaction())
{
var blockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
var blockTableRecord = tr.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;
foreach (var regionId in psr.Value.GetObjectIds())
{
if (!(tr.GetObject(regionId, OpenMode.ForWrite) is Region region)) continue;
using (region)
using (var origin = new Solid3d())
using (var geom = new Solid3d())
{
origin.Extrude(region, 1, 0); // экструдируем солид, чтобы не нужно было вертеть сечение
var center = origin.MassProperties.Centroid;
region.TransformBy(Matrix3d.Scaling(1 / 10D, center));
region.TransformBy(Matrix3d.Displacement(new Vector3d(-center.X, -center.Y, -center.Z)));
geom.Extrude(region, 1, 0); // экструдируем солид, чтобы не нужно было вертеть сечение
var x1 = geom.GeometricExtents.MinPoint.X.Abs();
var x2 = geom.GeometricExtents.MaxPoint.X.Abs();
var y1 = geom.GeometricExtents.MinPoint.Y.Abs();
var y2 = geom.GeometricExtents.MaxPoint.Y.Abs();
var data = new Data
{
Center = center,
A = geom.MassProperties.Volume,
Jx = geom.MassProperties.MomentsOfIntertia.X,
Jy = geom.MassProperties.MomentsOfIntertia.Y,
Wx = geom.MassProperties.MomentsOfIntertia.X / Math.Max(y1, y2),
Wy = geom.MassProperties.MomentsOfIntertia.Y / Math.Max(x1, x2),
};
foreach (var textId in blockTableRecord)
{
if (!(tr.GetObject(textId, OpenMode.ForRead) is DBText text)) continue;
if (text.Position.X < origin.GeometricExtents.MinPoint.X) continue;
if (text.Position.X > origin.GeometricExtents.MaxPoint.X) continue;
if (text.Position.Y < origin.GeometricExtents.MinPoint.Y) continue;
if (text.Position.Y > origin.GeometricExtents.MaxPoint.Y) continue;
data.Name = text.TextString;
break;
}
Datas.Add(data);
}
}
}
}
public class Data
{
public string Name { get; set; }
public Point3d Center { get; set; }
public double A { get; set; }
public double Jx { get; set; }
public double Wx { get; set; }
public double Jy { get; set; }
public double Wy { get; set; }
}
}
}
Скрипт на LISP
(defun C:mihar (/ *error* pt1 pt2 ent1)
(defun *error* (msg) (princ))
(vl-load-com)
(setq pt1 (getpoint "\nУкажите рамкой (с права на лево) расчетный участок: "))
(setq pt2 (getcorner pt1 "\nУкажите вторую точку: "))
(command "_section" "_f" pt1 pt2 "" "" "_yz" "_m2p" pt1 pt2 )
(command "_extrude" "Р" pt2 pt1 "" 0.0001)
(command "_union" "Р" pt2 pt1 "")
(setq ent1(entlast))
(defun centroid (entity /)
(vlax-safearray->list (vlax-variant-value (vla-get-centroid (vlax-ename->vla-object entity))))
) ;_ end of defun
(defun mass (entity /)
(vla-get-volume (vlax-ename->vla-object entity))
) ;_ end of defun
(if (setq ents (ssget "_L"))
(progn
(setq ents (vl-remove-if-not 'atom (mapcar 'cadr (ssnamex ents))))
(setq firstpoint (centroid (car ents)))
(setq firstpointmass (mass (car ents)))
(if (setq ents (cdr ents))
(progn
(foreach n ents
(setq secondpoint (centroid n))
(setq secondpointmass (mass n))
(setq length12 (sqrt (apply '+ (mapcar '(lambda (x) (* x x)) (mapcar '- firstpoint secondpoint)))))
(setq length1 (/ (* secondpointmass length12) (+ firstpointmass secondpointmass)))
(if (and (= length1 length12)(= length1 0))(setq length12 1))
(setq delta (mapcar '(lambda (x) (/ (* length1 x) length12)) (mapcar '- firstpoint secondpoint)))
(setq firstpoint (mapcar '- firstpoint delta))
(setq firstpointmass (+ firstpointmass secondpointmass))
) ;_ end of foreach
) ;_ end of progn
) ;_ end of if
(setq osmode (getvar "osmode")
firstpoint (trans firstpoint 0 1))
(vla-startundomark (vla-get-activedocument (vlax-get-acad-object)))
(setvar "osmode" 0)
(COMMAND "_ucs" "_o" firstpoint
)
(setvar "osmode" osmode)
))
(setvar "cmdecho" 1)
(vla-endundomark (vla-get-activedocument (vlax-get-acad-object)))
(command "_massprop" "_last" "" "Д" "" "_.undo" "5")
(princ)
) ;_ end of progn
) ;_ end of if
) ;_ end of defun[/quote]