mirror of
https://github.com/betaflight/betaflight-configurator.git
synced 2025-07-19 14:25:14 +03:00
Moving script.
This commit is contained in:
parent
bd2754a0de
commit
e871466869
1 changed files with 0 additions and 0 deletions
546
support/svg_model_motors.rb
Executable file
546
support/svg_model_motors.rb
Executable file
|
@ -0,0 +1,546 @@
|
|||
#!/usr/bin/ruby
|
||||
|
||||
# Simple SVG model generator for MW compatible FCs
|
||||
# (c) 2015 Jonathan Hudson
|
||||
# Licence MIT or GPL v2 or later (as you wish)
|
||||
|
||||
require 'cairo'
|
||||
require 'stringio'
|
||||
include Math
|
||||
|
||||
TFLAT=true # Whether to make Tri / V-tails flat or veed
|
||||
YFLAT=false # Whether to make Y{4,6} flat or veed
|
||||
|
||||
# Calculate motor coordinates for non-trivial platforms
|
||||
class ShapeFarm
|
||||
RAD=0.017453292
|
||||
def generate xp,yp,radius,ns=6,offset=0
|
||||
p=[]
|
||||
0.upto(ns-1) do |n|
|
||||
ang = n*360.0/ns + offset
|
||||
ang %= 360
|
||||
x = radius*sin(RAD*ang)
|
||||
y = radius*cos(RAD*ang)
|
||||
p << [xp+x, yp-y] # y axis inverted for cairo coord set
|
||||
end
|
||||
p
|
||||
end
|
||||
end
|
||||
|
||||
# The SVG generator
|
||||
class Model
|
||||
attr_accessor :lw, :radius
|
||||
|
||||
RAD = 0.017453292
|
||||
RADIUS=28
|
||||
|
||||
# Motor direction for arrow indicators
|
||||
CW=0
|
||||
CCW=1
|
||||
NOARROW=-1
|
||||
|
||||
# Position on the motor circle for arrow indicators
|
||||
NE=0
|
||||
SE=1
|
||||
SW=2
|
||||
NW=3
|
||||
|
||||
# We use StringIO in order to be able to add a (non-)copyright statement
|
||||
def initialize filename
|
||||
@lw = RADIUS
|
||||
@radius = RADIUS
|
||||
@name = filename
|
||||
@output = StringIO.new
|
||||
@surface = Cairo::SVGSurface.new(@output, 200,200)
|
||||
@cr = Cairo::Context.new(@surface)
|
||||
end
|
||||
|
||||
# Draw an arbitrary path, x,y pairs terminated by !
|
||||
def draw_path path,fill=:silver,round=false
|
||||
@cr.set_line_cap(Cairo::LINE_JOIN_ROUND) if round
|
||||
@cr.set_source_color(fill)
|
||||
@cr.set_line_width(@lw)
|
||||
first = true
|
||||
path.each do |p|
|
||||
if p == '!'
|
||||
@cr.close_path
|
||||
first = true
|
||||
elsif first
|
||||
@cr.move_to(*p)
|
||||
first = false
|
||||
else
|
||||
@cr.line_to(*p)
|
||||
end
|
||||
end
|
||||
@cr.fill
|
||||
@cr.stroke
|
||||
end
|
||||
|
||||
# Draw body parts, really just a rounded line
|
||||
def draw_body x1,y1,x2,y2
|
||||
@cr.set_source_color(:silver)
|
||||
@cr.set_line_width(@lw)
|
||||
@cr.set_line_join(Cairo::LINE_JOIN_ROUND)
|
||||
@cr.move_to(x1,y1)
|
||||
@cr.line_to(x2,y2)
|
||||
end
|
||||
|
||||
# Draw a servo box (in rcolor), and black text
|
||||
def draw_servo x,y,label,rcolor=:black
|
||||
@cr.set_source_color(rcolor)
|
||||
@cr.rectangle(x, y, 28, 28);
|
||||
@cr.set_font_size(16)
|
||||
@cr.stroke
|
||||
@cr.move_to(x+4,y+20)
|
||||
@cr.set_source_color(:black)
|
||||
@cr.show_text(label);
|
||||
@cr.stroke
|
||||
end
|
||||
|
||||
# Draw direction arrow at Y offset
|
||||
def draw_dirn y=80
|
||||
@cr.set_line_join(Cairo::LINE_JOIN_BEVEL)
|
||||
@cr.set_source_color(:red)
|
||||
@cr.move_to(100,y)
|
||||
@cr.set_line_width(12)
|
||||
@cr.rel_line_to(0, 40)
|
||||
@cr.stroke
|
||||
@cr.set_line_width(1)
|
||||
@cr.move_to(100,y-5)
|
||||
@cr.rel_line_to(-15, 15)
|
||||
@cr.rel_line_to(30, 0)
|
||||
@cr.rel_line_to(-15, -15)
|
||||
@cr.fill
|
||||
@cr.stroke
|
||||
end
|
||||
|
||||
# Draw a circle, perhaps with directional arrows
|
||||
# lyoffset, lxoffset change label position
|
||||
def draw_circle x,y,label,dirn=CCW,loc=NE,fill=nil,colour=nil,lyoffset=0,lxoffset=0
|
||||
col = (colour||Cairo::Color::ROYAL_BLUE)
|
||||
@cr.set_font_size(@radius)
|
||||
@cr.set_line_join(Cairo::LINE_JOIN_MITER)
|
||||
@cr.set_line_width(3)
|
||||
|
||||
if fill
|
||||
@cr.set_source_color(fill)
|
||||
@cr.circle(x,y, @radius)
|
||||
@cr.fill
|
||||
@cr.stroke
|
||||
end
|
||||
|
||||
@cr.set_source_color(col)
|
||||
@cr.circle(x,y, @radius)
|
||||
|
||||
if dirn != NOARROW
|
||||
arrow = @radius*0.6
|
||||
adelta = arrow*0.12
|
||||
x0 = x
|
||||
y0 = y
|
||||
dx = 0
|
||||
dy = 0
|
||||
radj = @radius / Math.sqrt(2)
|
||||
xadj = yadj = 0
|
||||
|
||||
case loc
|
||||
when NE
|
||||
x0 += radj
|
||||
y0 -= radj
|
||||
case dirn
|
||||
when CW
|
||||
xadj = yadj = -arrow
|
||||
dy = adelta
|
||||
when CCW
|
||||
xadj = yadj = arrow
|
||||
dx = -adelta
|
||||
end
|
||||
when SE
|
||||
x0 += radj
|
||||
y0 += radj
|
||||
case dirn
|
||||
when CW
|
||||
xadj = arrow
|
||||
yadj = -arrow
|
||||
dx = -adelta
|
||||
when CCW
|
||||
xadj = -arrow
|
||||
yadj = arrow
|
||||
dy = -adelta
|
||||
end
|
||||
when SW
|
||||
x0 -= radj
|
||||
y0 += radj
|
||||
case dirn
|
||||
when CW
|
||||
xadj = yadj = arrow
|
||||
dy = -adelta
|
||||
when CCW
|
||||
xadj = yadj = -arrow
|
||||
dx = adelta
|
||||
end
|
||||
when NW
|
||||
x0 -= radj
|
||||
y0 -= radj
|
||||
case dirn
|
||||
when CW
|
||||
xadj = -arrow
|
||||
yadj = arrow
|
||||
dx = adelta
|
||||
when CCW
|
||||
xadj = arrow
|
||||
yadj = -arrow
|
||||
dy = adelta
|
||||
end
|
||||
end
|
||||
@cr.move_to(x0,y0)
|
||||
@cr.rel_line_to(dx, yadj)
|
||||
@cr.move_to(x0,y0)
|
||||
@cr.rel_line_to(xadj, dy)
|
||||
end
|
||||
@cr.stroke
|
||||
@cr.move_to(x-@radius/4+lxoffset,y+@radius/4+lyoffset)
|
||||
@cr.set_source_color(:black)
|
||||
@cr.show_text(label);
|
||||
@cr.stroke
|
||||
end
|
||||
|
||||
# Reset line styles
|
||||
def end_body
|
||||
@cr.set_line_cap Cairo::LINE_CAP_ROUND
|
||||
@cr.stroke
|
||||
@cr.set_line_cap Cairo::LINE_CAP_BUTT
|
||||
end
|
||||
|
||||
# close a model, write out with attribution
|
||||
def close
|
||||
@cr.show_page
|
||||
@surface.finish
|
||||
@output.rewind
|
||||
cc=false
|
||||
File.open(@name, "w") do |f|
|
||||
@output.each do |l|#
|
||||
f.puts(l)
|
||||
unless cc
|
||||
f.puts("<!-- Public domain (CC-BY-SA if you or your laws insist), generated by Jonathan Hudson's svg_model_motors.rb -->")
|
||||
cc = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def render_bi
|
||||
m = Model.new "bicopter.svg"
|
||||
m.draw_body 40,100,160,100
|
||||
m.end_body
|
||||
m.draw_circle 40,100,"1",Model::CW,Model::NW
|
||||
m.draw_circle 160,100,"2",Model::CCW,Model::NE
|
||||
m.draw_servo 64, 120, "S1"
|
||||
m.draw_servo 108, 120, "S2"
|
||||
m.draw_dirn 70
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_tri
|
||||
m = Model.new "tri.svg"
|
||||
if TFLAT
|
||||
m.draw_body 40,40,160,40
|
||||
m.draw_body 100,40,100,160
|
||||
else
|
||||
m.draw_body 100,50,40,40
|
||||
m.draw_body 100,50,160,40
|
||||
m.draw_body 100,50,100,160
|
||||
end
|
||||
m.end_body
|
||||
m.draw_circle 100,160,"1",Model::CCW,Model::NW
|
||||
m.draw_circle 160,40,"2",Model::CCW,Model::NW
|
||||
m.draw_circle 40,40,"3", Model::CCW, Model::NE
|
||||
m.draw_servo 140, 140, "S1"
|
||||
m.draw_dirn 70
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_y4
|
||||
m = Model.new "y4.svg"
|
||||
m.draw_circle 100,170,"3",Model::CCW,Model::SE,false,:dark_green,14
|
||||
if YFLAT == true
|
||||
m.draw_body 40,40,160,40
|
||||
m.draw_body 100,40,100,140
|
||||
else
|
||||
m.draw_body 100,50,40,40
|
||||
m.draw_body 100,50,160,40
|
||||
m.draw_body 100,50,100,140
|
||||
end
|
||||
m.end_body
|
||||
m.draw_circle 160,40,"2",Model::CCW,Model::NE
|
||||
m.draw_circle 40,40,"4", Model::CW, Model::NW
|
||||
m.draw_circle 100,140,"1",Model::CW,Model::NE,"#fff8",nil,-10
|
||||
|
||||
m.draw_dirn 60
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_y6
|
||||
m = Model.new "y6.svg"
|
||||
m.draw_circle 100,170,"4",Model::CW,Model::SW,false,:dark_green,14
|
||||
m.draw_circle 30,30,"6",Model::CCW,Model::NE,false,:dark_green,-10
|
||||
m.draw_circle 170,30,"5",Model::CCW,Model::NW,false,:dark_green,-10
|
||||
if YFLAT == true
|
||||
m.draw_body 40,50,160,50
|
||||
m.draw_body 100,50,100,140
|
||||
else
|
||||
m.draw_body 100,60,40,50
|
||||
m.draw_body 100,60,160,50
|
||||
m.draw_body 100,60,100,140
|
||||
end
|
||||
m.end_body
|
||||
m.draw_circle 145,55,"2",Model::CW,Model::NW,"#fff8",nil,12
|
||||
m.draw_circle 55,55,"3", Model::CW, Model::NE,"#fff8",nil,12
|
||||
m.draw_circle 100,140,"1",Model::CCW,Model::NW,"#fff8",nil,-10
|
||||
m.draw_dirn 60
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_vtail
|
||||
m = Model.new "vtail_quad.svg"
|
||||
if TFLAT == true
|
||||
m.draw_body 40,40,160,40
|
||||
m.draw_body 100,40,100,180
|
||||
else
|
||||
m.draw_body 100,50,40,40
|
||||
m.draw_body 100,50,160,40
|
||||
m.draw_body 100,50,100,180
|
||||
end
|
||||
m.draw_body 100,180,140,160
|
||||
m.draw_body 100,180,60,160
|
||||
m.end_body
|
||||
m.draw_circle 140,160,"1",Model::CW,Model::SE
|
||||
m.draw_circle 160,40,"2",Model::CCW,Model::NE
|
||||
m.draw_circle 60,160,"3",Model::CCW,Model::SW
|
||||
m.draw_circle 40,40,"4",Model::CW,Model::NW
|
||||
m.draw_dirn
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_atail
|
||||
m = Model.new "atail_quad.svg"
|
||||
if TFLAT == true
|
||||
m.draw_body 40,40,160,40
|
||||
m.draw_body 100,40,100,140
|
||||
else
|
||||
m.draw_body 100,50,40,40
|
||||
m.draw_body 100,50,160,40
|
||||
m.draw_body 100,50,100,140
|
||||
end
|
||||
m.draw_body 100,140,140,160
|
||||
m.draw_body 100,140,60,160
|
||||
m.end_body
|
||||
m.draw_circle 60,160,"1",Model::CCW,Model::SW
|
||||
m.draw_circle 160,40,"2",Model::CCW,Model::NE
|
||||
m.draw_circle 140,160,"3",Model::CW,Model::SE
|
||||
m.draw_circle 40,40,"4",Model::CW,Model::NW
|
||||
m.draw_dirn
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_octox8 # just x8 surely?
|
||||
m = Model.new "octo_x8.svg"
|
||||
|
||||
m.draw_circle 170,170,"5",Model::CCW,Model::NE,false,:dark_green,14,8
|
||||
m.draw_circle 170,30,"6",Model::CW,Model::SE,false,:dark_green,-10,8
|
||||
m.draw_circle 30,170,"7",Model::CW,Model::NW,false,:dark_green,14,-10
|
||||
m.draw_circle 30,30,"8",Model::CCW,Model::SW,false,:dark_green,-10,-10
|
||||
|
||||
m.draw_body 50,50,150,150
|
||||
m.draw_body 50,150,150,50
|
||||
m.end_body
|
||||
m.draw_circle 150,150,"1",Model::CW,Model::SW,"#fff8",nil,-10
|
||||
m.draw_circle 150,50,"2",Model::CCW,Model::NW,"#fff8",nil,12
|
||||
m.draw_circle 50,150,"3",Model::CCW,Model::SE,"#fff8",nil,-10
|
||||
m.draw_circle 50,50,"4",Model::CW,Model::NE,"#fff8",nil,12
|
||||
m.draw_dirn
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_quadx
|
||||
m = Model.new "quad_x.svg"
|
||||
m.draw_body 40,40,160,160
|
||||
m.draw_body 40,160,160,40
|
||||
m.end_body
|
||||
m.draw_circle 160,160,"1",Model::CW,Model::SE
|
||||
m.draw_circle 160,40,"2",Model::CCW,Model::NE
|
||||
m.draw_circle 40,160,"3",Model::CCW,Model::SW
|
||||
m.draw_circle 40,40,"4",Model::CW,Model::NW
|
||||
m.draw_dirn
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_quadp
|
||||
m = Model.new "quad_p.svg"
|
||||
m.draw_body 40,100,160,100
|
||||
m.draw_body 100,40,100,160
|
||||
m.end_body
|
||||
m.draw_circle 100,160,"1",Model::CW,Model::SW
|
||||
m.draw_circle 160,100,"2",Model::CCW,Model::NE
|
||||
m.draw_circle 100,40,"4",Model::CW,Model::NE
|
||||
m.draw_circle 40,100,"3",Model::CCW,Model::SW
|
||||
m.draw_dirn
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_hexp
|
||||
s = ShapeFarm.new
|
||||
p = s.generate 100, 100, 60, 6
|
||||
|
||||
m = Model.new "hex_p.svg"
|
||||
m.draw_body *p[0],*p[3]
|
||||
m.draw_body *p[1],*p[4]
|
||||
m.draw_body *p[2],*p[5]
|
||||
m.end_body
|
||||
m.radius = 24
|
||||
m.draw_circle *p[0],"5",Model::CCW,Model::NW
|
||||
m.draw_circle *p[1],"2",Model::CW,Model::NE
|
||||
m.draw_circle *p[2],"1",Model::CCW,Model::SE
|
||||
m.draw_circle *p[3],"6",Model::CW,Model::SW
|
||||
m.draw_circle *p[4],"3",Model::CCW,Model::SW
|
||||
m.draw_circle *p[5],"4",Model::CW,Model::NW
|
||||
m.draw_dirn
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_hexx
|
||||
s = ShapeFarm.new
|
||||
p = s.generate 100, 100, 60, 6, 30
|
||||
|
||||
m = Model.new "hex_x.svg"
|
||||
m.draw_body *p[0],*p[3]
|
||||
m.draw_body *p[1],*p[4]
|
||||
m.draw_body *p[2],*p[5]
|
||||
m.end_body
|
||||
m.radius = 24
|
||||
m.draw_circle *p[0],"2",Model::CCW,Model::NE
|
||||
m.draw_circle *p[1],"5",Model::CW,Model::SE
|
||||
m.draw_circle *p[2],"1",Model::CCW,Model::SE
|
||||
m.draw_circle *p[3],"3",Model::CW,Model::SW
|
||||
m.draw_circle *p[4],"6",Model::CCW,Model::SW
|
||||
m.draw_circle *p[5],"4",Model::CW,Model::NW
|
||||
m.draw_dirn
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_octx
|
||||
s = ShapeFarm.new
|
||||
p = s.generate 100, 100, 70, 8, 22.5
|
||||
|
||||
m = Model.new "octo_flat_x.svg"
|
||||
m.lw = 20
|
||||
m.radius = 20
|
||||
m.draw_body *p[0],*p[4]
|
||||
m.draw_body *p[1],*p[5]
|
||||
m.draw_body *p[2],*p[6]
|
||||
m.draw_body *p[3],*p[7]
|
||||
m.end_body
|
||||
m.draw_circle *p[0],"2",Model::CCW,Model::NE
|
||||
m.draw_circle *p[1],"6",Model::CW,Model::NE
|
||||
m.draw_circle *p[2],"3",Model::CCW,Model::SE
|
||||
m.draw_circle *p[3],"7",Model::CW,Model::SE
|
||||
m.draw_circle *p[4],"4",Model::CCW,Model::SW
|
||||
m.draw_circle *p[5],"8",Model::CW,Model::SW
|
||||
m.draw_circle *p[6],"1",Model::CCW,Model::NW
|
||||
m.draw_circle *p[7],"5",Model::CW,Model::NW
|
||||
m.draw_dirn
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_octp
|
||||
s = ShapeFarm.new
|
||||
p = s.generate 100, 100, 70, 8
|
||||
|
||||
m = Model.new "octo_flat_p.svg"
|
||||
m.lw = 20
|
||||
m.radius = 20
|
||||
|
||||
m.draw_body *p[0],*p[4]
|
||||
m.draw_body *p[1],*p[5]
|
||||
m.draw_body *p[2],*p[6]
|
||||
m.draw_body *p[3],*p[7]
|
||||
m.end_body
|
||||
|
||||
m.draw_circle *p[0],"2",Model::CW,Model::NE
|
||||
m.draw_circle *p[1],"6",Model::CCW,Model::NE
|
||||
m.draw_circle *p[2],"3",Model::CW,Model::SE
|
||||
m.draw_circle *p[3],"7",Model::CCW,Model::SE
|
||||
m.draw_circle *p[4],"4",Model::CW,Model::SW
|
||||
m.draw_circle *p[5],"8",Model::CCW,Model::SW
|
||||
m.draw_circle *p[6],"1",Model::CW,Model::NW
|
||||
m.draw_circle *p[7],"5",Model::CCW,Model::NW
|
||||
m.draw_dirn
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_aero
|
||||
m = Model.new "airplane.svg"
|
||||
m.lw = 1
|
||||
|
||||
# For easy? of understanding, split into parts
|
||||
# Nose
|
||||
# m.draw_path([[85,20], [80,40], [120,40], [115,20],'!'],:silver, true)
|
||||
# Wing
|
||||
# m.draw_path([[80,40], [20,60], [20,100], [70,80], [130,80], [180,100],
|
||||
# [180,60], [120,40],'!'], :silver, true)
|
||||
# Aft
|
||||
# m.draw_path([[80,80],[90,150],[110,150],[120,80],'!'], :silver, true)
|
||||
# Tail
|
||||
# m.draw_path([[90,150], [50,155], [50,175], [150,175], [150,155], [110,150],'!'], :silver, true)
|
||||
|
||||
m.draw_path([[85,20], [80,40], [20,60], [20,100], [70,80],
|
||||
[80,80], [90,150], [50,155], [50,175],
|
||||
[150,175], [150,155], [110,150],[120,80],[130,80],
|
||||
[180,100], [180,60], [120,40], [115,20],'!'],:silver, true)
|
||||
m.draw_path([[20,80],[20,100],[70,80],[70,60], '!'], :red)
|
||||
m.draw_path([[180,80],[180,100],[130,80],[130,60], '!'], :green)
|
||||
m.draw_path([[50,165], [50,175], [150,175], [150,165],'!'],:orange)
|
||||
m.draw_path([[100,140], [95,150], [100,175], [105,150],'!'],:black)
|
||||
m.end_body
|
||||
m.radius = 14
|
||||
m.draw_circle 100,15,"1/2",Model::NOARROW,Model::SE, false, nil, 0, -9
|
||||
m.draw_servo 30, 100, " 3", :red
|
||||
m.draw_servo 142, 100, " 4", :green
|
||||
|
||||
m.draw_servo 64, 134, " 5", :black
|
||||
m.draw_servo 154, 168, " 6", :orange
|
||||
m.draw_dirn 50
|
||||
m.close
|
||||
end
|
||||
|
||||
def render_wing
|
||||
m = Model.new "flying_wing.svg"
|
||||
m.lw = 1
|
||||
m.draw_path([[80,20],[20,80],[20,120],[70,80],[130,80], [180,120],[180,80],
|
||||
[120,20],'!'], :silver)
|
||||
m.draw_path([[20,100],[20,120],[70,80],[70,60], '!'], :red)
|
||||
m.draw_path([[180,100],[180,120],[130,80],[130,60], '!'], :green)
|
||||
|
||||
m.draw_servo 30, 120, " 3", :red
|
||||
m.draw_servo 142, 120, " 4", :green
|
||||
m.draw_circle 100,110,"1/2",Model::NOARROW,Model::SE, false, nil, 0, -16
|
||||
m.draw_dirn 30
|
||||
m.close
|
||||
end
|
||||
|
||||
render_bi
|
||||
render_tri
|
||||
render_quadx
|
||||
render_quadp
|
||||
render_hexp
|
||||
render_hexx
|
||||
render_octx
|
||||
render_octp
|
||||
render_vtail
|
||||
render_atail
|
||||
render_y4
|
||||
render_y6
|
||||
render_octox8
|
||||
render_aero
|
||||
render_wing
|
Loading…
Add table
Add a link
Reference in a new issue