Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/iNavFlight/inav-configurator.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominic Clifton <me@dominicclifton.name>2015-02-02 03:06:45 +0300
committerDominic Clifton <me@dominicclifton.name>2015-02-02 03:07:44 +0300
commite871466869a9adf0200f3484d4ea7c95a2b51d51 (patch)
treead62f0b8c1d8b22ad64b14e310895e3b83ab146a /support/svg_model_motors.rb
parentbd2754a0de2080a1bf11d12d0923aac8e47b665f (diff)
Moving script.
Diffstat (limited to 'support/svg_model_motors.rb')
-rwxr-xr-xsupport/svg_model_motors.rb546
1 files changed, 546 insertions, 0 deletions
diff --git a/support/svg_model_motors.rb b/support/svg_model_motors.rb
new file mode 100755
index 00000000..97ee4f17
--- /dev/null
+++ b/support/svg_model_motors.rb
@@ -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