diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..7607fb4 Binary files /dev/null and b/.DS_Store differ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/celticbook.iml b/.idea/celticbook.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/celticbook.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..84ed080 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index a4ecf53..1acbb1a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -# celtic +# celticbook +A LaTeX learning project. The plan (not currently executed) is to create a book similar to dmackinnon1/Truchet-Book that covers some small +set of celtic patterns created using the grid method. + +## Original notes (dmackinnon1/celtic) Generator and editors for Celtic Knot patterns. Please see the live example here: https://dmackinnon1.github.io/celtic. See these blog posts: diff --git a/celtic/celtic.js b/celtic/celtic.js new file mode 100644 index 0000000..a48f599 --- /dev/null +++ b/celtic/celtic.js @@ -0,0 +1,1784 @@ +"use strict"; +/** + * Builders to be used for HTML construction. + * + */ +class Bldr { + constructor(name) { + this.name = name; + this.attributes = []; + this.elements = []; + } + att(name, value) { + let att = new Attribute(name, value); + this.attributes.push(att); + return this; + } + // add element allows you to add a builder to a builder + elem(bldr) { + this.elements.push(bldr); + return this; + } + text(text) { + this.elements.push (new RawHtml(text)); + return this; + } + build() { + let s = "<" + this.name; + for(let i = 0; i< this.attributes.length; i++) { + s += " " + this.attributes[i].toString(); + } + s += ">"; + for(let i = 0; i< this.elements.length; i++) { + s += " " + this.elements[i].build(); + } + s += ""; + return s; + } +}; + +class Attribute { + constructor(name, value) { + this.name = name; + this.value = value; + } + + toString() { + return "" + this.name + "='" + this.value + "'"; + } +}; + +class RawHtml { + constructor(raw) { + this.raw = raw; + } + build() { + return this.raw; + } +}; + + +/** + * Builders to be used for LaTeX construction. + * + */ + +class LaTeXEnv { + + constructor(l=null){ + this.label = l; + this.b = null; + this.content = []; + this.parent = null; + } + + begin(tag){ + this.b = tag; + return this; + } + + p(text){ + this.content.push(new LaTeXParagraph(text)); + return this; + } + + env(label){ + let environ = new LaTeXEnv(label); + this.content.push(environ); + return environ; + } + + command(c,a, nl=false){ + this.content.push(new LaTeXCommand(c,a, nl)); + return this; + } + + build(){ + let result = ""; + if (this.label != null){ + result += "%" + this.label + " \n"; + } + if (this.b !== null){ + result += "\\begin{" + this.b + "}\n"; + } + for (let i in this.content){ + result += this.content[i].build(); + } + if (this.b !== null){ + result += "\\end{" + this.b + "}\n"; + } + return result; + } +} + +class LaTeXCommand{ + constructor(c, a=null, nl=false){ + this.command = c; + this.argument = a; + this.newline = nl; + } + + build(){ + let result = "\\" + this.command; + if (this.argument !== null){ + result += "{" + this.argument + "}"; + } + if (this.newline){ + result +="\n"; + } + return result; + } + +} + +class LaTeXParagraph { + constructor(t, lb=false){ + this.text = t; + this.linebreak = lb; + return this; + } + + build(){ + let result = "" + if (this.linebreak){ + result += "\n"; + } + result += this.text; + if (this.linebreak){ + result += "\\\\"; + result += "\n "; + } + return result; + } +} + +class LaTeXDoc { + constructor(dc = "article"){ + this.content = []; + this.packages = []; + this.documentclass = dc; + } + clear(){ + this.content = []; + this.packages = []; + } + env(label){ + let environ = new LaTeXEnv(label); + this.content.push(environ); + environ.parent = this; + return environ; + } + p(content, lb=false){ + this.content.push(); + return this; + } + command(c,a){ + this.content.push(new LaTeXCommand(c,a)); + return this; + } + + package(name, arg = null){ + this.packages.push(new LaTeXPackage(name,arg)); + return this; + } + + defaultPackages(){ + this.package("inputenc","utf8"); + return this; + } + + frontMatter(){ + let fm = ""; //\\documentclass{" + this.documentclass + "}\n"; + for (let i in this.packages){ + fm += this.packages[i].build() + "\n"; + } + return fm; + } + + input(fileName){ + let s = new LaTeXCommand("input", fileName, true); + this.content.push(s); + return this; + } + + build(){ + let result = this.frontMatter(); + for (let i in this.content){ + result += this.content[i].build() + "\n"; + } + return result; + } + +} +class LaTeXPackage { + constructor(n, a = null){ + this.name = n; + this.argument = a; + } + build(){ + let result = "\\usepackage"; + if (this.argument != null){ + result += "["+this.argument +"]"; + } + result += "{" + this.name + "}"; + return result; + } +} + +//for node export +try{ + module.exports = new LaTeXDoc(); +} catch(err){ + console.log("non-node execution context"); +} + +"use strict"; + +class TikZBuilder { + + constructor(){ + this.components = []; + } + + build(){ + let s = this.buildOpen(); + + for(let c in this.components) { + s += " " + this.components[c].build(); + } + + s += this.buildClose(); + return s; + } + + buildOpen(){ + let s = ""; + s+= "\\begin{tikzpicture}[framed,background rectangle/.style={ultra thick,draw=black}]\n"; + return s; + } + + buildClose(){ + let s = ""; + s += "\\end{tikzpicture} \n"; + return s; + } + + addLine(x1, y1, x2, y2){ + let start = new TikZPoint(x1, y1); + let end = new TikZPoint(x2,y2); + this.components.push(new TikZLine(start,end)); + } +} + +class TikZComponent { + + constructor(){ + this.body = ""; + } + + build(){ + return this.body; + } +} + +class TikZLine extends TikZComponent { + + constructor(s, e){ + super(); + this.start = s; + this.end = e; + } + + build(){ + let s = "\\draw [line width=3pt, line cap=round] " + this.start.build() + " -- " + this.end.build() + "; \n" + return s; + } +} + +class TikZPoint { + constructor(x,y){ + this.x = x; + this.y = y; + } + + build(){ + return "(" + this.x + "," + this.y + ")"; + } + +} + + +/* +* A point on the primary grid. +*/ +class Point{ + constructor(x,y,grid){ + this.x = x; + this.y = y; + this.grid = grid; + this.junctions=[]; + this.decorator = null; + } + + setDecorator(d){ + this.decorator = d; + return this; + } + + distance(point){ + return Math.sqrt(Math.pow((this.x - point.x),2) + Math.pow((this.y - point.y), 2)); + } + west(){ + if (this.x == 0) return null; + return this.grid.primaryGrid[this.x-1][this.y] + } + east(){ + if (this.x == this.grid.xdim-1) return null; + return this.grid.primaryGrid[this.x+1][this.y] + } + north(){ + if (this.y == 0) return null; + return this.grid.primaryGrid[this.x][this.y-1] + } + south(){ + if (this.y == this.grid.ydim-1) return null; + return this.grid.primaryGrid[this.x][this.y+1] + } + junction(junction){ + this.junctions.push(junction); + } + + hasNSJunction(){ + if (this.junctions.length == 0) return false; + for (let j in this.junctions){ + if (this.junctions[j].dir =="NS") return true; + } + return false; + } + + hasEWJunction(){ + if (this.junctions.length == 0) return false; + for (let j in this.junctions){ + if (this.junctions[j].dir =="EW") return true; + } + return false; + } + isEven(){ + return this.x%2==0; + } + + isOdd(){ + return !this.isEven(); + } + + isOnSecondary(){ + return (this.x%2==0 && this.y%2 ==0)||(this.x%2==1 && this.y%2 ==1); + } +} + + +/* +* Points on the secondary grid play a different role, they +* have polygons drawn on them and are the connectors for the secondary lines. +*/ +class Node extends Point { + constructor(x,y,grid){ + super(x,y,grid); + } + + directionalRelationship(other){ + if (this.x == other.x){ + return "NS"; + } + if (this.y == other.y){ + return "EW"; + } + return null; + } + + isNodeNeighbor(node){ + if (this.distance(node) == 2){ + return true; + } + return false; + } + + isNorthNeighbor(node){ + return (this.isNodeNeighbor(node) && this.y == (node.y+2)); + } + + isSouthNeighbor(node){ + return (this.isNodeNeighbor(node) && this.y == (node.y-2)); + } + + isEastNeighbor(node){ + return (this.isNodeNeighbor(node) && this.x == (node.x-2)); + } + + isWestNeighbor(node){ + return (this.isNodeNeighbor(node) && this.x == (node.x+2)); + } + + northNorth(){ + if (this.north()!= null){ + return this.north().north(); + } + return null; + } + + southSouth(){ + if (this.south()!= null){ + return this.south().south(); + } + return null; + } + + westWest(){ + if (this.west()!= null){ + return this.west().west(); + } + return null; + } + + eastEast(){ + if (this.east()!= null){ + return this.east().east(); + } + return null; + } + + hasNSJunction(){ + if (this.north() !== null && this.north().hasNSJunction()){ + return true; + } + if (this.south() !== null && this.south().hasNSJunction()){ + return true; + } + return false; + } + + hasEWJunction(){ + if (this.east() !== null && this.east().hasEWJunction()){ + return true; + } + if (this.west() !== null && this.west().hasEWJunction()){ + return true; + } + return false; + } + + hasJunction(){ + return this.hasNSJunction() || this.hasEWJunction(); + } + + getOneStepConnected(){ + let connected = [this]; + if (this.north() !== null && this.north().hasNSJunction()){ + connected.push(this.northNorth()); + } + if (this.south() !== null && this.south().hasNSJunction()){ + connected.push(this.southSouth()); + } + if (this.east() !== null && this.east().hasEWJunction()){ + connected.push(this.eastEast()); + } + if (this.west() !== null && this.west().hasEWJunction()){ + connected.push(this.westWest()); + } + return connected; + } + + getFullConnected(){ + let connectedSet = new Set(this.getOneStepConnected()); + let currentSize = connectedSet.size; + let nextSet = new Set(connectedSet); + do { + connectedSet = new Set(nextSet); + connectedSet.forEach(function(value1, value2, set){ + let others = value2.getOneStepConnected(); + for (let x in others){ + nextSet.add(others[x]); + } + }); + } while (nextSet.size != connectedSet.size); + return nextSet; + } +} + +/* +* A connector between two secondary nodes, passes through +* a primary node. +*/ +class Junction { + constructor(sourceNode, medianPoint, targetNode, dir){ + this.sourceNode = sourceNode; + this.targetNode = targetNode; + this.medianPoint = medianPoint; + this.dir = dir; + medianPoint.junction(this); + } +} + +/* +* A helper class used to draw junctions in scripts. +*/ +class JunctionEnd { + constructor(grid, x, y){ + this.grid = grid; + this.x = x; + this.y = y; + } + + to(otherX, otherY){ + let p1 = new Point(this.x, this.y); + let p2 = new Point(otherX, otherY); + this.grid.boxFrame(p1,p2); + } +} + +/* +* The main class for the knot - consists of +* primary and secondary grids of points and knots, and junctions +* between them. +*/ +class Grid { + constructor(ydim, xdim){ + this.ydim = 2*ydim - 1; + this.xdim = 2*xdim - 1; + this.primaryGrid = []; + this.secondaryGrid = []; + this.nodes = []; + this.points = []; + this.junctions = []; + } + + initialize(){ + //set up points + for (let i = 0; i < this.xdim; i++){ + this.primaryGrid[i] = [] + this.secondaryGrid[i] = []; + for (let j= 0; j < this.ydim; j++){ + let p = new Point(i,j, this); + this.primaryGrid[i][j] = p; + this.points.push(p) + if ((i%2==0 && j%2 ==0)||(i%2==1 && j%2 ==1)){ + let n = new Node(i,j, this); + this.nodes.push(n); + this.secondaryGrid[i][j] = n; + this.primaryGrid[i][j] = n + } + } + } + return this; + } + + //used to draw junctions in scripts + from(x, y){ + return new JunctionEnd(this, x, y); + } + + boxFrame(p1, p2){ + let xMax = Math.max(p1.x,p2.x); + let xMin = Math.min(p1.x,p2.x); + let yMin = Math.min(p1.y,p2.y); + let yMax = Math.max(p1.y,p2.y); + + //only form a frame if both frames are same mod 2 + if ((p1.isEven() && p2.isOdd())||(p1.isOdd()&&p2.isEven())){ + return; + } + + for (let i = xMin; i < xMax; i = i+2){ + let node = this.secondaryGrid[i][yMin]; + if (node == undefined) break; + if (node.east() == null || node.eastEast() == null) break; + if (node.east().junctions.length!=0) continue; + let junction = new Junction(node, node.east(), node.eastEast(), "EW"); + this.junctions.push(junction); + } + for (let i = xMin; i < xMax; i = i+2){ + let node = this.secondaryGrid[i][yMax]; + if (node == undefined) break; + if (node.east() == null || node.eastEast() == null) break; + if (node.east().junctions.length!=0) continue; + let junction = new Junction(node, node.east(), node.eastEast(), "EW"); + this.junctions.push(junction); + } + for (let i = yMin; i < yMax; i = i+2){ + let node = this.secondaryGrid[xMin][i]; + if (node == undefined) break; + if (node.south() == null || node.southSouth() == null) break; + if (node.south().junctions.length!=0) continue; + let junction = new Junction(node, node.south(), node.southSouth(), "NS"); + this.junctions.push(junction); + } + for (let i = yMin; i < yMax ; i = i+2){ + let node = this.secondaryGrid[xMax][i]; + if (node == undefined) break; + if (node.south() == null || node.southSouth() == null) break; + if (node.south().junctions.length!=0) continue; + let junction = new Junction(node, node.south(), node.southSouth(), "NS"); + this.junctions.push(junction); + } + return this; + } + + borders(){ + return this.boxFrame(new Point(0,0), new Point(this.xdim-1, this.ydim-1)); + } + + innerFrame(step){ + return this.boxFrame(new Point(2*step,2*step), new Point(this.xdim-(2*step +1), this.ydim-(2*step + 1))); + } + + nodeAt(x,y){ + return this.secondaryGrid[x][y]; + } + + pointAt(x,y){ + return this.primaryGrid[x][y]; + } + + removeJunctionAt(i,j){ + let selected = this.pointAt(i,j); + if (i == this.xdim -1 || j == this.ydim -1 || i == 0 || j == 0){ + return; + } + if (selected.junctions.length == 0){ + return; + } + for (let k in selected.junctions){ + let jr = selected.junctions[k]; + this.junctions.splice(this.junctions.indexOf(jr),1); + } + selected.junctions = []; + } + + randomLines(probability = 50){ + //random lines + for (let n in this.nodes){ + let node = this.nodes[n]; + let junction = null; + if (randomInt(100) > probability) continue; + let r = randomInt(4); + if (r == 0) { + if (node.south() != null && node.southSouth() != null) { + if (node.south().junctions.length==0){ + junction = new Junction(node, node.south(), node.southSouth(), "NS"); + this.junctions.push(junction); + } else { + this.removeJunctionAt(node.south().x, node.south().y); + } + } + } else if (r == 1){ + if (node.east() != null && node.eastEast() != null){ + if (node.east().junctions.length==0){ + junction = new Junction(node, node.east(), node.eastEast(), "EW"); + this.junctions.push(junction); + } else { + this.removeJunctionAt(node.east().x, node.east().y); + } + } + } else if (r == 2){ + if (node.north() != null && node.northNorth() != null && node.north().junctions.length==0){ + junction = new Junction(node, node.north(), node.northNorth(),"NS"); + this.junctions.push(junction); + } + } else { + if (node.west() != null && node.westWest() != null && node.west().junctions.length==0){ + junction = new Junction(node, node.west(), node.westWest(),"EW"); + this.junctions.push(junction); + } + } + } + return this; + } +} + +//randomization utility +function randomInt(lessThan){ + let r = Math.floor(Math.random()*lessThan); + return r; +}; + +"use strict"; +/** + * Classes and functions in this script file are to provide + * decorative renderings of knots - dependencies is on celtic_base.celtic and bldrs.celtic. + * + * + * KnotDisplay classes provide different ways of displaying + * the knot defined by a Grid object. They use DisplayData objects + * to store display information about the grid before generating + * svg representations. + * + * KnotDisplay - just shows the raw primary and secondary grid + * and any junctions between secondary grid points. + * + * BasicKnotDisplay & DisplayData - draws a primitive knot pattern using the + * 'negative space' algorithm, which makes secondary points into + * gaps between the knot bands and draws gaps where the bands + * overlap. + * + * BeveledKnotDisplay & BeveledDisplayData - follows the + * 'negative space' algorithm but truncates the polygons drawn at + * secondary points so that the knot bands appear to bend. + * + * PositiveKnotDisplay PositiveDisplayData- folllows the 'positive space' + * algorithm, drawing lines and circles between the secondary points. + * + * RibbonKnotDisplay - adds multiple layers of thhe 'positive space' + * algorithm. + */ +class KnotDisplay { + + constructor(g, scale,foreground = "white", background = "black"){ + this.g = g; + this.scale = scale; + this.foregroundColor = foreground; + this.backgroundColor = background; + this.edge = scale/8; + this.junctionMultiplier = 2; + } + + init(){ + let height = (this.g.ydim-1)*this.scale; + let width = (this.g.xdim -1)*this.scale; + this.svgBldr = new Bldr("svg"); + this.svgBldr.att("version", "1.1").att("xmlns", "http://www.w3.org/2000/svg").att("xmlns:xlink", "http://www.w3.org/1999/xlink"); + this.svgBldr.att("align", "center").att("width", width).att("height", height); + this.svgBldr.elem(new Bldr("rect").att("width", width).att("height",height).att("fill",this.foregroundColor)); + return this; + } + + build(){ + this.buildStructure(); + this.buildSVG(); + return this.svgBldr.build(); + } + + + buildStructure(){ + //no calculation required + } + + buildSVG(){ + this.junctions(); + this.secondaryGrid(); + this.primaryGrid(); + + } + + primaryGrid(){ + for (let p in this.g.points){ + let point = this.g.points[p]; + let dot = new Bldr("circle").att("cx",point.x*this.scale).att("cy", point.y*this.scale); + dot.att("r",this.scale/8).att("stroke-width",0).att("fill","grey"); + this.svgBldr.elem(dot); + } + return this; + } + + secondaryGrid(){ + for (let p in this.g.nodes){ + let point = this.g.nodes[p]; + let dot = new Bldr("circle").att("cx",point.x*this.scale).att("cy", point.y*this.scale); + dot.att("r",this.scale/4).att("stroke-width",this.scale/8).att("fill",this.backgroundColor); + this.svgBldr.elem(dot); + } + return this; + } + + junctions(){ + for (let j in this.g.junctions){ + let junction = this.g.junctions[j]; + let line = new Bldr("line").att("x1", junction.sourceNode.x*this.scale).att("y1", junction.sourceNode.y*this.scale) + .att("x2", junction.targetNode.x*this.scale).att("y2", junction.targetNode.y*this.scale); + line.att("stroke-width",this.edge*this.junctionMultiplier).att("stroke", this.backgroundColor) + .att("stroke-linecap","round"); + this.svgBldr.elem(line); + } + return this; + } +} + +/* +* A helper for drawing SVG lines. Expects two points to connect. +*/ +class Line { + constructor(source, target){ + this.source = source; + this.target = target; + this.decorator - null; + } + setDecorator(d){ + this.decorator = d; + return this; + } +} + +class DisplayData { + constructor(){ + this.lines = []; + this.polygon = []; + } + + polyCalc(node){ + this.polygon = []; //reset polygon + this.polygon.push(new Point(node.x+(1/2),node.y)); + this.polygon.push(new Point(node.x, node.y+(1/2))); + this.polygon.push(new Point(node.x-(1/2), node.y)); + this.polygon.push(new Point(node.x, node.y-(1/2))); + } + + lineCalc(node){ + this.lines = []; + if (node.x%2==0){ + if (node.east() != null && node.east().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x+(1/2), node.y), + new Point(node.x+1, node.y-(1/2)))); + } + if (node.south() != null && node.south().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x, node.y+(1/2)), + new Point(node.x+(1/2), node.y +1))); + } + if (node.west() != null && node.west().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x-(1/2), node.y), + new Point(node.x-1, node.y +(1/2)))); + } + if (node.north() != null && node.north().junctions.length == 0) { + this.lines.push(new Line(new Point(node.x, node.y-(1/2)), + new Point(node.x-(1/2), node.y-1))); + } + } else { + if (node.east() != null && node.east().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x+(1/2), node.y), + new Point(node.x+1, node.y +(1/2)))); + } + if (node.south() != null && node.south().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x, node.y+(1/2)), + new Point(node.x-(1/2), node.y +1))); + } + if (node.west() !== null && node.west().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x-(1/2), node.y), + new Point(node.x-1, node.y -(1/2)))); + } + if (node.north() != null && node.north().junctions.length == 0) { + this.lines.push(new Line(new Point(node.x, node.y-(1/2)), + new Point(node.x+(1/2), node.y-1))); + } + } + } +} + +class BasicKnotDisplay extends KnotDisplay { + constructor(g, scale,foreground = "white", background = "black"){ + super(g, scale, foreground, background); + this.displayData = []; + } + + newDisplayData(){ + return new DisplayData(); + } + + buildStructure(){ + for(let n in this.g.nodes){ + let node = this.g.nodes[n]; + let d = this.newDisplayData(); + d.polyCalc(node); + d.lineCalc(node); + this.displayData.push(d); + } + } + + buildSVG(){ + this.nodes(); + this.junctions(); + this.lines(); + } + + nodes(){ + for (let n in this.displayData){ + let node = this.displayData[n]; + let plist = ""; + for (let p in node.polygon){ + let point = node.polygon[p]; + plist += "" + (point.x*this.scale) + "," +(point.y*this.scale) +" "; + } + let dot = new Bldr("polygon").att("points",plist); + dot.att("stroke-width",this.edge).att("fill",this.backgroundColor).att("stroke", this.backgroundColor); + this.svgBldr.elem(dot); + } + return this; + } + + junctions(){ + for (let j in this.g.junctions){ + let junction = this.g.junctions[j]; + let line = new Bldr("line").att("x1", junction.sourceNode.x*this.scale).att("y1", junction.sourceNode.y*this.scale) + .att("x2", junction.targetNode.x*this.scale).att("y2", junction.targetNode.y*this.scale); + line.att("stroke-width",this.edge*this.junctionMultiplier).att("stroke", this.backgroundColor) + .att("stroke-linecap","round"); + this.svgBldr.elem(line); + } + return this; + } + + lines(){ + for (let n in this.displayData){ + let node = this.displayData[n]; + for (let l in node.lines){ + let secLine = node.lines[l]; + let line = new Bldr("line").att("x1",secLine.source.x*this.scale) + .att("y1", secLine.source.y*this.scale) + .att("x2", secLine.target.x*this.scale) + .att("y2", secLine.target.y*this.scale) + .att("stroke-width",this.edge*1.1).att("stroke", this.backgroundColor) + .att("stroke-linecap","round"); + this.svgBldr.elem(line); + } + } + return this; + } +} + +class BeveledDisplayData extends DisplayData { + + constructor(){ + super(); + this.bevel = 1/4; + } + + polyCalc(node){ + this.polygon = []; //reset polygon + let sideCount = 0; + //north + if (node.north() != null && !node.north().hasEWJunction()){ + this.polygon.push(new Point(node.x, node.y - (1/2))); + } else { + sideCount ++; + this.polygon.push(new Point(node.x - this.bevel, node.y - this.bevel )); + this.polygon.push(new Point(node.x + this.bevel, node.y - this.bevel )); + } + //corner + if(node.north() != null && node.north().hasNSJunction() + && node.east() != null && node.east().hasEWJunction()){ + this.polygon.push(new Point(node.x, node.y)); + } + //east + if (node.east() != null && !node.east().hasNSJunction()){ + this.polygon.push(new Point(node.x + (1/2), node.y)); + } else { + sideCount ++; + this.polygon.push(new Point(node.x + this.bevel, node.y - this.bevel )); + this.polygon.push(new Point(node.x + this.bevel, node.y + this.bevel )); + } + //corner + if(node.east() != null && node.east().hasEWJunction() + && node.south() != null && node.south().hasNSJunction()){ + this.polygon.push(new Point(node.x, node.y)); + } + //south + if (node.south() != null && !node.south().hasEWJunction()){ + this.polygon.push(new Point(node.x, node.y+(1/2))); + } else { + sideCount ++; + this.polygon.push(new Point(node.x + this.bevel, node.y + this.bevel)); + this.polygon.push(new Point(node.x - this.bevel, node.y + this.bevel)); + } + //corner + if(node.south() != null && node.south().hasNSJunction() + && node.west() != null && node.west().hasEWJunction()){ + this.polygon.push(new Point(node.x, node.y)); + } + //west + if (node.west() != null && !node.west().hasNSJunction()){ + this.polygon.push(new Point(node.x - (1/2), node.y)); + } else { + sideCount ++; + this.polygon.push(new Point(node.x - this.bevel, node.y + this.bevel)); + this.polygon.push(new Point(node.x - this.bevel, node.y - this.bevel)); + } + //corner + if(node.west() != null && node.west().hasEWJunction() + && node.north() != null && node.north().hasNSJunction()){ + this.polygon.push(new Point(node.x, node.y)); + } + } + + +} + +class BeveledKnotDisplay extends BasicKnotDisplay { + + newDisplayData(){ + return new BeveledDisplayData(); + } +} + +class PositiveDisplayData extends DisplayData { + constructor(){ + super(); + this.circles = []; + } + + polyCalc(node){ + //do nothing + } + + lineCalc(node){ + this.lines = []; + if (node.x%2==0){ + if (node.east() != null && node.east().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x+1, node.y), + new Point(node.x+(1/2), node.y+(1/2)))); + } else if (node.east() != null && node.east().junctions.length != 0 && node.east().hasNSJunction()){ + this.lines.push(new Line(new Point(node.x+(1/2), node.y -(1/2)), + new Point(node.x+(1/2), node.y+(1/2)))); + this.circles.push(new Point(node.x+(1/2), node.y -(1/2))); + this.circles.push(new Point(node.x+(1/2), node.y+(1/2))); + if(node.south() != null && node.south().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x+(1/2), node.y+(1/2)), + new Point(node.x+(1/4), node.y+(3/4)))); + } + } + if (node.south() != null && node.south().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x, node.y+1), + new Point(node.x-(1/2), node.y +(1/2)))); + } else if (node.south() != null && node.south().junctions.length != 0 && node.south().hasEWJunction()){ + this.lines.push(new Line(new Point(node.x +(1/2), node.y+(1/2)), + new Point(node.x-(1/2), node.y +(1/2)))); + this.circles.push(new Point(node.x +(1/2), node.y+(1/2))); + this.circles.push(new Point(node.x-(1/2), node.y +(1/2))); + if (node.west() != null && node.west().junctions.length ==0){ + this.lines.push(new Line( new Point(node.x-(1/2), node.y +(1/2)), + new Point(node.x -(3/4), node.y+(1/4)))); + } + } + if (node.west() != null && node.west().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x-1, node.y), + new Point(node.x-(1/2), node.y - (1/2)))); + } else if (node.west() != null && node.west().junctions.length != 0 && node.west().hasNSJunction()) { + this.lines.push(new Line(new Point(node.x-(1/2), node.y +(1/2)), + new Point(node.x-(1/2), node.y - (1/2)))); + this.circles.push(new Point(node.x-(1/2), node.y +(1/2))); + this.circles.push(new Point(node.x-(1/2), node.y - (1/2))); + if (node.north!=null && node.north().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x-(1/2), node.y - (1/2)), + new Point(node.x-(1/4), node.y - (3/4)))); + } + } + if (node.north() != null && node.north().junctions.length == 0) { + this.lines.push(new Line(new Point(node.x, node.y-1), + new Point(node.x+(1/2), node.y-(1/2)))); + } else if (node.north() != null && node.north().junctions.length != 0 && node.north().hasEWJunction()){ + this.lines.push(new Line(new Point(node.x-(1/2), node.y-(1/2)), + new Point(node.x+(1/2), node.y-(1/2)))); + this.circles.push(new Point(node.x-(1/2), node.y -(1/2))); + this.circles.push(new Point(node.x+(1/2), node.y - (1/2))); + if (node.east()!=null && node.east().junctions.length==0){ + this.lines.push(new Line(new Point(node.x+(1/2), node.y-(1/2)), + new Point(node.x+(3/4), node.y-(1/4)))); + } + } + } else { + if (node.east() != null && node.east().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x+1, node.y), + new Point(node.x+(1/2), node.y-(1/2)))); + this.circles.push(new Point(node.x+(1/2), node.y -(1/2))); + if (node.north()!=null && node.north().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x+(1/2), node.y -(1/2)), + new Point(node.x+(1/4), node.y-(3/4)))); + } + } else if (node.east() != null && node.east().junctions.length != 0 && node.east().hasNSJunction()){ + this.lines.push(new Line(new Point(node.x+(1/2), node.y -(1/2)), + new Point(node.x+(1/2), node.y+(1/2)))); + this.circles.push(new Point(node.x+(1/2), node.y -(1/2))); + this.circles.push(new Point(node.x+(1/2), node.y +(1/2))); + if (node.north() != null && node.north().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x+(1/2), node.y -(1/2)), + new Point(node.x+(1/4), node.y-(3/4)))); + } + } + if (node.south() != null && node.south().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x, node.y+1), + new Point(node.x+(1/2), node.y +(1/2)))); + this.circles.push(new Point(node.x+(1/2), node.y +(1/2))); + if (node.east()!= null && node.east().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x+(1/2), node.y +(1/2)), + new Point(node.x+(3/4), node.y +(1/4)))); + } + } else if (node.south() != null && node.south().junctions.length != 0 && node.south().hasEWJunction()){ + this.lines.push(new Line(new Point(node.x +(1/2), node.y+(1/2)), + new Point(node.x-(1/2), node.y +(1/2)))); + this.circles.push(new Point(node.x+(1/2), node.y +(1/2))); + this.circles.push(new Point(node.x-(1/2), node.y +(1/2))); + if (node.east() != null && node.east().junctions.length ==0){ + this.lines.push(new Line(new Point(node.x +(1/2), node.y+(1/2)), + new Point(node.x+(3/4), node.y +(1/4)))); + } + } + if (node.west() != null && node.west().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x-1, node.y), + new Point(node.x-(1/2), node.y + (1/2)))); + this.circles.push(new Point(node.x-(1/2), node.y +(1/2))); + if (node.south()!=null && node.south().junctions.length ==0){ + this.lines.push(new Line(new Point(node.x-(1/2), node.y+(1/2)), + new Point(node.x-(1/4), node.y +(3/4)))); + } + } else if (node.west() != null && node.west().junctions.length != 0 && node.west().hasNSJunction()) { + this.lines.push(new Line(new Point(node.x-(1/2), node.y +(1/2)), + new Point(node.x-(1/2), node.y - (1/2)))); + this.circles.push(new Point(node.x-(1/2), node.y+(1/2))); + this.circles.push(new Point(node.x-(1/2), node.y-(1/2))); + if(node.south() !=null && node.south().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x-(1/2), node.y +(1/2)), + new Point(node.x-(1/4), node.y + (3/4)))); + } + } + if (node.north() != null && node.north().junctions.length == 0) { + this.lines.push(new Line(new Point(node.x, node.y-1), + new Point(node.x-(1/2), node.y-(1/2)))); + this.circles.push(new Point(node.x-(1/2), node.y -(1/2))); + if (node.west()!=null && node.west().junctions.length == 0){ + this.lines.push(new Line(new Point(node.x-(1/2), node.y-(1/2)), + new Point(node.x-(3/4), node.y-(1/4)))); + } + } else if (node.north() != null && node.north().junctions.length != 0 && node.north().hasEWJunction()){ + this.lines.push(new Line(new Point(node.x-(1/2), node.y-(1/2)), + new Point(node.x+(1/2), node.y-(1/2)))); + this.circles.push(new Point(node.x-(1/2), node.y -(1/2))); + this.circles.push(new Point(node.x+(1/2), node.y -(1/2))); + if (node.west()!= null && node.west().junctions.length ==0){ + this.lines.push(new Line(new Point(node.x-(1/2), node.y-(1/2)), + new Point(node.x-(3/4), node.y-(1/4)))); + } + } + } + } +} + +class PositiveKnotDisplay extends BasicKnotDisplay { + + buildSVG(){ + this.edge = this.scale/2; + this.lines(); + //console.log(this.buildTikZ()); + } + + newDisplayData(){ + return new PositiveDisplayData(); + } + + lines(){ + for (let n in this.displayData){ + let node = this.displayData[n]; + for (let l in node.lines){ + let secLine = node.lines[l]; + let line = new Bldr("line").att("x1",secLine.source.x*this.scale) + .att("y1", secLine.source.y*this.scale) + .att("x2", secLine.target.x*this.scale) + .att("y2", secLine.target.y*this.scale) + .att("stroke-width",this.edge).att("stroke", this.backgroundColor) + .att("stroke-linecap","butt"); + this.svgBldr.elem(line); + } + for (let j in node.circles){ + let joint = node.circles[j]; + let circle = new Bldr("circle").att("cx",joint.x*this.scale) + .att("cy", joint.y*this.scale) + .att("r", (this.edge/2)*(0.95)) + .att("fill", this.backgroundColor); + //.att("stroke-width",this.edge/3).att("stroke", this.backgroundColor); + this.svgBldr.elem(circle); + } + } + return this; + } + + buildTikZ() { + this.build();//ToDo: builds unnecessary svg structures + let tikZ = new TikZBuilder(); + let newScale = this.scale/40; //scaling factor - need to reduce size for tikZ + for (let n in this.displayData){ + let node = this.displayData[n]; + for (let l in node.lines){ + let secLine = node.lines[l]; + tikZ.addLine(secLine.source.x*newScale, + secLine.source.y*newScale, + secLine.target.x*newScale, + secLine.target.y*newScale); + } + } + return tikZ.build(); + } +} + +class RibbonKnotDisplay extends PositiveKnotDisplay { + + buildSVG(){ + super.buildSVG(); + this.stripeLines(this.edge/3, this.foregroundColor); + + } + + stripeLines(width, color){ + for (let n in this.displayData){ + let node = this.displayData[n]; + for (let l in node.lines){ + let secLine = node.lines[l]; + let line = new Bldr("line").att("x1",secLine.source.x*this.scale) + .att("y1", secLine.source.y*this.scale) + .att("x2", secLine.target.x*this.scale) + .att("y2", secLine.target.y*this.scale) + .att("stroke-width",width).att("stroke", color) + .att("stroke-linecap","butt"); + this.svgBldr.elem(line); + } + for (let j in node.circles){ + let joint = node.circles[j]; + let circle = new Bldr("circle").att("cx",joint.x*this.scale) + .att("cy", joint.y*this.scale) + .att("r", width/2) + .att("fill", color); + this.svgBldr.elem(circle); + } + } + return this; + } +} + +/** + * OLD CELTIC CALC FILE + * Classes and functions in this script file are for + * performing calculations on knots. Only dependency should + * be on celtic_base.celtic. + */ + +function crossingCount(grid){ + let count = 0; + for (let p in grid.points){ + let point = grid.points[p]; + if (!point.isOnSecondary() && point.junctions.length == 0){ + count++; + } + } + return count; +}; + +function setsOverlap(setA,setB){ + let arrayA = Array.from(setA); + for (let a in arrayA){ + let element = arrayA[a]; + if (setB.has(element)){ + return true; + } + } + return false; +}; + +function regionCount(grid){ + let regions = []; + for (let n in grid.nodes){ + let node = grid.nodes[n]; + let newSet = node.getFullConnected(); + let overlap = false; + for (let r in regions){ + let existingSet = regions[r]; + if (setsOverlap(newSet, existingSet)){ + overlap = true; + break; + } + } + if (!overlap){ + regions.push(newSet); + } + } + return regions.length; +} +/* Loop count calculation is more involved than crossing +* or region count, and involves a number of classes and +* functions defined below. +*/ + +/** + * The function loopCount() creates a PathBuilder which + * uses the Grid provided to build all paths and count them. + * It does this by looking at the set of primary points of the + * grid, and determines the individual "strands" of paths + * that pass by each Point. + * + * A Strand represents a fragment of a Path that exists + * in the neighbourhood of a primary Grid Point. Strands + * around a primary grid point are collected in StrandGroups + * The structure of the Strands around a primary Point is completely + * determined by the Junctions that go through the primary Point. + * Once all the StrandGroups are calculated, the individual Strands + * can be collected together into closed Paths, and the + * Paths can be counted. + */ + +class Strand { + constructor(end1, end2, group){ + this.ends = []; + this.ends.push(end1); + this.ends.push(end2); + this.group = group; + } + + toString() { + let s = "(" + this.group.point.x + ", " + this.group.point.y +")"; + s += "[" + this.ends +"] "; + return s; + } + + hasEnd(end){ + for(let e in this.ends){ + if (this.ends[e] === end) { + return true; + } + } + return false; + } + + getOtherEnd(end){ + for(let e in this.ends){ + if (this.ends[e] != end) { + return this.ends[e]; + } + } + } +} + +class StrandGroup { + + constructor(primaryPoint){ + this.point = primaryPoint; + this.strands = []; + } + + toString(){ + let s = "(" + this.point.x + ", " + this.point.y +")"; + s += " {" + this.strands + "} "; + return s; + } + + getStrandPair(end){ + let foundStrand = null; + for (let s in this.strands){ + if (this.strands[s].hasEnd(end)){ + foundStrand = this.strands[s]; + break; + } + } + let pair = [foundStrand, end]; + return pair; + } + + getStrand(end1, end2){ + for (let s in this.strands){ + let strand = this.strands[s]; + if (strand.hasEnd(end1) && strand.hasEnd(end2)){ + return strand; + } + } + return null; + } + + calculateStrands(){ + if (this.point.junctions.length === 0){ + this.strands.push(new Strand(0,2, this)); + this.strands.push(new Strand(1,3, this)); + } else if (this.point.hasNSJunction()){ + if (this.point.east() != null){ + this.strands.push(new Strand(1,2, this)); + } + if (this.point.west() != null){ + this.strands.push(new Strand(0,3, this)); + } + } else if (this.point.hasEWJunction()){ + if (this.point.north() != null){ + this.strands.push(new Strand(0,1, this)); + } + if (this.point.south() != null){ + this.strands.push(new Strand(2, 3, this)); + } + } + } +} + +class PathBuilder { + constructor(grid){ + this.grid = grid; + this.allStrands = []; + this.allPaths = []; + this.strandGroups = new Map(); + } + + buildAllStrands(){ + this.strandGroups.clear(); + for (let p in this.grid.points){ + let point = this.grid.points[p]; + if (point.isOnSecondary()){ + continue; + } + let group = new StrandGroup(point); + this.strandGroups.set(point,group); + group.calculateStrands(); + this.allStrands.push.apply(this.allStrands, group.strands); + } + } + + isFreshStrand(strand){ + for (let p in this.allPaths){ + let path = this.allPaths[p]; + if (path.contains(strand)){ + return false; + } + } + return true; + } + + buildAllPaths(){ + let pathIndex = 0; + for (let s in this.allStrands){ + let strand = this.allStrands[s]; + if (this.isFreshStrand(strand)){ + let p = new Path(strand, this, pathIndex); + pathIndex ++; + p.buildPath(); + this.allPaths.push(p); + } + } + } + + getNE(strandGroup){ + return this.strandGroups.get(strandGroup.point.north().east()); + } + + getNW(strandGroup){ + return this.strandGroups.get(strandGroup.point.north().west()); + } + + getSE(strandGroup){ + return this.strandGroups.get(strandGroup.point.south().east()); + } + + getSW(strandGroup){ + return this.strandGroups.get(strandGroup.point.south().west()); + } +} + +class Path { + constructor(start, pathBuilder, i = 0){ + this.startStrand = start; + this.strands = [this.startStrand]; + this.pathBuilder = pathBuilder; + this.index = i; + this.startStrand.index = this.index; + } + + contains(strand){ + for(let s in this.strands){ + if (this.strands[s] == strand){ + return true; + } + } + return false; + } + + length(){ + return this.strands.length + } + + findNextStrand(strand, end){ + if (!strand.hasEnd(end)){ + return null; + } + let nextEnd = strand.getOtherEnd(end); + let targetEnd = 0; + let nextGroup = null; + if (nextEnd === 0){ + nextGroup = this.pathBuilder.getNW(strand.group); + targetEnd = 2; + } else if (nextEnd === 1){ + nextGroup = this.pathBuilder.getNE(strand.group); + targetEnd = 3; + } else if (nextEnd === 2){ + nextGroup = this.pathBuilder.getSE(strand.group); + targetEnd = 0; + } else if (nextEnd === 3){ + nextGroup = this.pathBuilder.getSW(strand.group); + targetEnd = 1; + } + return nextGroup.getStrandPair(targetEnd); + } + + buildPath(){ + let currentStrand = this.startStrand; + let currentEnd = currentStrand.ends[0]; //pick one end + while(true){ + let result = this.findNextStrand(currentStrand, currentEnd); + + currentStrand = result[0]; + currentEnd = result[1]; + if (this.contains(currentStrand)){ + break; + } + currentStrand.index = this.index; + this.strands.push(currentStrand); + } + } + + totalPathLengths() { + let pl = 0; + for (let p in this.allPaths){ + pl += this.allPaths[p].length(); + } + return pl; + } + +} + +function loopCount(grid){ + let pb = new PathBuilder(grid); + pb.buildAllStrands(); + pb.buildAllPaths(); + return pb.allPaths.length; +} + +/** + * Below is a display type that uses the path calculation. + */ + +class PrimaryDisplayData extends DisplayData { + constructor(){ + super(); + this.lines = []; + this.circles = []; + this.crossing = null; + this.center = []; + this.rounded = true; + } + + polyCalc(strandGroup){ + let x = strandGroup.point.x; + let y = strandGroup.point.y; + this.center.push(new Point(x, y-(1/4))); + this.center.push(new Point(x+(1/4), y)); + this.center.push(new Point(x, y+(1/4))); + this.center.push(new Point(x-(1/4), y)); + } + + lineCalc(strandGroup){ + this.lines = []; + let x = strandGroup.point.x; + let y = strandGroup.point.y; + let strand = strandGroup.getStrand(0,1); + let d = null; + if (strand != null) { + d = new Decorator(strand.index); + if (!this.rounded){ + this.lines.push(new Line(new Point(x-(1/2), y-(1/2)),new Point(x+(1/2), y-(1/2))).setDecorator(d)); + } else { + this.lines.push(new Line(new Point(x-(1/2), y-(1/2)),new Point(x, y-(1/3))).setDecorator(d)); + this.lines.push(new Line(new Point(x, y-(1/3)),new Point(x+(1/2), y-(1/2))).setDecorator(d)); + this.circles.push(new Point(x,y-(1/3)).setDecorator(d)); + } + this.circles.push(new Point(x-(1/2),y-(1/2)).setDecorator(d)); + this.circles.push(new Point(x+(1/2),y-(1/2)).setDecorator(d)); + } + + strand = strandGroup.getStrand(0,2); + if (strand != null) { + d = new Decorator(strand.index); + this.lines.push(new Line(new Point(x-(1/2), y-(1/2)),new Point(x+(1/2), y+(1/2))).setDecorator(d)); + this.circles.push(new Point(x-(1/2),y-(1/2)).setDecorator(d)); + this.circles.push(new Point(x+(1/2),y+(1/2)).setDecorator(d)); + if (strandGroup.point.x % 2 == 0){ + this.crossing = new Line(new Point(x-(1/2), y-(1/2)),new Point(x+(1/2), y+(1/2))); + this.crossing.setDecorator(d); + } + } + + strand = strandGroup.getStrand(1,3); + if (strand != null) { + d = new Decorator(strand.index); + this.lines.push(new Line(new Point(x+(1/2), y-(1/2)),new Point(x-(1/2), y+(1/2))).setDecorator(d)); + this.circles.push(new Point(x+(1/2),y-(1/2)).setDecorator(d)); + this.circles.push(new Point(x-(1/2),y+(1/2)).setDecorator(d)); + if (strandGroup.point.x % 2 == 1){ + this.crossing = new Line(new Point(x+(1/2), y-(1/2)),new Point(x-(1/2), y+(1/2))); + this.crossing.setDecorator(d); + } + } + + strand = strandGroup.getStrand(0,3); + if (strand != null) { + d = new Decorator(strand.index); + if (!this.rounded){ + this.lines.push(new Line(new Point(x-(1/2), y-(1/2)),new Point(x-(1/2), y+(1/2))).setDecorator(d)); + } else { + this.lines.push(new Line(new Point(x-(1/2), y-(1/2)),new Point(x-(1/3), y)).setDecorator(d)); + this.lines.push(new Line(new Point(x-(1/3), y), new Point(x-(1/2), y+(1/2))).setDecorator(d)); + this.circles.push(new Point(x-(1/3),y).setDecorator(d)); + } + this.circles.push(new Point(x-(1/2),y-(1/2)).setDecorator(d)); + this.circles.push(new Point(x-(1/2),y+(1/2)).setDecorator(d)); + } + + strand = strandGroup.getStrand(1,2); + if (strand != null) { + d = new Decorator(strand.index); + if (!this.rounded){ + this.lines.push(new Line(new Point(x+(1/2), y-(1/2)),new Point(x+(1/2), y+(1/2))).setDecorator(d)); + } else { + this.lines.push(new Line(new Point(x+(1/2), y-(1/2)),new Point(x+(1/3), y)).setDecorator(d)); + this.lines.push(new Line(new Point(x+(1/3), y), new Point(x+(1/2), y+(1/2))).setDecorator(d)); + this.circles.push(new Point(x+(1/3),y).setDecorator(d)); + } + this.circles.push(new Point(x+(1/2),y-(1/2)).setDecorator(d)); + this.circles.push(new Point(x+(1/2),y+(1/2)).setDecorator(d)); + } + + strand = strandGroup.getStrand(2,3); + if (strand != null) { + d = new Decorator(strand.index); + if (!this.rounded){ + this.lines.push(new Line(new Point(x+(1/2), y+(1/2)),new Point(x-(1/2), y+(1/2))).setDecorator(d)); + } else { + this.lines.push(new Line(new Point(x+(1/2), y+(1/2)),new Point(x, y+(1/3))).setDecorator(d)); + this.lines.push(new Line(new Point(x, y+(1/3)), new Point(x-(1/2), y+(1/2))).setDecorator(d)); + this.circles.push(new Point(x,y+(1/3)).setDecorator(d)); + } + this.circles.push(new Point(x+(1/2),y+(1/2)).setDecorator(d)); + this.circles.push(new Point(x-(1/2),y+(1/2)).setDecorator(d)); + } + + } +} + +class Decorator { + constructor(i){ + this.index = i; + } + decorate(){ + //let colors = ['blue','red','pink','lightgreen','green']; + let colors = ['#a2b9bc', '#b2ad7f','#878f99','#6b5b95','#d6cbd3','#eca1a6','#bdcebe','#82b74b','#405d27']; + if (interactive.colorPallette != undefined){ + colors = interactive.colorPallette; + } + return colors[this.index%colors.length]; + } +} + +class PrimaryKnotDisplay extends BasicKnotDisplay { + + buildSVG(){ + this.edge = this.scale/2; + this.lines(); + } + + newDisplayData(){ + return new PrimaryDisplayData(); + } + + buildStructure(){ + let pb = new PathBuilder(this.g); + pb.buildAllStrands(); + pb.buildAllPaths(); + let v = pb.strandGroups.values() + let val = v.next().value; + while(val !== undefined) { + let d = this.newDisplayData(); + d.lineCalc(val); + d.polyCalc(val); + this.displayData.push(d); + val = v.next().value; + } + + } + + lines(){ + for (let n in this.displayData){ + let node = this.displayData[n]; + for (let l in node.lines){ + let secLine = node.lines[l]; + let line = new Bldr("line").att("x1",secLine.source.x*this.scale) + .att("y1", secLine.source.y*this.scale) + .att("x2", secLine.target.x*this.scale) + .att("y2", secLine.target.y*this.scale) + .att("stroke-linecap","butt"); + if (secLine.decorator != null){ + line.att("stroke-width",this.edge).att("stroke", secLine.decorator.decorate()); + } else { + line.att("stroke-width",this.edge).att("stroke", this.backgroundColor); + } + this.svgBldr.elem(line); + } + for (let j in node.circles){ + let joint = node.circles[j]; + let circle = new Bldr("circle").att("cx",joint.x*this.scale) + .att("cy", joint.y*this.scale) + .att("r", (this.edge/2)*(0.96)); + if (joint.decorator != null){ + circle.att("fill",joint.decorator.decorate()); + } else { + circle.att("fill", this.backgroundColor); + //.att("stroke-width",this.edge/3).att("stroke", this.backgroundColor); + } + this.svgBldr.elem(circle); + } + let xline = node.crossing; + if (xline != null) { + let plist = ""; + for (let p in node.center){ + let point = node.center[p]; + plist += "" + (point.x*this.scale) + "," +(point.y*this.scale) +" "; + } + + let crossing1 = new Bldr("polygon").att("points",plist); + crossing1.att("stroke-width",this.edge/2).att("fill",this.foregroundColor).att("stroke", this.foregroundColor); + + this.svgBldr.elem(crossing1); + + let crossing2 = new Bldr("line").att("x1",xline.source.x*this.scale) + .att("y1", xline.source.y*this.scale) + .att("x2", xline.target.x*this.scale) + .att("y2", xline.target.y*this.scale) + .att("stroke-linecap","butt"); + if (xline.decorator != null){ + let d = xline.decorator; + crossing2.att("stroke-width",this.edge).att("fill", d.decorate()).att("stroke", d.decorate()); + } else { + crossing2.att("stroke-width",this.edge/2).att("fill",this.foregroundColor).att("stroke", this.foregroundColor); + } + this.svgBldr.elem(crossing2); + } + } + return this; + } +} + +let pallettes = { + 'blues':['#011f4b','#03396c','#005b96','#6497b1','#b3cde0'], + 'gryffindor': ['#740001','#ae0001','#eeba30','#d3a625','#000000'], + 'greys':['#999999','#777777','#555555','#333333','#111111'], + 'pinks':['#ff00a9','#fb9f9f','#ff0065','#ffbfd3','#fb5858'], + 'metro':['#d11141','#00b159','#00aedb', '#f37735','#ffc425'], + 'pastel':['#ffb3ba','#ffdfba','#ffffba','#baffc9','#bae1ff'], + 'ravenclaw': ['#0e1a40','#222f5b','#5d5d5d','#946b2d','#000000'], + 'slytherin':['#1a472a','#2a623d','#5d5d5d','#aaaaaa','#000000'], + 'hufflepuff':['#ecb939','#f0c75e','#726255','#372e29','#000000'], + 'neon' : ['#fe0000','#fdfe02','#0bff01','#011efe','#fe00f6'], + 'seafoam' :['#a3c1ad','#a0d6b4','#5f9ea0','#317873','#49796b'] +} + +//for node export +try{ + module.exports.Grid = Grid; + module.exports.PositiveKnotDisplay = PositiveKnotDisplay; + module.exports.LaTeXDoc = LaTeXDoc; +} catch(err){ + console.log("non-node execution context"); +} diff --git a/ch1_generated_files/0000.tex b/ch1_generated_files/0000.tex new file mode 100644 index 0000000..5474a43 --- /dev/null +++ b/ch1_generated_files/0000.tex @@ -0,0 +1,34 @@ +\begin{tikzpicture}[framed,background rectangle/.style={ultra thick,draw=black}] + \draw [line width=3pt, line cap=round] (0.5,1) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.5,1) -- (0.75,0.75); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (0.875,0.625); + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.375,0.875); + \draw [line width=3pt, line cap=round] (0.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (1,1.5) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (0.75,1.25) -- (0.625,1.125); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.25,1.75); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.875,1.625); + \draw [line width=3pt, line cap=round] (0.25,1.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (0.5,1) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.25,1.25); + \draw [line width=3pt, line cap=round] (1,1.5) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (0.5,1) -- (0.75,0.75); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1,1.5) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.75,0.25) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1.25,0.75) -- (1.375,0.875); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.75,0.25); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.125,0.375); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.75,1.75); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.625,1.125); + \draw [line width=3pt, line cap=round] (1.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1,1.5) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.25,1.25); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (1.125,1.375); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.75,0.75); +\end{tikzpicture} diff --git a/ch1_generated_files/0001.tex b/ch1_generated_files/0001.tex new file mode 100644 index 0000000..9e3fc93 --- /dev/null +++ b/ch1_generated_files/0001.tex @@ -0,0 +1,30 @@ +\begin{tikzpicture}[framed,background rectangle/.style={ultra thick,draw=black}] + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (0.25,0.75); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (0.875,0.625); + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (1,1.5) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.25,1.75); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.875,1.625); + \draw [line width=3pt, line cap=round] (0.25,1.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (0.25,1.25) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.25,1.25); + \draw [line width=3pt, line cap=round] (1,1.5) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1,1.5) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.75,0.25) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1.25,0.75) -- (1.375,0.875); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.75,0.25); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.125,0.375); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.75,1.75); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.625,1.125); + \draw [line width=3pt, line cap=round] (1.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1,1.5) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.25,1.25); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (1.125,1.375); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.75,0.75); +\end{tikzpicture} diff --git a/ch1_generated_files/0011.tex b/ch1_generated_files/0011.tex new file mode 100644 index 0000000..c8eb312 --- /dev/null +++ b/ch1_generated_files/0011.tex @@ -0,0 +1,26 @@ +\begin{tikzpicture}[framed,background rectangle/.style={ultra thick,draw=black}] + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (0.25,0.75); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (0.875,0.625); + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.25,1.75); + \draw [line width=3pt, line cap=round] (0.25,1.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (0.25,1.25) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.25,1.25); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.75,0.25) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1.25,0.75) -- (1.375,0.875); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.75,0.25); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.125,0.375); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.75,1.75); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.625,1.125); + \draw [line width=3pt, line cap=round] (1.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.25,1.25); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.75,0.75); +\end{tikzpicture} diff --git a/ch1_generated_files/0012.tex b/ch1_generated_files/0012.tex new file mode 100644 index 0000000..6bea740 --- /dev/null +++ b/ch1_generated_files/0012.tex @@ -0,0 +1,26 @@ +\begin{tikzpicture}[framed,background rectangle/.style={ultra thick,draw=black}] + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.25,1.75); + \draw [line width=3pt, line cap=round] (0.25,1.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.25,1.25); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (0.75,1.25) -- (0.75,0.75); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (0.875,0.625); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.75,0.25) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1.25,0.75) -- (1.375,0.875); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.75,0.25); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.125,0.375); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.75,1.75); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.625,1.125); + \draw [line width=3pt, line cap=round] (1.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.25,1.25); + \draw [line width=3pt, line cap=round] (1.5,1) -- (1.75,0.75); +\end{tikzpicture} diff --git a/ch1_generated_files/0111.tex b/ch1_generated_files/0111.tex new file mode 100644 index 0000000..d3daac8 --- /dev/null +++ b/ch1_generated_files/0111.tex @@ -0,0 +1,22 @@ +\begin{tikzpicture}[framed,background rectangle/.style={ultra thick,draw=black}] + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (0.25,0.75); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (0.875,0.625); + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.25,1.75); + \draw [line width=3pt, line cap=round] (0.25,1.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (0.25,1.25) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.75,0.25) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1.75,0.75) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.75,0.25); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.125,0.375); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.75,1.75); + \draw [line width=3pt, line cap=round] (1.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (1.75,1.25); +\end{tikzpicture} diff --git a/ch1_generated_files/0112.tex b/ch1_generated_files/0112.tex new file mode 100644 index 0000000..b1ed613 --- /dev/null +++ b/ch1_generated_files/0112.tex @@ -0,0 +1,22 @@ +\begin{tikzpicture}[framed,background rectangle/.style={ultra thick,draw=black}] + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.25,1.75); + \draw [line width=3pt, line cap=round] (0.25,1.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (1,0.5) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (0.75,1.25) -- (0.75,0.75); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (0.875,0.625); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.75,0.25) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1.75,0.75) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1,0.5) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.75,0.25); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.125,0.375); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.75,1.75); + \draw [line width=3pt, line cap=round] (1.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (1.75,1.25); +\end{tikzpicture} diff --git a/ch1_generated_files/1111.tex b/ch1_generated_files/1111.tex new file mode 100644 index 0000000..503f4b3 --- /dev/null +++ b/ch1_generated_files/1111.tex @@ -0,0 +1,18 @@ +\begin{tikzpicture}[framed,background rectangle/.style={ultra thick,draw=black}] + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (0.25,0.75); + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.25,1.75); + \draw [line width=3pt, line cap=round] (0.25,1.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (0.25,1.25) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.75,0.25) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1.75,0.75) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.75,0.25); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.75,1.75); + \draw [line width=3pt, line cap=round] (1.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (1.75,1.25); +\end{tikzpicture} diff --git a/ch1_generated_files/1112.tex b/ch1_generated_files/1112.tex new file mode 100644 index 0000000..a3c72c9 --- /dev/null +++ b/ch1_generated_files/1112.tex @@ -0,0 +1,18 @@ +\begin{tikzpicture}[framed,background rectangle/.style={ultra thick,draw=black}] + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.25,1.75); + \draw [line width=3pt, line cap=round] (0.25,1.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (0.75,1.25); + \draw [line width=3pt, line cap=round] (0.75,1.25) -- (0.75,0.75); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.75,0.25) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1.75,0.75) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.75,0.25); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.75,1.75); + \draw [line width=3pt, line cap=round] (1.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (1.75,1.25); +\end{tikzpicture} diff --git a/ch1_generated_files/1122.tex b/ch1_generated_files/1122.tex new file mode 100644 index 0000000..705e81d --- /dev/null +++ b/ch1_generated_files/1122.tex @@ -0,0 +1,18 @@ +\begin{tikzpicture}[framed,background rectangle/.style={ultra thick,draw=black}] + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (0.25,0.75) -- (0.25,0.25); + \draw [line width=3pt, line cap=round] (0.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,1.25) -- (0.75,1.75); + \draw [line width=3pt, line cap=round] (0.75,1.75) -- (0.25,1.75); + \draw [line width=3pt, line cap=round] (0.25,1.75) -- (0.25,1.25); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (0.75,0.25); + \draw [line width=3pt, line cap=round] (0.75,1.25) -- (0.75,0.75); + \draw [line width=3pt, line cap=round] (0.75,0.75) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1.75,0.25) -- (1.75,0.75); + \draw [line width=3pt, line cap=round] (1.75,0.75) -- (1.25,0.75); + \draw [line width=3pt, line cap=round] (1.25,0.25) -- (1.75,0.25); + \draw [line width=3pt, line cap=round] (1.75,1.25) -- (1.75,1.75); + \draw [line width=3pt, line cap=round] (1.75,1.75) -- (1.25,1.75); + \draw [line width=3pt, line cap=round] (1.25,1.75) -- (1.25,1.25); + \draw [line width=3pt, line cap=round] (1.25,1.25) -- (1.75,1.25); +\end{tikzpicture} diff --git a/ch1_list.tex b/ch1_list.tex new file mode 100644 index 0000000..638807d --- /dev/null +++ b/ch1_list.tex @@ -0,0 +1,16 @@ +\input{ch1_generated_files/0002.tex} + +\input{ch1_generated_files/0011.tex} + +\input{ch1_generated_files/0012.tex} + +\input{ch1_generated_files/0111.tex} + +\input{ch1_generated_files/0112.tex} + +\input{ch1_generated_files/1111.tex} + +\input{ch1_generated_files/1112.tex} + +\input{ch1_generated_files/1122.tex} + diff --git a/index.html b/index.html index 0bbc708..0e92e44 100644 --- a/index.html +++ b/index.html @@ -19,14 +19,14 @@ text-align: center; } - - - - - - - - + + + + + + + + - -Celtic Knots - - - - - - - -
-