knotcode.sa


Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
 

-- Copyright (C) 1983 1996 Kouji KODAMA
-- 2002-11-17
-- VERTEXK: vector operations

-- 1999-4-1
-- KNOT: Graph(Theta curve) support

--1996-9-28 
--Linux version.

--1994-10-20 12:32:12  KDM
--smoothDraw bug fix

--1994-10-15 19:56:26  KDM
--DrawKnot: smooth version

--1993-10-31 16:44:30  KDM
--tpic bug fix

--1993-06-28 04:27:38  KDM
--LaTeX Tpic special: DrawKnotPic.
--DrawKnotPic: LaTeX Tpic-special.

--1983 Basic
--K.Kodama



class K

class K is shared Knot:KNOT; end;

class KNOT_TEST

class KNOT_TEST is ---------- test data ---------- trivial: KNOT is knot:KNOT; knot:=#; knot.NoCompo0; knot.trivial0; knot.CodeIn(100.int,-100,1); knot.CodeIn(100.int,-200,2); knot.CodeIn(200.int,-200,3); knot.CodeIn(200.int,-100,4); knot.CodeIn(100.int,-100,5); return knot; end; trifoil: KNOT is knot:KNOT; knot:=#; knot.NoCompo0; knot.trivial0; knot.CodeIn(119.int, -105,1); knot.CodeIn(243.int, -102,2); knot.CodeIn(219.int, -146,VERTEXC::cross_over,3); knot.CodeIn(181.int, -214,VERTEXC::cross_under,4); knot.CodeIn(137.int, -293,5); knot.CodeIn(78.int ,-151,6); knot.CodeIn(144.int, -149,VERTEXC::cross_over,7); knot.CodeIn(219.int, -146,VERTEXC::cross_under,8); knot.CodeIn(271.int, -144,9); knot.CodeIn(216.int, -274,10); knot.CodeIn(181.int, -214,VERTEXC::cross_over,11); knot.CodeIn(144.int, -149,VERTEXC::cross_under,12); knot.CodeIn(119.int, -105,13); -- CHECK_KNOT_ALG::checkKnotD(knot); return knot; end; end;

class VERTEXK

class VERTEXK is attr x,y,work:INT; attr sep:VERTEXC; create(nx,ny,nw:INT,c:VERTEXC):SAME is res::=new; res.x:=nx; res.y:=ny; res.work:=nw; res.sep:=c; return res; end; create(nx,ny:INT, nc:VERTEXC):SAME is return create(nx,ny,0.int,nc); end; create(nx,ny:INT):SAME is return create(nx,ny,0.int,VERTEXC::normal); end; create(nx,ny:FLT):SAME is return create(nx.round.int,ny.round.int,0.int,VERTEXC::normal); end; create(nc:VERTEXC):SAME is return create(0.int,0.int,0.int,nc); end; create:SAME is return create(0.int,0.int,0.int,VERTEXC::normal); end; clone:SAME is return create(x,y,work,sep.clone); end; -- As points/vectors sameCoord(other:SAME):BOOL is return (x=other.x)and(y=other.y); end; plus(other:SAME):SAME is return create(x+other.x, y+other.y); end; plus(other:SAME) is x:=x+other.x; y:=y+other.y; end; plus(dx,dy:INT):SAME is return create(x+dx, y+dy); end; plus(dx,dy:INT) is x:=x+dx; y:=y+dy; end; minus(other:SAME):SAME is return create(x-other.x, y-other.y); end; minus(dx,dy:INT):SAME is return create(x-dx, y-dy); end; times(t:INT):SAME is return create(x*t, y*t); end; times(t:CARD):SAME is return create(x*t.int, y*t.int); end; times(t:FLT):SAME is return create(x.flt*t, y.flt*t); end; times(t:FLT) is x:=(x.flt*t).round.int; y:=(y.flt*t).round.int; end; div(t:FLT):SAME is return create(x.flt/t, y.flt/t); end; div(t:INT):SAME is return create(x/t, y/t); end; inner(other:SAME):INT is -- inner product self . other return x*other.x+y*other.y; end; inner(o1,o2:SAME):INT is -- inner product (o1-self).(o2-self) return (o1-self).inner(o2-self); end; times(other:SAME):INT is -- inner product return inner(other); end; outer(other:SAME):INT is --outer product self x other return x*other.y-y*other.x; end; outer(o1, o2:SAME):INT is --outer product (o1-self)x(o2-self) return (o1-self).outer(o2-self); end; max(mx,my:INT):SAME is return create(x.max(mx),y.max(my)); end; max(m:SAME):SAME is return create(x.max(m.x),y.max(m.y)); end; min(mx,my:INT):SAME is return create(x.min(mx),y.min(my)); end; min(m:SAME):SAME is return create(x.min(m.x),y.min(m.y)); end; abs1:INT is return x.abs+y.abs; end; distance1(other:SAME):INT is return (x-other.x).abs+(y-other.y).abs; end; abs2:INT is return x*x+y*y; end; abs:FLT is return (x*x+y*y).flt.sqrt; end; rotation(p0,p1,p2:SAME):INT is -- orientation of points p1,p2,p3 around self. v0::=self-p0; v1::=self-p1; v2::=self-p2; return VEC_ALG::rotation(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y); end; rotation(v1,v2:SAME):INT is -- orientation of 3 vectors self,v2,v3 around origin O. return VEC_ALG::rotation(x, y, v1.x, v1.y, v2.x, v2.y); end; transform(p,q,r,s:INT):SAME is -- linear transformation return create(p*x+q*y, r*x+s*y); end; transform(p,q,r,s:FLT):SAME is -- linear transformation fx::=x.flt; fy::=y.flt; return create(p*fx+q*fy, r*fx+s*fy); end; transform(p,q,r,s:INT) is -- linear transformation wx::=p*x+q*y; wy::=r*x+s*y; x:=wx; y:=wy; end; transform(p,q,r,s:FLT) is -- linear transformation fx::=x.flt; fy::=y.flt; x:=(p*fx+q*fy).round.int; y:=(r*fx+s*fy).round.int; end; transform(p,s:INT):SAME is -- linear transformation with diagonal element (p,s). return create(x*p,y*s); end; transform(other:SAME):SAME is -- linear transformation with diagonal element from other. return create(x*other.x, y*other.y); end; rotate(t:FLT):SAME is s::=t.sin; c::=t.cos; return transform(c,-s, s, c); end; trace:INT is return x+y; end; end; -- VERTEXK

class KNOT

class KNOT is include KCODE{VERTEXK} create->kcode_create, clone->kcode_clone; attr updateCross:BOOL; -- true if crossing data is changed and needed CrossSet. create:SAME is res::=kcode_create; res.updateCross:=false; return res; end; clone:SAME is res::=kcode_clone; res.updateCross:=updateCross; return res; end; SetTCode(out tcode:TCODE):BOOL is return SET_TCODE_ALG::SetTCode(self,out tcode); end; NoCompo0 is -- set Knot be empty updateCross:=false; k:=#(1); k[0]:=#(VERTEXC::code_e); end; NoCompo0:SAME is -- set Knot be empty res:SAME:=#; res.k:=#(1); res.k[0]:=#(VERTEXC::code_e); return res; end; is_nocompo:BOOL is return k.size<3; end; trivial0 is updateCross:=false; k:=#(3); k[0]:=#(VERTEXC::knot_s); k[1]:=#(VERTEXC::knot_e); k[2]:=#(VERTEXC::code_e); end; trivial0:SAME is res:SAME:=#; res.k:=#(3); res.k[0]:=#(VERTEXC::knot_s); res.k[1]:=#(VERTEXC::knot_e); res.k[2]:=#(VERTEXC::code_e); return res; end; SLength is i:INT:=0.int; if void(self) then raise "KNOT:SLength: knot is void.\n"; end; loop if (i+1)>k.size.int then raise "KNOT::SLength: Knot has no end_code.\n"; elsif [i].sep=VERTEXC::code_e then if (i+1)=k.size.int then return; else k:=k.resize(i.card+1); #OUT+"KNOT::SLength: k.size is too high.\n"; return; end; end; i:=i+1; end; end; ---------------------check/search pairings----------------- Match(i1,i2:INT):BOOL is --TRUE if coord (x1,y1)=(x2,y2) return has_ind(i1) and has_ind(i2) and [i1].sameCoord([i2]); end; Match2(i1,i2:INT):BOOL is --Match with band adjustment if ~(has_ind(i1) and has_ind(i2)) then return false; end; if VERTEXC::band_s=[i1].sep then i1:=i1+1; elsif VERTEXC::band_e=[i1].sep then i1:=i1-1; end; if VERTEXC::band_s=[i2].sep then i2:=i2+1; elsif VERTEXC::band_e=[i2].sep then i2:=i2-1; end; return Match(i1,i2); end; MatchPt(i,from:INT):INT is -- return j where Knot[i].x=Knot[j].x, Knot[i].y=Knot[j].y, i#j. -- Return -1 if not exist. loop j::=from.upto!(k.size.int-2); if ([i].sameCoord([j]))and(i/=j)and (~ VERTEXC::separator.in([j].sep)) then return j; end; end; return -1; end; MatchPtS(i,from:INT):INT is -- return MatchPt if exist . return (i) if not exist j::=MatchPt(i,from); if j.is_neg then j:=i; end; return j; end; cmpOf(i:INT):INT is -- return -1 if no companion if ~has_ind(i) then return -1; end; j:INT; if VERTEXC::ks.in([i].sep) then j:=endOfString(i,1.int); if (j.is_non_neg)and Match(i+1,j-1) then return j; end; elsif VERTEXC::ke.in([i].sep) then j:=endOfString(i,-1); if (j.is_non_neg)and Match(i-1,j+1) then return j; end; elsif VERTEXC::ts.in([i].sep) then j:=0.int; loop j:=MatchPt(i+1,j+1); if (j.is_neg) then return -1; end; if VERTEXC::band.in([j].sep) then return j; end; end; elsif VERTEXC::te.in([i].sep) then j:=0.int; loop j:=MatchPt(i-1,j+1); if (j.is_neg) then return -1; end; if (VERTEXC::band.in([j].sep)) then return j; end; end; elsif VERTEXC::band.in([i].sep) then j:=0.int; loop j:=MatchPt(i,j+1); if (j.is_neg) then return -1; end; if (VERTEXC::ts.in([j-1].sep)) then return j; end; if (VERTEXC::te.in([j+1].sep)) then return j; end; end; elsif VERTEXC::crossing.in([i].sep) then j:=0.int; loop j:=MatchPt(i,j+1); if (j.is_neg) then return -1; end; if VERTEXC::crossing.in([j].sep) then return j; end; end; elsif VERTEXC::ks.in([i-1].sep) then j:=cmpOf(i-1); if j.is_non_neg then return j-1; end; elsif VERTEXC::ke.in([i+1].sep) then j:=cmpOf(i+1); if j.is_non_neg then return j+1; end; elsif VERTEXC::ts.in([i-1].sep) then j:=cmpOf(i-1); if j.is_non_neg then return j; end; elsif VERTEXC::te.in([i+1].sep) then j:=cmpOf(i+1); if j.is_non_neg then return j; end; end; return -1; end; nextPt(i:INT, dir:INT):INT is -- return next point. Normally i+dir but ks,ke,ts,te. -- dir:=1,-1. if next pt is not exist return -1. i0:INT:=i; i:=i+dir; if VERTEXC::ts.in([i].sep) then i:=-1; elsif VERTEXC::te.in([i].sep) then i:=-1; elsif VERTEXC::ks.in([i].sep) then i:= endOfString(i,1.int)-1; if Match(i0,i) then i:=i-1;else i:=-1; end; elsif VERTEXC::ke.in([i].sep) then i:= endOfString(i,-1)+1; if Match(i0,i) then i:=i+1;else i:=-1; end; else loop while!(VERTEXC::crossing.in([i].sep)); i:=i+dir; end; end; return i; end; --------- find & check -------- countVertex(i:INT):INT is --count vertices on the string c:INT:=0.int; i:=endOfString(i,-1)+1; loop while!(~VERTEXC::separator.in([i].sep)); if VERTEXC::normal.in([i].sep) then c:=c+1; end; i:=i+1; end; return c; end; const near:INT:=16; const far:INT:=10000; distV(i,j:INT):INT is -- return distance ( Knot[i], Knot[j]) if VERTEXC::separator.in([i].sep+[j].sep) then return far; end; return [i].distance1([j]); end; tooShort(i:INT):BOOL is -- true if the string is too short to shrink j0::=endOfString(i, -1); j1::=endOfString(i, 1.int); nv::=countVertex(j0); if VERTEXC::ks.in([j0].sep) and Match(j0+1,j1-1) and (nv<=4.int) then return true; elsif VERTEXC::ks.in([j0].sep)and(nv<=2.int) then return true; elsif VERTEXC::ts.in([j0].sep)and(nv<=2.int) then return true; else return false; end; end; band_attach_sgn(bi, ti0,ti1:INT):INT is -- bi points 'band', ti points 'ts' or 'te' if has_ind(bi).not or has_ind(ti0).not or has_ind(ti1).not then return 0.int; end; if VERTEXC::band.in([bi].sep).not then return 0.int; end; if VERTEXC::separator.in([ti1].sep) then return 0.int; end; if VERTEXC::normal.in([ti0].sep).not then return 0.int; end; return [bi].rotation([bi+1], [bi-1], [ti1]); end; band_attach_sgn(bi, ti:INT):INT is -- bi points 'band', ti points 'ts' or 'te' ti0,ti1:INT; if VERTEXC::ts.in([ti].sep) then ti0:=ti+1; ti1:=ti0+1; elsif VERTEXC::te.in([ti].sep) then ti0:=ti-1; ti1:=ti0-1; elsif VERTEXC::ts.in([ti-1].sep) then ti0:=ti; ti1:=ti0+1; elsif VERTEXC::te.in([ti+1].sep) then ti0:=ti; ti1:=ti0-1; else return 0; end; return band_attach_sgn(bi,ti0,ti1); end; band_attach_sgn(i:INT):INT is if VERTEXC::band.in([i].sep) then return band_attach_sgn(i,MatchPt(i,bandStart)); elsif VERTEXC::ts.in([i].sep) then return band_attach_sgn(MatchPt(i+1,0.int),i+1,i+2); elsif VERTEXC::te.in([i].sep) then return band_attach_sgn(MatchPt(i-1,0.int),i-1,i-2); elsif VERTEXC::ts.in([i-1].sep) then return band_attach_sgn(MatchPt(i,0.int),i,i+1); elsif VERTEXC::te.in([i+1].sep) then return band_attach_sgn(MatchPt(i,0.int),i,i-1); else return 0.int; end; end; is_coherent(b:INT):BOOL is -- check if band connectiong b is coherent. -- if the band is not proper then return __true__ . j0:INT; if VERTEXC::band.in([b].sep) then j0:=endOfString(MatchPt(b,bandStart),-1); else j0:=endOfString(b,-1); end; if VERTEXC::ts.in([j0].sep) then -- check coherent and identify return (band_attach_sgn(j0)*band_attach_sgn(endOfString(j0,1.int))).is_non_neg; else return true; end; end; ---------------search near pts----------------- const vertex, edge, other; miniVE(gx,gy:INT, stp,enp:INT, sw:INT, out d:INT):INT is --search nearest vertex/edge on Knot[]. --sw=0: vertex, --sw=1:edge --sw=2: other( dummy ) --returns (number of the vertex) and set distance (d). dr,dw:INT; -- distance i,j,js:INT; i:=0.int; dr:=far; j:=stp.max(0.int); v:VERTEXK:=#(gx+gx,-(gy+gy)); enp:=enp.min(k.size.int-2); loop js:=j+sw; if (js>enp) then break!; end; if (~(VERTEXC::separator.in([j].sep+[js].sep))) and (~((sw=0.int)and(VERTEXC::crossing.in([j].sep)))) then dw:=v.distance1([j]+[js]); if dw<dr then i:=j; dr:=dw; end; end; j:=j+1; end; d := dr/2; return i; end; miniCrossing(gx, gy:INT, stp, enp:INT, out d:INT):INT is dw:INT; -- distance i::=0.int; d:=far; j::=stp.max(0.int); enp:=enp.min(k.size.int-2); v:VERTEXK:=#(gx,-gy); loop if (j>enp) then break!; end; if VERTEXC::crossing.in([j].sep) then dw:=v.distance1([j]); if dw<d then i:=j; d:=dw; end; end; j:=j+1; end; return i; end; miniPt(gx,gy:INT, out pt:INT, out d:INT, out sw:INT) is -- find near point of (mouseX,mouseY) ptw,dw:INT; pt:=miniVE(gx,gy,0.int,length.int,0.int,out d); sw:=0.int; ptw:=miniVE(gx,gy,0.int,length.int,1.int,out dw); if dw<d then pt:=ptw;d:=dw;sw:=1.int; end; end; nearStumpVertex(gx,gy: INT, out pt:INT, out d:INT) is -- find near stump Vertex of knot p1,p2:INT; pt:=miniVE(gx,gy,0.int,length.int,vertex.int,out d); if pt.is_non_pos then d:=far; end; if d<near then if VERTEXC::ks.in([pt-1].sep) or VERTEXC::ke.in([pt+1].sep) then -- end-point p1:=endOfString(pt,-1)+1; p2:=endOfString(pt,1.int)-1; if [p1].sameCoord([p2]) then d:=far; end; else d:=far; end; end; end; LookMouseV(stp, enp:INT, inout i0:INT, inout x:INT, inout y:INT,inout left:BOOL, inout right:BOOL) is i,sw, d:INT; #OUT+"LookMouseV is uncertified.\n"; -- MouseK.State(left, right, x, y);*) i:=miniVE(x, y, stp, enp, vertex.int, out d); sw:=vertex.int; DRAW_ALG::UpdateVE(self,inout i0, i,inout sw,vertex.int); end; LookMouseVE(MDistance:INT,stp, enp:INT, inout i0 :INT, inout veSw:INT,inout x, y:INT, inout left, right:BOOL) is -- mark if near than MDistance -- veSw 0:vertex, 1:edge -- state of mouse i, ie, sw1, d, de:INT; #OUT+"LookMouseVE is uncertified.\n"; -- MouseK.State(left, right, x, y); i :=miniVE(x, y, stp, enp,vertex.int,out d ); sw1:=vertex.int; ie:=miniVE(x, y, stp, enp,edge.int,out de); if de<d then i:=ie; sw1:=edge.int; d:=de; end; if MDistance<d then sw1:=other.int; end; DRAW_ALG::UpdateVE(self, inout i0, i, inout veSw, sw1); end; nearVertexV(i1,i2:INT, out pt, out d:INT) is -- find the nearest point from i1, except i1,i2 dw,j:INT; if (~has_ind(i1))or(VERTEXC::separator.in([i1].sep)) then return; end; pt:=-1; d:=far; if (~has_ind(i2))or(VERTEXC::separator.in([i2].sep)) then i2:=i1; end; loop j:=k.ind!.int; if VERTEXC::normal.in([j].sep)and(j/=i1)and(j/=i2) then dw:=[i1].distance1([j]); if dw<d then d:=dw; pt:=j; end; end; end; end; -------------- add/delete ------------------ CodeIn(x,y:INT, i:CARD) is CodeIn(#VERTEXK(x,y),i) end; CodeIn(x,y:INT, i:INT) pre i.is_neg.not is CodeIn(x,y,i.card); end; CodeIn(x,y:INT, c:VERTEXC, i:CARD) is CodeIn(#VERTEXK(x,y,c),i); end; CodeIn(x,y:INT, c:VERTEXC, i:INT) pre i.is_neg.not is CodeIn(x,y,i.card); end; append(x,y:CARD) is CodeIn(#VERTEXK(x.int,y.int),k.size-1); end; append(x,y:INT) is CodeIn(#VERTEXK(x,y),k.size-1); end; DelV(i:INT) is -- Del 1 code1. if band then del 1code at ts/te, too. -- Knot[i] is not ks,ke,ts,te j, j0, j1:INT; ClCrossEdge(inout i, 1.int); ClCrossEdge(inout i, -1); if tooShort(i) then delStr(inout i); else if VERTEXC::band.in([i].sep) then j:=cmpOf(i); if j.is_non_neg then if countVertex(j)<=2.int then delStr(inout j); else if VERTEXC::ts.in([j-1].sep) then ClCrossEdge(inout j, 1.int); else ClCrossEdge(inout j,-1); end; CodeDel(j.card); end; end; end; CodeDel(i.card); end; -- ClCrossErr(i); chkStr(i); end; delStr(inout i:INT) is --del code of string ks..ke/ts..te cantaining i with codeDel. j::=endOfString(i,1.int); i:=endOfString(i,-1); loop while!(j>=i); CodeDel(j.card); j:=j-1; end; end; BandDel(i:INT) is -- not check crossing. k1, k2, b1, b2:INT; if VERTEXC::band.is_subset([i].sep) then b1:=cmpOf(i); else b1:=i; end; b1:=endOfString(b1,-1); if (b1.is_neg)or (~(VERTEXC::ts.is_subset([b1].sep))) then return; end; b2:=endOfString(b1,1.int); k1:=cmpOf(b1); if k1.is_non_neg then [k1].sep:=VERTEXC::normal; end; k2:=cmpOf(b2); if k2.is_non_neg then [k2].sep:=VERTEXC::normal; end; delStr(inout b1); -- move down end; ClCross is -- delete all crossings i:INT:=0.int; loop if VERTEXC::code_e= [i].sep then break!; elsif VERTEXC::crossing.in( [i].sep) then CodeDel(i.card); else i:=i+1; end; end; end; ClCrossErr(inout vp:INT) is i:INT:=0; loop if VERTEXC::code_e=[i].sep then break!; elsif VERTEXC::crossing.in([i].sep)and(cmpOf(i).is_neg) then if i<=vp then vp:=vp-1; end; CodeDel(i.card); else i:=i+1; end; end; end; ClCrossEdge(inout edge:INT, dir:INT) is if ~has_ind(edge) then return; end; if ~ VERTEXC::normal.in( [edge].sep) then return; end; i::=edge+dir; if dir=1.int then if VERTEXC::te.in([i].sep) then dir:=-1; i:=edge+dir; elsif VERTEXC::ke.in([i].sep) then i:=endOfString(i,-1)+1; if Match(i,edge) then i:=i+1; else return; end; end; elsif dir=-1 then if VERTEXC::ts.in([i].sep) then dir:=1; i:=edge+dir; elsif VERTEXC::ks.in([i].sep) then i:=endOfString(i,1.int)-1; if Match(edge,i) then i:=i-1; else return; end; end; end; loop while!(VERTEXC::crossing.in([i].sep)); if i<edge then edge:=edge-1; end; CodeDel(i.card); if dir=-1 then i:=i-1; end; end; end; attach(i,j:INT) is -- Knot[i] <-- Knot[j] [i].x:=[j].x; [i].y:=[j].y; end; StringSplice(i,j:INT) is i:=endOfString(i,-1); j:=endOfString(j,-1); CodeSplice(i,endOfString(i,1.int),j,endOfString(j,1.int)); if j<i then i:=j; end; i:=endOfString(i,1.int); CodeDel(i.card); CodeDel(i.card); if Match(i,i-1) then CodeDel(i.card); end; end; PointInEdge(i:INT) pre (VERTEXC::normal.in([i].sep) or VERTEXC::normal.in([i+1].sep) or VERTEXC::crossing.in([i].sep)) is CodeIn(([i]+[i+1])/2.int, i.card+1); end;
make_coherent is -- if knot has bands, try orientation reversing on knots -- to make coherent along band connections. if ~has_band then return; end; bs::=bandStart; c,c0,c1:INT; -- component number -- set component number cTbl:KNOT:=clone; loop i:INT:=0.int.upto!(bs); if VERTEXC::ks.in([i].sep) then c:=1.int.up!; end; cTbl[i].work:=c; end; -- identify components along coherent band i0,i1,j0,j1,sgn0,sgn1:INT; loop i::=0.int.upto!(bs); if VERTEXC::band.in([i].sep) then i0:=i; j0:=MatchPt(i0,bs); if VERTEXC::ts.in([j0-1].sep) then j1:=endOfString(j0,1.int)-1; elsif VERTEXC::te.in([j0+1].sep) then j1:=endOfString(j0,-1)+1; end; i1:=MatchPt(j1,0.int); -- check coherent and identify if (i0<i1) and(cTbl[i0].work/=cTbl[i1].work) and (band_attach_sgn(i0,j0)*band_attach_sgn(i1,j1)).is_pos then c0:=cTbl[i0].work; c1:=cTbl[i1].work; -- identify c1 with c0 loop j::=0.int.upto!(bs); if cTbl[j].work=c1 then cTbl[j].work:=c0; end; end; end; end; end; -- reverse and identify components along incoherent band loop i::=0.int.upto!(bs); if VERTEXC::band.in([i].sep) then i0:=i; j0:=MatchPt(i0,bs); if VERTEXC::ts.in([j0-1].sep) then j1:=endOfString(j0,1.int)-1; elsif VERTEXC::te.in([j0+1].sep) then j1:=endOfString(j0,-1)+1; end; i1:=MatchPt(j1,0.int); if (i0<i1)and(cTbl[i0].work/=cTbl[i1].work) then -- ori. reverse _c1_ components c0:=cTbl[i0].work; c1:=cTbl[i1].work; loop j::=0.int.upto!(bs); if (VERTEXC::ks.in([j].sep))and(c1=cTbl[j].work) then revK(j); end; end; -- identify c1 with c0 loop j::=0.int.upto!(bs); if cTbl[j].work=c1 then cTbl[j].work:=c0; end; end; end; end; end; end; Shift(ofsX,ofsY:INT) is loop i::=k.ind!; if (VERTEXC::normal.in([i].sep))or (VERTEXC::crossing.in([i].sep)) then [i].plus(ofsX,ofsY); end; end; end; width(out minX,out maxX,out minY,out maxY:INT) is maxX:=INT::minint; minX:=INT::maxint; maxY:=maxX; minY:=minX; loop i::=k.ind!; if (VERTEXC::normal.in([i].sep))or (VERTEXC::crossing.in([i].sep)) then maxX:=maxX.max([i].x); minX:=minX.min([i].x); maxY:=maxY.max([i].y); minY:=minY.min([i].y); end; end; end; shiftToInside is if is_nocompo then return; end; maxX,minX,maxY,minY,ofsX,ofsY:INT; width(out minX,out maxX,out minY,out maxY); ofsX:=(KNOTXW::GraphWidth-(maxX+minX))/2; if (minX+ofsX)<10.int then ofsX:=10.int-minX; end; ofsY:=(-KNOTXW::GraphWidth-(maxY+minY))/2; if (maxY+ofsY)>(-10) then ofsY:=-10-maxY; end; if (ofsX.is_non_zero) or (ofsY.is_non_zero) then self.Shift(ofsX,ofsY); end; end; transform(p,q,r,s:INT) is -- linear transformation of Knot loop [k.ind!].transform(p,q,r,s); end; shiftToInside; end; transform(mag:FLT) is -- linear transformation of Knot loop [k.ind!]*mag; end; shiftToInside; end; mirrorX is -- mirror x --> -x transform(-1,0.int,0.int,1.int); end; mirrorY is -- mirror y --> -y transform(1.int,0.int,0.int,-1); end; mirrorZ is -- change all crossings exg::=VERTEXC::cross_exg; loop i::=k.ind!; if VERTEXC::crossing.in(k[i].sep) then k[i].sep:=k[i].sep/exg; end; end; end; CrossSet(stp,enp:INT) is k:=CROSS_SET::CrossSet(self,stp,enp).k; end; CrossSet:BOOL is knot::=clone; r::=CROSS_SET::CrossSetM(inout knot,0.int,length.int,true,false); if r then k:=knot.k; end; return r; end; --------------------------- vector ---------------------- distanceL2(ki:INT, x, y:INT, rot:INT):INT is -- distance( edge(ki--(ki+1), point(x,y) )^2 -- rot; 1:only left side. -1: right side. 0:each side. l2, inn, outer, d2:INT; -- if (ki<0)or(length<=ki) -- or (~normal.in(Knot[ki].sep)) or(separator.in(Knot[ki+1].sep)) then -- return -1; -- end; ki1::=ki; loop ki1:=ki1+1; until!(VERTEXC::normal.in([ki1].sep)); end; p:VERTEXK:=#(x,y); u::=[ki1]-[ki]; v::=p-[ki]; outer:=u.outer(v); l2:=u.abs2; if (outer.is_pos)=(rot.is_pos) then outer:=outer.abs; inn:=u.inner(v); if inn.is_non_pos then d2:=v.abs2; -- d(e,p)=d(ki,p) elsif inn>=l2 then v:=v-u; d2:=v.abs2; -- d(ki+1, p) elsif outer>=l2 then d2:=l2; else d2:= outer.flt.square.div(l2.flt).round.int; end; else d2:= l2; end; if (l2<d2) then d2:=l2; end; return d2; end;
------------------- check -----------------------------------------
is_theta:BOOL is -- true if theta curve(1-component and 1-band). if ~is_proper then #OUT+"Not a theta curve.(not proper)\n"; return false; end; if number_compo>1.int then #OUT+"Not a theta curve.(too many component)\n"; return false; end; if ~has_band then #OUT+"Not a theta curve.(need 1 band)\n"; return false; end; b1:INT:=bandStart; b2:INT:=endOfString(b1,1.int); if (b2+1)/=length.int then #OUT+"Not a theta curve.(too many band)\n"; return false; end; return true; end; is_proper:BOOL is -- knot code is proper for braid, ndata, invariants etc. knot:KNOT:=clone; if ~checkCode(true) then #OUT+"Bad code in knot data\n"; return false; end; if (length<=1) then #OUT+"Knot has no component.\n"; return false; end; if ~is_Closed then #OUT+"Diagram is not closed.\n"; return false; end; if ~CROSS_SET::CrossSetM(inout knot,0.int,length.int,false,true) then #OUT+"Knot is not regular.\n"; return false; end; return true; end; checkCode(message:BOOL):BOOL is i:INT; cod0,cod,cod1:VERTEXC; res:BOOL:=true; if void(self) then bad(message,0,0.int);return false; end; if size<=1 then return true; end; cod:=VERTEXC::graph_e; cod0:=cod; cod1:=k[0].sep; i:=0; loop if (i>length.int)and(i.is_pos) then bad(message,12,i); res:=false;break!; end; cod0:=cod;cod:=cod1;cod1:=[i+1].sep; -- #OUT+"cod0="+cod0.int+" cod="+cod.int+" cod1="+cod1.int+"\n"; if VERTEXC::normal.in(cod) and VERTEXC::normal.in(cod0) and Match(i,i-1) then bad(message,10,i); res:=false; end; if VERTEXC::normal=cod then ; elsif VERTEXC::band_attach=cod then ; elsif VERTEXC::crossing.in(cod) then if (cod-VERTEXC::cross_all).is_empty.not then bad(message,20,i); res:=false; elsif VERTEXC::under.in(cod)=VERTEXC::over.in(cod) then bad(message,21,i); res:=false; elsif VERTEXC::positive.in(cod) and VERTEXC::negative.in(cod) then bad(message,22,i); res:=false; end; elsif VERTEXC::graph_s=cod then -- #OUT+"'ts"; if VERTEXC::normal /= cod1 then bad(message,35,i); res:=false; end; if VERTEXC::graph_e/=cod0 then bad(message,36,i); res:=false; end; if (VERTEXC::graph_e/=[i+2].sep) then bad(message,37,i); res:=false; end; elsif VERTEXC::graph_e=cod then if (VERTEXC::normal/=cod0) then bad(message,47,i); res:=false; end; if (VERTEXC::graph_s=cod1) then elsif (VERTEXC::knot_s=cod1) then elsif (VERTEXC::band_s=cod1) then elsif (VERTEXC::code_e=cod1) then else bad(message,48,i); res:=false; end; elsif VERTEXC::knot_s=cod then if (VERTEXC::normal/=cod1) then bad(message,51,i); res:=false; end; if (VERTEXC::graph_e= cod0) then elsif (VERTEXC::knot_e= cod0) then else bad(message,52,i); res:=false; end; elsif VERTEXC::knot_e=cod then if (VERTEXC::normal/=cod0) then bad(message,63,i); res:=false; end; if (VERTEXC::knot_s=cod1) then elsif (VERTEXC::band_s=cod1) then elsif (VERTEXC::code_e=cod1) then else bad(message,64,i); res:=false; end; elsif VERTEXC::band_s=cod then -- #OUT+"ts"; if (VERTEXC::normal/=cod1) then bad(message,75,i); res:=false; end; if (VERTEXC::graph_e=cod0) then elsif (VERTEXC::knot_e=cod0) then elsif (VERTEXC::band_e=cod0) then else bad(message,76,i); res:=false; end; elsif VERTEXC::band_e=cod then if (VERTEXC::normal/=cod0) then bad(message,87,i); res:=false; end; if (VERTEXC::band_s=cod1) then elsif (VERTEXC::code_e=cod1) then else bad(message,88,i); res:=false; end; else bad(message,100,i); res:=false; end; if VERTEXC::code_e=cod1 then if VERTEXC::graph_e=cod then elsif VERTEXC::knot_e=cod then elsif VERTEXC::band_e=cod then else bad(message,99,i); res:=false; end; break!; end; i:=i+1; end; -- if ~res then checkKnotD(Knot); end; return res; end; checkCode:BOOL is -- no check on crossings return checkCode(true); end; printD is -- print for debug cod:VERTEXC; if void(self) then #OUT+"Knot is void\n"; return; end; #OUT+"Knot.k.size="+size.str+"\n"; #OUT+"index:(x,y),cod\n"; loop i::=k.ind!; --#OUT+i.fmt("<####>") -- +Knot[i].x.fmt("<####>")+Knot[i].y.fmt("<####>") -- +Knot[i].sep.int.fmt("<hex#####> "); if i>=k.size then break!; end; #OUT+i.str+":("+[i].x.str+","+[i].y.str+"),"+[i].sep.card.hex_str+" "; sep::=[i].sep; if VERTEXC::ks.in(sep) then #OUT+"["; elsif VERTEXC::ke.in(sep) then #OUT+"]"; elsif VERTEXC::ts.in(sep) then #OUT+"("; elsif VERTEXC::te.in(sep) then #OUT+")"; elsif VERTEXC::gs.in(sep) then #OUT+"<"; elsif VERTEXC::ge.in(sep) then #OUT+">"; elsif VERTEXC::endc.in(sep) then #OUT+"/"; elsif VERTEXC::band.in(sep) then #OUT+"b"; elsif VERTEXC::crossing.in(sep) then if VERTEXC::under.in(sep) then #OUT+"u"; elsif VERTEXC::over.in(sep) then #OUT+"o"; end; if VERTEXC::positive.in(sep) then #OUT+"+"; elsif VERTEXC::negative.in(sep) then #OUT+"-"; end; end; #OUT+"\n"; end; end; is_Closed(i:INT):BOOL is -- true if the string containing "i" is closed. -- check if (1)string of ks..ke is closed -- and (2)string of ts..te is attached to knot. if ~has_ind(i) then return false; end; stp::=endOfString(i,-1); if ~has_ind(stp) then return false; end; stpm::=cmpOf(stp); if ~has_ind(stpm) then return false; end; stpmm::=cmpOf(stpm); if ~has_ind(stpmm) then return false; end; enp::=endOfString(i,1.int); if ~has_ind(enp) then return false; end; enpm::=cmpOf(enp); if ~has_ind(enpm) then return false; end; enpmm::=cmpOf(enpm); if ~has_ind(enpmm) then return false; end; if VERTEXC::ks.in([stp].sep) then if enp<stp+5 then return false; -- too short end; elsif VERTEXC::ts.in([stp].sep) then if enp<stp+3 then return false; -- too short end; -- ts if ~VERTEXC::band.in([stpm].sep) then return false; elsif (stp+1)/=stpmm then return false; end; -- te if ~VERTEXC::band.in([enpm].sep) then return false; elsif (enp-1)/=enpmm then return false; end; else return false; end; return true; end; is_Closed:BOOL is if VERTEXC::code_e /= [length].sep then return false; end; i:INT:=0.int; loop if VERTEXC::code_e=[i].sep then return i=length.int; end; if length.int<=i then return false; end; if is_Closed(i) then i:=endOfString(i,1.int)+1; else return false; end; end; return false; end; concat_at_tail(i:INT) is -- concatinate strings if (look like) connected in diagram. j:INT; -- tail of a component i1,j1:INT; -- head/tail of a component to concatinate loop i:=endOfString(i,-1); j:=endOfString(i,1.int); if [i+1].sameCoord([j-1]) then break!; end; -- when loop. i1:=MatchPt(j-1,j); if i1<j then break!; end; -- not match i1:=endOfString(i1,-1); j1:=endOfString(i1,1.int); if [i1+1].sameCoord([j1-1]) then break!; -- when loop. elsif [j-1].sameCoord([i1+1]) then StringSplice(i,i1); elsif [j-1].sameCoord([j1-1]) then revK(i1); StringSplice(i,i1); else break!; end; end; end; concat is -- concatinate strings if (look like) connected in diagram. i::=0.int; -- head of a component loop -- unify at tail point concat_at_tail(i); i:=endOfString(i,1.int)+1; if [i].sep=VERTEXC::code_e then break!; end; end; i:=0.int; loop -- unify at head point revK(i); concat_at_tail(i); revK(i); i:=endOfString(i,1.int)+1; if [i].sep=VERTEXC::code_e then break!; end; end; end; edge_clean is -- If edges v1-v2-v3 is straight then remove v2 as v1-v3. i:CARD:=1; loop if i>=size then break!; end; if VERTEXC::normal.in([i].sep) and [i].outer([i-1],[i+1]).is_zero and (VERTEXC::normal.in([i-1].sep) or VERTEXC::crossing.in([i-1].sep)) and (VERTEXC::normal.in([i+1].sep) or VERTEXC::crossing.in([i+1].sep)) then CodeDel(i); else i:=i+1; end; end; end; endOfBridge(i:INT, dir:INT):INT is if dir.is_neg and (VERTEXC::ks.in([i].sep) or VERTEXC::ts.in([i].sep) or VERTEXC::gs.in([i].sep) or VERTEXC::under.in([i].sep) )then return i; end; if dir.is_pos and (VERTEXC::ke.in([i].sep) or VERTEXC::te.in([i].sep) or VERTEXC::ge.in([i].sep) or VERTEXC::endc.in([i].sep) )then return i; end; j:INT:=i; loop j:=j+dir; if VERTEXC::separator.in([j].sep) or VERTEXC::under.in([j].sep) then break!; end; end; return j; end; nextBridge(i:INT):INT is j:INT; if VERTEXC::ke.in([i].sep) then return i+1; elsif VERTEXC::te.in([i].sep) then return i+1; elsif VERTEXC::endc.in([i].sep) then return i; end; j:=endOfBridge(i,1.int); if VERTEXC::ke.in([j].sep) then return j+1; elsif VERTEXC::te.in([j].sep) then return j+1; end; return j; end; end; -- class KNOT

class CROSS_SET

class CROSS_SET is shared stp,enp,i1, i2, i1e, i2e, bStart:INT; shared p10,p11,p20,p21,u,v,p: VERTEXK; shared max,min:VERTEXK; shared d, t, s:INT; shared Succeed:BOOL; setU1(Knot:KNOT) is p10:=Knot[i1]; p11:=Knot[i1+1]; min:=#(p10.x.min(p11.x),p10.y.min(p11.y)); max:=#(p10.x.max(p11.x),p10.y.max(p11.y)); u:=p11-p10; end; CrossCheck0(Knot:KNOT):BOOL is if (VERTEXC::separator.in(Knot[i1].sep))or (VERTEXC::separator.in(Knot[i1+1].sep)) then i2:=i2e; return false; elsif (VERTEXC::separator.in(Knot[i2].sep))or (VERTEXC::separator.in(Knot[i2+1].sep)) then return false; end; return true; end; CrossCheck2(Knot:KNOT):BOOL is p20:=Knot[i2]; p21:=Knot[i2+1]; if (max.x<=p20.x)and(max.x<=p21.x) then return false; end; if (p20.x<=min.x)and(p21.x<=min.x) then return false; end; if (max.y<=p20.y)and(max.y<=p21.y) then return false; end; if (p20.y<=min.y)and(p21.y<=min.y) then return false; end; v:=p21-p20; d:=v.outer(u); return d.is_non_zero; end; CrossCheck3(Knot:KNOT):BOOL is neg:BOOL:=(d.is_neg); t:=u.outer(p20-p10); if neg then d:=-d; t:=-t; end; if (t.is_non_pos) or (d<=t) then return false; end; s:=v.outer(p20-p10); if neg then s:=-s; end; return (s.is_pos and (s<d)); end; errorm(messageP:BOOL) is Succeed:=false; if messageP then #OUT+"Check if the projection is regular.\n"; end; end; CrossCheck4(Knot:KNOT,messageP:BOOL):BOOL is p:=u*(s.flt/d.flt)+p10; if p.sameCoord(p20) then errorm(messageP); return false; elsif p.sameCoord(p21) then errorm(messageP); return false; elsif p.sameCoord(p10) then errorm(messageP); return false; elsif p.sameCoord(p11) then errorm(messageP); return false; end; return true; end; i1Over(inout Knot:KNOT) is Knot[i2].sep:=VERTEXC::cross_under; Knot[i1+1].sep:=VERTEXC::cross_over; end; i2Over(inout Knot:KNOT) is Knot[i2].sep:=VERTEXC::cross_over; Knot[i1+1].sep:=VERTEXC::cross_under; end; CrossIn(inout Knot:KNOT) is add:INT; i2e:=i2e+2; i1e:=i1e+2; add:=0; if i1<stp then add:=add+1; end; if i2<stp then add:=add+1; end; stp:=stp+add; add:=0; if i1<enp then add:=add+1; end; if i2<enp then add:=add+1; end; enp:=enp+add; add:=0; if i1<bStart then add:=add+1; end; if i2<bStart then add:=add+1; end; bStart:=bStart+add; Knot.CodeIn(p.clone, i2.card+1); i2:=i2+1; Knot.CodeIn(p.clone, i1.card+1); i2:=i2+1; if i1<stp then i2Over(inout Knot); elsif enp<i2 then i1Over(inout Knot); else -- stp<=i1<i2<enp. (Cannot be i2=enp.) if (bStart<i1)/=(bStart<i2) then i2Over(inout Knot); else i1Over(inout Knot); end; end; setU1(Knot); end; CrossSetM(inout Knot:KNOT, stp_org, enp_org:INT, messageP:BOOL, only_check:BOOL):BOOL pre Knot.has_ind(stp_org) and Knot.has_ind(enp_org) is -- find and set crossings from stp to enp. -- I assume that stp < enp. if ~Knot.checkCode then return false; end; stp:=stp_org; enp:=enp_org; Knot0::=Knot.clone; Succeed:=true; bStart::=Knot.bandStart; i1e:=Knot.length.int-4; i2e:=i1e+2; i1:=1.int; loop while! ((i1<i1e)and(i1<stp) ); setU1(Knot); i2:=i1+2; if i2<stp then i2:=stp; end; loop while! ((i2<i2e)and(i2<enp) ); if CrossCheck0(Knot)and CrossCheck2(Knot)and CrossCheck3(Knot)and CrossCheck4(Knot,messageP) then CrossIn(inout Knot); end; i2:=i2+1; end; i1:=i1+1; end; i1:=stp; loop while! ((i1<i1e)and(i1<enp) ); setU1(Knot); i2:=i1+2; loop while! (i2<i2e ); if CrossCheck0(Knot)and CrossCheck2(Knot)and CrossCheck3(Knot)and CrossCheck4(Knot,messageP) then CrossIn(inout Knot); end; i2:=i2+1; end; i1:=i1+1; end; if only_check then Knot:=Knot0; end; return Succeed; end; CrossSet(Knot_org:KNOT, stp_org, enp_org:INT):KNOT is -- set crossings on a regular projection and make a diagram. k:KNOT:=Knot_org.clone; r::=CrossSetM(inout k, stp_org, enp_org, false,false); return k; end; end; -- class CROSS_SET