class TaskJuggler::CollisionDetector
Public Class Methods
Source
# File lib/taskjuggler/reports/CollisionDetector.rb, line 22 def initialize(width, height) @width = width @height = height # The zones are stored as Arrays of line segments. Horizontal blocks are # stored separately from vertical blocks. Blocked segments for a # particular x coordinate are stored in @vLines, for y coordinates in # @hLines. Each entry is an Array of [ start, end ] values that describe # the blocked segments of that particular line. Start and end point are # part of the segment. A listed segment will not be overwritten during # routing. @hLines = Array.new(@height) { |i| i = [] } @vLines = Array.new(@width) { |i| i = [] } end
Public Instance Methods
Source
# File lib/taskjuggler/reports/CollisionDetector.rb, line 41 def addBlockedZone(x, y, w, h, horiz, vert) # Clip the input rectangle to fit within the handled area of this router. x = clip(x.to_i, @width - 1) y = clip(y.to_i, @height - 1) w = clip(w.to_i, @width - x) h = clip(h.to_i, @height - y) # We can ignore empty zones. return if w == 0 || h == 0 # Break the rectangle into line segments and add them to the appropriate # line Arrays. if horiz y.upto(y + h - 1) do |i| addSegment(@hLines[i], [ x, x + w - 1 ]) end end if vert x.upto(x + w - 1) do |i| addSegment(@vLines[i], [ y, y + h - 1 ]) end end end
This function registers an area as don’t-cross-zone. The rectangular zone is described by x, y, w and h. If horiz is true, the zone will be blocked for horizontal lines, if vert is true the zone will be blocked for vertical lines.
Source
# File lib/taskjuggler/reports/CollisionDetector.rb, line 68 def collision?(pos, segment, horizontal) line = (horizontal ? @hLines : @vLines)[pos] # For complex charts, the segment lists can be rather long. We use a # binary search to be fairly efficient. l = 0 u = line.length - 1 while l <= u # Look at the element in the middle between l and u. p = l + ((u - l) / 2).to_i return true if overlaps?(line[p], segment) if segment[0] > line[p][1] # The potential target is above p. Adjust lower bound. l = p + 1 else # The potential target is below p. Adjust upper bound. u = p - 1 end end false end
Find out if there is a block at line pos for the start/end coordinates given by segment. If horizontal is true, we are looking for a horizontal block, otherwise a vertical.
Source
# File lib/taskjuggler/reports/CollisionDetector.rb, line 91 def to_html html = [] # Change this to determine what zones you want to see. if true # Show vertical blocks x = 0 @vLines.each do |line| line.each do |segment| html << lineToHTML(x, segment[0], x, segment[1], 'white') end x += 1 end else # Show horizontal blocks y = 0 @hLines.each do |line| line.each do |segment| html << lineToHTML(segment[0], y, segment[1], y, 'white') end y += 1 end end html end
Private Instance Methods
Source
# File lib/taskjuggler/reports/CollisionDetector.rb, line 128 def addSegment(line, newSegment) # Search for overlaping or directly attaching segments in the list. i = 0 while (i < line.length) segment = line[i] if mergeable?(newSegment, segment) # Merge exiting segment into new one merge(newSegment, segment) # Remove the old one from the list and restart with the newly created # one at the same position. line.delete_at(i) next elsif segment[0] > newSegment[1] # Segments are stored in ascending order. If the next segment starts # with a larger value, we insert the new segment before the larger # one. line.insert(i, newSegment) return end i += 1 end # Append new segment line << newSegment end
This function adds a new segment to the line. In case the new segment overlaps with or directly attaches to existing segments, these segments are merged into a single segment.
Source
# File lib/taskjuggler/reports/CollisionDetector.rb, line 119 def clip(v, max) v = 0 if v < 0 v = max if v > max v end
Simple utility function to limit v between 0 and max.
Source
# File lib/taskjuggler/reports/CollisionDetector.rb, line 170 def merge(dst, seg) dst[0] = seg[0] if seg[0] < dst[0] dst[1] = seg[1] if seg[1] > dst[1] end
Merge the two segments described by dst and src into dst.
Source
# File lib/taskjuggler/reports/CollisionDetector.rb, line 163 def mergeable?(s1, s2) overlaps?(s1, s2) || (s1[1] + 1 == s2[0]) || (s2[1] + 1 == s1[0]) end
Return true if the two segments described by s1 and s2 overlap each other or are directly attached to each other.
Source
# File lib/taskjuggler/reports/CollisionDetector.rb, line 156 def overlaps?(s1, s2) (s1[0] <= s2[0] && s2[0] <= s1[1]) || (s2[0] <= s1[0] && s1[0] <= s2[1]) end
Return true if the two segments described by s1 and s2 overlap each other. A segment is a [ start, end ] Array. The two points are part of the segment.