Работа с API компас в C#. Получение размеров детали.

Автор D.I.R.W., 10.11.15, 13:35:37

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

D.I.R.W.

Недавно начал писать программы под компас и знакомиться с его API. Пишу на C#.
-Столкнулся с тем, что не знаю, через какую функцию получить размеры 3d детали.
Даже не знаю с чего начать (SDK читал, написано очень непонятно).

#programmer

Уточните, какие размеры?

Для получения габаритов:
IBody7.GetGabarit
IPart.GetGabarit

Для получения размеров 3D см.
ISymbols3DContainer - свойства:

AngleDimensions3D - Интерфейс коллекции угловых размеров 3D
Bases3D - Интерфейс коллекции обозначений базы 3D
DiametralDimensions3D - Интерфейс коллекции диаметральных размеров 3D
Leaders3D - Интерфейс коллекции линий-выносок 3D
LineDimensions3D - Интерфейс коллекции линейных размеров 3D
RadialDimensions3D - Интерфейс коллекции радиальных размеров 3D
Roughs3D - Интерфейс коллекции обозначений шероховатости 3D
Tolerances3D - Интерфейс коллекции обозначений допусков формы 3D

+ Благодарностей: 1

D.I.R.W.

-Габариты, в вашем ответе нашел, благодарю.

Denis78

#3
Тоже пытаюсь получить параметры размера 3Д детали. За основу взял пример Bracket (у всех, думаю, после установки компаса он есть, у меня, например, он здесь C:\Program Files\ASCON\KOMPAS-3D v18\Samples\Models\Bracket.m3d)
Я добавил в него пару размеров. Пока разбираюсь с линейным.
Написал такой кусок кода:

IPart7Ptr part7(doc3D->GetTopPart());
ISymbols3DContainerPtr s3d;
HRESULT res = part7.QueryInterface(IID_ISymbols3DContainer, &s3d);

if (s3d)
{
    IBases3DPtr bases = s3d->GetBases3D();
    ILeaders3DPtr leaders = s3d->GetLeaders3D();
 
    Dbg("Bases cnt: ", bases->GetCount());            // Здесь, почему-то, 0
    Dbg("Leaders cnt: ", leaders->GetCount());        // И здесь тоже 0
 
    ILineDimensions3DPtr dims3d = s3d->GetLineDimensions3D();
    for (long i = 0; i < dims3d->GetCount(); i++)    // dims3d->GetCount() возвращает 1
    {
        ILineDimension3DPtr dim = dims3d->GetLineDimension3D(i);
        IDimensionParamsPtr dimPars(dim);
 
        IBase3DPtr base = bases->GetBase3D(i);                // null, по понятным причинам
        IBaseLeader3DPtr leader = leaders->GetLeader3D(i);    // null
 
        if (dimPars)
        {
            ksDimensionArrowPosEnum arrPos = dimPars->GetArrowPos();   // Много чего есть, кроме того, что мне нужно
            ksArrowEnum arrType1 = dimPars->GetArrowType1();
            ksArrowEnum arrType2 = dimPars->GetArrowType2();
            bool isGap = dimPars->GetGap();
            long gapVal = dimPars->GetGapValue();
            bool rl1 = dimPars->GetRemoteLine1();
            bool rl2 = dimPars->GetRemoteLine2();
            double shelfAngle = dimPars->GetShelfAngle();
            ksShelfDirectionEnum shelfDir = dimPars->GetShelfDirection();
            double shelfLen = dimPars->GetShelfLength();
            ksDimensionBaseEnum txtBase = dimPars->GetTextBase();
            ksDimensionTextPosEnum txtPos = dimPars->GetTextOnLine();
            ksDimensionTextTypeEnum txtType = dimPars->GetTextType();
        }
        IDimensionTextPtr dimText(dim);
        if (dimText)
        {
            double nomVal = dimText->GetNominalValue();
            ITextLinePtr dimTextLine = dimText->GetNominalText();
            ksDimensionTextBracketsEnum txtBracket = dimText->GetBrackets();
            ksDimensionDeviationEnum dimDev = dimText->GetDeviationType();
            bool hasTolerance = dimText->GetHasTolerance();
            ITextLinePtr highDev = dimText->GetHighDeviation();
            ITextLinePtr lowDev = dimText->GetLowDeviation();
            ITextLinePtr prefix = dimText->GetPrefix();
            bool rect = dimText->GetRectangle();
            long sign = dimText->GetSign();
            BSTR signFont = dimText->GetSignFont();
            DbgW(L"signFont: ", signFont);
            ITextLinePtr suffix = dimText->GetSuffix();
            ksDimensionTextAlignEnum txtAlign = dimText->GetTextAlign();
            ksDimTextFormatEnum txtFmt = dimText->GetTextFormat();
            ITextPtr textUnder = dimText->GetTextUnder();
        }
        BSTR name = dim->GetName(); // name будет "Линейный от отрезка до точки:1", хотя не понятно мне, почему такое название, я когда строил этот размер, то указывал 2 грани на детали и плоскость
        IModelObjectPtr obj1 = dim->GetObject1();   // Как-то можно этот объект использовать
        double len = dim->GetLength();
        IModelObjectPtr obj2 = dim->GetObject2();   // И этот?
        IModelObjectPtr plane = dim->GetPlane();
 
        IModelObjectPtr dimMo = dims3d->GetItem(i);
        IPart7Ptr dimPart7 = dimMo->GetPart();
        IPlacement3DPtr dimPlmt = dimPart7->GetPlacement();  // из IPlacement3D не нашел ничего стоящего, что можно было бы получить
    }
}

Этот код мало что дает.
Например, мне нужны координаты выносных линий (3 координаты начала и три координаты конца), координаты размерной линии.
Я думал, что смогу получить их через соответствующие интерфейсы:

Цитата: undefinedIBases3DPtr bases = s3d->GetBases3D();
ILeaders3DPtr leaders = s3d->GetLeaders3D();

Но, как я уже писал в комментариях к коду, bases->GetCount() и leaders->GetCount() возвращают 0.

Что я делаю не правильно?

p3452

Пытаетесь получить то чего у Вас нет...

На примере Линейного размера последовательность будет такой:
IPart7 as Symbols3DContainer
ISymbols3DContainer.LineDimensions3D
LineDimensions3D.LineDimension3D
IBaseLineDimension3D
IBaseLineDimension3D as IDimensionText
IBaseLineDimension3D as IDimensionParams
   IDimensionText...
   IDimensionParams...

Denis78

ЦитироватьПытаетесь получить то чего у Вас нет...

Вот не совсем понял, что имеется ввиду. Вроде как, выносные линии есть (они красным на чертеже выделены), неужели нельзя получить координаты начала/конца этих линий?! И размерной тоже. На двумерном чертеже у меня такое получалось. К сожалению, на трехмерном все иначе и опыт двумерного чертежа тут бесполезен.

А по поводу приведенной последовательности, так у меня почти все так и есть. Только IBaseLineDimension3D я не использую, там все равно ничего интересного для меня нет(((
IDimensionText и IDimensionParams я получаю (можно прямо поиском пройти, чтобы весь код не шерстить), только там содержится не все, что мне надо.

Denis78

#6
Нашел такой пример кода
Цитироватьmo:=sc.LineDimensions3D.LineDimension3D.Object1;
vd:=IUnknown(ksTransferInterface(LtDefine.PIUnknown(mo),ksAPI3DCom,o3d_vertex)) as iVertexDefinition;
if vd<>nil then
    begin
    vd.GetPoint(x1,y1,z1);
    showmessage(floattostr(x1)+' '+floattostr(y1)+' '+floattostr(z1)+' ');
    end;

Здесь sc - это указатель на интерфейс ISymbols3DContainer

Object1  у меня уже есть, пытаюсь провернуть то же самое на плюсах:

IModelObjectPtr obj1 = dim->GetObject1();
ksVertexDefinitionPtr vd(IUnknownPtr(kompas->TransferInterface(obj1, ksAPI3DCom, o3d_vertex)));

При чем kompas->TransferInterface() возвращает какой-то валидный указатель, то есть не null.
А вот vd все равно становится равным null, не знаю почему.
Запись типа
ЦитироватьksVertexDefinitionPtr vd = IUnknownPtr(kompas->TransferInterface(obj1, ksAPI3DCom, o3d_vertex));
Дает то же самое, то есть vd все равно равен null.

Что-то можно с этим сделать?

p3452

Цитата: Denis78 от 27.05.22, 11:21:19Вот не совсем понял, что имеется ввиду...

IBases3D - Интерфейс коллекции обозначений базы 3D
ILeaders3D - Интерфейс коллекции линий-выносок 3D
У Вас в модели нет ни того ни другого...

Еще раз прочтите пост №4.


Denis78

Так, может, я с терминологией ошибаюсь.

Вот размер, состоит, грубо говоря из трех отрезков (размерные линии, наверное, правильно они называются) и текста. Текст я получать умею. А вот координаты этих трех отрезков (красным на чертеже выделены) как получить?

p3452

Цитата: Denis78 от 27.05.22, 14:19:03Так, может, я с терминологией ошибаюсь.
"может" :)
(Зайдите в Компас - проверьте)

Denis78

Давайте не будем к словам цепляться.

Я специально красным выделил те размерные линии, координаты которых мне нужны.

Знаете как их получить?

p3452

Цитата: Denis78 от 27.05.22, 15:02:57Знаете как их получить?
см. пост №4
(Диалог прекращаю - Вы не умеете читать, не хотите думать...)

Denis78

Уж коли не знаешь, нафига пальцы гнуть?

А коли знаешь, так объясни по-человечески. И что за пост №4? В этой теме? Так это мой.

Если имелся ввиду пятый, то есть, вот этот:
ЦитироватьНа примере Линейного размера последовательность будет такой:
IPart7 as Symbols3DContainer
ISymbols3DContainer.LineDimensions3D
LineDimensions3D.LineDimension3D
IBaseLineDimension3D
IBaseLineDimension3D as IDimensionText
IBaseLineDimension3D as IDimensionParams
   IDimensionText...
   IDimensionParams...

Так про  него я уже писал.

ЦитироватьА по поводу приведенной последовательности, так у меня почти все так и есть. Только IBaseLineDimension3D я не использую, там все равно ничего интересного для меня нет(((
IDimensionText и IDimensionParams я получаю (можно прямо поиском пройти, чтобы весь код не шерстить), только там содержится не все, что мне надо.

То есть, все упомянутые интерфейсы уже получены, но нужных координат там НЕТ!!!

Vi2

Цитата: Denis78 от 27.05.22, 12:00:22Object1  у меня уже есть, пытаюсь провернуть то же самое на плюсах:
IModelObjectPtr obj1 = dim->GetObject1();
ksVertexDefinitionPtr vd(IUnknownPtr(kompas->TransferInterface(obj1, ksAPI3DCom, o3d_vertex)));
При чем kompas->TransferInterface() возвращает какой-то валидный указатель, то есть не null.
А вот vd все равно становится равным null, не знаю почему.
...
Что-то можно с этим сделать?
А ответ прост: у ненулевого интерфейса запрашивается тот интерфейс, который этот объект не поддерживает.
В Компасе на объекте есть смешение интерфейсов API5, API7 и API3DCOM, которые TransferInterface переключает и описывает так:
ЦитироватьksAPI5Auto 1 API5 - интерфейсы автоматизации, т.е. ksVertexDefinition
ksAPI7Dual 2 API7 - дуальные интерфейсы. т.е. IModelObject
ksAPI3DCom 3 API 3D COM - интерфейсы, т.е. IVertexDefinition
Соответственно, что запрашиваешь, то и пытайся получить: запрашиваешь ksAPI3DCom, значит, и интерфейс IVertexDefinition. Который между прочим и указан в исходном примере.

Denis78

Пробовал и так
IVertexDefinitionPtr vd(kompas->TransferInterface(obj1, ksAPI3DCom, o3d_vertex));

vd все равно NULL.

Если вместо obj1 подставлять obj2 и plane, то все равно vd будет NULL, хотя в дебагере видно, что TransferInterface() возвращает валидый указатель. Зануляется он только в конструкторе IVertexDefinitionPtr.

PS Запись вида:
IVertexDefinitionPtr vd = kompas->TransferInterface(obj1, ksAPI3DCom, o3d_vertex);
сути не меняет, все равно NULL, при чем история такая же, TransferInterface() возвращает валидый указатель, после операции присвоения же vd становится NULL

Vi2

Цитата: Denis78 от 30.05.22, 14:18:46Пробовал и так
IVertexDefinitionPtr vd(kompas->TransferInterface(obj1, ksAPI3DCom, o3d_vertex));

vd все равно NULL.
Попробуй интерфейс IEntity, а потом перейдёшь к IVertexDefinition через IEntity::GetDefinition().

По поводу PS: на С++ это почти эквивалентные предложения, поэтому не удивительно, что результат одинаков.
+ Благодарностей: 1

Denis78

Цитата: Vi2 от 30.05.22, 14:27:38Попробуй интерфейс IEntity, а потом перейдёшь к IVertexDefinition через IEntity::GetDefinition().

Пробовал так:

// здесь doc - указатель на ksDocument3D (ksDocument3DPtr)
ksPartPtr part(doc->GetPart(pTop_Part));
if (part)
{
    ksEntityCollectionPtr ec = part->EntityCollection(o3d_lineDimension3D);
    for (long i = 0; i < ec->GetCount(); ++i)  // ec->GetCount() возвращает 1, что, полагаю, верно, поскольку на чертеже только один линейный размер
    {
        ksEntityPtr ent = ec->GetByIndex(i);   // Валидный указатель
        Obj3dType type = (Obj3dType)doc->GetObjectType(ent->GetDefinition());  // А вот здесь странно, type = o3d_lineDimension3D
        ksVertexDefinitionPtr vx = ent->GetDefinition();    // Здесь NULL, то есть, всё плохо
    }
}


Вообще, в документации метод описан так:
LPUNKNOWN GetDefinition();

В примечании сказано: "Для доступа к параметрам объекта полученный интерфейс необходимо привести к соот­ветствующему типу"
Тогда вопрос, а как узнать, к чему приводить?
В моем примере возвращаемый type равен o3d_lineDimension3D.

В той же доке есть соответствие объектов и интерфейсов API 5 и API 7. Согласно ей,
o3d_lineDimension3D - Линейный размер 3D соответствует ILineDimension3D
Но объект типа ILineDimension3D у меня уже есть.

Возможно, нужно вместо ksEntityPtr использовать именно IEntity, но как его получить, я не знаю (аналогичным образом, через GetPart() не получается)

KrissKross

Предпосылки:
Когда выделяем 3д размер - видим характерные точки

Возможное решение:
Попробуйте получить параметры - характерных точек / манипуляторов
для API7
посмотрите интерфейсы:
IProcess3D
IManipulators
IPlacement3D

у IPlacement3D есть метод GetMatrix3D() - Получить матрицу системы координат в виде массива
+ Благодарностей: 1

p3452


Denis78

#19
Цитата: KrissKross от 30.05.22, 18:14:09Предпосылки:
Когда выделяем 3д размер - видим характерные точки

Возможное решение:
Попробуйте получить параметры - характерных точек / манипуляторов
для API7
посмотрите интерфейсы:
IProcess3D
IManipulators
IPlacement3D

у IPlacement3D есть метод GetMatrix3D() - Получить матрицу системы координат в виде массива

Да, идея хорошая, но вот я никак не могу ее реализовать

IKompasDocument3D1Ptr doc3D1(newKompasAPI->ActiveDocument);
ksSelectionMngPtr selMgr = doc->GetSelectionMng();

if (selMgr)
{
    bool res = selMgr->Select(dim);  // Здесь dim - объект типа ILineDimension3D, я его уже получил
    // К сожалению, res возвращается равным false, то есть функция Select() завершилась неудачей. Почему - не ясно, неужели невозможно выделить размер? Вручную-то можно.

    IProcess3DPtr proc(doc3D1->LibProcess[ksProcess3DPlacementAndEntity]);
    if (proc)
    {
        IManipulatorsPtr mans = proc->GetManipulators();  // Вот здесь вообще вылетает Exception. Почему, не знаю. proc - валидный указатель. Возможно, потому, что ничего не выделено.
        // Хотя предположение так себе, ведь в данной ситуации проще было бы возвращать нулевой указатель.

        if (mans)
        {
            long mansCnt = mans->GetCount();  // Сюда мы, соответственно, не попадаем
        }
    }
}

Что касается IPlacement3D, то согласно документации, это "Интерфейс локальной системы координат"
Но я его все равно его получил и распечатал (код не прилагаю, вряд ли кому это интересно)
GetMatrix3D() возвращает матрицу 4х4 (описана, например, здесь https://studref.com/472293/tehnika/matrichnye_metody_preobrazovaniya_koordinat_robototehnike)
Выглядит она так:
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
Еще у плэйсмента есть GetOrigin(), но и тут одни нули:
GetOrigin: x = 0.000000 , y = 0.000000 , z = 0.000000
Хотя, если учесть, что IPlacement3D - это интерфейс ЛСК, то, вроде бы, все логично

Возможно, где-то что-то не "докрутил"

PS. Вообще, мне кажется, должен быть способ проще. Что я имею ввиду.
Если написать так:
IUnknownPtr vd(kompas->TransferInterface(obj1, ksAPI3DCom, o3d_vertex));
то vd - валидный указатель. Но на что? Казалось бы, ответ очевиден, на IVertexDefinition, но нет. Если написать так:
IVertexDefinitionPtr vd(kompas->TransferInterface(obj2, ksAPI3DCom, o3d_vertex));
vd будет равным NULL. То есть вместо IVertexDefinitionPtr нужно что-то иное.