Class: Ballistics::Projectile

Inherits:
Object
  • Object
show all
Defined in:
lib/ballistics/projectile.rb

Constant Summary collapse

YAML_DIR =
'projectiles'
MANDATORY =
{
  "name"   => :string,
  "cal"    => :float,
  "grains" => :count,
}
BALLISTIC_COEFFICIENT =

one of these fields is mandatory

{
  "g1" => :float,
  "g7" => :float,
}
OPTIONAL =
{
  "sd"       => :float,
  "intended" => :string,
  "base"     => :string,
  "desc"     => :string,
}
DRAG_FUNCTION =
{
  "flat" => "g1",
  "boat" => "g7",
}
DRAG_NUMBER =
{
  "g1" => 1,
  "g7" => 7,
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hsh) ⇒ Projectile

Returns a new instance of Projectile.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/ballistics/projectile.rb', line 63

def initialize(hsh)
  @yaml_data = hsh
  MANDATORY.each { |field, type|
    val = hsh.fetch(field)
    Ballistics::YAML.check_type!(val, type)
    self.instance_variable_set("@#{field}", val)
  }

  # Extract ballistic coefficients per drag model (e.g. G1)
  # We need at least one
  #
  @ballistic_coefficient = {}
  BALLISTIC_COEFFICIENT.each { |field, type|
    if hsh.key?(field)
      val = hsh[field]
      if !Ballistics::YAML.check_type?(val, type)
        raise(TypeError, "#{val} (#{field}) is not #{type}")
      end
      self.instance_variable_set("@#{field}", val)
      @ballistic_coefficient[field] = val
    end
  }
  raise "no valid BC" if @ballistic_coefficient.empty?

  OPTIONAL.each { |field, type|
    if hsh.key?(field)
      val = hsh[field]
      val = val.to_s if field == "intended" and type == :string
      Ballistics::YAML.check_type!(val, type)
      if field == "base"
        @base = self.class.base(val)
      else
        self.instance_variable_set("@#{field}", val)
      end
    end
  }

  # Keep track of fields that we don't expect
  @extra = {}
  (hsh.keys -
   MANDATORY.keys -
   BALLISTIC_COEFFICIENT.keys -
   OPTIONAL.keys).each { |k|
    @extra[k] = hsh[k]
  }

  # Make sure @base and @drag_function are initialized so that
  # self.drag_function works without warnings
  #
  @base ||= nil
  @drag_function = nil
end

Instance Attribute Details

#ballistic_coefficientObject (readonly)

Returns the value of attribute ballistic_coefficient.



61
62
63
# File 'lib/ballistics/projectile.rb', line 61

def ballistic_coefficient
  @ballistic_coefficient
end

#extraObject (readonly)

Returns the value of attribute extra.



61
62
63
# File 'lib/ballistics/projectile.rb', line 61

def extra
  @extra
end

#yaml_dataObject (readonly)

Returns the value of attribute yaml_data.



61
62
63
# File 'lib/ballistics/projectile.rb', line 61

def yaml_data
  @yaml_data
end

Class Method Details

.base(candidate) ⇒ Object

Normalize common flat-base and boat-tail terms to flat or boat



40
41
42
43
44
45
46
47
48
49
50
# File 'lib/ballistics/projectile.rb', line 40

def self.base(candidate)
  c = candidate.to_s.downcase.gsub(/[\-\_ ]/, '')
  case c
  when "boat", "boattail", "bt"
    "boat"
  when "flat", "flatbase", "fb"
    "flat"
  else
    raise "unknown base: #{candidate}"
  end
end

.drag_number(drag_function) ⇒ Object

Convert e.g. G1 to 1



54
55
56
# File 'lib/ballistics/projectile.rb', line 54

def self.drag_number(drag_function)
  DRAG_NUMBER.fetch(drag_function.to_s.downcase)
end

.find(file: nil, id: nil) ⇒ Object

Load a built-in YAML file and instantiate projectile objects Return a hash of projectile objects keyed by projectile id (per the YAML)



34
35
36
# File 'lib/ballistics/projectile.rb', line 34

def self.find(file: nil, id: nil)
  Ballistics::YAML.find(klass: self, file: file, id: id)
end

Instance Method Details

#bcObject

Return the BC for the preferred drag function



132
133
134
# File 'lib/ballistics/projectile.rb', line 132

def bc
  @ballistic_coefficient.fetch(self.drag_function)
end

#drag_functionObject

Return the preferred drag function if there is a BC available



118
119
120
121
122
123
124
125
126
127
128
# File 'lib/ballistics/projectile.rb', line 118

def drag_function
  return @drag_function if @drag_function
  @drag_function = @ballistic_coefficient.keys.first
  if @base
    preferred = DRAG_FUNCTION.fetch(@base)
    if @ballistic_coefficient.key?(preferred)
      @drag_function = preferred
    end
  end
  @drag_function
end

#multilineObject

Return lines of text separated by newlines



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/ballistics/projectile.rb', line 146

def multiline
  lines = ["PROJECTILE: #{@name}", "=========="]
  fields = {
    "Caliber" => @cal,
    "Grains" => @grains,
  }
  @ballistic_coefficient.each { |df, bc|
    fields["BC (#{df.upcase})"] = bc
  }
  fields["Desc"] = @desc if @desc
  fields.each { |name, val|
    lines << [name.rjust(7, ' '), val].join(': ')
  }
  lines.join("\n")
end

#paramsObject

Return params that can be used by Ballistics::Problem



138
139
140
141
142
# File 'lib/ballistics/projectile.rb', line 138

def params
  { drag_function: self.drag_function,
    drag_number: self.class.drag_number(self.drag_function),
    ballistic_coefficient: self.bc }
end