<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -2,6 +2,7 @@ require 'strscan'
 
 require 'celtic_knot/edge'
 require 'celtic_knot/node'
+require 'celtic_knot/knot'
 
 module CelticKnot
   class Graph
@@ -43,5 +44,9 @@ module CelticKnot
     def initialize(nodes)
       @nodes = nodes
     end
+
+    def build_knot
+      Knot.new(self)
+    end
   end
 end</diff>
      <filename>lib/celtic_knot/graph.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,19 +1,133 @@
 require 'celtic_knot/thread'
+require 'celtic_knot/direction'
+require 'curves/hermite'
 
 module CelticKnot
   class Knot
+    attr_reader :graph
     attr_reader :threads
     attr_reader :overlaps
 
-    def initialize
+    def initialize(graph)
+      @graph = graph
       @threads = []
       @overlaps = Hash.new { |h,k| h[k] = [] }
+      generate!
     end
 
-    def new_thread
-      thread = Thread.new(self)
-      @threads &lt;&lt; thread
-      return thread
-    end
+    private
+
+      def generate!
+        compute_crossings
+        define_threads
+        compute_overlaps
+        # smooth_threads
+        # decompose
+      end
+
+      def compute_crossings
+        graph.nodes.each do |node|
+          if node.edges.empty?
+            # FIXME: implement this case
+            new_singularity(node)
+          else
+            node.edges.each do |edge|
+              next if edge.marked?(node, Direction::CCW)
+              follow_thread_from(node, edge)
+            end
+          end
+        end
+      end
+
+      def follow_thread_from(node, edge)
+        thread = Thread.new(self)
+        threads &lt;&lt; thread
+
+        direction = Direction::CCW
+        midpoint = edge.virtual_midpoint(node, direction, :start)
+
+        step = 0
+
+        loop do
+          step += 1
+
+          far = edge.other(node)
+          parallel = far - node
+          vector = edge.vector(parallel, direction)
+
+          break if thread.closes?(midpoint, vector)
+
+          far_edge = far.nearest_edge_to(edge, direction)
+          difference = edge.difference(far_edge, direction)
+          difference = 1.0 if difference == 0.0
+
+# puts &quot;%d: %s %s&quot; % [step, node, edge]
+# puts &quot;   far edge:   %s&quot; % far_edge
+# puts &quot;   parallel:   %s&quot; % parallel
+# puts &quot;   vector:     %s&quot; % vector
+# puts &quot;   midpoint:   %s&quot; % midpoint
+# puts &quot;   direction:  %s&quot; % direction
+# puts &quot;   difference: %f&quot; % difference
+
+          thread.add_connection(midpoint, vector, 4.5 * difference, edge.normal?)
+          edge.mark(node, direction)
+
+          edge = far_edge
+          midpoint = edge.virtual_midpoint(far, direction, :enter)
+
+          # if the edge is being ignored, then we reverse direction,
+          # keeping all else the same. This has the effect of just
+          # passing through the edge.
+
+          if edge.ignore?
+            node = edge.other(far)
+          else
+            node = far
+            direction = direction.opposite if edge.normal?
+          end
+        end
+      end
+
+      def define_threads
+        threads.each { |thread| define_thread(thread) }
+      end
+
+      def define_thread(thread)
+        near = thread.head
+        loop do
+          far = near[:next]
+
+          near[:curve] = Curves::Hermite.new([near[:at], near[:vector] * near[:magnitude], far[:at], far[:vector] * near[:magnitude]])
+
+          near = far
+          break if near == thread.head
+        end
+      end
+
+      def compute_overlaps
+        threads.each { |thread| compute_overlaps_for(thread.head) }
+      end
+
+      def compute_overlaps_for(start, offset=1)
+        c = start
+        loop do
+          if c[:intersection]
+            if c[:offset]
+              offset = c[:offset]
+            else
+              c[:offset] = offset
+            end
+
+            offset = -offset
+
+            crosses = overlaps[c[:at]]
+            other = crosses[0][:thread] == start[:thread] ? crosses[1] : crosses[0]
+            compute_overlaps_for(other, offset) unless other[:offset]
+          end
+
+          c = c[:next]
+          break if c == start
+        end
+      end
   end
 end</diff>
      <filename>lib/celtic_knot/knot.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>lib/celtic_knot/builder.rb</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>901e655c3f54b1463934138bf885ea71ac3c66fc</id>
    </parent>
  </parents>
  <author>
    <name>Jamis Buck</name>
    <email>jamis@37signals.com</email>
  </author>
  <url>http://github.com/jamis/celtic_knot/commit/0d4d9c91c604a0acd7387a2481a81e3d81bf41bb</url>
  <id>0d4d9c91c604a0acd7387a2481a81e3d81bf41bb</id>
  <committed-date>2009-06-10T21:49:35-07:00</committed-date>
  <authored-date>2009-06-10T21:49:35-07:00</authored-date>
  <message>faster knot generation</message>
  <tree>ddd25d4fdf9e302689809ccdceaebad73fb1fae4</tree>
  <committer>
    <name>Jamis Buck</name>
    <email>jamis@37signals.com</email>
  </committer>
</commit>
