Module: ChemScanner::ChemDraw::BaseValue

Included in:
BaseNode
Defined in:
lib/chem_scanner/chem_draw/node/base_value.rb

Overview

ChemDraw basic Node

Constant Summary collapse

TEXT_ATTRIBUTES =
%w[font face size color].freeze
CDXML_CDX_POINT =
(1.0e6 / 65536)
ARROW_NOGO_CROSS =
2
CDXML_ARROW_TYPE =
{
  # "HalfHead" => 1,
  # "FullHead" => 2,
  "Full" => 2,
  # "Resonance" => 4,
  # "Equilibrium" => 8,
  # "Hollow" => 16,
  # "RetroSynthetic" => 32,
  # "NoGo" => 64,
  # "Dipole" => 128,
}.freeze
CDXML_GRAPHIC_TYPE =
{
  "Line" => 1,
  "Arc" => 2,
  "Rectangle" => 3,
  "Oval" => 4,
  "Orbital" => 5,
}.freeze
CDXML_LINE_TYPE =
{
  "Dashed" => 1,
}.freeze
CDXML_NODE_TYPE =
{
  "Unspecified" => 0,
  "Nickname" => 4,
  "Fragment" => 5,
  "GenericNickname" => 7,
  "AnonymousAlternativeGroup" => 8,
  "ExternalConnectionPoint" => 12,
}.freeze
CDXML_ATOM_EXTERNAL_CONNECTION_TYPE =
{
  "Unspecified" => 0,
  "Diamond" => 1,
  "Star" => 2,
  "PolymerBead" => 3,
  "Wavy" => 4,
}.freeze
CDXML_OVAL_TYPE =
{
  "Circle" => 1,
  "Shaded" => 2,
  "Circle Shaded" => 3,
  "Filled" => 4,
  "Dashed" => 8,
  "Bold" => 16,
  "Shadowed" => 32,
}.freeze
CDXML_ORBITAL_TYPE =
{
  "s" => 0,
  "oval" => 1,
  "lobe" => 2,
  "p" => 3,
  "hybridPlus" => 4,
  "hybridMinus" => 5,
  "dz2Plus" => 6,
  "dz2Minus" => 7,
  "dxy" => 8,
  "sShaded" => 256,
  "ovalShaded" => 257,
  "lobeShaded" => 258,
  "pShaded" => 259,
  "sFilled" => 512,
  "ovalFilled" => 513,
  "lobeFilled" => 514,
  "pFilled" => 515,
  "hybridPlusFilled" => 516,
  "hybridMinusFilled" => 517,
  "dz2PlusFilled" => 518,
  "dz2MinusFilled" => 519,
  "dxyFilled" => 520,
}.freeze

Instance Method Summary collapse

Instance Method Details

#binary_chunks(string, size) ⇒ Object



186
187
188
189
190
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 186

def binary_chunks(string, size)
  Array.new(((string.length + size - 1) / size)) do |i|
    string.slice(i * size, size)
  end
end

#cdx_styles(data, runs) ⇒ Object

Output example: [{ start: 1, face: 96 }]



222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 222

def cdx_styles(data, runs)
  style_list = (0..runs - 1).each_with_object([]) do |sb, list|
    sr = data[sb * 10, 10]
    attr_list = (["start"] + TEXT_ATTRIBUTES)
    style = attr_list.each_with_object({}).with_index do |(attr, acc), id|
      acc[attr.to_sym] = read_int(sr[id * 2, 2], true)
    end

    list.push(style)
  end

  style_list.sort_by { |x| x[:start] }
end

#cdx_text(data) ⇒ Object



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 196

def cdx_text(data)
  style_runs = read_int(data[0, 2], true)
  text_pos = style_runs * 10 + 2
  plain = data[text_pos, data.size - text_pos]

  styles = cdx_styles(data[2..-1], style_runs)
  if styles.empty?
    return [{ text: plain, font: 3, face: 0, size: 8, color: 0 }]
  end

  plain_arr = plain.dup.split("")

  styled_text = []
  styles.each_with_index do |style, idx|
    t_start = style.delete(:start)
    t_end = (styles[idx + 1] || {}).fetch(:start, plain.length)
    text = plain_arr[t_start..t_end - 1].join("")
    style[:text] = text
    style[:size] = style[:size] / 20
    styled_text.push(style)
  end

  styled_text
end

#cdxml_text(data) ⇒ Object



236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 236

def cdxml_text(data)
  styled_text = []
  data.xpath("./s").each do |s|
    style = TEXT_ATTRIBUTES.each_with_object({}) do |attr, acc|
      acc[attr.to_sym] = s.attr(attr).to_i
      acc[:text] = s.text
    end

    styled_text.push(style)
  end

  styled_text
end

#do_unhandled(tag) ⇒ Object



136
137
138
139
140
141
142
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 136

def do_unhandled(tag)
  return if @parser_type == "cdxml"

  return unless (tag & CdxReader::TAG_OBJECT).nonzero?

  loop { break if @parser.reader.read_next.positive? }
end

#initialize(parser, parser_type, id) ⇒ Object



192
193
194
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 192

def initialize(parser, parser_type, id)
  super(parser, parser_type, id)
end

#point_2d(data) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 144

def point_2d(data)
  x = 0
  y = 0

  if @parser_type == "cdx"
    y, x = binary_chunks(data, 4).map { |v| read_int(v, false) * 1.0e-6 }
  elsif @parser_type == "cdxml"
    values = data.text.split(" ")
    x, y = values[0..1].map { |v| v.to_f / CDXML_CDX_POINT }
  end

  [x.round(5), -y.round(5)]
end

#point_3d(data) ⇒ Object



158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 158

def point_3d(data)
  x = 0
  y = 0

  if @parser_type == "cdx"
    x, y, = binary_chunks(data, 4).map { |v| read_int(v, false) * 1.0e-6 }
  elsif @parser_type == "cdxml"
    values = data.text.split(" ")
    x, y = values[0..1].map { |v| v.to_f / CDXML_CDX_POINT }
  end

  [x.round(5), -y.round(5)]
end

#polygon_from_bb(data) ⇒ Object

Get polygon based on bounding box data



110
111
112
113
114
115
116
117
118
119
120
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 110

def polygon_from_bb(data)
  btop, left, bbottom, right = read_bounding_box(data)
  top = - btop
  bottom = - bbottom

  points = [
    Geometry::Point.new(left, bottom), Geometry::Point.new(left, top),
    Geometry::Point.new(right, top), Geometry::Point.new(right, bottom)
  ]
  Geometry::Polygon.new(points)
end

#read_bounding_box(data) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 122

def read_bounding_box(data)
  if @parser_type == "cdxml"
    left, top, right, bottom = data.text.split(" ").map do |x|
      x.to_f / CDXML_CDX_POINT
    end
  else
    top, left, bottom, right = binary_chunks(data, 4).map do |x|
      read_int(x, false) * 1.0e-6
    end
  end

  [top, left, bottom, right]
end

#read_ids(data) ⇒ Object



250
251
252
253
254
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 250

def read_ids(data)
  return data.text.split(" ").map(&:to_i) if @parser_type == "cdxml"

  binary_chunks(data, 4).map { |v| read_int(v, false) }
end

#read_int(data, unsigned) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 172

def read_int(data, unsigned)
  return data.text.to_i if @parser_type == "cdxml"

  type = case data.length
         when 1 then "c"
         when 2 then "s"
         when 4 then "l"
         end

  unsigned = unsigned || false
  type = unsigned ? type.upcase : type.downcase
  data.unpack(type)[0]
end

#read_type(tag, data, cdxml_type) ⇒ Object



87
88
89
90
91
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 87

def read_type(tag, data, cdxml_type)
  return read_value(tag, data) if @parser_type == "cdx"

  cdxml_type[data.text]
end

#read_value(prop_name, data) ⇒ Object



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/chem_scanner/chem_draw/node/base_value.rb', line 93

def read_value(prop_name, data)
  data_type = PROPS_DATA_TYPE[@props_ref[prop_name]]

  unless (/U?INT[8(16)(32)]/ =~ data_type).nil?
    return read_int(data, data_type[0] == "U")
  end

  case data_type
  when "CDXObjectID" then read_int(data, true)
  when "CDXPoint2D" then point_2d(data)
  when "CDXPoint3D" then point_3d(data)
  when "CDXRectangle" then polygon_from_bb(data)
  when "CDXObjectIDArray" then read_ids(data)
  end
end