Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

шестерни с эвольвентой #58

Open
oleg-medovikov opened this issue Jun 2, 2020 · 12 comments
Open

шестерни с эвольвентой #58

oleg-medovikov opened this issue Jun 2, 2020 · 12 comments

Comments

@oleg-medovikov
Copy link

oleg-medovikov commented Jun 2, 2020

Привет.
Хотел я запилить тебе шестеренки с эвольвентой
вот такие
y-06-03_Jun:12:50

но в последний момент, когда хочу объединить всю фигуру через sew() получается что-то странное
не могу понять что

там, где m = c должно быть m = sew(c)

from zencad import *

r = 50          # радиус шестеренки
r_zub = 65      # радиус вместе с зубом
N_zub = 12      # количество зубов

def rad(k):
    return k*math.pi/180

alfa =round( (180/math.pi)*math.acos(1 - (r_zub**2 - r**2)/(2*r**2)) )

print(alfa)


pnts=[]

for i in range(0,alfa):
    pnts.append([ r*(math.cos(rad(i)) + rad(i)*math.sin(rad(i))),\
            r*(math.sin(rad(i)) - rad(i)*math.cos(rad(i)))      ])


omega = math.atan((r*(math.sin(rad(alfa)) - rad(alfa)*math.cos(rad(alfa))) )/(r*(math.cos(rad(alfa)) + rad(alfa)*math.sin(rad(alfa)))))

omega=(180/math.pi)*omega
teta = round(360/N_zub)
print(omega)

evolv= polysegment(pnts,closed=False)

print(teta)
def c1(k):
    return evolv.rotateZ(deg(k*teta))
def c2(k):
    d =(0.5*teta - omega)* r_zub/r
    return evolv.rotateX(deg(180)).rotateZ(deg((k+1)*teta-d))

c =[]
for i in range(N_zub):
    o = sew([c1(i), segment(c1(i).endpoints()[-1], c2(i).endpoints()[-1])])
    p = segment(c2(i).endpoints()[0], c1(i+1).endpoints()[0])
    c.append(o)
    c.append(c2(i))
    c.append(p)



m = c

disp(m)
#disp(circle(r,wire=True),color.red)
#disp(circle(r_zub,wire=True),color.blue)

show()
@oleg-medovikov
Copy link
Author

Я сделал!
y-06-03_Jun:43:25

Решил, что если не выходит с sew, то проще нарисовать шестерню одним циклом )

И вот оно есть:

from zencad import *

r = 50          # радиус шестеренки
r_zub = 65      # радиус вместе с зубом
N_zub = 12      # количество зубов

def rad(k):
    return k*math.pi/180

alfa =round( (180/math.pi)*math.acos(1 - (r_zub**2 - r**2)/(2*r**2)) )

omega = math.atan((r*(math.sin(rad(alfa)) - rad(alfa)*math.cos(rad(alfa))) )/(r*(math.cos(rad(alfa)) + rad(alfa)*math.sin(rad(alfa)))))

teta = 2*math.pi/N_zub
d =(0.5*teta - omega)* r_zub/r

pnts=[]

for k in range(N_zub):
    for i in range(0,alfa):
        x = r*(math.cos(rad(i)) + rad(i)*math.sin(rad(i)))
        y = r*(math.sin(rad(i)) - rad(i)*math.cos(rad(i)))
        pnts.append([x*math.cos(-k*teta) + y*math.sin(-k*teta),\
                -x*math.sin(-k*teta)+y*math.cos(-k*teta)])
    for i in range(alfa,0,-1):
        x = r*(math.cos(rad(i)) + rad(i)*math.sin(rad(i)))
        y = -r*(math.sin(rad(i)) - rad(i)*math.cos(rad(i)))
        pnts.append([x*math.cos(-(k+1)*teta+d) + y*math.sin(-(k+1)*teta+d),\
                -x*math.sin(-(k+1)*teta+d)+y*math.cos(-(k+1)*teta+d)])

evolv= polysegment(pnts,closed=True)

m = evolv

disp(m)

show()

@oleg-medovikov
Copy link
Author

Для полноценной шестерни не хватает скругления на конце и у основания зуба
Я попробовал использовать rounded_polysegment, но:

  1. он сработал коряво у основания
  2. у него нет параметра closed, что вообще-то обидно

@mirmik
Copy link
Owner

mirmik commented Jun 4, 2020

Я сейчас пока в командировке. Позже посмотрю.

@oleg-medovikov
Copy link
Author

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


from zencad import *

r = 40          # радиус без зуба
r_zub = 50      # радиус вместе с зубом
N_zub = 20      # количество зубов
x_zub = 2       # толщина конца зуба
n_tochek = 20   # Количество точек на эвольвенту



# Максимальная длинна эвольвенты
alfa = math.sqrt(r_zub**2 - r**2)/r
# Угол дуги окружности, которую занимает эвольвента
omega = math.asin((r*(math.sin(alfa) - alfa*math.cos(alfa)) )/ r_zub)
# Угол дуги окружности, которую занимает зуб
teta = 2*math.pi/N_zub
# Угол смещения второй грани зуба относительно первой
ax = 2*math.asin(x_zub/(2*r_zub))
d =  - 2 * omega - ax

pnts=[]

for k in range(N_zub):
    for j in range(0,n_tochek+1):
        a = j*alfa/n_tochek
        # Считаем точки эвольвенты первой грани
        x = r*(math.cos(a) + a*math.sin(a))
        y = r*(math.sin(a) - a*math.cos(a))
        # Добавляем точки первой эвольвенты относительно повернутой системы координат
        pnts.append([x*math.cos(-k*teta) + y*math.sin(-k*teta),\
            -x*math.sin(-k*teta)+y*math.cos(-k*teta)])
    for j in range(n_tochek,0,-1):
        a = j*alfa/n_tochek
        # Считаем точки эвольвенты второй грани
        x = r*(math.cos(a) + a*math.sin(a))
        y = -r*(math.sin(a) - a*math.cos(a))
        # Добавляем точки второй эвольвенты относительно повернутой системы координат
        pnts.append([x*math.cos(-k*teta +d) + y*math.sin(-k*teta+d),\
            -x*math.sin(-k*teta+d)+y*math.cos(-k*teta+d)])

# Собираем точки вместе
evolv= polysegment(pnts,closed=True)

m = linear_extrude(proto=evolv, vec=(0,0,10), center=True)

#disp(evolv)
disp(m)
disp(circle(r_zub,wire=True),color.red)
show()

@mirmik
Copy link
Owner

mirmik commented Jun 6, 2020

Выглядит круто.

Я позволил себе немного переписать с использованием инструмента интерполяции и оформить в виде функции:

from zencad import *

r = 40          # радиус без зуба
r_zub = 50      # радиус вместе с зубом
N_zub = 20      # количество зубов
x_zub = 2       # толщина конца зуба


def gear_profile(r, r_zub, N_zub, x_zub, n_tochek=20):
	"""
		r:         радиус без зуба
		r_zub:     радиус вместе с зубом
		N_zub:     количество зубов
		x_zub:     толщина конца зуба
		n_tochek:  количество точек в апроксимации эвольвенты
	"""

	# Максимальная длинна эвольвенты
	alfa = math.sqrt(r_zub**2 - r**2)/r
	# Угол дуги окружности, которую занимает эвольвента
	omega = math.asin((r*(math.sin(alfa) - alfa*math.cos(alfa)) )/ r_zub)
	# Угол дуги окружности, которую занимает зуб
	teta = 2*math.pi/N_zub
	# Угол смещения второй грани зуба относительно первой
	ax = 2*math.asin(x_zub/(2*r_zub))
	d =  - 2 * omega - ax
	
	#pnts=[]
	
	wires = []
	abases = []
	bbases = []
	
	for k in range(N_zub):
		apnts = []
		for j in range(0,n_tochek+1):
			a = j*alfa/n_tochek
			# Считаем точки эвольвенты первой грани
			x = r*(math.cos(a) + a*math.sin(a))
			y = r*(math.sin(a) - a*math.cos(a))
			# Добавляем точки первой эвольвенты относительно повернутой системы координат
			apnts.append([x*math.cos(-k*teta) + y*math.sin(-k*teta),\
				-x*math.sin(-k*teta)+y*math.cos(-k*teta)])
	
		bpnts = []
		for j in range(n_tochek,0,-1):
			a = j*alfa/n_tochek
			# Считаем точки эвольвенты второй грани
			x = r*(math.cos(a) + a*math.sin(a))
			y = -r*(math.sin(a) - a*math.cos(a))
			# Добавляем точки второй эвольвенты относительно повернутой системы координат
			bpnts.append([x*math.cos(-k*teta +d) + y*math.sin(-k*teta+d),\
				-x*math.sin(-k*teta+d)+y*math.cos(-k*teta+d)])
	
		# Создать эвольвентные рёбра зуба
		wires.append(interpolate(apnts))
		wires.append(interpolate(bpnts))
		
		# Создать рёбро вершины зуба
		wires.append(segment(apnts[-1], bpnts[0]))
		
		# Запомнить точки основания зубьев
		abases.append(apnts[0])
		bbases.append(bpnts[-1])
	
	# Добавляем рёбра между основанием зубьев 
	wires.append(segment(abases[0], bbases[-1]))
	for k in range(N_zub - 1):
		wires.append(segment(abases[k+1], bbases[k]))
	
	# Собираем все элементы в единый wire
	evolv = sew(wires)
	
	return evolv

m = gear_profile(r, r_zub, N_zub, x_zub).fill()
m = linear_extrude(proto=m, vec=(0,0,10), center=True)

disp(m)
disp(circle(r_zub,wire=True),color.red)
show()

Единственное, возможно параметры не совсем те, которые могут ожидаться. Тут скорее всего должен как-то фигурировать модуль шестерни, делительный диаметр и всё такое. Надо понять, какие должны быть входные параметры и можно добавить как стандартный элемент.

@mirmik
Copy link
Owner

mirmik commented Jun 6, 2020

Да... У rounded_polysegment действительно нету параметра closed. Это, пожалуй, даже баг.
Он там должен быть.

Скругления в основании добавить стоит ниже профиля эвольвенты (типо проточка). А вот на вершинах зубьев, мне кажется никаких скруглений быть не должно, чтобы не портить рабочую поверхность. Надо подумать, как это можно устроить. polysegment бы использовать нехотелось, он больно ребрист, а интерполированные участки fillet не скругляет :(.

@mirmik
Copy link
Owner

mirmik commented Jun 6, 2020

p.s. Я добавил проточку в основание зуба, но прямо сейчас оно не соберётся, потому что по ходу дела в алгоритме сшивки рёбер обнаружился баг. После обновления можно будет так:

from zencad import *
import zencad.geom.ops1d2d

zencad.lazy.fastdo=True
zencad.lazy.decache=False

def gear_profile(r, r_zub, N_zub, x_zub, paz_deep=None, n_tochek=20):
	"""
		r:         радиус без зуба
		r_zub:     радиус вместе с зубом
		N_zub:     количество зубов
		x_zub:     толщина конца зуба
		n_tochek:  количество точек в апроксимации эвольвенты
	"""

	# Максимальная длинна эвольвенты
	alfa = math.sqrt(r_zub**2 - r**2)/r
	# Угол дуги окружности, которую занимает эвольвента
	omega = math.asin((r*(math.sin(alfa) - alfa*math.cos(alfa)) )/ r_zub)
	# Угол дуги окружности, которую занимает зуб
	teta = 2*math.pi/N_zub
	# Угол смещения второй грани зуба относительно первой
	ax = 2*math.asin(x_zub/(2*r_zub))
	d =  - 2 * omega - ax
	
	#pnts=[]
	
	wires = []
	abases = []
	bbases = []
	
	for k in range(N_zub):
		apnts = []
		for j in range(0,n_tochek+1):
			a = j*alfa/n_tochek
			# Считаем точки эвольвенты первой грани
			x = r*(math.cos(a) + a*math.sin(a))
			y = r*(math.sin(a) - a*math.cos(a))
			# Добавляем точки первой эвольвенты относительно повернутой системы координат
			apnts.append(point3([
				x*math.cos(-k*teta) + y*math.sin(-k*teta),\
				-x*math.sin(-k*teta)+y*math.cos(-k*teta)
			]))
	
		bpnts = []
		for j in range(n_tochek,0,-1):
			a = j*alfa/n_tochek
			# Считаем точки эвольвенты второй грани
			x = r*(math.cos(a) + a*math.sin(a))
			y = -r*(math.sin(a) - a*math.cos(a))
			# Добавляем точки второй эвольвенты относительно повернутой системы координат
			bpnts.append(point3([
				x*math.cos(-k*teta +d) + y*math.sin(-k*teta+d),\
				-x*math.sin(-k*teta+d)+y*math.cos(-k*teta+d)
			]))
	
		# Создать эвольвентные рёбра зуба
		wires.append(interpolate(apnts))
		wires.append(interpolate(bpnts))

		# Создать рёбро вершины зуба
		wires.append(segment(apnts[-1], bpnts[0]))
		
		# Запомнить точки основания зубьев
		abases.append(apnts[0])
		bbases.append(bpnts[-1])
	
	if paz_deep is None:
		# Добавляем рёбра между основанием зубьев 
		wires.append(segment(abases[0], bbases[-1]))
		for k in range(N_zub - 1):
			wires.append(segment(abases[k+1], bbases[k]))
	
	else:
		# Добавляем проточку между основанием зубьев 
		scl = scale((r_zub-paz_deep)/r_zub)
		abases2 = [ scl(a) for a in abases ]
		bbases2 = [ scl(b) for b in bbases ]

		wires.append(rounded_polysegment(r=paz_deep, 
			pnts=[abases[0], abases2[0], bbases2[-1], bbases[-1]]))

		for k in range(N_zub-1):
			wires.append(rounded_polysegment(r=paz_deep, 
				pnts=[abases[k+1], abases2[k+1], bbases2[k], bbases[k]]))

	evolv = sew(wires)

	return evolv

m = gear_profile(r=40, r_zub=50, N_zub=20, x_zub=2, paz_deep=1).fill()
m = linear_extrude(proto=m, vec=(0,0,10), center=True)

disp(m)
disp(circle(50,wire=True),color.red)
show()

Screenshot 2020-06-06 15:54:05

@oleg-medovikov
Copy link
Author

к слову, circle() очень криво выглядит. Двумерные фигуры нельзя представлять в виде границ, только полигогами?

@mirmik
Copy link
Owner

mirmik commented Jun 7, 2020

Да, я тоже замечал. Это особенность работы 3д рендера. Он принципиально полигональный. Наверное можно где-то настройку точности подкрутить. Надо будет посмотреть.

@mirmik
Copy link
Owner

mirmik commented Jun 7, 2020

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

@oleg-medovikov
Copy link
Author

oleg-medovikov commented Apr 20, 2021

Я (наконец-то! ) построил по точкам шестеренку через модуль и количество зубьев.

import numpy as np
from numpy import pi,sin,cos,sqrt,arctan
from PIL import Image

x_max = 1000
y_max = 1000

array = np.zeros([x_max,y_max,3],dtype=np.uint8)
array.fill(255)
#array[int(0.5*x_max),:] = 0
#array[:,int(0.5*y_max)] = 0



def add_point(x,y,color):
    array[int(3*y + 0.5*y_max) , int(3*x + 0.5*x_max) ] = color
    
def circle(d, color):
    for a in range(360):
        x = d*cos(a)
        y = d*sin(a)
        add_point(x,y,color) 


    

def gear_profile(m, z):
    d   = z*m           # Диаметр делительный
    h   = 2.25*m        # Высота зуба
    ha  = m             # Высота головки
    hf  = 1.25*m        # Высота ножки
    da  = d + 2*ha      # Диаметр вершин зубьев           
    df  = d - 2*hf      # Диаметр впадин зубчатого колеса  
    db  = d*cos(pi/9)   # Диаметр основной окружности
    b   = 8*m           # Ширина венца зубчатого колеса
    Pt  = pi*m          # Окружной шаг зубьев
    St  = 0.5*Pt        # Окружная толщина зуба
    Et  = 0.5*Pt        # Окружная ширина впадины зубчатого колеса
    Qf  = 0.25*m        # Радиус кривизны переходной кривой зуба
  
    circle(d,(255,100,0))
    #circle(da,(155,0,0))
    circle(df,(0,155,0))
    circle(db,(0,0,155))
    # Еще параметров
    teta = 2*pi/z  # Угол дуги окружности, которую занимает зуб

    for k in range(z):
        a = 0
        while True:
            # Считаем точки эвольвенты первой грани
            x =  db*(cos(a) + a*sin(a))
            y = -db*(sin(a) - a*cos(a))
            # Меняем точки первой эвольвенты относительно повернутой системы координат
            turn = k*teta
            X =  x*cos(turn) + y*sin(turn)
            Y = -x*sin(turn) + y*cos(turn)
            a += pi/180
            if X**2 + Y**2 <= da**2:
                add_point(X,Y,0)
            else:
                break
                        
        d_a = arctan(-y/x)       # угол который занимает эвольвента
        d_b = 0.5*teta - d_a     # угол который занимает впадина или зуб
        a_max = a                # максимальный угол эвольвенты
        a = 0 
        while True:
            # Считаем точки вершины зуба
            x = da*cos(a)
            y = da*sin(a)
            turn = k* teta + d_a
            X =  x*cos(turn) + y*sin(turn)
            Y = -x*sin(turn) + y*cos(turn)
            a -= pi/180
            if a > -0.5*d_b*(d/da):
                add_point(X,Y,0)
            else:
                break
       
        a = a_max
        while True:
            # Считаем точки эвольвенты второй грани
            x =  db*(cos(a) + a*sin(a)) 
            y =  db*(sin(a) - a*cos(a))
            # Меняем точки первой эвольвенты относительно повернутой системы координат
            turn = k*teta + d_a + d_b
            X =  x*cos(turn) + y*sin(turn)
            Y = -x*sin(turn) + y*cos(turn)
            a -= pi/180
            if (X**2 + Y**2) > db**2 and a > 0 :
                if (X**2 + Y**2) < da**2 :
                    add_point(X,Y,0)
            else:
                break
            
        a = 0        
        while True:
            # Считаем точки эвольвенты второй грани(низ зуба)
            x = db*(cos(a) - a*sin(a))
            y = db*(sin(a) - a*cos(a))
            # Меняем точки первой эвольвенты относительно повернутой системы координат
            turn = k*teta + d_a + d_b
            X =  x*cos(turn) + y*sin(turn)
            Y = -x*sin(turn) + y*cos(turn)
            a += pi/180
            if X**2 + Y**2 >= (0.5*(df+db))**2:
                add_point(X,Y,0)
            else:
                break   
         
        # Считаем эллипс между зубами    
        d_d = arctan(y/x) # Угол, который занимает маленькая эвольвента
        r1 = 0.5*(db-df)
        r2 = 0.5*(df+db) * sin((d_b - d_d)) 
        for i in range(16,7,-1):
            i = pi*i/12
            x = r1*cos(i) + 0.5*(df+db)
            y = r2*sin(i)
            turn = (k+1)*teta  - 0.5*(d_a + d_b) 
            X =  x*cos(turn) + y*sin(turn)
            Y = -x*sin(turn) + y*cos(turn)
            add_point(X,Y,0)
       
                
        a = 0        
        while True:
            # Считаем точки эвольвенты второй грани(низ зуба)
            x =  db*(cos(a) - a*sin(a))
            y = -db*(sin(a) - a*cos(a))
            # Меняем точки первой эвольвенты относительно повернутой системы координат
            turn = (k+1)*teta 
            X =  x*cos(turn) + y*sin(turn)
            Y = -x*sin(turn) + y*cos(turn)
            a += pi/180
            if X**2 + Y**2 >= (0.5*(df+db))**2:
                add_point(X,Y,0)
            else:
                break  
    
gear_profile(16,6)

img = Image.fromarray(array)
img.save('test.png')

Без названия

@mirmik
Copy link
Owner

mirmik commented Apr 20, 2021

Выглядит неплохо.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants