Тема: Перпендикуляр от полилинии

Помогите, пожалуйста, с такой задачей. Есть двумерная полилиния (вообще-то состоит только из прямых, но интересен был бы и более общий случай). На ней необходимо нарисовать ряд перпендикулярных отрезков через определённые промежутки. Что у меня получилось сделать - создать слой, получать точки на полилинии на определённом расстоянии. Но как нарисовать линию перепендикулярную полилинии в заданной точке? Есть ли какой-нибудь разумный способ (можно конечно считать через синусы да косинусы или там с помощью окружностей). Неужели нет автокад не умеет этого делать?  :o

Re: Перпендикуляр от полилинии

Команда РАЗМЕТИТЬ может вставлять не только точки, но и блоки. Создайте блок из вертикального отрезка и вставьте его экземпляры упомянутой командой, задав опцию согласования с направлением полилинии.

(изменено: Александр Ривилис, 4 марта 2011г. 12:54:01)

Re: Перпендикуляр от полилинии

Михаил
Так как Вы написали в разделе ObjectARX, то нужно понимать, что Вы пишете программу с использованием ObjectARX на C++. И у Вас остался только вопрос как получить нормаль к линии в точке на полилинии? Я не буду расписывать весь алгоритм, но у класса AcDbCurve (прародительнице всех кривых в AutoCAD, в том числе и прародительнице полилинии) есть метод getFirstDeriv(), который возвращает вектор "вдоль кривой" в заданной точке (или определенной параметром). Остается повернуть вектор на 90 градусов. Поищите по форуму getFirstDeriv.

Re: Перпендикуляр от полилинии

Спасибо, Александр,

Я использую C#, думаю разницы большой не должно быть. Обязательно попробую адаптировать один из примеров кода на C#. Обязательно отпишусь, что получилось.

Re: Перпендикуляр от полилинии

Михаил,

Михаил пишет:

Я использую C#

Тогда Вы написали не в ту ветку форума. Нужно было сюда: https://www.caduser.ru/forum/forum49.html
Этот пример может быть полезен: http://through-the-interface.typepad.co … tchin.html

(изменено: Михаил, 4 марта 2011г. 23:36:48)

Re: Перпендикуляр от полилинии

Пример, который Вы превели действительно интересный, на том сайте достаточно много полезных примеров, только уж больно форматирование ужасное. У меня не получилось создавать требуемые перпендикуляры. Я не понимаю почему не работает ниже приведённый код (моё собственное произведение). Названия правильные, логика действий ясна, но не работает.

        private Polyline createPerpendicularLineAtPoint(Polyline polyline, Point3d point)
        {
            Vector3d vector = polyline.GetFirstDerivative(point);
            Vector3d pvector = vector.GetNormal();();

            Polyline newPolyline = new Polyline(2);
            newPolyline.AddVertexAt(0, new Point2d(0d, 0d), 0d, 1d, 1d);
            newPolyline.AddVertexAt(1, new Point2d(pvector.X, pvector.Y), 0d, 1d, 1d);
            newPolyline.TransformBy(Matrix3d.Displacement(point - new Point3d(0d, 0d, 0d)));
            
            return newPolyline;
        }

И ещё вопрос. Эту тему перенесут в другой тред или мне самому надо создать тему в другом треде и продолжать писать там?

(изменено: Александр Ривилис, 5 марта 2011г. 17:21:49)

Re: Перпендикуляр от полилинии

Михаил пишет:

И ещё вопрос. Эту тему перенесут в другой тред или мне самому надо создать тему в другом треде и продолжать писать там?

Переносить некому, так что оставим здесь. Это я написал на будущее.

Михаил пишет:

Я не понимаю почему не работает ниже приведённый код (моё собственное произведение).

А где ты перпендикуляр к вектору получаешь? И что это такое:

   Vector3d pvector = vector.GetNormal();(); 

GetNormal() возвращает единичный вектор (длина его равна единице), но никак не перпендикуляр.

Re: Перпендикуляр от полилинии

Заработало! Ура!

На месте GetNormal() была куча разных функций. Ничего не помогало. Главное, что я не понял, что возвращаемый вектор направлен из 0 точки. Это конечно не логично, но с этим можно жить.
В метод я добавил дополнительно перенос отсечек, так чтобы полилиния проходила через них по середине (для этого я использовал Ray применение которого я подсмотрел в одном из примеров, на который Вы дали ссылку). В итоге вот что получилось:

        private Polyline createPerpendicularLineAtPoint(Polyline polyline, Point3d point)
        {
            Vector3d vector = polyline.GetFirstDerivative(point);
            Vector3d pvector = vector.GetPerpendicularVector();

            Point3d zeroPoint = new Point3d(0d, 0d, 0d);
            Point3d endPoint = new Point3d();
            Vector3d middleMoveVector = new Vector3d();

            using (Ray perpendicularRay = new Ray())
            {
                perpendicularRay.BasePoint = zeroPoint;
                perpendicularRay.UnitDir = pvector;
                endPoint = perpendicularRay.GetPointAtDist(PICKET_LENGTH);
                Point3d middlePoint = perpendicularRay.GetPointAtDist(PICKET_LENGTH / 2);
                middleMoveVector = zeroPoint - middlePoint;
            }

            Polyline newPolyline = new Polyline(2);
            newPolyline.AddVertexAt(0, new Point2d(0d, 0d), 0d, 0d, 0d);
            newPolyline.AddVertexAt(1, new Point2d(endPoint.X, endPoint.Y), 0d, 0d, 0d);

            newPolyline.TransformBy(Matrix3d.Displacement(point - zeroPoint));
            newPolyline.TransformBy(Matrix3d.Displacement(middleMoveVector));
            return newPolyline;
        }

Re: Перпендикуляр от полилинии

Работает и ладно, но в принципе ты слишком всё переусложнил.

Re: Перпендикуляр от полилинии

А как проще? Я ведь только начинаю разбираться со структурой классов и методами, так что понять как лучше тоже важно.

Re: Перпендикуляр от полилинии

Средствами обычного векторного исчисления. Получаешь вектор перпендикуляру, нормализуешь его, умножаешь на PICKET_LENGTH*0.5, прибавляешь и вычитаешь этот вектор к точке на полилинии. Вот и всё. Ray в данном случае совершенно не нужен.

Re: Перпендикуляр от полилинии

Позволю себе обновить эту древнюю тему.
Столкнулся с подобной задачей, привожу свой рабочий код без Ray.

PromptEntityOptions promptOptions = new PromptEntityOptions( "\nSelect Polyline: " );
PromptEntityResult entity = Application.DocumentManager.MdiActiveDocument.Editor.GetEntity( promptOptions );

// Exit if the user presses ESC or cancels the command
if ( entity.Status != PromptStatus.OK )
{
    return;
}

PromptPointOptions promptPointOptions = new PromptPointOptions( "\nSelect Point: " );
PromptPointResult userPoint = Application.DocumentManager.MdiActiveDocument.Editor.GetPoint( promptPointOptions );

// Exit if the user presses ESC or cancels the command
if ( userPoint.Status != PromptStatus.OK )
{
    return;
}

// Get the current document and database
Document document = Application.DocumentManager.MdiActiveDocument;
Database database = document.Database;

// Start a transaction
using ( Transaction transaction = database.TransactionManager.StartTransaction() )
{
    using ( Curve curve = (Curve)transaction.GetObject( entity.ObjectId, OpenMode.ForRead ) )
    {
        Point3d pointOnCurve = curve.GetClosestPointTo( userPoint.Value, true );
        Vector3d tangentVector = curve.GetFirstDerivative( pointOnCurve );
        Vector3d perpendicularVector = tangentVector.GetPerpendicularVector();
        perpendicularVector = perpendicularVector.GetNormal();

        double distance = 50.0;
        Point3d startPoint = pointOnCurve + perpendicularVector * distance;
        Point3d endPoint = pointOnCurve - perpendicularVector * distance;

        using ( BlockTable blockTable = (BlockTable)transaction.GetObject( database.BlockTableId, OpenMode.ForRead ) )
        {
            using ( BlockTableRecord blockTableRecord = (BlockTableRecord)transaction.GetObject( blockTable[ BlockTableRecord.ModelSpace ], OpenMode.ForWrite ) )
            {
                Circle circle = new Circle();
                circle.SetDatabaseDefaults();
                circle.ColorIndex = 1;
                circle.Radius = 10;
                circle.Center = pointOnCurve;
                blockTableRecord.AppendEntity( circle );
                transaction.AddNewlyCreatedDBObject( circle, true );

                Polyline perpendicularPolyline = new Polyline();
                perpendicularPolyline.SetDatabaseDefaults();
                perpendicularPolyline.ColorIndex = 2;
                perpendicularPolyline.AddVertexAt( 0, new Point2d( startPoint.X, startPoint.Y ), 0, 0, 0 );
                perpendicularPolyline.AddVertexAt( 1, new Point2d( endPoint.X, endPoint.Y ), 0, 0, 0 );

                blockTableRecord.AppendEntity( perpendicularPolyline );
                transaction.AddNewlyCreatedDBObject( perpendicularPolyline, true );
            }
        }
    }

    transaction.Commit();
}

Application.DocumentManager.MdiActiveDocument.Editor.UpdateScreen();