Звезда не активнаЗвезда не активнаЗвезда не активнаЗвезда не активнаЗвезда не активна

В решении некоторых плагинов бывает возникает такая задача и мы начинаем искать решения в интернете, а там сложные формулы прямой на плоскости или в пространстве.

Но есть решение куда проще в реализации и понятнее. И поможет нам в этом скалярное произведение векторов (DotProduct):

Если векторное произведение двух единичных векторов по модулю равно 1, то эти два вектора коллинеарны (параллельны друг другу).

Если произведение будет 1 – вектора направлены в одну сторону, а если -1 – в противоположные. Но в нашей задаче это не важно и нас интересует только модуль произведения. Из первого утверждения получаем метод проверки параллельности:

/// <summary>
/// Проверка параллельности двух векторов
/// </summary>
/// <param name="vector">Первый вектор</param>
/// <param name="checkedVector">Второй вектор</param>
/// <param name="tolerance">Допуск расстояния при проверке</param>
public static bool IsParallelTo(this XYZ vector, XYZ checkedVector, double tolerance = 0.0001)
{
    return Math.Abs(Math.Abs(vector.DotProduct(checkedVector)) - 1.0) < tolerance;
}

/// <summary>
/// Проверка параллельности двух отрезков
/// </summary>
/// <param name="line">Первый отрезок</param>
/// <param name="checkedLine">Второй отрезок</param>
/// <param name="tolerance">Допуск расстояния при проверке</param>
public static bool IsParallelTo(this Line line, Line checkedLine, double tolerance = 0.0001)
{
    return line.Direction.IsParallelTo(checkedLine.Direction, tolerance);
}

Мы уже решили половину задачи. А полное решение искомой задачи звучит так:

Два отрезка лежат на одной прямой если каждый единичный вектор, построенный через любую пару концевых точек двух отрезков, коллинеарен единичному вектору направления одного из отрезков.

Причем это утверждение будет работать и в 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. Данный код не учитывает таких различий

Звезда не активнаЗвезда не активнаЗвезда не активнаЗвезда не активнаЗвезда не активна

Листая блог Джереми Таммика наткнулся на статью FilterRule Use and Retrieving Exterior Walls одной из тем которой была тема поиска наружных стен. Там приводится несколько вариантов решения. При этом есть важное условие – наружные стены обязательно должны образовывать замкнутый контур. И даже при этом предложенные варианты могут не дать нужного варианта.

В нескольких моих плагинах решалась похожая задача и был придуман алгоритм поиска наружных стен. Скорее всего и мой алгоритм не идеален, но при тестировании показал высокие результаты. В самой статье я не буду выкладывать частей кода – в конце статьи вы найдете ссылку на репозиторий GitHub.

Итак, мой алгоритм состоит из двух частей:

Рейтинг:  5 / 5

Звезда активнаЗвезда активнаЗвезда активнаЗвезда активнаЗвезда активна

Будет такая небольшая рубрика - Вы могли не знать как это работает. Буду в этой рубрике писать о случаях, когда какое-то свойство или метод оказались не тем, что я предполагал. Записей возможно будет немного

Сегодня в этой рубрике рассмотрим свойство Origin у типа PlanarFace. Сама PlanarFace - это грань тела или оболочки, ограниченная контуром. У PlanarFace есть контуры, которые мы можем получить из свойства EdgeLoops родительского класса Face. Т.е. зрительно мы себе можем представить как выглядит PlanarFace - некоторая ограниченная плоскость, расположенная в пространстве.

А вот самое интересное - у PlanarFace есть свойство Origin - т.е. начало плоскости - которое НЕ ОБЯЗАТЕЛЬНО НАХОДИТСЯ ВНУТРИ КОНТУРА ПЛОСКОСТИ! Графически такой случай будет выглядеть примерно так:

Так что прежде чем использовать свойство Origin в своих целях, учтите, что эта точка может лежать достаточно далеко от самой PlanarFace!

Рейтинг:  5 / 5

Звезда активнаЗвезда активнаЗвезда активнаЗвезда активнаЗвезда активна

Стояла передо мной задача - проставить марки для 2D-семейств, представляющих собой арматурный каркас. Основная загвоздка при этом - нужно создать несколько марок, которые будут расположены в одной точке. По картинке, думаю, понятнее:

blog1 1

Tags: ,
© 2018-2020 modplus.org