Запрет перемещения объекта

Автор Тема: Запрет перемещения объекта  (Прочитано 18842 раз)

0 Пользователей и 6 Гостей просматривают эту тему.

Оффлайн AlexАвтор темы

  • ADN Club
  • Сообщений: 36
  • Карма: 1
Здравствуйте.
Ситуация следующая: на чертеже есть блок (BlockReference). Хотелось бы дать пользователю возможность этот блок вращать, но при этом не разрешать его перемещение (а в идеале - и удаление, и все остальное, кроме вращения).
Идеальным вариантом было бы вообще заблокировать слой - но тогда и вращать не получается.(
Можно, конечно, написать отдельную процедуру и сделать свою обвязку для вращения блока - но как-то не хочется, потому что в AutoCAD все и так здорово работает.
----
Первой моей мыслью было посмотреть события BlockReference. Навскидку нашлись Modified и OpenedForModify - но при попытке изменить кооринату блока внутри этих событий AutoCAD начинает ОЧЕНЬ меня не любить.(
На форуме AutoCAD я несколько раз (тема №1, тема №2) встретил хмурую точку зрения, гласящую, что отменить перемещение в событии вообще никак нельзя, а желающие вместо этого могут запоминать ID измененных объектов, чтобы потом вручную положить их на прежнее место - например, в событии Editor.EnteringQuiencentState.
----
Собственно вопросы:
1. Можно ли исходную задачу (запретить перемещение блока, разрешив при этом вращение) решить более простым способом?
2. Если нет - можно ли отменить перемещение объекта непосредственно в момент изменения (в рамках какого-либо события), а не после него?
Спасибо.
« Последнее редактирование: 28-01-2014, 21:39:33 от Alex »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Запрет перемещения объекта
« Ответ #1 : 29-01-2014, 04:11:19 »
1. Можно ли исходную задачу (запретить перемещение блока, разрешив при этом вращение) решить более простым способом?
Простых способов нет.
2. Если нет - можно ли отменить перемещение объекта непосредственно в момент изменения (в рамках какого-либо события), а не после него?
Нет, если речь идет о событии.
НО!!! Можно попробовать пойти совсем другим путем, который называется Overrule (а точнее TransformOverrule). Я не нашел готового примера на .NET. Вот пример с использованием ObjectARX: Locking an Entity in AutoCAD using ObjectARX (я его еще не успел перевести).
Тебе придется переопределить метод TransfomBy и анализировать матрицу Matrix3d передаваемую в этот метод на предмет того только ли операция поворота затребована.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей Бушман

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Запрет перемещения объекта
« Ответ #2 : 29-01-2014, 10:37:36 »
Я не нашел готового примера на .NET. Вот пример с использованием ObjectARX: Locking an Entity in AutoCAD using ObjectARX (я его еще не успел перевести).
Полагаю, что ему не сильно поможет пример, написанный на native C++. Ежели вы всё же решите переводить обозначенную вами заметку, то наличие альтернативного кода на C# было бы не лишним (имхо).

Цитата: Alex
Собственно вопросы...
Чертёж могут открыть на компьютере, где твой плагин отсутствует и спокойно выполнить все те операции, которые ты желаешь запретить (скорее всего именно так и будут поступать, когда возникнет желание обойти созданные тобою ограничения). Так что способ не надёжен (имхо).

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Запрет перемещения объекта
« Ответ #3 : 29-01-2014, 18:58:09 »
Ежели вы всё же решите переводить обозначенную вами заметку, то наличие альтернативного кода на C# было бы не лишним (имхо).
Статью обязательно переведу и сделаю вариант с использованием AutoCAD .NET API. В первую очередь потому, что не нашел нигде готового примера использующего подмену TransfomBy в TransformOverrule.
Так что способ не надёжен (имхо).
Абсолютно с тобой согласен. Единственный надежный, но очень неудобный вариант - это Custom Entity (т.е. чистый ObjectARX). Но это приведет в последствии к таким сложностям, что лучше уж разрешить пользователю делать с этим блоком всё что угодно.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн AlexАвтор темы

  • ADN Club
  • Сообщений: 36
  • Карма: 1
Re: Запрет перемещения объекта
« Ответ #4 : 29-01-2014, 19:19:31 »
Спасибо за ответы и рекомендацию.
Я еще не пробовал применять этот пример, но если в .NET API есть реализации этих классов Object ARX, то я попробую все прикрутить.
Если получится - напишу, если не получится - напишу тем более.)
P. S. Я понимаю, что при желании с чертежом можно будет сделать все, что угодно. Но использовать этот чертеж без плагина будет бессмысленно.
Объекты на плане - это только отображение данных; изменение чертежа к изменениям данных приводить не должно.
Во всяком случае, пока.
Во всяком случае, я так думаю.)

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Запрет перемещения объекта
« Ответ #5 : 29-01-2014, 19:22:41 »
Я еще не пробовал применять этот пример, но если в .NET API есть реализации этих классов Object ARX, то я попробую все прикрутить.
Есть. Класс TransformOverrule.

Во всяком случае, я так думаю.)
Я бы добавил: "Во всяком случае, я пока так думаю."
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн AlexАвтор темы

  • ADN Club
  • Сообщений: 36
  • Карма: 1
Re: Запрет перемещения объекта
« Ответ #6 : 29-01-2014, 19:28:14 »
Я бы добавил: "Во всяком случае, я пока так думаю."
Именно такой смысл и предполагался.)
В конце концов, программирование - это же не точная наука!  ;D

Оффлайн AlexАвтор темы

  • ADN Club
  • Сообщений: 36
  • Карма: 1
Re: Запрет перемещения объекта
« Ответ #7 : 30-01-2014, 00:33:24 »
Да, с ходу взять ObjectARX не вышло.)
Но я нашел два примера у Kean Walmsley: TransformOverrule, GripOverrule.
TransformOverrule отлично работает, обычное перемещение блоков блокируется.
А вот с GripOverrule получается печаль: при переопределении стандартной GripOverrule почему-то пропадает сам ползунок вращения. Просто пропадает, и все.
Есть интересный ответ Kean'а посетителю блога:
Цитировать
...if you overrule grips for blocks - even with an implementation of your methods that just supermessages to the base class - the existing grip move operation appears to stop working (although you could basically implement it yourself, if you needed to overrule grip move for blocks and have additional behaviour to want to implement).
Либо я где-то ошибся, либо для того, чтобы все заработало, нужно вручную переписать методы GripOverrule...

Оффлайн Дмитрий Загорулькин

  • ADN
  • *
  • Сообщений: 2531
  • Карма: 737
Re: Запрет перемещения объекта
« Ответ #8 : 30-01-2014, 10:28:20 »
Там была какая-то ошибка в кодах по GripOverrule. Вот тут я разбирался с ним: http://forum.dwg.ru/showthread.php?t=99011&highlight=gripoverrule
Насколько я помню, первая ошибка была в построении командного класса, из-за которого лишние действия происходили. А вторая - неправильное вычисление положения переопределенных ручек, из-за чего они улетали "в космос". Возможно, что и в Вашем случае ползунок не пропадает, а находится где-то в стороне.
« Последнее редактирование: 30-01-2014, 10:42:10 от Загорулькин Дмитрий »

Оффлайн Константин Соков

  • ADN Club
  • **
  • Сообщений: 56
  • Карма: 0
Re: Запрет перемещения объекта
« Ответ #9 : 01-02-2014, 01:11:14 »
запретить перемещение блока, разрешив при этом вращение
Может можно средствами ArxDbg это сделать

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Запрет перемещения объекта
« Ответ #10 : 01-02-2014, 02:48:51 »
Может можно средствами ArxDbg это сделать
Поясни как ты себе это представляешь? И кстати написана она на чистом C++ с использованием ObjectARX, и использует такие вещи, которых в AutoCAD .NET API нет.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн AlexАвтор темы

  • ADN Club
  • Сообщений: 36
  • Карма: 1
Re: Запрет перемещения объекта
« Ответ #11 : 01-02-2014, 19:38:26 »
Вот тут я разбирался с ним
Большое спасибо за ссылку, этот пример очень помог.
Как выяснилось, дело было в переопределении метода GetGripPoints().
В интерфейсе Autodesk.AutoCAD.DatabaseServices.GripOverrule присутствует два метода GetGripPoints:
public virtual void GetGripPoints(Entity entity, Point3dCollection gripPoints, IntegerCollection snapModes, IntegerCollection geometryIds);
public virtual void GetGripPoints(Entity entity, GripDataCollection grips, double curViewUnitSize, int gripSize, Vector3d curViewDir, GetGripPointsFlags bitFlags);
В примере, который я нашел в блоге Kean'а, переопределялся только первый метод GetGripPoints(). При этом у блока остается ручка, отвечающая за перемещение, но пропадает ручка, отвечающая за поворот.
А в том примере, который предоставил Дмитрий, переопределялся второй метод GetGripPoints(). При этом у блока сохраняется как ручка, отвечающая за перемещение, так и ручка, отвечающая за поворот.
P.S. Только что проверял. Создаю реализацию интерфейса GripOverrule,  которую потом активизирую:
GripOverrule.AddOverrule(RXClass.GetClass(typeof(BlockReference)), new GripVectorOverrule(), true);
GripVectorOverrule.Overruling = true;
В первом случае пишу реализацию класса GripVectorOverrule так:
public class GripVectorOverrule : GripOverrule
{
public override void GetGripPoints(Entity entity, Point3dCollection gripPoints, IntegerCollection snapModes, IntegerCollection geometryIds)
{
base.GetGripPoints(entity, gripPoints, snapModes, geometryIds);
}
}
При таком определении ручка вращения пропадает.
А можно попробовать такую реализацию GripVectorOverrule:
public class GripVectorOverrule : GripOverrule
{
public override void GetGripPoints (Entity entity, GripDataCollection grips, double curViewUnitSize, int gripSize, Vector3d curViewDir, GetGripPointsFlags bitFlags)
{
base.GetGripPoints(entity, grips, curViewUnitSize, gripSize, curViewDir, bitFlags);
}
}
При таком определении ручка вращения остается на месте.
Пока так... Сейчас еще один пост напишу, отчетный.)

Оффлайн AlexАвтор темы

  • ADN Club
  • Сообщений: 36
  • Карма: 1
Re: Запрет перемещения объекта
« Ответ #12 : 01-02-2014, 20:09:54 »
Итого в сухом остатке сделал так:
1) в TransformOverrule решение о том, перемещать блок или нет, принимается на основе слоя, на котором расположен блок (других блоков на этом слое нет; но в принципе при необходимости можно проверять и имя блока);
2) в GripOverrule я не стал анализировать матрицы, а просто убрал ручку, отвечающую за перемещение блока (этот прием изложен здесь).
Теперь двигать блоки вроде бы нельзя. По крайней мере, случайно блок не сдвинешь - а мне как раз это и требовалось.)

Код:
public class Commands : IExtensionApplication
{
public void Initialize()
{
ObjectOverrule.AddOverrule(RXClass.GetClass(typeof(BlockReference)), new TransformVectorOverrule(), true);
GripOverrule.AddOverrule(RXClass.GetClass(typeof(BlockReference)), new GripVectorOverrule(), true);
TransformVectorOverrule.Overruling = true;
GripVectorOverrule.Overruling = true;
}
}

public class TransformVectorOverrule : TransformOverrule
{
public override void TransformBy(Entity entity, Matrix3d matrix)
{
if ((entity as BlockReference) != null && ((entity as BlockReference).Layer == myLayerName))
{
return;
}
base.TransformBy(entity, matrix);
return;
}
}

public class GripVectorOverrule : GripOverrule
{
public override void GetGripPoints (Entity entity, GripDataCollection grips, double curViewUnitSize, int gripSize, Vector3d curViewDir, GetGripPointsFlags bitFlags)
{
base.GetGripPoints(entity, grips, curViewUnitSize, gripSize, curViewDir, bitFlags);

if ((entity as BlockReference) != null && ((entity as BlockReference).Layer == myLayerName))
{
    GripData toRemove = null;
    foreach (GripData gd in grips)
    {
        if (gd.GripPoint == (entity as BlockReference).Position)
        {
            toRemove = gd;
            break;
        }
    }
    if (toRemove != null)
        grips.Remove(toRemove);
}
}
}

P.S. Остались неясными два вопроса.

1. Вместо
TransformVectorOverrule.Overruling = true;
GripVectorOverrule.Overruling = true;
можно с тем же успехом написать
Overrule.Overruling = true;
Нужно ли было переопределять свойство Overruling для классов TransformVectorOverrule и GripVectorOverrule? У меня такое чувство, что да...

2. В статье про удаление ручек для удаления ручки из списка почему-то используется довольно вычурная конструкция
GripData toRemove = null;
foreach (GripData gd in grips)
{
if (gd.GripPoint == (entity as BlockReference).Position)
{
toRemove = gd;
break;
}
}
if (toRemove != null)
grips.Remove(toRemove);
Я попробовал переписать ее чуть короче:
foreach (GripData gd in grips)
{
if (gd.GripPoint == (entity as BlockReference).Position)
{
grips.Remove(gd);
break;
}
}
Это вроде тоже работает. Зачем авторы примера вводят дополнительную переменную toRemove?

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13882
  • Карма: 1787
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Запрет перемещения объекта
« Ответ #13 : 01-02-2014, 20:17:07 »
TransformBy - это не только перемещение, но и поворот. Поэтому без анализа матрицы в TransformVectorOverrule (IMHO) ты запрещаешь для этого блока команду _ROTATE, что не есть правильно в твоей постановке задачи.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн AlexАвтор темы

  • ADN Club
  • Сообщений: 36
  • Карма: 1
Re: Запрет перемещения объекта
« Ответ #14 : 01-02-2014, 20:51:14 »
поворот
Здесь написано, что для матрицы преобразования
(
    (a b c x)
    (d e f y)
    (g h j z)
    (0 0 0 1)
)
угол поворота будет вычисляться по формуле
θ  =  atan(d/a)
Это соответствует действительности?
Я попробовал изменить условие:
if ((entity as BlockReference) != null && ((entity as BlockReference).Layer == XChange.surappDrillersLayerName) && (System.Math.Atan(matrix[1,0]/matrix[0,0]) == 0))
Теперь поворачивается в том числе и командой _ROTATE.