Class: Sunniesnow::Tools::SvgPath::Path

Inherits:
Object
  • Object
show all
Defined in:
lib/sscharter/tools/svg_path.rb

Constant Summary collapse

COMMANDS =
{
	m: Command.new(:move_to, %i[point], :line_to),
	l: Command.new(:line_to, %i[point]),
	h: Command.new(:line_to, %i[point_x]),
	v: Command.new(:line_to, %i[point_y]),
	z: Command.new(:close, %i[], :unexpected_token),
	c: Command.new(:cubic, %i[point point point]),
	s: Command.new(:smooth_cubic, %i[point point]),
	q: Command.new(:quadratic, %i[point point]),
	t: Command.new(:smooth_quadratic, %i[point]),
	a: Command.new(:arc, %i[vector number boolean boolean point]),
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data) ⇒ Path

Returns a new instance of Path.

Parameters:

  • data (String)


376
377
378
379
380
381
382
383
384
385
# File 'lib/sscharter/tools/svg_path.rb', line 376

def initialize data
	@segments = []
	@lengths = [0.0]
	@last_initial = 0
	@current = Vector2D.new 0.0, 0.0
	data = data.gsub /[a-df-zA-DF-Z]/, ' \0 ' # exclude E for scientific notation
	data.gsub! /[,\s]+/, ' '
	data.strip!
	parse_instructions data.split
end

Instance Attribute Details

#currentVector2D (readonly)

Returns:



373
374
375
# File 'lib/sscharter/tools/svg_path.rb', line 373

def current
  @current
end

Instance Method Details

#add_segment(segment) ⇒ Vector2D

Parameters:

Returns:



456
457
458
459
460
# File 'lib/sscharter/tools/svg_path.rb', line 456

def add_segment segment
	@segments.push segment
	@lengths.push @lengths.last + segment.length
	@current = segment.end
end

#arc(radius, rotation, large_arc, sweep_positive, point) ⇒ Vector2D

Parameters:

  • radius (Numeric)
  • rotation (Numeric)
  • large_arc (Boolean)
  • sweep_positive (Boolean)
  • point (Vector2D)

Returns:



450
451
452
# File 'lib/sscharter/tools/svg_path.rb', line 450

def arc radius, rotation, large_arc, sweep_positive, point
	add_segment Arc.new @current, radius, rotation*Math::PI/180, large_arc, sweep_positive, point
end

#at_length(s) ⇒ Vector2D

Parameters:

  • s (Float)

Returns:



469
470
471
472
473
474
475
# File 'lib/sscharter/tools/svg_path.rb', line 469

def at_length s
	len = length
	s %= len*2
	s = 2*len - s if s > len
	i = @lengths.bsearch_index { _1 > s } - 1
	@segments[i].at_length s - @lengths[i]
end

#closeVector2D

Returns:



407
408
409
410
# File 'lib/sscharter/tools/svg_path.rb', line 407

def close
	point = @segments[@last_initial].begin
	@current == point ? point : line_to(point)
end

#cubic(control1, control2, point) ⇒ Vector2D

Parameters:

Returns:



416
417
418
# File 'lib/sscharter/tools/svg_path.rb', line 416

def cubic control1, control2, point
	add_segment CubicBezier.new @current, control1, control2, point
end

#lengthFloat

Returns:

  • (Float)


463
464
465
# File 'lib/sscharter/tools/svg_path.rb', line 463

def length
	@lengths.last
end

#line_to(point) ⇒ Vector2D

Parameters:

Returns:



402
403
404
# File 'lib/sscharter/tools/svg_path.rb', line 402

def line_to point
	add_segment Line.new @current, point
end

#move_to(point) ⇒ Vector2D

Parameters:

Returns:



395
396
397
398
# File 'lib/sscharter/tools/svg_path.rb', line 395

def move_to point
	@last_initial = @segments.length
	@current = point
end

#quadratic(control, point) ⇒ Vector2D

Parameters:

Returns:



432
433
434
# File 'lib/sscharter/tools/svg_path.rb', line 432

def quadratic control, point
	add_segment QuadraticBezier.new @current, control, point
end

#samples(range, total = range.is_a?(Range) ? range.end : range) {|x, y, i| ... } ⇒ Path

Returns self.

Parameters:

  • range (Range, Integer)
  • total (Integer) (defaults to: range.is_a?(Range) ? range.end : range)

Yield Parameters:

  • x (Float)
  • y (Float)
  • i (Integer)

Returns:



483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
# File 'lib/sscharter/tools/svg_path.rb', line 483

def samples range, total = range.is_a?(Range) ? range.end : range
	return to_enum __method__, range, total unless block_given?
	range = 0...range unless range.is_a? Range
	len = length
	delta = len / total.to_f
	s = range.begin * delta
	sign = 1
	s %= len*2
	if s > len
		s = 2*len - s
		sign *= -1
	end
	i = @lengths.bsearch_index { _1 > s } - 1
	range.each do |j|
		if j == range.begin
			yield *@segments[i].at_length(s - @lengths[i]).to_a, j
			next
		end
		s += delta*sign
		s %= len*2
		if s > len
			s = 2*len - s
			sign *= -1
		end
		i -= 1 while i > 0 && s < @lengths[i]
		i += 1 while i < @lengths.length - 1 && s > @lengths[i+1]
		yield *@segments[i].at_length(s - @lengths[i]).to_a, j
	end
	self
end

#smooth_cubic(control2, point) ⇒ Vector2D

Parameters:

Returns:



423
424
425
426
427
# File 'lib/sscharter/tools/svg_path.rb', line 423

def smooth_cubic control2, point
	last = @segments.last
	control1 = last.is_a?(CubicBezier) ? @current*2 - last.control2 : @current
	cubic control1, control2, point
end

#smooth_quadratic(point) ⇒ Vector2D

Parameters:

Returns:



438
439
440
441
442
# File 'lib/sscharter/tools/svg_path.rb', line 438

def smooth_quadratic point
	last = @segments.last
	control = last.is_a?(QuadraticBezier) ? @current*2 - last.control : @current
	quadratic control, point
end

#unexpected_tokenvoid

This method returns an undefined value.

Raises:



389
390
391
# File 'lib/sscharter/tools/svg_path.rb', line 389

def unexpected_token
	raise CommandError.new 'Unexpected token'
end