как нарисовать дугу под уклоном?

Статус
Закрыто для дальнейших ответов.

ekali

Участник
Топикстартер
Сообщения
19
Реакции
0
Нужно программными средствами рисовать дуги. Простая дуга (полукруг на горизонтальной линии) у меня получилась. Вот так:

Код:
rad = 50
otr = rad * 0.55
xAb = 0
yAb = 0
ugol = 90
plecho = rad / 3
Set crv = CreateCurve(ActiveDocument)
Set sp = crv.CreateSubPath(xAb - plecho, yAb)
sp.AppendLineSegment xAb, yAb
sp.AppendCurveSegment xAb + rad, yAb + rad, otr, ugol, otr, ugol - 270, False
sp.AppendCurveSegment xAb + rad * 2, yAb, otr, ugol - 90, otr, ugol, False
sp.AppendLineSegment xAb + rad * 2 + plecho, yAb
sp.AppendLineSegment xAb + rad * 2 + plecho, yAb - rad * 5
sp.AppendLineSegment xAb - plecho, yAb - rad * 5
sp.AppendLineSegment xAb - plecho, yAb
sp.Closed = true
Set s = ActiveLayer.CreateCurve(crv)
s.Fill.ApplyNoFills.Outline.SetProperties 0.007874, OutlineStyles(0), CreateRGBColor(19, 145, 191), ArrowHeads(0), ArrowHeads(0), cdrFalse, cdrFalse, cdrOutlineButtLineCaps, cdrOutlineMiterLineJoin, 0#, 100, MiterLimit:=5#

То есть это линия Безье, которая практически точно повторяет часть окружности (для проверки я рисовала там же эллипс - линии накладываются в ноль).

Углы контрольных линий записаны просто наглядно-практическим путем, а то, что длина этих контрольных линий - 0,55 от радиуса - это просто попалось наугад. Я не знаю, почему эта цифра.

Теперь вот мне интересно - а если я захочу эту дугу наклонить? Или взять меньший сектор, скажем, 45 градусов? Немного попробовала через тригонометрию, но слишком сложно показалось.

Может, кто-нибудь формулы знает?
 

_MBK_

Пикирующий бомбардировщик
15 лет на форуме
Сообщения
33 235
Реакции
10 852
Ответ: как нарисовать дугу под уклоном?

Наклонить, в смысле, повернуть на угол, или Scew? На мой взгляд, если не заморачиваться с тригонометрией, то, через соответствующие методы, ну, или, на крайняк, матрицу трансформации.
 

_MBK_

Пикирующий бомбардировщик
15 лет на форуме
Сообщения
33 235
Реакции
10 852
Ответ: как нарисовать дугу под уклоном?

Ну вот, например:

Shape.Rotate
Sub Rotate(ByVal Angle As Double)
- повернуть

Shape.Skew
Sub Skew(ByVal AngleX As Double, ByVal AngleY As Double)
- наклонить

Shape.Stretch
Sub Stretch(ByVal StretchX As Double, [ByVal StretchY As Double = 0], [ByVal StretchCharactersSize As Boolean = False])
- растянуть/сжать


Shape.TransformMatrix
Sub TransformMatrix(ByVal d11 As Double, ByVal d12 As Double, ByVal d21 As Double, ByVal d22 As Double, ByVal tx As Double, ByVal ty As Double)

Shape.SetMatrix
Sub SetMatrix(ByVal d11 As Double, ByVal d12 As Double, ByVal d21 As Double, ByVal d22 As Double, ByVal tx As Double, ByVal ty As Double)
- преобразование через матрицу трансформации

А вообще, зачем вы таким сложным путем саму дугу создаете? Не проще ли создать сразу сектор эллипса с нужными углами:

Function CreateEllipse(ByVal Left As Double, ByVal Top As Double, ByVal Right As Double, ByVal Bottom As Double, [ByVal StartAngle As Double = 90], [ByVal EndAngle As Double = 90], [ByVal Pie As Boolean = False]) As Shape

а потом отрезать узел?
 

ekali

Участник
Топикстартер
Сообщения
19
Реакции
0
Ответ: как нарисовать дугу под уклоном?

я отказалась от обработки subpath как объектов, по следующим соображениям (возможно, неверным)

мне для управляющей программы фрезеровки нужна сплошная последовательная линия. Поэтому все ее участки создаются как последовательные subpath. Конечно, можно создавать отдельные объекты и их объединять, а потом преобразовывать контур в кривую, но у меня совершенно недостаточно компетенции, чтобы четко это все соединить в одну последовательность. Там что-то около 138 кривых в файле сейчас создается, и это еще не конец. Я что-то в этом духе делала в первый раз, вручную рисовала, так фрезер метался как полоумный из одной точки рабочего поля в другое. Не говоря уже о том, что бывают глюки при передаче файлов из одной программы в другую, для создания УП. Типа ты думаешь, что это линия, а там две линии... или их порядок как-то меняется... (вообще слабо себе все это представляю) Я поэтому решила от греха подальше вычерчивать каждый раскрой или рельеф одной линией, чтобы потом не путаться в объектах. И ведь получается, никаких проблем. Несколько нудно, но решаемо. Аккуратно и понятно. Только дуги - пока загадка. Прочитала статью про аппроксимацию, ничего не поняла.

http://www.netlib.narod.ru/library/book0039/ch13_04.htm

Там команды непонятно как применять, в языках разное количество данных (New Point vs CreateSubpath). Ну и про наклоны (Scew либо Rotate, неважно) тоже неясно.
 

_MBK_

Пикирующий бомбардировщик
15 лет на форуме
Сообщения
33 235
Реакции
10 852
Ответ: как нарисовать дугу под уклоном?

Конечно, можно создавать отдельные объекты и их объединять, а потом преобразовывать контур в кривую,
Именно! Потому как запаритесь вы контур вычерчивать линиями безье. Разбить на прямолинейные участки, вычертить, а скругления сделать логическими операциями с кружками и эллипсами соответствующих диаметров.
Типа такого:
line.jpg
 

_MBK_

Пикирующий бомбардировщик
15 лет на форуме
Сообщения
33 235
Реакции
10 852
Ответ: как нарисовать дугу под уклоном?

То же самое, в принципе, можно сделать, создав Fillet нужного радиуса для соответствующих Node
Другой способ:
Рисуете ломанную, а потом меняете Type для соответствующих Node на cdrSmoothNode:
line2.jpg
 

ekali

Участник
Топикстартер
Сообщения
19
Реакции
0
Ответ: как нарисовать дугу под уклоном?

Большое спасибо! Fillet вроде бы работает. Она тут предпочтительней, так как все в одном объекте и так как можно задать радиус (с cdrSmoothNode я не знаю, можно или нет)

И на вс. случай: после вызова Fillet количество узлов в кривой увеличивается. Я их обрабатывала циклом и не могла понять, почему последний узел не меняется. А потому что цикл переходил к вновь созданным узлам и не доходил до старых. Тогда запустила я цикл в обратную сторону, Step -1, и все сработало.
 

_MBK_

Пикирующий бомбардировщик
15 лет на форуме
Сообщения
33 235
Реакции
10 852
Ответ: как нарисовать дугу под уклоном?

с cdrSmoothNode я не знаю, можно или нет
Нельзя конечно, там разные подходы совсем. Кстати, обратите внимание, что Fillet узел обрезает, а smothing оставляет на своих местах, просто сглаживает линии между ними.
 

ekali

Участник
Топикстартер
Сообщения
19
Реакции
0
Ответ: как нарисовать дугу под уклоном?

да, хорошенький вопрос, а куда ставить тот вспомогательный узел, из которого потом получится дуга? То есть по условной горизонтали понятно - в центре воображаемой окружности, то есть радиус примерно от предыдущей точки. Но по условной вертикали.... выяснилось, что чем дальше отвести - тем точнее совпадение кривой с идеальной дугой. Я отодвигала до 10000 радиусов, но тут узел заглючил (еще проблема при построении была, как запомнить этот узел, который нужно потом преобразовать - получается, лишь по координатам, перебором - так вот, когда задаешь высоту = радиус х 10000, то узел перестает вообще находиться). Так что сейчас высота стоит - 2000 х радиус. Точность не идеальная, но приличная.

Код:
Sub nnn() Dim s As Shape
 Dim crv As Curve
 Dim sp As SubPath
 Dim c As New Color
 Dim otr As Double, rad As Double, xAb As Double, yAb As Double, plecho As Double, ugol As Double, x As Double, y As Double
 Dim i As Long, iE As Long
ActiveDocument.ReferencePoint = cdrCenter
ActiveDocument.Unit = cdrMillimeter


rad = 50
otr = rad * 0.55
xAb = 0 '300
yAb = 0 ' 100
ugol = 90
plecho = rad / 3


Set s = ActiveLayer.CreateEllipse2(xAb + rad, yAb, rad)




Set crv = CreateCurve(ActiveDocument)
Set sp = crv.CreateSubPath(xAb - plecho, yAb)
sp.AppendLineSegment xAb, yAb
sp.AppendLineSegment xAb + rad, yAb + rad * 2000, False
sp.AppendLineSegment xAb + rad * 2, yAb, False
sp.AppendLineSegment xAb + rad * 2 + plecho, yAb
sp.AppendLineSegment xAb + rad * 2 + plecho, yAb - rad * 5
sp.AppendLineSegment xAb - plecho, yAb - rad * 5
sp.AppendLineSegment xAb - plecho, yAb
sp.Closed = True


Set s = ActiveLayer.CreateCurve(crv)
 
s.Fill.ApplyNoFill
s.Outline.SetProperties 0.007874, OutlineStyles(0), CreateRGBColor(19, 145, 191), ArrowHeads(0), ArrowHeads(0), cdrFalse, cdrFalse, cdrOutlineButtLineCaps, cdrOutlineMiterLineJoin, 0#, 100, MiterLimit:=5#


iE = s.Curve.Nodes.Count


For i = 1 To iE
    s.Curve.Nodes(i).GetPosition x, y
    If x = xAb + rad And y = yAb + rad * 2000 Then
        s.Curve.Nodes(i).Fillet rad, True
        i = iE
    End If
Next i




End Sub
 

_MBK_

Пикирующий бомбардировщик
15 лет на форуме
Сообщения
33 235
Реакции
10 852
Ответ: как нарисовать дугу под уклоном?

Ну это уж вообще такое, что, даже, такой старый извращенец как я, удивился. ;)
Я вовсе не это имел в виду, когда предлагал вам filletом пользоваться. Для вашего случая лучше просто сделать Weld эллипса с прямоугольником.
Вот так:
Код:
Set s = ActiveLayer.CreateEllipse2(xAb + rad, yAb, rad)




Set crv = ActiveDocument.CreateCurve
Set sp = crv.CreateSubPath(xAb - plecho, yAb)
sp.AppendLineSegment xAb, yAb
'sp.AppendLineSegment xAb + rad, yAb + rad * 2000, False
sp.AppendLineSegment xAb + rad * 2, yAb, False
sp.AppendLineSegment xAb + rad * 2 + plecho, yAb
sp.AppendLineSegment xAb + rad * 2 + plecho, yAb - rad * 5
sp.AppendLineSegment xAb - plecho, yAb - rad * 5
sp.AppendLineSegment xAb - plecho, yAb
sp.Closed = True


Set d = ActiveLayer.CreateCurve(crv)
Set s1 = d.Weld(s)
 

ekali

Участник
Топикстартер
Сообщения
19
Реакции
0
Ответ: как нарисовать дугу под уклоном?

честно говоря, насчет weld и прочих средств у меня сомнения. Откуда я знаю, в какую сторону ориентирован этот эллипс? А вдруг противоположно моей кривой? Я их объединю, а фреза потом начнет прыгать туда-сюда. Или нет? Или в арткаме рассыплется внезапно (еще не дошла до туда, чисто предполагаю со слов)

И - ладно, пусть weld, - полюбас, остается за гранью моего разумения, как с помощью эллипсов / формирований чертить скругления, которые внутри контура (как на Вашем рисунке в посте 5). Это что будет? Явно не объединение... и не пересечение... и не слияние же... чем?

Филлетом вроде самое простое.
 

_MBK_

Пикирующий бомбардировщик
15 лет на форуме
Сообщения
33 235
Реакции
10 852
Ответ: как нарисовать дугу под уклоном?

На самом деле, бояться не надо. В результате Weld создается связный объект с непрерывным контуром - следовательно непрерывным будет и направление обхода этого контура, независимо от того, как были ориентированы исходные контура. А вот, в случае филлета "с бесконечно удаленным узлом", действительно, возможны проблемы, ибо, настолько длинные направляющие - вещь противоестественная, в будущем при отрисовке такого контура могут возникнуть всякие непрндсказуемые эффекты, связанные с переполнением. Самый естественный путь в данном случае - аппроксимация сегментами окружностей и эллипсов. А вот, в случае, который я нарисовал выше - действительно, удобнее пользоваться филлетами, там и узлы считаются просто и в явном виде, а не удалены в бесконечность. Теоретически можно и окружностями, но, сложнее.
 

xm

иксэ́м
R.I.P.
Сообщения
4 978
Реакции
2 667

_MBK_

Пикирующий бомбардировщик
15 лет на форуме
Сообщения
33 235
Реакции
10 852
Ответ: как нарисовать дугу под уклоном?

Если уж вам так нравятся филлеты, то лучше делать полукруглый выступ не на одной, а на двух опорных нодах, вот так:
fillet2.jpg

Не по теме:
Иксэм, хватит к девушке клеиться, филлет - не лучший повод для знакомства. Ну ни за что не поверю, что такой монстр корела, как вы, не знает, что это такое. :D
 

Auto

Участник
Сообщения
15
Реакции
0
Ответ: как нарисовать дугу под уклоном?

Это самое близкое по теме из того что ищу.

Как описать скрипт который выделит все объекты (а их много), либо считает выделенные объекты. Запихнуть их в массив(извиняюсь если коряво выражаюсь, я учил MEL -язык программирования, с VBA сталкиваюсь впервые). А потом брать первый с следующий за ним объект(не важно в каком порядке) и применять операцию WELD. Таким образом по одному присоединять их друг к другу.
Объясняю зачем такое понадобилось. Имеется много объектов разбросанных по полю в разном хаотичном порядке (пересекающиеся, к примеру буквы в кривых). При их выделении и попытке применения операции Weld, программа погружается в долгое обдумывание а потом выдает сбой в работе или нехватку памяти (установленной памяти в системе х64 12гиг, при обработке файла загрузка не больше половины, поэтому вопрос с нехваткой памяти отпадает), предполагаю что программа пытается обработать сразу весь массив выделенных объектов так как если выбирать по несколько то операция Weld работает но долго.
При слиянии большого количества объектов операцией Weld, размер такого файла уменьшается в 10! раз(пробовал на меньшем количестве где Weld работает), так как система уже считает не огромное количество объектов с узлами а один объект с большим количеством узлов. Ну и нужен такой файл для плотерной резки и как писалось выше для фрезеровки.

Подскажите если не сложно.
 

qsedftghk

фея
15 лет на форуме
Сообщения
2 032
Реакции
1 198
Ответ: как нарисовать дугу под уклоном?


Не по теме:
Рекомендую Вам поспрашивать здесь.
 

_MBK_

Пикирующий бомбардировщик
15 лет на форуме
Сообщения
33 235
Реакции
10 852
Ответ: как нарисовать дугу под уклоном?

Нет, не сложно.
Данная идея порочна в корне. Объясняю почему: при объединении достаточно большого количества кривых в одну (например в результате скурвливания текста или кривой трассировки) мы получаем мегакривую с безумным количеством узлов. Это только на первый взгляд, она будет занимать меньше места в файле и быстрее обрабатываться. На самом деле, при превышении определенного лимита на узлы возможны непредсказуемые глюки (начиная со сбоев при выводе такого файла в постскрипт или даже на плоттер), вплоть до полного обрушения корела. Поэтому, к данной операции необходимо относиться без фанатизма, и уж, конечно, не объединять независимые непересекающиеся объекты в один через weld.

Не по теме:
Кроме того, вы действительно обратились не туда. Я имею в виду, не cdrpro, а то, что тут существует правило "один вопрос-одна тема".
 

Auto

Участник
Сообщения
15
Реакции
0
Ответ: как нарисовать дугу под уклоном?

И все таки. Хотелось бы по пробовать.

написал такой сценарий
Код:
Sub e()
Dim I As Long, count As Long
count = ActiveLayer.Shapes.count
For I = 1 To count
Set sI = ActiveLayer.Shapes(count).Weld(ActiveLayer.Shapes(count - 1), True, True)
Next I
End Sub

но он соединяет по два объекта в массиве
подскажите как исправить

Код:
Sub e()
Dim I As Long, count As Long
count = ActiveLayer.Shapes.count
For I = 1 To count
Dim sI As Shape
Set sI = ActiveLayer.Shapes(count).Weld(ActiveLayer.Shapes(count - I), True, True)
Next I
End Sub
такой вариант соединяет все объекты но делает лишние операции по соединению
 

_MBK_

Пикирующий бомбардировщик
15 лет на форуме
Сообщения
33 235
Реакции
10 852
Ответ: как нарисовать дугу под уклоном?

такой вариант соединяет все объекты но делает лишние операции по соединению
Какие лишние операции он делает? Хотя, да, правильнее было бы, скорее, так:
Код:
Sub e()
Dim I As Long, count As Long
count = ActiveLayer.Shapes.count
Dim sI As Shape
set  sI=ActiveLayer.Shapes(count)
For I = 1 To count-1
Set sI = sI.Weld(ActiveLayer.Shapes(count-I), True, True)
Next I
End Sub
 

Auto

Участник
Сообщения
15
Реакции
0
Ответ: как нарисовать дугу под уклоном?

Так почему то предпоследний объект остается не объединенным
 
Статус
Закрыто для дальнейших ответов.