В данной небольшой заметке я не открою Америку и не расскажу что-то уникальное. Но заметку я решил написать, так как не сразу можно догадаться о причинах такого поведения.
Итак, у вас есть команда, работающая по сценарию: запуск команды, выбор примитива, какие-то действия с примитивом. И может случиться так: вы запустили команду, начался запрос на выбор примитива, вы покрутили колесиком, а затем нажали Esc и произошло зуммирование к тем границам экрана, которые были до вызова команды. Иногда это может сильно бесить пользователей.
This article was written to bring together scattered information about working with colors in the AutoCAD .NET API. It also covers some practical use cases beyond simply changing an entity’s color.
Листая блог Джереми Таммика наткнулся на статью FilterRule Use and Retrieving Exterior Walls одной из тем которой была тема поиска наружных стен. Там приводится несколько вариантов решения. При этом есть важное условие – наружные стены обязательно должны образовывать замкнутый контур. И даже при этом предложенные варианты могут не дать нужного варианта.
В нескольких моих плагинах решалась похожая задача и был придуман алгоритм поиска наружных стен. Скорее всего и мой алгоритм не идеален, но при тестировании показал высокие результаты. В самой статье я не буду выкладывать частей кода – в конце статьи вы найдете ссылку на репозиторий GitHub.
В решении некоторых плагинов бывает возникает такая задача и мы начинаем искать решения в интернете, а там сложные формулы прямой на плоскости или в пространстве.
Если скалярное произведение двух единичных векторов по модулю равно 1, то эти два вектора коллинеарны (параллельны друг другу).
Если произведение будет 1 – вектора направлены в одну сторону, а если -1 – в противоположные. Но в нашей задаче это не важно и нас интересует только модуль произведения. Из первого утверждения получаем метод проверки параллельности:
Мы уже решили половину задачи. А полное решение искомой задачи звучит так:
Два отрезка лежат на одной прямой если каждый единичный вектор, построенный через любую пару концевых точек двух отрезков, коллинеарен единичному вектору направления одного из отрезков.
Причем это утверждение будет работать и в 3D пространстве, а не только на плоскости.
Ну и конечно код этого решения в виде метода расширения для отрезка:
/// <summary>
/// Лежат ли текущий и проверяемый отрезок на одной прямой.
/// </summary>
/// <param name="firstLine">Текущий отрезок</param>
/// <param name="secondLine">Проверяемый отрезок</param>
/// <param name="tolerance">Допуск на сравнение чисел</param>
public static bool IsLieOnSameStraightLine(this Line firstLine, Line secondLine, double tolerance = 0.0001)
{
// Если два отрезка не параллельны, то и дальнейшая проверка не требуется
if (!firstLine.IsParallelTo(secondLine))
return false;
// Можно получить все концевые точки методом GetEndPoint(int), но это приведет к раздутию
// кода и его некрасивости. Поэтому используем метод Tessellate(), который для отрезков вернет
// те же самые две концевые точки
var firstLinePoints = firstLine.Tessellate();
var secondLinePoints = secondLine.Tessellate();
// Вектор первого отрезка будем использовать как эталон проверки.
// Свойство Direction всегда содержит единичный вектор
var fv = firstLine.Direction;
// Нам требуется проверять попарно концевые точки первого отрезка с концевыми точками второго.
// Это удобно сделать двумя итерациями
foreach (var firstLinePoint in firstLinePoints)
{
foreach (var secondLinePoint in secondLinePoints)
{
// Если два отрезка будут будут иметь общую концевую точку, то проверка сработает не верно,
// так как произведение векторов даст 0.0. Такие пары просто пропускаем
if (Math.Abs(firstLinePoint.DistanceTo(secondLinePoint)) < tolerance)
continue;
// Не важно из какой какую точку отнимать. Главное, привести к единичному вектору
var v = (secondLinePoint - firstLinePoint).Normalize();
// Если вектора не параллельны, то и отрезки не лежат на одной прямой
if (!fv.IsParallelTo(v))
return false;
}
}
// Если в предыдущих итерациях мы не вышли из метода, значит два отрезка лежат на одной прямой
return true;
}
Не забывайте, что в Revit есть отрезки, а есть лучи, и оба они представлены типом Line. Данный код не учитывает таких различий
Earlier we had a post about Origin in PlanarFace, where we wrote that Origin may not be within the PlanarFace plane contour boundaries. And recently we came across another undocumented aspect of Revit API, which in some cases can lead to incorrect operation of the intended algorithm. And this aspect is the Origin property of a Line obtained by the Solid.IntersectWithCurve method.
Let's describe it by example: let's create an element with a solid body in an empty project and take its Solid:
var uiDoc = commandData.Application.ActiveUIDocument;
var doc = uiDoc.Document;
var element = doc.GetElement(uiDoc.Selection.PickObject(ObjectType.Element));
var solid = (Solid)element
.get_Geometry(new Options { DetailLevel = ViewDetailLevel.Fine })
.GetTransformed(Transform.Identity)
.First(e => e is Solid { Volume: > 0 });
Since we used a column for the example, we know for sure that it has an insertion point. Let's take this point and use it to create a long auxiliary Line:
var pt = ((LocationPoint)element.Location).Point;
var helpLine = Line.CreateBound(
pt - (XYZ.BasisZ * 1000),
pt + (XYZ.BasisZ * 1000));
Then we use the Solid.IntersectWithCurve method and get a Line located inside the Solid of our element:
var result = solid.IntersectWithCurve(
helpLine,
new SolidCurveIntersectionOptions { ResultType = SolidCurveIntersectionMode.CurveSegmentsInside });
var insideLine = (Line)result.GetCurveSegment(0);
So, if we now look at the properties of this Line, we see that its Origin remains the same as the original auxiliary Line! And if you take the parameters of this Line at the beginning and at the end, you will get not the most expected values:
While there are not many cases where this can negatively affect the algorithm, there are still cases. Therefore, it is better to know about this feature in advance
Ранее у нас была заметка про Origin у PlanarFace, где мы писали, что Origin может не находиться в границах контура плоскости PlanarFace. А недавно мы столкнулись с еще одной недокументированной особенностью Revit API, которая в некоторых случаях может привести к неправильной работе задуманного алгоритма. И эта особенность – свойство Origin у отрезка, полученного методом Solid.IntersectWithCurve.
Опишем сразу на примере: создадим в пустом проекте элемент с твердым телом и возьмём его твердое тело:
var uiDoc = commandData.Application.ActiveUIDocument;
var doc = uiDoc.Document;
var element = doc.GetElement(uiDoc.Selection.PickObject(ObjectType.Element));
var solid = (Solid)element
.get_Geometry(new Options { DetailLevel = ViewDetailLevel.Fine })
.GetTransformed(Transform.Identity)
.First(e => e is Solid { Volume: > 0 });
Так как для примера мы использовали колонну, то мы точно знаем, что у неё есть точка вставки. Возьмем эту точку и с ее помощью создадим длинный вспомогательный отрезок:
var pt = ((LocationPoint)element.Location).Point;
var helpLine = Line.CreateBound(
pt - (XYZ.BasisZ * 1000),
pt + (XYZ.BasisZ * 1000));
Ну а далее используем метод Solid.IntersectWithCurve и получим отрезок, расположенный внутри твердого тела нашего элемента:
var result = solid.IntersectWithCurve(
helpLine,
new SolidCurveIntersectionOptions { ResultType = SolidCurveIntersectionMode.CurveSegmentsInside });
var insideLine = (Line)result.GetCurveSegment(0);
Так вот, если теперь мы посмотрим на свойства этого отрезка, то увидим, что его Origin остался такой-же, как был у исходного вспомогательного отрезка! И если вы возьмете у этого отрезка параметры в начале и в конце, то получите не самые ожидаемые значения:
И хотя случаев, где это может негативно сказаться на работе алгоритма, не много, они все же есть. Поэтому лучше знать про эту особенность заранее
Маленькая заметка для всех программистов, использующих в своих проектах WPF. Наверняка многие из вас задавались вопросом «как увеличить время отображения подсказок?» или «как сделать так, чтобы подсказка выскочила сразу при наведении мышки на элемент?»
Как оказалось, в WPF есть целая служба, которая предоставляет свойства и события для управления отображением и поведением подсказок – ToolTipService. Единственная проблема использования этого сервиса заключается в том, что IntelliSense не показывает нам наличие этого сервиса, и поэтому многие о нём просто не знают!
Самые полезные (лично для меня) свойства, которые предоставляет сервис:
InitialShowDelay - получает или задает интервал времени до открытия подсказки.
ShowDuration - получает или задает количество времени отображения подсказки.
ShowOnDisabled - получает или задает значение, указывающее, отображается ли всплывающая подсказка для объекта, который не активен.
Со всеми остальными свойствами и примером использования Вы можете ознакомиться в справке на MSDN. Берите себе на заметку!
Будет такая небольшая рубрика - Вы могли не знать как это работает. Буду в этой рубрике писать о случаях, когда какое-то свойство или метод оказались не тем, что я предполагал. Записей возможно будет немного
Сегодня в этой рубрике рассмотрим свойство Origin у типа PlanarFace. Сама PlanarFace - это грань тела или оболочки, ограниченная контуром. У PlanarFace есть контуры, которые мы можем получить из свойства EdgeLoops родительского класса Face. Т.е. зрительно мы себе можем представить как выглядит PlanarFace - некоторая ограниченная плоскость, расположенная в пространстве.
А вот самое интересное - у PlanarFace есть свойство Origin - т.е. начало плоскости - которое НЕ ОБЯЗАТЕЛЬНО НАХОДИТСЯ ВНУТРИ КОНТУРА ПЛОСКОСТИ! Графически такой случай будет выглядеть примерно так:
Так что прежде чем использовать свойство Origin в своих целях, учтите, что эта точка может лежать достаточно далеко от самой PlanarFace!
Стояла передо мной задача - проставить марки для 2D-семейств, представляющих собой арматурный каркас. Основная загвоздка при этом - нужно создать несколько марок, которые будут расположены в одной точке. По картинке, думаю, понятнее:
Стояла у меня задача, для выполнения которой требовалось создание собственного типа для системного семейства Текст (Текстовое примечание).
Немного поискав информацию на просторах интернета, я наткнулся на данный пример, объясняющий, что для создания типа требуется создавать дубликат существующего типа. Вот только в примере совсем не уделено внимание тому, как и какие параметры задавать. Особенно остро стоит вопрос задания значения для параметра «Цвет».
Почитав в теме комментарии, я понял, что вопрос волновал многих и, к моему сожалению, в комментариях нет правильного ответа. Я решил исправить эту маленькую несправедливость и сделал небольшой пример создания типа для системного семейства Текст. Все пояснения я оставил в виде комментариев к коду.
Эта статья написана, чтобы собрать воедино разрозненную информацию про цвета в AutoCAD .NET API. А также немного рассказать о практическом применении, помимо изменения цвета.
Мы используем файлы cookie и аналогичные технологии для улучшения вашего опыта на нашем веб-сайте.