Last active
June 20, 2017 13:20
-
-
Save youqad/c2f734f54f5a2e3176e7a998a229b51f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************* | |
* | |
* MathJax/extensions/TeX/xypic.js | |
* | |
* Implements Xy-pic environment. | |
* | |
* --------------------------------------------------------------------- | |
* | |
* Copyright (c) 2011-2014 Isao Sonobe <[email protected]>. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
(function () { | |
var FP = MathJax.Extension.fp = { | |
version: "0.1" | |
}; | |
/************ Matcher **************/ | |
FP.Matcher = MathJax.Object.Subclass({ | |
Init: function () { this.cases = []; }, | |
Case: function (klass, f) { | |
this.cases.push([klass, f]); | |
return this; | |
}, | |
match: function (x) { | |
if (x instanceof Object && "isa" in x) { | |
var i, count, klass, op; | |
i = 0; | |
count = this.cases.length; | |
while (i < count) { | |
klass = this.cases[i][0]; | |
if (x.isa(klass)) { | |
op = klass.unapply(x); | |
if (op.isDefined) { | |
return this.cases[i][1](op.get); | |
} | |
} | |
i = i + 1; | |
} | |
} | |
throw FP.MatchError(x); | |
} | |
}); | |
/************ Option **************/ | |
FP.Option = MathJax.Object.Subclass({}); | |
FP.Option.Some = FP.Option.Subclass({ | |
Init: function (value) { | |
this.get = value; | |
}, | |
isEmpty: false, | |
isDefined: true, | |
getOrElse: function (ignore) { return this.get; }, | |
flatMap: function (k) { | |
return k(this.get); | |
}, | |
map: function (f) { | |
return FP.Option.Some(f(this.get)); | |
}, | |
foreach: function (f) { | |
f(this.get); | |
}, | |
toString: function () { | |
return "Some(" + this.get + ")"; | |
} | |
}, { | |
unapply: function (x) { return FP.Option.Some(x.get); } | |
}); | |
FP.Option.None = FP.Option.Subclass({ | |
Init: function () {}, | |
isEmpty: true, | |
isDefined: false, | |
getOrElse: function (value) { return value; }, | |
flatMap: function (k) { return this; }, | |
foreach: function (f) {}, | |
map: function (k) { return this; }, | |
toString: function () { return "None"; } | |
}, { | |
unapply: function (x) { return FP.Option.Some(x); } | |
}); | |
FP.Option.Augment({}, { | |
empty: FP.Option.None() | |
}); | |
/************ List **************/ | |
FP.List = MathJax.Object.Subclass({}); | |
FP.List.Cons = FP.List.Subclass({ | |
Init: function (head, tail) { | |
this.head = head; | |
this.tail = tail; | |
}, | |
isEmpty: false, | |
at: function (index) { | |
if (index < 0 || index >= this.length()) { | |
throw Error("no such element at " + index + ". index must be lower than " + this.length() + "."); | |
} | |
var t = this; | |
for (var i = 0; i < index; i++) { | |
t = t.tail; | |
} | |
return t.head; | |
}, | |
length: function () { | |
var t = this; | |
var l = 0; | |
while (!t.isEmpty) { | |
l++; | |
t = t.tail; | |
} | |
return l; | |
}, | |
prepend: function (element) { | |
return FP.List.Cons(element, this); | |
}, | |
append: function (element) { | |
var result = FP.List.Cons(element, FP.List.empty); | |
this.reverse().foreach(function (e) { | |
result = FP.List.Cons(e, result); | |
}); | |
return result; | |
}, | |
concat: function (that) { | |
var result = that; | |
this.reverse().foreach(function (e) { | |
result = FP.List.Cons(e, result); | |
}); | |
return result; | |
}, | |
foldLeft: function (x0, f) { | |
var r, c; | |
r = f(x0, this.head); | |
c = this.tail; | |
while (!c.isEmpty) { | |
r = f(r, c.head); | |
c = c.tail; | |
} | |
return r; | |
}, | |
foldRight: function (x0, f) { | |
if (this.tail.isEmpty) { | |
return f(this.head, x0); | |
} else { | |
return f(this.head, this.tail.foldRight(x0, f)); | |
} | |
}, | |
map: function (f) { | |
return FP.List.Cons(f(this.head), this.tail.map(f)); | |
}, | |
flatMap: function (k) { | |
return k(this.head).concat(this.tail.flatMap(k)); | |
}, | |
foreach: function (f) { | |
var e = this; | |
while (!e.isEmpty) { | |
f(e.head); | |
e = e.tail; | |
} | |
}, | |
reverse: function () { | |
var r = FP.List.empty; | |
this.foreach(function (c) { | |
r = FP.List.Cons(c, r); | |
}); | |
return r; | |
}, | |
mkString: function () { | |
var open, delim, close; | |
switch (arguments.length) { | |
case 0: | |
open = delim = close = ""; | |
break; | |
case 1: | |
delim = arguments[0]; | |
open = close = ""; | |
break; | |
case 2: | |
open = arguments[0]; | |
delim = arguments[1]; | |
close = ""; | |
break; | |
default: | |
open = arguments[0]; | |
delim = arguments[1]; | |
close = arguments[2]; | |
break; | |
} | |
var desc, nxt; | |
desc = open + this.head.toString(); | |
nxt = this.tail; | |
while (nxt.isa(FP.List.Cons)) { | |
desc += delim + nxt.head.toString(); | |
nxt = nxt.tail; | |
} | |
desc += close; | |
return desc; | |
}, | |
toString: function () { | |
return this.mkString("[", ", ", "]"); | |
} | |
}, { | |
unapply: function (x) { return FP.Option.Some([x.head, x.tail]); } | |
}); | |
FP.List.Nil = FP.List.Subclass({ | |
isEmpty: true, | |
at: function (index) { | |
throw Error("cannot get element from an empty list."); | |
}, | |
length: function () { return 0; }, | |
prepend: function (element) { | |
return FP.List.Cons(element, FP.List.empty); | |
}, | |
append: function (element) { | |
return FP.List.Cons(element, FP.List.empty); | |
}, | |
concat: function (that) { | |
return that; | |
}, | |
foldLeft: function (x0, f) { return x0; }, | |
foldRight: function (x0, f) { return x0; }, | |
flatMap: function (f) { return this; }, | |
map: function (f) { return this; }, | |
foreach: function (f) {}, | |
reverse: function () { return this; }, | |
mkString: function () { | |
switch (arguments.length) { | |
case 0: | |
case 1: | |
return ""; | |
case 2: | |
return arguments[0] | |
default: | |
return arguments[0]+arguments[2]; | |
} | |
}, | |
toString: function () { return '[]'; } | |
}, { | |
unapply: function (x) { return FP.Option.Some(x); } | |
}); | |
FP.List.Augment({}, { | |
empty: FP.List.Nil(), | |
fromArray: function (as) { | |
var list, i; | |
list = FP.List.empty; | |
i = as.length - 1; | |
while (i >= 0) { | |
list = FP.List.Cons(as[i], list); | |
i -= 1; | |
} | |
return list; | |
} | |
}); | |
/************ MatchError **************/ | |
FP.MatchError = MathJax.Object.Subclass({ | |
Init: function (obj) { this.obj = obj; }, | |
// getMessage: function () { | |
// if (this.obj === null) { | |
// return "null" | |
// } else { | |
// return obj.toString() + " (of class " + obj. + ")" | |
// } | |
// } | |
toString: function () { return "MatchError(" + this.obj + ")"; } | |
}); | |
/************ OffsetPosition **************/ | |
FP.OffsetPosition = MathJax.Object.Subclass({ | |
Init: function (source, offset) { | |
// assert(source.length >= offset) | |
this.source = source; | |
if (offset === undefined) { this.offset = 0; } else { this.offset = offset; } | |
this._index = null; | |
this._line = null; | |
}, | |
index: function () { | |
if (this._index !== null) { return this._index; } | |
this._index = []; | |
this._index.push(0); | |
var i = 0; | |
while (i < this.source.length) { | |
if (this.source.charAt(i) === '\n') { this._index.push(i + 1); } | |
i += 1; | |
} | |
this._index.push(this.source.length); | |
return this._index; | |
}, | |
line: function () { | |
var lo, hi, mid; | |
if (this._line !== null) { return this._line; } | |
lo = 0; | |
hi = this.index().length - 1; | |
while (lo + 1 < hi) { | |
mid = (hi + lo) >> 1; | |
if (this.offset < this.index()[mid]) { | |
hi = mid; | |
} else { | |
lo = mid; | |
} | |
} | |
this._line = lo + 1; | |
return this._line; | |
}, | |
column: function () { | |
return this.offset - this.index()[this.line() - 1] + 1; | |
}, | |
lineContents: function () { | |
var i, l; | |
i = this.index(); | |
l = this.line(); | |
return this.source.substring(i[l - 1], i[l]); | |
}, | |
toString: function () { return this.line().toString() + '.' + this.column(); }, | |
longString: function () { | |
var desc, i; | |
desc = this.lineContents() + '\n'; | |
i = 0; | |
while (i < this.column()) { | |
if (this.lineContents().charAt(i) === '\t') { | |
desc += '\t'; | |
} else { | |
desc += ' '; | |
} | |
i += 1; | |
} | |
desc += '^'; | |
return desc; | |
}, | |
isLessThan: function (that) { | |
if (that.isa(FP.OffsetPosition)) { | |
return this.offset < that.offset; | |
} else { | |
return ( | |
this.line() < that.line() || | |
(this.line() === that.line() && this.column() < that.column()) | |
); | |
} | |
} | |
}); | |
/************ StringReader **************/ | |
FP.StringReader = MathJax.Object.Subclass({ | |
Init: function (source, offset, context) { | |
this.source = source; | |
this.offset = offset; | |
this.context = context; | |
}, | |
first: function () { | |
if (this.offset < this.source.length) { | |
return this.source.charAt(this.offset); | |
} else { | |
return FP.StringReader.EofCh; | |
} | |
}, | |
rest: function () { | |
if (this.offset < this.source.length) { | |
return FP.StringReader(this.source, this.offset + 1, this.context); | |
} else { | |
return this; | |
} | |
}, | |
pos: function () { return FP.OffsetPosition(this.source, this.offset); }, | |
atEnd: function () { return this.offset >= this.source.length; }, | |
drop: function (n) { | |
var r, count; | |
r = this; | |
count = n; | |
while (count > 0) { | |
r = r.rest(); | |
count -= 1; | |
} | |
return r; | |
} | |
}, { | |
EofCh: '\x03' | |
}); | |
/************ Parsers **************/ | |
FP.Parsers = MathJax.Object.Subclass({}, { | |
parse: function (p, input) { | |
return p.apply(input); | |
}, | |
parseAll: function (p, input) { | |
return p.andl(function () { return FP.Parsers.eos(); }).apply(input); | |
}, | |
parseString: function (p, str) { | |
var input = FP.StringReader(str, 0, { lastNoSuccess: undefined }); | |
return FP.Parsers.parse(p, input); | |
}, | |
parseAllString: function (p, str) { | |
var input = FP.StringReader(str, 0, { lastNoSuccess: undefined }); | |
return FP.Parsers.parseAll(p, input); | |
}, | |
_handleWhiteSpace: function (input) { | |
var whiteSpaceRegex = input.context.whiteSpaceRegex; | |
var source = input.source; | |
var offset = input.offset; | |
var m = whiteSpaceRegex.exec(source.substring(offset, source.length)); | |
if (m !== null) { | |
return offset + m[0].length; | |
} else { | |
return offset; | |
} | |
}, | |
literal: function (str) { | |
return FP.Parsers.Parser(function (input) { | |
var source, offset, start, i, j, found; | |
source = input.source; | |
offset = input.offset; | |
start = FP.Parsers._handleWhiteSpace(input); | |
i = 0; | |
j = start; | |
while (i < str.length && j < source.length && | |
str.charAt(i) === source.charAt(j)) { | |
i += 1; | |
j += 1; | |
} | |
if (i === str.length) { | |
return FP.Parsers.Success(str, input.drop(j - offset)); | |
} else { | |
if (start === source.length) { | |
found = "end of source"; | |
} else { | |
found = "`" + source.charAt(start) + "'"; | |
} | |
return FP.Parsers.Failure( | |
"`" + str + "' expected but " + found + " found", | |
input.drop(start - offset) | |
); | |
} | |
}); | |
}, | |
regex: function (rx /* must start with ^ */) { | |
if (rx.toString().substring(0, 2) !== "/^") { | |
throw ("regex must start with `^' but " + rx); | |
} | |
return FP.Parsers.Parser(function (input) { | |
var source, offset, m, found; | |
source = input.source; | |
offset = input.offset; | |
m = rx.exec(source.substring(offset, source.length)); | |
if (m !== null) { | |
return FP.Parsers.Success(m[0], input.drop(m[0].length)); | |
} else { | |
if (offset === source.length) { | |
found = "end of source"; | |
} else { | |
found = "`" + source.charAt(offset) + "'"; | |
} | |
return FP.Parsers.Failure( | |
"string matching regex " + rx + " expected but " + found + " found", | |
input | |
); | |
} | |
}); | |
}, | |
regexLiteral: function (rx /* must start with ^ */) { | |
if (rx.toString().substring(0, 2) !== "/^") { | |
throw ("regex must start with `^' but " + rx); | |
} | |
return FP.Parsers.Parser(function (input) { | |
var source, offset, start, m, found; | |
source = input.source; | |
offset = input.offset; | |
start = FP.Parsers._handleWhiteSpace(input); | |
m = rx.exec(source.substring(start, source.length)); | |
if (m !== null) { | |
return FP.Parsers.Success(m[0], input.drop(start + m[0].length - offset)); | |
} else { | |
if (start === source.length) { | |
found = "end of source"; | |
} else { | |
found = "`" + source.charAt(start) + "'"; | |
} | |
return FP.Parsers.Failure( | |
"string matching regex " + rx + " expected but " + found + " found", | |
input.drop(start - offset) | |
); | |
} | |
}); | |
}, | |
eos: function () { | |
return FP.Parsers.Parser(function (input) { | |
var source, offset, start; | |
source = input.source; | |
offset = input.offset; | |
start = FP.Parsers._handleWhiteSpace(input); | |
if (source.length === start) { | |
return FP.Parsers.Success("", input); | |
} else { | |
return FP.Parsers.Failure("end of source expected but `" + | |
source.charAt(start) + "' found", input); | |
} | |
}); | |
}, | |
commit: function (/*lazy*/ p) { | |
return FP.Parsers.Parser(function (input) { | |
var res = p()(input); | |
return (FP.Matcher() | |
.Case(FP.Parsers.Success, function (x) { return res; }) | |
.Case(FP.Parsers.Error, function (x) { return res; }) | |
.Case(FP.Parsers.Failure, function (x) { | |
return FP.Parsers.Error(x[0], x[1]); | |
}).match(res) | |
); | |
}); | |
}, | |
//elem: function (kind, p) | |
elem: function (e) { return FP.Parsers.accept(e).named('"' + e + '"'); }, | |
accept: function (e) { | |
return FP.Parsers.acceptIf( | |
function (x) { return x === e; }, | |
function (x) { return "`" + e + "' expected but `" + x + "' found"; } | |
); | |
}, | |
acceptIf: function (p, err) { | |
return FP.Parsers.Parser(function (input) { | |
if (p(input.first())) { | |
return FP.Parsers.Success(input.first(), input.rest()); | |
} else { | |
return FP.Parsers.Failure(err(input.first()), input); | |
} | |
}); | |
}, | |
//acceptMatch: function (expected, f) | |
//acceptSeq: function (es) | |
failure: function (msg) { | |
return FP.Parsers.Parser(function (input) { | |
return FP.Parsers.Failure(msg, input); | |
}); | |
}, | |
err: function (msg) { | |
return FP.Parsers.Parser(function (input) { | |
return FP.Parsers.Error(msg, input); | |
}); | |
}, | |
success: function (v) { | |
return FP.Parsers.Parser(function (input) { | |
return FP.Parsers.Success(v, input); | |
}); | |
}, | |
log: function (/*lazy*/ p, name) { | |
return FP.Parsers.Parser(function (input) { | |
console.log("trying " + name + " at " + input); | |
var r = p().apply(input); | |
console.log(name + " --> " + r); | |
return r; | |
}); | |
}, | |
rep: function (/*lazy*/ p) { | |
var s = FP.Parsers.success(FP.List.empty); | |
return FP.Parsers.rep1(p).or(function () { return s; }); | |
}, | |
rep1: function (/*lazy*/ p) { | |
return FP.Parsers.Parser(function (input) { | |
var elems, i, p0, res; | |
elems = []; | |
i = input; | |
p0 = p(); | |
res = p0.apply(input); | |
if (res.isa(FP.Parsers.Success)) { | |
while (res.isa(FP.Parsers.Success)) { | |
elems.push(res.result); | |
i = res.next; | |
res = p0.apply(i); | |
} | |
return FP.Parsers.Success(FP.List.fromArray(elems), i); | |
} else { | |
return res; | |
} | |
}); | |
}, | |
//rep1: function (/*lazy*/ first, /*lazy*/ p) | |
repN: function (num, /*lazy*/ p) { | |
if (num === 0) { | |
return FP.Parsers.success(FP.List.empty); | |
} | |
return FP.Parsers.Parser(function (input) { | |
var elems, i, p0, res; | |
elems = []; | |
i = input; | |
p0 = p(); | |
res = p0.apply(i); | |
while (res.isa(FP.Parsers.Success)) { | |
elems.push(res.result); | |
i = res.next; | |
if (num === elems.length) { | |
return FP.Parsers.Success(FP.List.fromArray(elems), i); | |
} | |
res = p0.apply(i); | |
} | |
return res; // NoSuccess | |
}); | |
}, | |
repsep: function (/*lazy*/ p, /*lazy*/ q) { | |
var s = FP.Parsers.success(FP.List.empty); | |
return FP.Parsers.rep1sep(p, q).or(function () { return s; }); | |
}, | |
rep1sep: function (/*lazy*/ p, /*lazy*/ q) { | |
return p().and(FP.Parsers.rep(q().andr(p))).to(function (res) { | |
return FP.List.Cons(res.head, res.tail); | |
}); | |
}, | |
// chainl1: function (/*lazy*/ p, /*lazy*/ q) { | |
// return this.chainl1(p, p, q) | |
// }, | |
chainl1: function (/*lazy*/ first, /*lazy*/ p, /*lazy*/ q) { | |
return first().and(FP.Parsers.rep(q().and(p))).to(function (res) { | |
return res.tail.foldLeft(res.head, function (a, fb) { return fb.head(a, fb.tail); }); | |
}); | |
}, | |
chainr1: function (/*lazy*/ p, /*lazy*/ q, combine, first) { | |
return p().and(this.rep(q().and(p))).to(function (res) { | |
return FP.List.Cons(FP.Parsers.Pair(combine, res.head), | |
res.tail).foldRight(first, function (fa, b) { return fa.head(fa.tail, b); } | |
); | |
}); | |
}, | |
opt: function (/*lazy*/ p) { | |
return p().to(function (x) { | |
return FP.Option.Some(x); | |
}).or(function () { | |
return FP.Parsers.success(FP.Option.empty); | |
}); | |
}, | |
not: function (/*lazy*/ p) { | |
return FP.Parsers.Parser(function (input) { | |
var r = p().apply(input); | |
if (r.successful) { | |
return FP.Parsers.Failure("Expected failure", input); | |
} else { | |
return FP.Parsers.Success(FP.Option.empty, input); | |
} | |
}); | |
}, | |
guard: function (/*lazy*/ p) { | |
return FP.Parsers.Parser(function (input) { | |
var r = p().apply(input); | |
if (r.successful) { | |
return FP.Parsers.Success(r.result, input); | |
} else { | |
return r; | |
} | |
}); | |
}, | |
//positioned: function (/*lazy*/ p) | |
//phrase: function (p) | |
mkList: function (pair) { return FP.List.Cons(pair.head, pair.tail); }, | |
fun: function (x) { return function () { return x; }; }, | |
lazyParser: function (x) { | |
var lit, r; | |
if (x instanceof String || (typeof x) === "string") { | |
lit = FP.Parsers.literal(x); | |
return function () { return lit; }; | |
} else if (x instanceof Function) { | |
// x is deemed to be a function which has the return value as Parser. | |
return x; | |
} else if (x instanceof Object) { | |
if("isa" in x && x.isa(FP.Parsers.Parser)) { | |
return function () { return x; }; | |
} else if (x instanceof RegExp) { | |
r = FP.Parsers.regexLiteral(x); | |
return function () { return r; }; | |
} else { | |
return FP.Parsers.err("unhandlable type"); | |
} | |
} else { | |
return FP.Parsers.err("unhandlable type"); | |
} | |
}, | |
seq: function () { | |
var count, parser, i; | |
count = arguments.length; | |
if (count === 0) { return FP.Parsers.err("at least one element must be specified"); } | |
parser = FP.Parsers.lazyParser(arguments[0])(); | |
i = 1; | |
while (i < count) { | |
parser = parser.and(FP.Parsers.lazyParser(arguments[i])); | |
i += 1; | |
} | |
return parser; | |
}, | |
or: function () { | |
var count, parser, i; | |
count = arguments.length; | |
if (count === 0) { return FP.Parsers.err("at least one element must be specified"); } | |
parser = FP.Parsers.lazyParser(arguments[0])(); | |
i = 1; | |
while (i < count) { | |
parser = parser.or(FP.Parsers.lazyParser(arguments[i])); | |
i += 1; | |
} | |
return parser; | |
} | |
}); | |
/************ Pair **************/ | |
FP.Parsers.Pair = MathJax.Object.Subclass({ | |
Init: function (head, tail) { | |
this.head = head; | |
this.tail = tail; | |
}, | |
toString: function () { return '(' + this.head + '~' + this.tail + ')'; } | |
}, { | |
unapply: function (x) { return FP.Option.Some([x.head, x.tail]); } | |
}); | |
/************ ParseResult **************/ | |
FP.Parsers.ParseResult = MathJax.Object.Subclass({ | |
Init: function () {}, | |
isEmpty: function () { return !this.successful; }, | |
getOrElse: function (/*lazy*/ defaultValue) { | |
if (this.isEmpty) { return defaultValue(); } else { return this.get(); } | |
} | |
}); | |
/************ Success **************/ | |
FP.Parsers.Success = FP.Parsers.ParseResult.Subclass({ | |
Init: function (result, next) { | |
this.result = result; | |
this.next = next; | |
}, | |
map: function (f) { return FP.Parsers.Success(f(this.result), this.next); }, | |
mapPartial: function (f, err) { | |
try { | |
return FP.Parsers.Success(f(this.result), this.next); | |
} catch (e) { | |
if ("isa" in e && e.isa(FP.MatchError)) { | |
return FP.Parsers.Failure(err(this.result), this.next); | |
} else { | |
throw e; | |
} | |
} | |
}, | |
flatMapWithNext: function (f) { return f(this.result).apply(this.next); }, | |
append: function (/*lazy*/ a) { return this; }, | |
get: function () { return this.result; }, | |
successful: true, | |
toString: function () { return '[' + this.next.pos() + '] parsed: ' + this.result; } | |
}, { | |
unapply: function (x) { return FP.Option.Some([x.result, x.next]); } | |
}); | |
/************ NoSuccess **************/ | |
FP.Parsers.NoSuccess = FP.Parsers.ParseResult.Subclass({ | |
Init: function () {}, | |
_setLastNoSuccess: function () { | |
var context = this.next.context; | |
if (context.lastNoSuccess === undefined || !this.next.pos().isLessThan(context.lastNoSuccess.next.pos())) { | |
context.lastNoSuccess = this; | |
} | |
}, | |
map: function (f) { return this; }, | |
mapPartial: function (f, error) { return this; }, | |
flatMapWithNext: function (f) { return this; }, | |
get: function () { return FP.Parsers.error("No result when parsing failed"); }, | |
successful: false | |
}); | |
/************ Failure **************/ | |
FP.Parsers.Failure = FP.Parsers.NoSuccess.Subclass({ | |
Init: function (msg, next) { | |
this.msg = msg; | |
this.next = next; | |
this._setLastNoSuccess(); | |
}, | |
append: function (/*lazy*/ a) { | |
var alt = a(); | |
if (alt.isa(FP.Parsers.Success)) { | |
return alt; | |
} else if (alt.isa(FP.Parsers.NoSuccess)) { | |
if (alt.next.pos().isLessThan(this.next.pos())) { | |
return this; | |
} else { | |
return alt; | |
} | |
} else { | |
throw FP.MatchError(alt); | |
} | |
}, | |
toString: function () { return ('[' + this.next.pos() + '] failure: ' + | |
this.msg + '\n\n' + this.next.pos().longString()); } | |
}, { | |
unapply: function (x) { return FP.Option.Some([x.msg, x.next]); } | |
}); | |
/************ Error **************/ | |
FP.Parsers.Error = FP.Parsers.NoSuccess.Subclass({ | |
Init: function (msg, next) { | |
this.msg = msg; | |
this.next = next; | |
this._setLastNoSuccess(); | |
}, | |
append: function (/*lazy*/ a) { return this; }, | |
toString: function () { return ('[' + this.next.pos() + '] error: ' + | |
this.msg + '\n\n' + this.next.pos().longString()); } | |
}, { | |
unapply: function (x) { return FP.Option.Some([x.msg, x.next]); } | |
}); | |
/************ Parser **************/ | |
FP.Parsers.Parser = MathJax.Object.Subclass({ | |
Init: function (f) { this.apply = f; }, | |
name: '', | |
named: function (name) { this.name = name; return this; }, | |
toString: function () { return 'Parser (' + this.name + ')'; }, | |
flatMap: function (f) { | |
var app = this.apply; | |
return FP.Parsers.Parser(function (input) { | |
return app(input).flatMapWithNext(f); | |
}); | |
}, | |
map: function (f) { | |
var app = this.apply; | |
return FP.Parsers.Parser(function (input) { | |
return app(input).map(f); | |
}); | |
}, | |
append: function (/*lazy*/ p) { | |
var app = this.apply; | |
return FP.Parsers.Parser(function (input) { | |
return app(input).append(function () { | |
return p().apply(input); | |
}); | |
}); | |
}, | |
and: function (/*lazy*/ p) { | |
return this.flatMap(function (a) { | |
return p().map(function (b) { | |
return FP.Parsers.Pair(a, b); | |
}); | |
}).named('~'); | |
}, | |
andr: function (/*lazy*/ p) { | |
return this.flatMap(function (a) { | |
return p().map(function (b) { | |
return b; | |
}); | |
}).named('~>'); | |
}, | |
andl: function (/*lazy*/ p) { | |
return this.flatMap(function (a) { | |
return p().map(function (b) { | |
return a; | |
}); | |
}).named('<~'); | |
}, | |
or: function (/*lazy*/ q) { return this.append(q).named("|"); }, | |
andOnce: function (/*lazy*/ p) { | |
var flatMap = this.flatMap; | |
return FP.Parsers.OnceParser(function () { | |
return flatMap(function (a) { | |
return FP.Parsers.commit(p).map(function (b) { | |
return FP.Parsers.Pair(a, b); | |
}); | |
}).named('~!'); | |
}); | |
}, | |
longestOr: function (/*lazy*/ q0) { | |
var app = this.apply; | |
return FP.Parsers.Parser(function (input) { | |
var res1, res2; | |
res1 = app(input); | |
res2 = q0()(input); | |
if (res1.successful) { | |
if (res2.successful) { | |
if (res2.next.pos().isLessThan(res1.next.pos())) { | |
return res1; | |
} else { | |
return res2; | |
} | |
} else { | |
return res1; | |
} | |
} else if (res2.successful) { | |
return res2; | |
} else if (res1.isa(FP.Parsers.Error)) { | |
return res1; | |
} else { | |
if (res2.next.pos().isLessThan(res1.next.pos())) { | |
return res1; | |
} else { | |
return res2; | |
} | |
} | |
}).named("|||"); | |
}, | |
to: function (f) { return this.map(f).named(this.toString() + '^^'); }, | |
ret: function (/*lazy*/ v) { | |
var app = this.apply; | |
return FP.Parsers.Parser(function (input) { | |
return app(input).map(function (x) { return v(); }); | |
}).named(this.toString() + "^^^"); | |
}, | |
toIfPossible: function (f, error) { | |
if (error === undefined) { | |
error = function (r) { return "Constructor function not defined at " + r; }; | |
} | |
var app = this.apply; | |
return FP.Parsers.Parser(function (input) { | |
return app(input).mapPartial(f, error); | |
}).named(this.toString() + "^?"); | |
}, | |
into: function (fq) { return this.flatMap(fq); }, | |
rep: function () { | |
var p = this; | |
return FP.Parsers.rep(function () { return p; }); | |
}, | |
chain: function (/*lazy*/ sep) { | |
var p, lp; | |
p = this; | |
lp = function () { return p; }; | |
return FP.Parsers.chainl1(lp, lp, sep); | |
}, | |
rep1: function () { | |
var p = this; | |
return FP.Parsers.rep1(function () { return p; }); | |
}, | |
opt: function () { | |
var p = this; | |
return FP.Parsers.opt(function () { return p; }); | |
} | |
}); | |
/************ OnceParser **************/ | |
FP.Parsers.OnceParser = FP.Parsers.Parser.Subclass({ | |
Init: function (f) { this.apply = f; }, | |
and: function (p) { | |
var flatMap = this.flatMap; | |
return FP.Parsers.OnceParser(function () { | |
return flatMap(function (a) { | |
return FP.Parsers.commit(p).map(function (b) { | |
return FP.Parsers.Pair(a, b); | |
}); | |
}); | |
}).named('~'); | |
} | |
}); | |
MathJax.Hub.Startup.signal.Post("Functional Programming library Ready"); | |
})(); | |
MathJax.Extension.xypic = { | |
version: "0.1", | |
constants: { | |
whiteSpaceRegex: /^(\s+|%[^\r\n]*(\r\n|\r|\n)?)+/, | |
unsupportedBrowserErrorMessage: "Unsupported Browser. Please open with Firefox/Safari/Chrome/Opera" | |
}, | |
signalHandler: { | |
signals: [], | |
hookedSignals: [], | |
chains: [], | |
chainSignal: function (successor, predecessors) { | |
for (var i = 0; i < predecessors.length; i++) { | |
MathJax.Extension.xypic.signalHandler.addSignal(predecessors[i]); | |
} | |
MathJax.Extension.xypic.signalHandler.chains.push({succ:successor, pred:predecessors}); | |
}, | |
addSignal: function (signal) { | |
var signals = MathJax.Extension.xypic.signalHandler.signals; | |
for (var i = 0; i < signals.length; i++) { | |
if (signals[i] === signal) { | |
return; | |
} | |
} | |
MathJax.Extension.xypic.signalHandler.signals.push(signal); | |
var handler = MathJax.Extension.xypic.signalHandler.handleSignal(signal); | |
MathJax.Hub.Register.StartupHook(signal, handler); | |
}, | |
handleSignal: function (signal) { | |
return function () { | |
MathJax.Extension.xypic.signalHandler.hookedSignals.push(signal); | |
MathJax.Extension.xypic.signalHandler.handleChains(); | |
} | |
}, | |
handleChains: function () { | |
var i = 0; | |
var chains = MathJax.Extension.xypic.signalHandler.chains; | |
var remainingChains = []; | |
var invokableSignals = []; | |
while (i < chains.length) { | |
var c = chains[i]; | |
var pred = c.pred; | |
var invokable = true; | |
for (var j = 0; j < pred.length; j++) { | |
var p = pred[j]; | |
if (!MathJax.Extension.xypic.signalHandler.listenedSignal(p)) { | |
invokable = false; | |
break; | |
} | |
} | |
if (invokable) { | |
invokableSignals.push(c.succ); | |
} else { | |
remainingChains.push(c); | |
} | |
i++; | |
} | |
MathJax.Extension.xypic.signalHandler.chains = remainingChains; | |
for (i = 0; i < invokableSignals.length; i++) { | |
MathJax.Hub.Startup.signal.Post(invokableSignals[i]); | |
} | |
}, | |
listenedSignal: function (signal) { | |
var signals = MathJax.Extension.xypic.signalHandler.hookedSignals; | |
for (var i = 0; i < signals.length; i++) { | |
if (signals[i] === signal) { | |
return true; | |
} | |
} | |
return false; | |
} | |
} | |
} | |
// "TeX Xy-pic" depends on "Functional Programming library" and "TeX Jax". | |
MathJax.Extension.xypic.signalHandler.chainSignal("TeX Xy-pic Require", ["Functional Programming library Ready", "TeX Jax Ready"]); | |
// "HTML-CSS Xy-pic Config" depends on "TeX Xy-pic" and "HTML-CSS Jax". | |
MathJax.Extension.xypic.signalHandler.chainSignal("HTML-CSS Xy-pic Config Require", ["TeX Xy-pic Ready", "HTML-CSS Jax Ready"]); | |
// "SVG Xy-pic Config" depends on "TeX Xy-pic" and "SVG Jax". | |
MathJax.Extension.xypic.signalHandler.chainSignal("SVG Xy-pic Config Require", ["TeX Xy-pic Ready", "SVG Jax Ready"]); | |
// "Device-Independent Xy-pic" depends on "TeX Xy-pic" OR "SVG Jax". | |
MathJax.Extension.xypic.signalHandler.chainSignal("Device-Independent Xy-pic Require", ["HTML-CSS Xy-pic Config Ready"]); | |
MathJax.Extension.xypic.signalHandler.chainSignal("Device-Independent Xy-pic Require", ["SVG Xy-pic Config Ready"]); | |
// "HTML-CSS Xy-pic" depends on "HTML-CSS Xy-pic Config" and "Device-Independent Xy-pic". | |
MathJax.Extension.xypic.signalHandler.chainSignal("HTML-CSS Xy-pic Require", ["HTML-CSS Xy-pic Config Ready", "Device-Independent Xy-pic Ready"]); | |
// "SVG Xy-pic" depends on "SVG Xy-pic Config" and "Device-Independent Xy-pic". | |
MathJax.Extension.xypic.signalHandler.chainSignal("SVG Xy-pic Require", ["SVG Xy-pic Config Ready", "Device-Independent Xy-pic Ready"]); | |
MathJax.Hub.Register.StartupHook("TeX Xy-pic Require",function () { | |
var FP = MathJax.Extension.fp; | |
var MML = MathJax.ElementJax.mml; | |
var TEX = MathJax.InputJax.TeX; | |
var TEXDEF = TEX.Definitions; | |
var xypic = MathJax.Extension.xypic; | |
var AST = xypic.AST = MathJax.Object.Subclass({}); | |
MathJax.Hub.Insert(TEXDEF, { | |
macros: { | |
//hole: ['Macro', '{\\bbox[3pt]{}}'] | |
hole: ['Macro', '{\\style{visibility:hidden}{x}}'], | |
objectstyle: ['Macro', '\\textstyle'], | |
labelstyle: ['Macro', '\\scriptstyle'], | |
twocellstyle: ['Macro', '\\scriptstyle'], | |
xybox: 'Xybox', | |
xymatrix: 'Xymatrix', | |
newdir: 'XypicNewdir', | |
includegraphics: 'Xyincludegraphics' | |
}, | |
environment: { | |
xy: ['ExtensionEnv', null, 'XYpic'] | |
} | |
}); | |
// override MathJax.InputJax.TeX.formatError function to display parse error. | |
var tex_formatError = TEX.formatError; | |
TEX.formatError = function (err, math, displaystyle, script) { | |
if (err.xyjaxError !== undefined) { | |
return err.toMML(); | |
} else { | |
return tex_formatError(err, math, displaystyle, script); | |
} | |
} | |
xypic.memoize = function (object, funcName) { | |
var func = object[funcName]; | |
var memo = function () { | |
var value = func.call(this); | |
var constFunc = function () { | |
return value; | |
} | |
constFunc.reset = reset; | |
object[funcName] = constFunc; | |
return value; | |
} | |
var reset = function () { | |
object[funcName] = memo; | |
} | |
memo.reset = reset; | |
reset(); | |
}; | |
AST.xypic = MML.mbase.Subclass({ | |
Init: function (cmd) { | |
this.data = []; | |
this.cmd = cmd; | |
}, | |
type: "xypic", | |
inferRow: false, | |
defaults: { | |
mathbackground: MML.INHERIT, | |
mathcolor: MML.INHERIT, | |
notation: MML.NOTATION.LONGDIV, | |
texClass: MML.TEXCLASS.ORD | |
}, | |
setTeXclass: MML.mbase.setSeparateTeXclasses, | |
toString: function () { return this.type + "(" + this.cmd + ")"; } | |
}); | |
AST.xypic.newdir = MML.mbase.Subclass({ | |
Init: function (cmd) { | |
this.data = []; | |
this.cmd = cmd; | |
}, | |
type: "newdir", | |
inferRow: false, | |
defaults: { | |
mathbackground: MML.INHERIT, | |
mathcolor: MML.INHERIT, | |
notation: MML.NOTATION.LONGDIV, | |
texClass: MML.TEXCLASS.ORD | |
}, | |
setTeXclass: MML.mbase.setSeparateTeXclasses, | |
toString: function () { return this.type + "(" + this.cmd + ")"; } | |
}); | |
AST.xypic.includegraphics = MML.mbase.Subclass({ | |
Init: function (cmd) { | |
this.data = []; | |
this.cmd = cmd; | |
}, | |
type: "includegraphics", | |
inferRow: false, | |
defaults: { | |
mathbackground: MML.INHERIT, | |
mathcolor: MML.INHERIT, | |
notation: MML.NOTATION.LONGDIV, | |
texClass: MML.TEXCLASS.ORD | |
}, | |
setTeXclass: MML.mbase.setSeparateTeXclasses, | |
toString: function () { return this.type + "(" + this.cmd + ")"; } | |
}); | |
// <pos-decor> ::= <pos> <decor> | |
AST.PosDecor = MathJax.Object.Subclass({ | |
Init: function (pos, decor) { | |
this.pos = pos; | |
this.decor = decor; | |
}, | |
toString: function () { | |
return this.pos.toString() + " " + this.decor; | |
} | |
}); | |
// <pos> | |
AST.Pos = MathJax.Object.Subclass({}); | |
// <pos> ::= <coord> <pos2>* | |
AST.Pos.Coord = MathJax.Object.Subclass({ | |
Init: function (coord, pos2s) { | |
this.coord = coord; | |
this.pos2s = pos2s; | |
}, | |
toString: function () { | |
return this.coord.toString() + " " + this.pos2s.mkString(" "); | |
} | |
}); | |
// <pos2> ::= '+' <coord> | |
AST.Pos.Plus = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return "+(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= '-' <coord> | |
AST.Pos.Minus = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return "-(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= '!' <coord> | |
AST.Pos.Skew = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return "!(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= '.' <coord> | |
AST.Pos.Cover = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return ".(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= ',' <coord> | |
AST.Pos.Then = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return ",(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= ';' <coord> | |
AST.Pos.SwapPAndC = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return ";(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= ':' <coord> | |
AST.Pos.SetBase = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return ":(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= '::' <coord> | |
AST.Pos.SetYBase = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return "::(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= '**' <object> | |
AST.Pos.ConnectObject = MathJax.Object.Subclass({ | |
Init: function (object) { | |
this.object = object; | |
}, | |
toString: function () { | |
return "**(" + this.object + ")"; | |
} | |
}); | |
// <pos2> ::= '*' <object> | |
AST.Pos.DropObject = MathJax.Object.Subclass({ | |
Init: function (object) { | |
this.object = object; | |
}, | |
toString: function () { | |
return "*(" + this.object + ")"; | |
} | |
}); | |
// <pos2> ::= '?' <place> | |
AST.Pos.Place = MathJax.Object.Subclass({ | |
Init: function (place) { | |
this.place = place; | |
}, | |
toString: function () { | |
return "?(" + this.place + ")"; | |
} | |
}); | |
// <pos2> ::= '@+' <coord> | |
AST.Pos.PushCoord = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return "@+(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= '@-' <coord> | |
AST.Pos.EvalCoordThenPop = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return "@-(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= '@=' <coord> | |
AST.Pos.LoadStack = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return "@=(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= '@@' <coord> | |
AST.Pos.DoCoord = MathJax.Object.Subclass({ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return "@@(" + this.coord + ")"; | |
} | |
}); | |
// <pos2> ::= '@i' | |
AST.Pos.InitStack = MathJax.Object.Subclass({ | |
Init: function () { | |
}, | |
toString: function () { | |
return "@i"; | |
} | |
}); | |
// <pos2> ::= '@(' | |
AST.Pos.EnterFrame = MathJax.Object.Subclass({ | |
Init: function () { | |
}, | |
toString: function () { | |
return "@("; | |
} | |
}); | |
// <pos2> ::= '@)' | |
AST.Pos.LeaveFrame = MathJax.Object.Subclass({ | |
Init: function () { | |
}, | |
toString: function () { | |
return "@)"; | |
} | |
}); | |
// <pos2> ::= '=' '"' <id> '"' | |
AST.Pos.SavePos = MathJax.Object.Subclass({ | |
Init: function (id) { | |
this.id = id; | |
}, | |
toString: function () { | |
return '="' + this.id + '"'; | |
} | |
}); | |
// <pos2> ::= '=' <coord> '"' <id> '"' | |
AST.Pos.SaveMacro = MathJax.Object.Subclass({ | |
Init: function (macro, id) { | |
this.macro = macro; | |
this.id = id; | |
}, | |
toString: function () { | |
return "=(" + this.macro + ' "' + this.id + '")'; | |
} | |
}); | |
// <pos2> ::= '=:' '"' <id> '"' | |
AST.Pos.SaveBase = MathJax.Object.Subclass({ | |
Init: function (id) { | |
this.id = id; | |
}, | |
toString: function () { | |
return '=:"' + this.id + '"'; | |
} | |
}); | |
// <pos2> ::= '=@' '"' <id> '"' | |
AST.Pos.SaveStack = MathJax.Object.Subclass({ | |
Init: function (id) { | |
this.id = id; | |
}, | |
toString: function () { | |
return '=@"' + this.id + '"'; | |
} | |
}); | |
// <coord> | |
AST.Coord = MathJax.Object.Subclass({}); | |
// <coord> ::= <vector> | |
AST.Coord.Vector = MathJax.Object.Subclass({ | |
Init: function (vector) { | |
this.vector = vector; | |
}, | |
toString: function () { | |
return this.vector.toString(); | |
} | |
}); | |
// <coord> ::= <empty> | 'c' | |
AST.Coord.C = MathJax.Object.Subclass({ | |
toString: function () { | |
return "c"; | |
} | |
}); | |
// <coord> ::= 'p' | |
AST.Coord.P = MathJax.Object.Subclass({ | |
toString: function () { | |
return "p"; | |
} | |
}); | |
// <coord> ::= 'x' | |
AST.Coord.X = MathJax.Object.Subclass({ | |
toString: function () { | |
return "x"; | |
} | |
}); | |
// <coord> ::= 'y' | |
AST.Coord.Y = MathJax.Object.Subclass({ | |
toString: function () { | |
return "y"; | |
} | |
}); | |
// <coord> ::= '"' <id> '"' | |
AST.Coord.Id = MathJax.Object.Subclass({ | |
Init: function (id) { | |
this.id = id; | |
}, | |
toString: function () { | |
return '"' + this.id + '"'; | |
} | |
}); | |
// <coord> ::= '{' <pos> <decor> '}' | |
AST.Coord.Group = MathJax.Object.Subclass({ | |
Init: function (posDecor) { | |
this.posDecor = posDecor; | |
}, | |
toString: function () { | |
return '{' + this.posDecor + '}'; | |
} | |
}); | |
// <coord> ::= 's' <digit> | |
// <coord> ::= 's' '{' <nonnegative-number> '}' | |
AST.Coord.StackPosition = MathJax.Object.Subclass({ | |
Init: function (number) { | |
this.number = number; | |
}, | |
toString: function () { | |
return 's{' + this.number + '}'; | |
} | |
}); | |
// coordinate for xymatrix | |
// <coord> ::= '[' ('"'<prefix>'"')? <number> ',' <number> ']' | |
AST.Coord.DeltaRowColumn = MathJax.Object.Subclass({ | |
/** | |
* @param {String} prefix name of the xymatrix | |
* @param {Number} dr rows below | |
* @param {Number} dc columns right | |
*/ | |
Init: function (prefix, dr, dc) { | |
this.prefix = prefix; | |
this.dr = dr; | |
this.dc = dc; | |
}, | |
toString: function () { | |
return '[' + (this.prefix === ''? '' : '"' + this.prefix + '"') + this.dr + "," + this.dc + "]"; | |
} | |
}); | |
// coordinate for xymatrix | |
// <coord> ::= '[' ('"'<prefix>'"')? ( 'l' | 'r' | 'u' | 'd' )* ']' | |
AST.Coord.Hops = MathJax.Object.Subclass({ | |
/** | |
* @param {String} prefix name of the xymatrix | |
* @param {List[String]} hops hops | |
*/ | |
Init: function (prefix, hops) { | |
this.prefix = prefix; | |
this.hops = hops; | |
}, | |
toString: function () { | |
return '[' + (this.prefix === ''? '' : '"' + this.prefix + '"') + this.hops.mkString("") + "]"; | |
} | |
}); | |
// coordinate for xymatrix | |
// <coord> ::= '[' ('"'<prefix>'"')? ( 'l' | 'r' | 'u' | 'd' )+ <place> ']' | |
AST.Coord.HopsWithPlace = MathJax.Object.Subclass({ | |
/** | |
* @param {String} prefix name of the xymatrix | |
* @param {List[String]} hops hops | |
* @param {AST.Pos.Place} place place | |
*/ | |
Init: function (prefix, hops, place) { | |
this.prefix = prefix; | |
this.hops = hops; | |
this.place = place; | |
}, | |
toString: function () { | |
return '[' + (this.prefix === ''? '' : '"' + this.prefix + '"') + this.hops.mkString("") + this.place + "]"; | |
} | |
}); | |
// <vector> | |
AST.Vector = MathJax.Object.Subclass({}); | |
// <vector> ::= '(' <factor> ',' <factor> ')' | |
AST.Vector.InCurBase = MathJax.Object.Subclass({ | |
Init: function (x, y) { | |
this.x = x; | |
this.y = y; | |
}, | |
toString: function () { | |
return "(" + this.x + ", " + this.y + ")"; | |
} | |
}); | |
// <vector> ::= '<' <dimen> ',' <dimen> '>' | |
// <vector> ::= '<' <dimen> '>' | |
AST.Vector.Abs = MathJax.Object.Subclass({ | |
Init: function (x, y) { | |
this.x = x; | |
this.y = y; | |
}, | |
toString: function () { | |
return "<" + this.x + ", " + this.y + ">"; | |
} | |
}); | |
// <vector> ::= 'a' '(' <number> ')' | |
AST.Vector.Angle = MathJax.Object.Subclass({ | |
Init: function (degree) { | |
this.degree = degree; | |
}, | |
toString: function () { | |
return "a(" + this.degree + ")"; | |
} | |
}); | |
// <vector> ::= '/' <direction> <dimen> '/' | |
AST.Vector.Dir = MathJax.Object.Subclass({ | |
Init: function (dir, dimen) { | |
this.dir = dir; | |
this.dimen = dimen; | |
}, | |
toString: function () { | |
return "/" + this.dir + " " + this.dimen + "/"; | |
} | |
}); | |
// <vector> ::= <corner> | |
// | <corner> '(' <factor> ')' | |
AST.Vector.Corner = MathJax.Object.Subclass({ | |
Init: function (corner, factor) { | |
this.corner = corner; | |
this.factor = factor; | |
}, | |
toString: function () { | |
return this.corner.toString() + "(" + this.factor + ")"; | |
} | |
}); | |
// <corner> ::= 'L' | 'R' | 'D' | 'U' | |
// | 'CL' | 'CR' | 'CD' | 'CU' | |
// | 'LD' | 'RD' | 'LU' | 'RU' | |
// | 'E' | 'P' | |
// | 'A' | |
AST.Corner = MathJax.Object.Subclass({}); | |
AST.Corner.L = MathJax.Object.Subclass({ | |
toString: function () { return "L"; } | |
}); | |
AST.Corner.R = MathJax.Object.Subclass({ | |
toString: function () { return "R"; } | |
}); | |
AST.Corner.D = MathJax.Object.Subclass({ | |
toString: function () { return "D"; } | |
}); | |
AST.Corner.U = MathJax.Object.Subclass({ | |
toString: function () { return "U"; } | |
}); | |
AST.Corner.CL = MathJax.Object.Subclass({ | |
toString: function () { return "CL"; } | |
}); | |
AST.Corner.CR = MathJax.Object.Subclass({ | |
toString: function () { return "CR"; } | |
}); | |
AST.Corner.CD = MathJax.Object.Subclass({ | |
toString: function () { return "CD"; } | |
}); | |
AST.Corner.CU = MathJax.Object.Subclass({ | |
toString: function () { return "CU"; } | |
}); | |
AST.Corner.LD = MathJax.Object.Subclass({ | |
toString: function () { return "LD"; } | |
}); | |
AST.Corner.RD = MathJax.Object.Subclass({ | |
toString: function () { return "RD"; } | |
}); | |
AST.Corner.LU = MathJax.Object.Subclass({ | |
toString: function () { return "LU"; } | |
}); | |
AST.Corner.RU = MathJax.Object.Subclass({ | |
toString: function () { return "RU"; } | |
}); | |
AST.Corner.NearestEdgePoint = MathJax.Object.Subclass({ | |
toString: function () { return "E"; } | |
}); | |
AST.Corner.PropEdgePoint = MathJax.Object.Subclass({ | |
toString: function () { return "P"; } | |
}); | |
AST.Corner.Axis = MathJax.Object.Subclass({ | |
toString: function () { return "A"; } | |
}); | |
// <place> ::= '<' <place> | |
// <place> ::= '>' <place> | |
// <place> ::= '(' <factor> ')' <place> | |
// <place> ::= '!' '{' <pos> '}' <slide> | |
// <place> ::= <slide> | |
AST.Place = MathJax.Object.Subclass({ | |
Init: function (shaveP, shaveC, factor, slide) { | |
this.shaveP = shaveP; | |
this.shaveC = shaveC; | |
this.factor = factor; | |
this.slide = slide; | |
}, | |
compound: function (that) { | |
return AST.Place( | |
this.shaveP + that.shaveP, | |
this.shaveC + that.shaveC, | |
that.factor === undefined? this.factor : that.factor, | |
that.slide); | |
}, | |
toString: function () { | |
var desc = ""; | |
for (var l = 0; l < this.shaveP; l++) { | |
desc += "<"; | |
} | |
for (var r = 0; r < this.shaveC; r++) { | |
desc += ">"; | |
} | |
if (this.factor !== undefined) { | |
desc += "(" + this.factor + ")"; | |
} | |
this.slide.dimen.foreach(function (d) { | |
desc += "/" + d + "/"; | |
}); | |
return desc; | |
} | |
}); | |
AST.Place.Factor = MathJax.Object.Subclass({ | |
Init: function (factor) { | |
this.factor = factor; | |
}, | |
isIntercept: false, | |
toString: function () { | |
return this.factor.toString(); | |
} | |
}); | |
AST.Place.Intercept = MathJax.Object.Subclass({ | |
Init: function (pos) { | |
this.pos = pos; | |
}, | |
isIntercept: true, | |
toString: function () { | |
return "!{" + this.pos + "}"; | |
} | |
}); | |
// <slide> ::= <empty> | |
// <slide> ::= '/' <dimen> '/' | |
AST.Slide = MathJax.Object.Subclass({ | |
Init: function (dimen) { | |
this.dimen = dimen; | |
}, | |
toString: function () { | |
return this.dimen.getOrElse(""); | |
} | |
}); | |
// <object> ::= <modifier>* <objectbox> | |
AST.Object = MathJax.Object.Subclass({ | |
Init: function (modifiers, object) { | |
this.modifiers = modifiers; | |
this.object = object; | |
}, | |
dirVariant: function () { return this.object.dirVariant(); }, | |
dirMain: function () { return this.object.dirMain(); }, | |
isDir: function () { return this.object.isDir(); }, | |
toString: function () { | |
return this.modifiers.mkString() + this.object.toString(); | |
} | |
}); | |
// <objectbox> | |
AST.ObjectBox = MathJax.Object.Subclass({ | |
dirVariant: function () { return undefined; }, | |
dirMain: function () { return undefined; }, | |
isDir: function () { return false; }, | |
isEmpty: false | |
}); | |
// <objectbox> ::= '{' <text> '}' | |
// <objectbox> ::= <TeX box> '{' <text> '}' | |
AST.ObjectBox.Text = AST.ObjectBox.Subclass({ | |
Init: function (math) { | |
this.math = math; | |
}, | |
toString: function () { return "{" + this.math.toString() + "}"; } | |
}); | |
AST.ObjectBox.Empty = AST.ObjectBox.Subclass({ | |
isEmpty: true, | |
toString: function () { return "{}"; } | |
}); | |
// <objectbox> ::= 'xymatrix' <xymatrix> | |
AST.ObjectBox.Xymatrix = AST.ObjectBox.Subclass({ | |
/** | |
* @param {AST.Command.Xymatrix} xymatrix xymatrix | |
*/ | |
Init: function (xymatrix) { | |
this.xymatrix = xymatrix; | |
}, | |
toString: function () { return this.xymatrix.toString(); } | |
}); | |
// <objectbox> ::= '\txt' <width> <style> '{' <text> '}' | |
AST.ObjectBox.Txt = AST.ObjectBox.Subclass({ | |
Init: function (width, textObject) { | |
this.width = width; | |
this.textObject = textObject; | |
}, | |
toString: function () { return "\\txt" + this.width + "{" + this.textObject.toString() + "}"; } | |
}); | |
AST.ObjectBox.Txt.Width = AST.ObjectBox.Subclass({ | |
}); | |
AST.ObjectBox.Txt.Width.Vector = AST.ObjectBox.Subclass({ | |
Init: function (vector) { | |
this.vector = vector; | |
}, | |
toString: function () { return this.vector.toString(); } | |
}); | |
AST.ObjectBox.Txt.Width.Default = AST.ObjectBox.Subclass({ | |
toString: function () { return ""; } | |
}); | |
// <objectbox> ::= '\object' <object> | |
AST.ObjectBox.WrapUpObject = AST.ObjectBox.Subclass({ | |
Init: function (object) { | |
this.object = object; | |
}, | |
toString: function () { return "\\object" + this.object.toString(); } | |
}); | |
// <objectbox> ::= '\composite' '{' <composite_object> '}' | |
// <composite_object> ::= <object> ( '*' <object> )* | |
AST.ObjectBox.CompositeObject = AST.ObjectBox.Subclass({ | |
Init: function (objects) { | |
this.objects = objects; | |
}, | |
toString: function () { return "\\composite{" + this.objects.mkString(" * ") + "}"; } | |
}); | |
// <objectbox> ::= '\xybox' '{' <pos> <decor> '}' | |
AST.ObjectBox.Xybox = AST.ObjectBox.Subclass({ | |
Init: function (posDecor) { | |
this.posDecor = posDecor; | |
}, | |
toString: function () { return "\\xybox{" + this.posDecor.toString() + "}"; } | |
}); | |
// <objectbox> ::= '\cir' <radius> '{' <cir> '}' | |
// <cir_radius> ::= <vector> | |
// | <empty> | |
// <cir> ::= <diag> <orient> <diag> | |
// | <empty> | |
AST.ObjectBox.Cir = AST.ObjectBox.Subclass({ | |
Init: function (radius, cir) { | |
this.radius = radius; | |
this.cir = cir; | |
}, | |
toString: function () { | |
return "\\cir"+this.radius+"{"+this.cir+"}"; | |
} | |
}); | |
AST.ObjectBox.Cir.Radius = MathJax.Object.Subclass({}); | |
AST.ObjectBox.Cir.Radius.Vector = MathJax.Object.Subclass({ | |
Init: function (vector) { | |
this.vector = vector; | |
}, | |
toString: function () { return this.vector.toString(); } | |
}); | |
AST.ObjectBox.Cir.Radius.Default = MathJax.Object.Subclass({ | |
toString: function () { return ""; } | |
}); | |
AST.ObjectBox.Cir.Cir = MathJax.Object.Subclass({}); | |
AST.ObjectBox.Cir.Cir.Segment = MathJax.Object.Subclass({ | |
Init: function (startDiag, orient, endDiag) { | |
this.startDiag = startDiag; | |
this.orient = orient; | |
this.endDiag = endDiag; | |
}, | |
toString: function () { return this.startDiag.toString()+this.orient+this.endDiag; } | |
}); | |
AST.ObjectBox.Cir.Cir.Full = MathJax.Object.Subclass({ | |
toString: function () { return ""; } | |
}); | |
// <objectbox> ::= '\dir' <variant> '{' <main> '}' | |
// <variant> ::= '^' | '_' | '0' | '1' | '2' | '3' | <empty> | |
// <main> ::= ('-' | '.' | '~' | '>' | '<' | '(' | ')' | '`' | "'" | '|' | '*' | '+' | 'x' | '/' | 'o' | '=' | ':' | /[a-zA-Z@ ]/)* | |
AST.ObjectBox.Dir = AST.ObjectBox.Subclass({ | |
Init: function (variant, main) { | |
this.variant = variant; | |
this.main = main; | |
}, | |
dirVariant: function () { return this.variant; }, | |
dirMain: function () { return this.main; }, | |
isDir: function () { return true; }, | |
toString: function () { return "\\dir" + this.variant + "{" + this.main + "}"; } | |
}); | |
// <objectbox> ::= '\crv' <curve-modifier> '{' <curve-object> <curve-poslist> '}' | |
AST.ObjectBox.Curve = AST.ObjectBox.Subclass({ | |
Init: function (modifiers, objects, poslist) { | |
this.modifiers = modifiers; | |
this.objects = objects; | |
this.poslist = poslist; | |
}, | |
dirVariant: function () { return ""; }, | |
dirMain: function () { return "-"; }, | |
isDir: function () { return false; }, | |
toString: function () { return "\\curve"+this.modifiers.mkString("")+"{"+this.objects.mkString(" ")+" "+this.poslist.mkString("&")+"}"; } | |
}); | |
// <curve-modifier> ::= ( '~' <curve-option> )* | |
// <curve-option> ::= 'p' | 'P' | 'l' | 'L' | 'c' | 'C' | |
// | 'pc' | 'pC' | 'Pc' | 'PC' | |
// | 'lc' | 'lC' | 'Lc' | 'LC' | |
// | 'cC' | |
AST.ObjectBox.Curve.Modifier = MathJax.Object.Subclass({}); | |
AST.ObjectBox.Curve.Modifier.p = MathJax.Object.Subclass({ | |
toString: function () { return "~p"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.P = MathJax.Object.Subclass({ | |
toString: function () { return "~P"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.l = MathJax.Object.Subclass({ | |
toString: function () { return "~l"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.L = MathJax.Object.Subclass({ | |
toString: function () { return "~L"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.c = MathJax.Object.Subclass({ | |
toString: function () { return "~c"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.C = MathJax.Object.Subclass({ | |
toString: function () { return "~C"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.pc = MathJax.Object.Subclass({ | |
toString: function () { return "~pc"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.pC = MathJax.Object.Subclass({ | |
toString: function () { return "~pC"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.Pc = MathJax.Object.Subclass({ | |
toString: function () { return "~Pc"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.PC = MathJax.Object.Subclass({ | |
toString: function () { return "~PC"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.lc = MathJax.Object.Subclass({ | |
toString: function () { return "~lc"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.lC = MathJax.Object.Subclass({ | |
toString: function () { return "~lC"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.Lc = MathJax.Object.Subclass({ | |
toString: function () { return "~Lc"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.LC = MathJax.Object.Subclass({ | |
toString: function () { return "~LC"; } | |
}); | |
AST.ObjectBox.Curve.Modifier.cC = MathJax.Object.Subclass({ | |
toString: function () { return "~cC"; } | |
}); | |
// <curve-object> ::= <empty> | |
// | '~*' <object> <curve-object> | |
// | '~**' <object> <curve-object> | |
AST.ObjectBox.Curve.Object = MathJax.Object.Subclass({}); | |
AST.ObjectBox.Curve.Object.Drop = MathJax.Object.Subclass({ | |
Init: function (object) { | |
this.object = object; | |
}, | |
toString: function () { return "~*" + this.object; } | |
}); | |
AST.ObjectBox.Curve.Object.Connect = MathJax.Object.Subclass({ | |
Init: function (object) { | |
this.object = object; | |
}, | |
toString: function () { return "~**" + this.object; } | |
}); | |
// <curve-poslist> ::= <empty> ^^ Empty List | |
// | '&' <curve-poslist2> ^^ (c, <poslist>) | |
// | <nonemptyPos> ^^ (<nonemptyPos>, Nil) | |
// | <nonemptyPos> '&' <curve-poslist2> ^^ (<nonemptyPos>, <poslist>) | |
// | '~@' ^^ (~@, Nil) | |
// | '~@' '&' <curve-poslist2> ^^ (~@, <poslist>) | |
// <curve-poslist2> ::= <empty> ^^ (c, Nil) | |
// | '&' <curve-poslist2> ^^ (c, <poslist>) | |
// | <nonemptyPos> ^^ (<nonemptyPos>, Nil) | |
// | <nonemptyPos> '&' <curve-poslist2> ^^ (<nonemptyPos>, <poslist>) | |
// | '~@' ^^ (~@, Nil) | |
// | '~@' '&' <curve-poslist2> ^^ (~@, <poslist>) | |
AST.ObjectBox.Curve.PosList = MathJax.Object.Subclass({}); | |
AST.ObjectBox.Curve.PosList.CurPos = MathJax.Object.Subclass({ | |
toString: function () { return ""; } | |
}); | |
AST.ObjectBox.Curve.PosList.Pos = MathJax.Object.Subclass({ | |
Init: function (pos) { | |
this.pos = pos; | |
}, | |
toString: function () { return this.pos.toString(); } | |
}); | |
AST.ObjectBox.Curve.PosList.AddStack = MathJax.Object.Subclass({ | |
toString: function () { return "~@"; } | |
}); | |
// <modifier> | |
AST.Modifier = MathJax.Object.Subclass({ | |
}); | |
// <modifier> ::= '!' <vector> | |
AST.Modifier.Vector = AST.Modifier.Subclass({ | |
Init: function (vector) { | |
this.vector = vector; | |
}, | |
toString: function () { return "!" + this.vector; } | |
}); | |
// <modifier> ::= '!' | |
AST.Modifier.RestoreOriginalRefPoint = AST.Modifier.Subclass({ | |
toString: function () { return "!"; } | |
}); | |
// <modifier> ::= <add-op> <size> | |
// <add-op> ::= '+' | '-' | '=' | '+=' | '-=' | |
// <size> ::= <vector> | <empty> | |
AST.Modifier.AddOp = AST.Modifier.Subclass({ | |
Init: function (op, size) { | |
this.op = op; | |
this.size = size; | |
}, | |
toString: function () { return this.op.toString() + " " + this.size; } | |
}); | |
AST.Modifier.AddOp.Grow = MathJax.Object.Subclass({ | |
toString: function () { return '+'; } | |
}); | |
AST.Modifier.AddOp.Shrink = MathJax.Object.Subclass({ | |
toString: function () { return '-'; } | |
}); | |
AST.Modifier.AddOp.Set = MathJax.Object.Subclass({ | |
toString: function () { return '='; } | |
}); | |
AST.Modifier.AddOp.GrowTo = MathJax.Object.Subclass({ | |
toString: function () { return '+='; } | |
}); | |
AST.Modifier.AddOp.ShrinkTo = MathJax.Object.Subclass({ | |
toString: function () { return '-='; } | |
}); | |
AST.Modifier.AddOp.VactorSize = MathJax.Object.Subclass({ | |
Init: function (vector) { | |
this.vector = vector; | |
}, | |
isDefault: false, | |
toString: function () { return this.vector.toString(); } | |
}); | |
AST.Modifier.AddOp.DefaultSize = MathJax.Object.Subclass({ | |
isDefault: true, | |
toString: function () { return ""; } | |
}); | |
// <modifier> ::= '[' <shape> ']' | |
// <shape> ::= '.' | |
// | <frame_shape> | |
// | <alphabets> | |
// | '=' <alphabets> | |
// | <empty> | |
// <alphabets> ::= /[a-zA-Z]+/ | |
AST.Modifier.Shape = MathJax.Object.Subclass({}); | |
AST.Modifier.Shape.Point = AST.Modifier.Subclass({ | |
toString: function () { return "[.]"; } | |
}); | |
AST.Modifier.Shape.Rect = AST.Modifier.Subclass({ | |
toString: function () { return "[]"; } | |
}); | |
AST.Modifier.Shape.Alphabets = AST.Modifier.Subclass({ | |
Init: function (alphabets) { | |
this.alphabets = alphabets; | |
}, | |
toString: function () { return "[" + this.alphabets + "]"; } | |
}); | |
AST.Modifier.Shape.DefineShape = AST.Modifier.Subclass({ | |
Init: function (shape) { | |
this.shape = shape; | |
}, | |
toString: function () { return "[" + this.shape + "]"; } | |
}); | |
// 以下はxypic.ModifierRepositoryに格納されるもの | |
AST.Modifier.Shape.Circle = AST.Modifier.Subclass({ | |
toString: function () { return "[o]"; } | |
}); | |
AST.Modifier.Shape.L = AST.Modifier.Subclass({ | |
toString: function () { return "[l]"; } | |
}); | |
AST.Modifier.Shape.R = AST.Modifier.Subclass({ | |
toString: function () { return "[r]"; } | |
}); | |
AST.Modifier.Shape.U = AST.Modifier.Subclass({ | |
toString: function () { return "[u]"; } | |
}); | |
AST.Modifier.Shape.D = AST.Modifier.Subclass({ | |
toString: function () { return "[d]"; } | |
}); | |
AST.Modifier.Shape.C = AST.Modifier.Subclass({ | |
toString: function () { return "[c]"; } | |
}); | |
AST.Modifier.Shape.ChangeColor = AST.Modifier.Subclass({ | |
Init: function (colorName) { | |
this.colorName = colorName; | |
}, | |
toString: function () { return "[" + this.colorName + "]"; } | |
}); | |
// ユーザ定義されたshape | |
AST.Modifier.Shape.CompositeModifiers = AST.Modifier.Subclass({ | |
/** | |
* @param {List[AST.Modifier.Shape.*]} modifiers ユーザ定義されたmodifierのリスト | |
*/ | |
Init: function (modifiers) { | |
this.modifiers = modifiers; | |
}, | |
toString: function () { return this.modifiers.mkString(""); } | |
}); | |
// <frame_shape> ::= 'F' <frame_main> ( ':' ( <frame_radius_vector> | <color_name> ))* | |
AST.Modifier.Shape.Frame = AST.Modifier.Subclass({ | |
Init: function (main, options) { | |
this.main = main; | |
this.options = options; | |
}, | |
toString: function () { | |
return "[F" + this.main + this.options.mkString("") + "]"; | |
} | |
}); | |
AST.Modifier.Shape.Frame.Radius = MathJax.Object.Subclass({ | |
Init: function (vector) { | |
this.vector = vector; | |
}, | |
toString: function () { | |
return ":" + this.vector; | |
} | |
}); | |
// <color_name> ::= /[a-zA-Z][a-zA-Z0-9]*/ | |
AST.Modifier.Shape.Frame.Color = MathJax.Object.Subclass({ | |
Init: function (colorName) { | |
this.colorName = colorName; | |
}, | |
toString: function () { | |
return ":" + this.colorName; | |
} | |
}); | |
// <modifier> ::= 'i' | |
AST.Modifier.Invisible = AST.Modifier.Subclass({ | |
toString: function () { return "i"; } | |
}); | |
// <modifier> ::= 'h' | |
AST.Modifier.Hidden = AST.Modifier.Subclass({ | |
toString: function () { return "h"; } | |
}); | |
// <modifier> ::= <nonempty-direction> | |
AST.Modifier.Direction = AST.Modifier.Subclass({ | |
Init: function (direction) { | |
this.direction = direction; | |
}, | |
toString: function () { return this.direction.toString(); } | |
}); | |
// <direction> | |
AST.Direction = MathJax.Object.Subclass({}); | |
// <direction> ::= <direction0> <direction1>* | |
AST.Direction.Compound = MathJax.Object.Subclass({ | |
Init: function (dir, rots) { | |
this.dir = dir; | |
this.rots = rots; | |
}, | |
toString: function () { | |
return this.dir.toString() + this.rots.mkString(); | |
} | |
}); | |
// <direction0> ::= <diag> | |
AST.Direction.Diag = MathJax.Object.Subclass({ | |
Init: function (diag) { | |
this.diag = diag; | |
}, | |
toString: function () { return this.diag.toString(); } | |
}); | |
// <direction0> ::= 'v' <vector> | |
AST.Direction.Vector = MathJax.Object.Subclass({ | |
Init: function (vector) { | |
this.vector = vector; | |
}, | |
toString: function () { return "v" + this.vector.toString(); } | |
}); | |
// <direction0> ::= 'q' '{' <pos> <decor> '}' | |
AST.Direction.ConstructVector = MathJax.Object.Subclass({ | |
Init: function (posDecor) { | |
this.posDecor = posDecor; | |
}, | |
toString: function () { return "q{" + this.posDecor.toString() + "}"; } | |
}); | |
// <direction1> ::= ':' <vector> | |
AST.Direction.RotVector = MathJax.Object.Subclass({ | |
Init: function (vector) { | |
this.vector = vector; | |
}, | |
toString: function () { return ":" + this.vector.toString(); } | |
}); | |
// <direction1> ::= '_' | |
AST.Direction.RotAntiCW = MathJax.Object.Subclass({ | |
toString: function () { return "_"; } | |
}); | |
// <direction1> ::= '^' | |
AST.Direction.RotCW = MathJax.Object.Subclass({ | |
toString: function () { return "^"; } | |
}); | |
// <diag> | |
AST.Diag = MathJax.Object.Subclass({}); | |
// <diag> ::= <empty> | |
AST.Diag.Default = MathJax.Object.Subclass({ | |
toString: function () { return ""; } | |
}); | |
// <diag> ::= 'l' | 'r' | 'd' | 'u' | 'ld' | 'rd' | 'lu' | 'ru' | |
AST.Diag.Angle = MathJax.Object.Subclass({ | |
toString: function () { return this.symbol; } | |
}); | |
AST.Diag.LD = AST.Diag.Angle.Subclass({ | |
symbol: 'ld', | |
ang: -3*Math.PI/4, | |
turn: function (orient) { | |
return (orient === "^"? AST.Diag.RD() : AST.Diag.LU()); | |
} | |
}); | |
AST.Diag.RD = AST.Diag.Angle.Subclass({ | |
symbol: 'rd', | |
ang: -Math.PI/4, | |
turn: function (orient) { | |
return (orient === "^"? AST.Diag.RU() : AST.Diag.LD()); | |
} | |
}); | |
AST.Diag.LU = AST.Diag.Angle.Subclass({ | |
symbol: 'lu', | |
ang: 3*Math.PI/4, | |
turn: function (orient) { | |
return (orient === "^"? AST.Diag.LD() : AST.Diag.RU()); | |
} | |
}); | |
AST.Diag.RU = AST.Diag.Angle.Subclass({ | |
symbol: 'ru', | |
ang: Math.PI/4, | |
turn: function (orient) { | |
return (orient === "^"? AST.Diag.LU() : AST.Diag.RD()); | |
} | |
}); | |
AST.Diag.L = AST.Diag.Angle.Subclass({ | |
symbol: 'l', | |
ang: Math.PI, | |
turn: function (orient) { | |
return (orient === "^"? AST.Diag.D() : AST.Diag.U()); | |
} | |
}); | |
AST.Diag.R = AST.Diag.Angle.Subclass({ | |
symbol: 'r', | |
ang: 0, | |
turn: function (orient) { | |
return (orient === "^"? AST.Diag.U() : AST.Diag.D()); | |
} | |
}); | |
AST.Diag.D = AST.Diag.Angle.Subclass({ | |
symbol: 'd', | |
ang: -Math.PI/2, | |
turn: function (orient) { | |
return (orient === "^"? AST.Diag.R() : AST.Diag.L()); | |
} | |
}); | |
AST.Diag.U = AST.Diag.Angle.Subclass({ | |
symbol: 'u', | |
ang: Math.PI/2, | |
turn: function (orient) { | |
return (orient === "^"? AST.Diag.L() : AST.Diag.R()); | |
} | |
}); | |
// <objectbox> ::= '\frm' <frame_radius> '{' <frame_main> '}' | |
// <frame_radius> ::= <frame_radius_vector> | |
// | <empty> | |
// <frame_main> ::= ( '-' | '=' | '.' | ',' | 'o' | 'e' | '*' )* | |
// | ( '_' | '^' )? ( '\{' | '\}' | '(' | ')' ) | |
// <frame_radius_vector> ::= '<' <dimen> ',' <dimen> '>' | |
// | '<' <dimen> '>' | |
AST.ObjectBox.Frame = AST.ObjectBox.Subclass({ | |
Init: function (radius, main) { | |
this.radius = radius; | |
this.main = main; | |
}, | |
toString: function () { | |
return "\\frm"+this.radius+"{"+this.main+"}"; | |
} | |
}); | |
AST.ObjectBox.Frame.Radius = MathJax.Object.Subclass({}); | |
AST.ObjectBox.Frame.Radius.Vector = MathJax.Object.Subclass({ | |
Init: function (vector) { | |
this.vector = vector; | |
}, | |
toString: function () { return this.vector.toString(); } | |
}); | |
AST.ObjectBox.Frame.Radius.Default = MathJax.Object.Subclass({ | |
toString: function () { return ""; } | |
}); | |
// <decor> ::= <command>* | |
AST.Decor = MathJax.Object.Subclass({ | |
Init: function (commands) { | |
this.commands = commands; | |
}, | |
toString: function () { | |
return this.commands.mkString(" "); | |
} | |
}); | |
AST.Command = MathJax.Object.Subclass({}); | |
// <command> ::= '\save' <pos> | |
AST.Command.Save = MathJax.Object.Subclass({ | |
Init: function (pos) { | |
this.pos = pos; | |
}, | |
toString: function () { | |
return "\\save " + this.pos; | |
} | |
}); | |
// <command> ::= '\restore' | |
AST.Command.Restore = MathJax.Object.Subclass({ | |
toString: function () { | |
return "\\restore"; | |
} | |
}); | |
// <command> ::= '\POS' <pos> | |
AST.Command.Pos = MathJax.Object.Subclass({ | |
Init: function (pos) { | |
this.pos = pos; | |
}, | |
toString: function () { | |
return "\\POS " + this.pos; | |
} | |
}); | |
// <command> ::= '\afterPOS' '{' <decor> '}' <pos> | |
AST.Command.AfterPos = MathJax.Object.Subclass({ | |
Init: function (decor, pos) { | |
this.decor = decor; | |
this.pos = pos; | |
}, | |
toString: function () { | |
return "\\afterPOS{" + this.decor + "} " + this.pos; | |
} | |
}); | |
// <command> ::= '\drop' <object> | |
AST.Command.Drop = MathJax.Object.Subclass({ | |
Init: function (object) { | |
this.object = object; | |
}, | |
toString: function () { | |
return "\\drop " + this.object; | |
} | |
}); | |
// <command> ::= '\connect' <object> | |
AST.Command.Connect = MathJax.Object.Subclass({ | |
Init: function (object) { | |
this.object = object; | |
}, | |
toString: function () { | |
return "\\connect " + this.object; | |
} | |
}); | |
// <command> ::= '\relax' | |
AST.Command.Relax = MathJax.Object.Subclass({ | |
toString: function () { | |
return "\\relax"; | |
} | |
}); | |
// <command> ::= '\xyignore' '{' <pos> <decor> '}' | |
AST.Command.Ignore = MathJax.Object.Subclass({ | |
Init: function (pos, decor) { | |
this.pos = pos; | |
this.decor = decor; | |
}, | |
toString: function () { | |
return "\\ignore{" + this.pos + " " + this.decor + "}"; | |
} | |
}); | |
// <command> ::= '\xyshowAST' '{' <pos> <decor> '}' | |
AST.Command.ShowAST = MathJax.Object.Subclass({ | |
Init: function (pos, decor) { | |
this.pos = pos; | |
this.decor = decor; | |
}, | |
toString: function () { | |
return "\\xyshowAST{" + this.pos + " " + this.decor + "}"; | |
} | |
}); | |
// <command> ::= '\PATH' <path> | |
AST.Command.Path = MathJax.Object.Subclass({ | |
Init: function (path) { | |
this.path = path; | |
}, | |
toString: function () { | |
return "\\PATH " + this.path; | |
} | |
}); | |
// <command> ::= '\afterPATH' '{' <decor> '}' <path> | |
AST.Command.AfterPath = MathJax.Object.Subclass({ | |
Init: function (decor, path) { | |
this.decor = decor; | |
this.path = path; | |
}, | |
toString: function () { | |
return "\\afterPATH{" + this.decor + "} " + this.path; | |
} | |
}); | |
// <path> ::= <path2>(Nil) | |
AST.Command.Path.Path = MathJax.Object.Subclass({ | |
Init: function (pathElements) { | |
this.pathElements = pathElements; | |
}, | |
toString: function () { | |
return this.pathElements.mkString("[", ", ", "]"); | |
} | |
}); | |
// <path2> ::= '~' <action> '{' <pos> <decor> '}' <path2>(fc) | |
// <action> ::= '=' | '/' | |
AST.Command.Path.SetBeforeAction = MathJax.Object.Subclass({ | |
Init: function (posDecor) { | |
this.posDecor = posDecor; | |
}, | |
toString: function () { | |
return "~={" + this.posDecor + "}"; | |
} | |
}); | |
AST.Command.Path.SetAfterAction = MathJax.Object.Subclass({ | |
Init: function (posDecor) { | |
this.posDecor = posDecor; | |
}, | |
toString: function () { | |
return "~/{" + this.posDecor + "}"; | |
} | |
}); | |
// <path2> ::= '~' <which> '{' <labels> '}' <path2>(fc) | |
// <which> ::= '<' | '>' | '+' | |
AST.Command.Path.AddLabelNextSegmentOnly = MathJax.Object.Subclass({ | |
Init: function (labels) { | |
this.labels = labels; | |
}, | |
toString: function () { | |
return "~<{" + this.labels + "}"; | |
} | |
}); | |
AST.Command.Path.AddLabelLastSegmentOnly = MathJax.Object.Subclass({ | |
Init: function (labels) { | |
this.labels = labels; | |
}, | |
toString: function () { | |
return "~>{" + this.labels + "}"; | |
} | |
}); | |
AST.Command.Path.AddLabelEverySegment = MathJax.Object.Subclass({ | |
Init: function (labels) { | |
this.labels = labels; | |
}, | |
toString: function () { | |
return "~+{" + this.labels + "}"; | |
} | |
}); | |
// <path2> ::= "'" <segment> <path2>(fc) | |
AST.Command.Path.StraightSegment = MathJax.Object.Subclass({ | |
Init: function (segment) { | |
this.segment = segment; | |
}, | |
toString: function () { | |
return "'" + this.segment; | |
} | |
}); | |
// <path2> ::= '`' <turn> <segment> <path2>(fc) | |
AST.Command.Path.TurningSegment = MathJax.Object.Subclass({ | |
Init: function (turn, segment) { | |
this.turn = turn; | |
this.segment = segment; | |
}, | |
toString: function () { | |
return "`" + this.turn + " " + this.segment; | |
} | |
}); | |
// <path2> ::= <segment> | |
AST.Command.Path.LastSegment = MathJax.Object.Subclass({ | |
Init: function (segment) { | |
this.segment = segment; | |
}, | |
toString: function () { | |
return this.segment.toString(); | |
} | |
}); | |
// <turn> ::= <diag> <turn-radius> | |
AST.Command.Path.Turn = MathJax.Object.Subclass({}); | |
AST.Command.Path.Turn.Diag = MathJax.Object.Subclass({ | |
Init: function (diag, radius) { | |
this.diag = diag; | |
this.radius = radius; | |
}, | |
toString: function () { | |
return this.diag.toString() + " " + this.radius; | |
} | |
}); | |
// <turn> ::= <cir> <turnradius> | |
AST.Command.Path.Turn.Cir = MathJax.Object.Subclass({ | |
Init: function (cir, radius) { | |
this.cir = cir; | |
this.radius = radius; | |
}, | |
toString: function () { | |
return this.cir.toString() + " " + this.radius; | |
} | |
}); | |
// <turn-radius> ::= <empty> | '/' <dimen> | |
AST.Command.Path.TurnRadius = MathJax.Object.Subclass({}); | |
AST.Command.Path.TurnRadius.Default = MathJax.Object.Subclass({ | |
toString: function () { | |
return ""; | |
} | |
}); | |
AST.Command.Path.TurnRadius.Dimen = MathJax.Object.Subclass({ | |
Init: function (dimen) { | |
this.dimen = dimen; | |
}, | |
toString: function () { | |
return "/" + this.dimen; | |
} | |
}); | |
// <segment> ::= <nonempty-pos> <slide> <labels> | |
AST.Command.Path.Segment = MathJax.Object.Subclass({ | |
Init: function (pos, slide, labels) { | |
this.pos = pos; | |
this.slide = slide; | |
this.labels = labels; | |
}, | |
toString: function () { | |
return this.pos.toString() + " " + this.slide + " " + this.labels; | |
} | |
}); | |
// <labels> ::= <label>* | |
AST.Command.Path.Labels = MathJax.Object.Subclass({ | |
Init: function (labels) { | |
this.labels = labels; | |
}, | |
toString: function () { | |
return this.labels.mkString(" "); | |
} | |
}); | |
// <label> ::= '^' <anchor> <it> <alias>? | |
// <anchor> ::= '-' | <place> | |
// <it> ::= ( '[' <shape> ']' )* <it2> | |
// <it2> ::= <digit> | <letter> | |
// | '{' <text> '}' | |
// | '*' <object> | |
// | '@' <dir> | |
AST.Command.Path.Label = MathJax.Object.Subclass({ | |
Init: function (anchor, it, aliasOption) { | |
this.anchor = anchor; | |
this.it = it; | |
this.aliasOption = aliasOption; | |
} | |
}); | |
AST.Command.Path.Label.Above = AST.Command.Path.Label.Subclass({ | |
toString: function () { | |
return "^(" + this.anchor + " " + this.it + " " + this.aliasOption + ")"; | |
} | |
}); | |
// <label> ::= '_' <anchor> <it> <alias>? | |
AST.Command.Path.Label.Below = AST.Command.Path.Label.Subclass({ | |
toString: function () { | |
return "_(" + this.anchor + " " + this.it + " " + this.aliasOption + ")"; | |
} | |
}); | |
// <label> ::= '|' <anchor> <it> <alias>? | |
AST.Command.Path.Label.At = AST.Command.Path.Label.Subclass({ | |
toString: function () { | |
return "|(" + this.anchor + " " + this.it + " " + this.aliasOption + ")"; | |
} | |
}); | |
// <command> ::= '\ar' ( <arrow_form> )* <path> | |
AST.Command.Ar = MathJax.Object.Subclass({ | |
Init: function (forms, path) { | |
this.forms = forms; | |
this.path = path; | |
}, | |
toString: function () { | |
return "\\ar " + this.forms.mkString(" ") + " " + this.path; | |
} | |
}); | |
// <arrow_form> | |
AST.Command.Ar.Form = MathJax.Object.Subclass({}); | |
// <arrow_form> ::= '@' <variant> ( '{' <tip> ( <conn> <tip> )? '}' )? | |
// <variant> ::= /[^_0123]/ | <empty> | |
AST.Command.Ar.Form.BuildArrow = AST.Command.Ar.Form.Subclass({ | |
/** | |
* @param {String} variant variant | |
* @param {AST.Command.Ar.Form.Tip.*} tailTip arrow tail | |
* @param {AST.Command.Ar.Form.Conn.*} stemConn arrow stem | |
* @param {AST.Command.Ar.Form.Tip.*} headTip arrow head | |
*/ | |
Init: function (variant, tailTip, stemConn, headTip) { | |
this.variant = variant; | |
this.tailTip = tailTip; | |
this.stemConn = stemConn; | |
this.headTip = headTip; | |
}, | |
toString: function () { | |
return "@" + this.variant + "{" + this.tailTip.toString() + ", " + this.stemConn.toString() + ", " + this.headTip.toString() + "}"; | |
} | |
}); | |
// <arrow_form> ::= '@' <variant> | |
AST.Command.Ar.Form.ChangeVariant = AST.Command.Ar.Form.Subclass({ | |
/** | |
* @param {String} variant variant | |
*/ | |
Init: function (variant) { | |
this.variant = variant; | |
}, | |
toString: function () { | |
return "@" + this.variant; | |
} | |
}); | |
// <tip> ::= /[<>()|'`+/a-zA-Z ]+/ | |
// | <arrow_dir> | |
// | <empty> | |
// <arrow_dir> ::= '*' <object> | |
// | <dir> | |
AST.Command.Ar.Form.Tip = MathJax.Object.Subclass({}); | |
AST.Command.Ar.Form.Tip.Tipchars = MathJax.Object.Subclass({ | |
/** | |
* @param {String} tipchars tip characters | |
*/ | |
Init: function (tipchars) { | |
this.tipchars = tipchars; | |
}, | |
toString: function () { | |
return this.tipchars; | |
} | |
}); | |
AST.Command.Ar.Form.Tip.Object = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Object} object object as a dir | |
*/ | |
Init: function (object) { | |
this.object = object; | |
}, | |
toString: function () { | |
return "*" + this.object; | |
} | |
}); | |
AST.Command.Ar.Form.Tip.Dir = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.ObjectBox.Dir} dir dir | |
*/ | |
Init: function (dir) { | |
this.dir = dir; | |
}, | |
toString: function () { | |
return this.dir; | |
} | |
}); | |
// <conn> ::= /[\-\.~=:]+/ | |
// | <arrow_dir> | |
// | <empty> | |
AST.Command.Ar.Form.Conn = MathJax.Object.Subclass({}); | |
AST.Command.Ar.Form.Conn.Connchars = MathJax.Object.Subclass({ | |
/** | |
* @param {String} connchars direction name | |
*/ | |
Init: function (connchars) { | |
this.connchars = connchars; | |
}, | |
toString: function () { | |
return this.connchars; | |
} | |
}); | |
AST.Command.Ar.Form.Conn.Object = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Object} object object as a dir | |
*/ | |
Init: function (object) { | |
this.object = object; | |
}, | |
toString: function () { | |
return "*" + this.object; | |
} | |
}); | |
AST.Command.Ar.Form.Conn.Dir = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.ObjectBox.Dir} dir dir | |
*/ | |
Init: function (dir) { | |
this.dir = dir; | |
}, | |
toString: function () { | |
return this.dir; | |
} | |
}); | |
// <arrow_form> ::= '@' <conchar> | |
// <conchar> ::= /[\-\.~=:]/ | |
AST.Command.Ar.Form.ChangeStem = MathJax.Object.Subclass({ | |
/** | |
* @param {String} connchar arrow stem name | |
*/ | |
Init: function (connchar) { | |
this.connchar = connchar; | |
}, | |
toString: function () { | |
return "@" + this.connchar; | |
} | |
}); | |
// <arrow_form> ::= '@' '!' | |
AST.Command.Ar.Form.DashArrowStem = MathJax.Object.Subclass({ | |
toString: function () { | |
return "@!"; | |
} | |
}); | |
// <arrow_form> ::= '@' '/' <direction> ( <loose-dimen> )? '/' | |
AST.Command.Ar.Form.CurveArrow = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Direction.*} curve direction | |
* @param {String} dist curve distance (dimension) | |
*/ | |
Init: function (direction, dist) { | |
this.direction = direction; | |
this.dist = dist; | |
}, | |
toString: function () { | |
return "@/" + this.direction + " " + this.dist + "/"; | |
} | |
}); | |
// <arrow_form> ::= '@' '(' <direction> ',' <direction> ')' | |
AST.Command.Ar.Form.CurveFitToDirection = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Direction.*} out direction | |
* @param {AST.Direction.*} in direction | |
*/ | |
Init: function (outDirection, inDirection) { | |
this.outDirection = outDirection; | |
this.inDirection = inDirection; | |
}, | |
toString: function () { | |
return "@(" + this.outDirection + "," + this.inDirection + ")"; | |
} | |
}); | |
// <arrow_form> ::= '@' '`' <coord> | |
AST.Command.Ar.Form.CurveWithControlPoints = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Coord} controlPoints | |
*/ | |
Init: function (coord) { | |
this.coord = coord; | |
}, | |
toString: function () { | |
return "@`{" + this.coord + "}" | |
} | |
}); | |
// <arrow_form> ::= '@' '[' <shape> ']' | |
AST.Command.Ar.Form.AddShape = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Modifier.Shape.*} shape shape | |
*/ | |
Init: function (shape) { | |
this.shape = shape; | |
}, | |
toString: function () { | |
return "@[" + this.shape + "]"; | |
} | |
}); | |
// <arrow_form> ::= '@' '*' '{' ( <modifier> )* '}' | |
AST.Command.Ar.Form.AddModifiers = MathJax.Object.Subclass({ | |
/** | |
* @param {List[AST.Modifier.*]} modifiers modifiers | |
*/ | |
Init: function (modifiers) { | |
this.modifiers = modifiers; | |
}, | |
toString: function () { | |
return "@*{" + this.modifiers.mkString(" ") + "}"; | |
} | |
}); | |
// <arrow_form> ::= '@' '<' <dimen> '>' | |
AST.Command.Ar.Form.Slide = MathJax.Object.Subclass({ | |
/** | |
* @param {String} slide dimension | |
*/ | |
Init: function (slideDimen) { | |
this.slideDimen = slideDimen; | |
}, | |
toString: function () { | |
return "@<" + this.slideDimen + ">"; | |
} | |
}); | |
// <arrow_form> ::= '|' <anchor> <it> | |
AST.Command.Ar.Form.LabelAt = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Place} anchor label anchor | |
* @param {AST.Object} it label | |
*/ | |
Init: function (anchor, it) { | |
this.anchor = anchor; | |
this.it = it; | |
}, | |
toString: function () { | |
return "|" + this.anchor + " " + this.it; | |
} | |
}); | |
// <arrow_form> ::= '^' <anchor> <it> | |
AST.Command.Ar.Form.LabelAbove = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Place} anchor label anchor | |
* @param {AST.Object} it label | |
*/ | |
Init: function (anchor, it) { | |
this.anchor = anchor; | |
this.it = it; | |
}, | |
toString: function () { | |
return "^" + this.anchor + " " + this.it; | |
} | |
}); | |
// <arrow_form> ::= '_' <anchor> <it> | |
AST.Command.Ar.Form.LabelBelow = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Place} anchor label anchor | |
* @param {AST.Object} it label | |
*/ | |
Init: function (anchor, it) { | |
this.anchor = anchor; | |
this.it = it; | |
}, | |
toString: function () { | |
return "_" + this.anchor + " " + this.it; | |
} | |
}); | |
// <arrow_form> ::= '@' '?' | |
AST.Command.Ar.Form.ReverseAboveAndBelow = MathJax.Object.Subclass({ | |
toString: function () { | |
return "@?"; | |
} | |
}); | |
// <decor> ::= '\xymatrix' <xymatrix> | |
// <xymatrix> ::= <setup> '{' <rows> '}' | |
AST.Command.Xymatrix = MathJax.Object.Subclass({ | |
/** | |
* @param {List[AST.Command.Xymatrix.Setup.*]} setup setup configurations | |
* @param {List[AST.Command.Xymatrix.Row]} rows rows | |
*/ | |
Init: function (setup, rows) { | |
this.setup = setup; | |
this.rows = rows; | |
}, | |
toString: function () { | |
return "\\xymatrix" + this.setup + "{\n" + this.rows.mkString("", "\\\\\n", "") + "\n}"; | |
} | |
}); | |
// <setup> ::= <switch>* | |
AST.Command.Xymatrix.Setup = MathJax.Object.Subclass({}); | |
// <switch> ::= '"' <prefix> '"' | |
AST.Command.Xymatrix.Setup.Prefix = MathJax.Object.Subclass({ | |
/** | |
* @param {String} prefix name of the xymatrix | |
*/ | |
Init: function (prefix) { | |
this.prefix = prefix; | |
}, | |
toString: function () { | |
return '"' + this.prefix + '"'; | |
} | |
}); | |
// <switch> ::= '@' <rcchar> <add op> <dimen> | |
AST.Command.Xymatrix.Setup.ChangeSpacing = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Modifier.AddOp.*} addop sizing operator | |
* @param {String} dimen size | |
*/ | |
Init: function (addop, dimen) { | |
this.addop = addop; | |
this.dimen = dimen; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.ChangeSpacing.Row = AST.Command.Xymatrix.Setup.ChangeSpacing.Subclass({ | |
toString: function () { | |
return "@R" + this.addop + this.dimen; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.ChangeSpacing.Column = AST.Command.Xymatrix.Setup.ChangeSpacing.Subclass({ | |
toString: function () { | |
return "@C" + this.addop + this.dimen; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.ChangeSpacing.RowAndColumn = AST.Command.Xymatrix.Setup.ChangeSpacing.Subclass({ | |
toString: function () { | |
return "@" + this.addop + this.dimen; | |
} | |
}); | |
// <switch> ::= '@' '!' <rcchar> '0' | |
// <switch> ::= '@' '!' <rcchar> '=' <dimen> | |
// <rcchar> ::= 'R' | 'C' | <empty> | |
AST.Command.Xymatrix.Setup.PretendEntrySize = MathJax.Object.Subclass({ | |
/** | |
* @param {String} dimen size | |
*/ | |
Init: function (dimen) { | |
this.dimen = dimen; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.PretendEntrySize.Height = AST.Command.Xymatrix.Setup.PretendEntrySize.Subclass({ | |
toString: function () { | |
return "@!R=" + this.dimen; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.PretendEntrySize.Width = AST.Command.Xymatrix.Setup.PretendEntrySize.Subclass({ | |
toString: function () { | |
return "@!C=" + this.dimen; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.PretendEntrySize.HeightAndWidth = AST.Command.Xymatrix.Setup.PretendEntrySize.Subclass({ | |
toString: function () { | |
return "@!=" + this.dimen; | |
} | |
}); | |
// <switch> ::= '@' '!' <rcchar> | |
AST.Command.Xymatrix.Setup.FixGrid = MathJax.Object.Subclass({}); | |
AST.Command.Xymatrix.Setup.FixGrid.Row = AST.Command.Xymatrix.Setup.FixGrid.Subclass({ | |
toString: function () { | |
return "@!R"; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.FixGrid.Column = AST.Command.Xymatrix.Setup.FixGrid.Subclass({ | |
toString: function () { | |
return "@!C"; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.FixGrid.RowAndColumn = AST.Command.Xymatrix.Setup.FixGrid.Subclass({ | |
toString: function () { | |
return "@!"; | |
} | |
}); | |
// <switch> ::= '@' ( 'M' | 'W' | 'H' ) <add op> <dimen> | |
// <switch> ::= '@' '1' | |
AST.Command.Xymatrix.Setup.AdjustEntrySize = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Modifier.AddOp.*} addop sizing operator | |
* @param {String} dimen size | |
*/ | |
Init: function (addop, dimen) { | |
this.addop = addop; | |
this.dimen = dimen; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.AdjustEntrySize.Margin = AST.Command.Xymatrix.Setup.AdjustEntrySize.Subclass({ | |
toString: function () { | |
return "@M" + this.addop + this.dimen; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.AdjustEntrySize.Width = AST.Command.Xymatrix.Setup.AdjustEntrySize.Subclass({ | |
toString: function () { | |
return "@W" + this.addop + this.dimen; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.AdjustEntrySize.Height = AST.Command.Xymatrix.Setup.AdjustEntrySize.Subclass({ | |
toString: function () { | |
return "@H" + this.addop + this.dimen; | |
} | |
}); | |
// <switch> ::= '@' 'L' <add op> <dimen> | |
AST.Command.Xymatrix.Setup.AdjustLabelSep = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Modifier.AddOp.*} addop sizing operator | |
* @param {String} dimen size | |
*/ | |
Init: function (addop, dimen) { | |
this.addop = addop; | |
this.dimen = dimen; | |
}, | |
toString: function () { | |
return "@L" + this.addop + this.dimen; | |
} | |
}); | |
// <switch> ::= '@' <nonemptyDirection> | |
AST.Command.Xymatrix.Setup.SetOrientation = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Direction} direction the orientation of the row | |
*/ | |
Init: function (direction) { | |
this.direction = direction; | |
}, | |
toString: function () { | |
return "@" + this.direction; | |
} | |
}); | |
// <switch> ::= '@' '*' '[' <shape> ']' | |
// | '@' '*' <add op> <size> | |
AST.Command.Xymatrix.Setup.AddModifier = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Modifier.*} shape object shape modifier for all entries | |
*/ | |
Init: function (modifier) { | |
this.modifier = modifier; | |
}, | |
toString: function () { | |
return "@*" + this.modifier; | |
} | |
}); | |
// <rows> ::= <row> ( '\\' <row> )* | |
// <row> ::= <entry> ( '&' <entry> )* | |
AST.Command.Xymatrix.Row = MathJax.Object.Subclass({ | |
/** | |
* @param {List[AST.Command.Xymatrix.Entry.*]} entries entries in the row | |
*/ | |
Init: function (entries) { | |
this.entries = entries; | |
}, | |
toString: function () { | |
return this.entries.mkString(" & "); | |
} | |
}); | |
// <entry> ::= ( '**' '[' <shape> ']' | '**' '{' <modifier>* '}' )* <loose objectbox> <decor> | |
// | '*' <object> <pos> <decor> | |
// <loose objectbox> ::= <objectbox> | |
// | /[^\\{}&]+/* ( ( '\' not( '\' | <decor command names> ) ( '{' | '}' | '&' ) | '{' <text> '}' ) /[^\\{}&]+/* )* | |
// <decor command names> ::= 'ar' | 'xymatrix' | 'PATH' | 'afterPATH' | |
// | 'save' | 'restore' | 'POS' | 'afterPOS' | 'drop' | 'connect' | 'xyignore' | |
AST.Command.Xymatrix.Entry = MathJax.Object.Subclass({}); | |
AST.Command.Xymatrix.Entry.SimpleEntry = AST.Command.Xymatrix.Entry.Subclass({ | |
/** | |
* @param {List[AST.Modifier.*]} modifiers object modifiers | |
* @param {AST.ObjectBox.*} objectbox entry objectbox | |
* @param {AST.Decor} decor decoration | |
*/ | |
Init: function (modifiers, objectbox, decor) { | |
this.modifiers = modifiers; | |
this.objectbox = objectbox; | |
this.decor = decor; | |
}, | |
isEmpty: false, | |
toString: function () { | |
return this.modifiers.mkString("**{", "", "}") + " " + this.objectbox + " " + this.decor; | |
} | |
}); | |
AST.Command.Xymatrix.Entry.ObjectEntry = AST.Command.Xymatrix.Entry.Subclass({ | |
/** | |
* @param {AST.Object} object entry object | |
* @param {AST.Pos.Coord} pos position (ignorable) | |
* @param {AST.Decor} decor decoration | |
*/ | |
Init: function (object, pos, decor) { | |
this.object = object; | |
this.pos = pos; | |
this.decor = decor; | |
}, | |
isEmpty: false, | |
toString: function () { | |
return "*" + this.object + " " + this.pos + " " + this.decor; | |
} | |
}); | |
AST.Command.Xymatrix.Entry.EmptyEntry = AST.Command.Xymatrix.Entry.Subclass({ | |
/** | |
* @param {AST.Decor} decor decoration | |
*/ | |
Init: function (decor) { | |
this.decor = decor; | |
}, | |
isEmpty: true, | |
toString: function () { | |
return "" + this.decor; | |
} | |
}); | |
// <command> ::= <twocell> <twocell switch>* <twocell arrow> | |
AST.Command.Twocell = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Command.Twocell.Hops2cell} twocell 2-cell | |
* @param {List[AST.Command.Twocell.Switch.*]} switches switches | |
* @param {AST.Command.Twocell.Arrow.*} arrow | |
*/ | |
Init: function (twocell, switches, arrow) { | |
this.twocell = twocell; | |
this.switches = switches; | |
this.arrow = arrow; | |
}, | |
toString: function () { | |
return this.twocell.toString() + this.switches.mkString("") + this.arrow; | |
} | |
}); | |
// <twocell> ::= '\' /[lrud]+/ 'twocell' | |
// | '\xtwocell' '[' /[lrud]+/ ']' '{' <text> '}' | |
AST.Command.Twocell.Hops2cell = MathJax.Object.Subclass({ | |
/** | |
* @param {String} hops hops | |
* @param {Option[AST.Object]} maybeDisplace displacement | |
*/ | |
Init: function (hops, maybeDisplace) { | |
this.hops = hops; | |
this.maybeDisplace = maybeDisplace; | |
} | |
}); | |
AST.Command.Twocell.Twocell = AST.Command.Twocell.Hops2cell.Subclass({ | |
toString: function () { | |
return "\\xtwocell[" + this.hops + "]" + this.maybeDisplace.getOrElse("{}"); | |
} | |
}); | |
// | '\' /[lrud]+/ 'uppertwocell' | |
// | '\xuppertwocell' '[' /[lrud]+/ ']' '{' <text> '}' | |
AST.Command.Twocell.UpperTwocell = AST.Command.Twocell.Hops2cell.Subclass({ | |
toString: function () { | |
return "\\xuppertwocell[" + this.hops + "]" + this.maybeDisplace.getOrElse("{}"); | |
} | |
}); | |
// | '\' /[lrud]+/ 'lowertwocell' | |
// | '\xlowertwocell' '[' /[lrud]+/ ']' '{' <text> '}' | |
AST.Command.Twocell.LowerTwocell = AST.Command.Twocell.Hops2cell.Subclass({ | |
toString: function () { | |
return "\\xlowertwocell[" + this.hops + "]" + this.maybeDisplace.getOrElse("{}"); | |
} | |
}); | |
// | '\' /[lrud]+/ 'compositemap' | |
// | '\xcompositemap' '[' /[lrud]+/ ']' '{' <text> '}' | |
AST.Command.Twocell.CompositeMap = AST.Command.Twocell.Hops2cell.Subclass({ | |
toString: function () { | |
return "\\xcompositemap[" + this.hops + "]" + this.maybeDisplace.getOrElse("{}"); | |
} | |
}); | |
// <twocell switch> ::= '^' <twocell label> | |
AST.Command.Twocell.Switch = MathJax.Object.Subclass({}); | |
AST.Command.Twocell.Switch.UpperLabel = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Command.Twocell.Label} label label | |
*/ | |
Init: function (label) { | |
this.label = label; | |
}, | |
toString: function () { | |
return "^" + this.label; | |
} | |
}); | |
// | '_' <twocell label> | |
AST.Command.Twocell.Switch.LowerLabel = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Command.Twocell.Label} label label | |
*/ | |
Init: function (label) { | |
this.label = label; | |
}, | |
toString: function () { | |
return "_" + this.label; | |
} | |
}); | |
// | <nudge> | |
AST.Command.Twocell.Switch.SetCurvature = MathJax.Object.Subclass({ | |
/** | |
* @param {AST.Command.Twocell.Nudge.*} nudge | |
*/ | |
Init: function (nudge) { | |
this.nudge = nudge; | |
}, | |
toString: function () { | |
return this.nudge.toString(); | |
} | |
}); | |
// | '\omit' | |
AST.Command.Twocell.Switch.DoNotSetCurvedArrows = MathJax.Object.Subclass({ | |
toString: function () { | |
return "\\omit"; | |
} | |
}); | |
// | '~!' | |
AST.Command.Twocell.Switch.PlaceModMapObject = MathJax.Object.Subclass({ | |
toString: function () { | |
return "~!"; | |
} | |
}); | |
// | '~' ( '`' | "'" ) '{' <object> '}' | |
AST.Command.Twocell.Switch.ChangeHeadTailObject = MathJax.Object.Subclass({ | |
/** | |
* @param {String} what | |
* @param {AST.Object} object | |
*/ | |
Init: function (what, object) { | |
this.what = what; | |
this.object = object; | |
}, | |
toString: function () { | |
return "~" + this.what + "{" + this.object + "}"; | |
} | |
}); | |
// | '~' ( '' | '^' | '_' ) '{' <object> ( '~**' <object> )? '}' | |
AST.Command.Twocell.Switch.ChangeCurveObject = MathJax.Object.Subclass({ | |
/** | |
* @param {String} what | |
* @param {AST.Object} spacer | |
* @param {AST.Object} maybeObject | |
*/ | |
Init: function (what, spacer, maybeObject) { | |
this.what = what; | |
this.spacer = spacer; | |
this.maybeObject = maybeObject; | |
}, | |
toString: function () { | |
return "~" + this.what + "{" + this.spacer + (this.maybeObject.isDefined? "~**" + this.maybeObject.get : "") + "}"; | |
} | |
}); | |
// <twocell label> ::= <digit> | <letter> | <cs> | |
// | '{' <nudge>? '*' <object> '}' | |
// | '{' <nudge>? <text> '}' | |
AST.Command.Twocell.Label = MathJax.Object.Subclass({ | |
/** | |
* @param {Option[AST.Command.Twocell.Nudge.*]} maybeNudge | |
* @param {AST.Object} labelObject | |
*/ | |
Init: function (maybeNudge, labelObject) { | |
this.maybeNudge = maybeNudge; | |
this.labelObject = labelObject; | |
}, | |
toString: function () { | |
return this.maybeNudge.toString() + this.labelObject; | |
} | |
}); | |
// <nudge> ::= '<' <factor> '>' | |
// | '<\omit>' | |
AST.Command.Twocell.Nudge = MathJax.Object.Subclass({}); | |
AST.Command.Twocell.Nudge.Number = AST.Command.Twocell.Nudge.Subclass({ | |
/** | |
* @param {Number} number number | |
*/ | |
Init: function (number) { | |
this.number = number; | |
}, | |
toString: function () { | |
return "<" + this.number + ">"; | |
} | |
}); | |
AST.Command.Twocell.Nudge.Omit = AST.Command.Twocell.Nudge.Subclass({ | |
toString: function () { | |
return "<\\omit>"; | |
} | |
}); | |
// <twocell arrow> ::= '{' <twocell tok> (<twocell label entry> '}' | |
// | '{' <twocell label entry> '}' | |
// | <empty> | |
// <twocell tok> ::= '^' | '_' | '=' | |
// | '\omit' | |
// | '`' | "'" | '"' | '!' | |
// <twocell label entry> ::= '*' <object> | |
// | <text> | |
AST.Command.Twocell.Arrow = MathJax.Object.Subclass({}); | |
AST.Command.Twocell.Arrow.WithOrientation = AST.Command.Twocell.Arrow.Subclass({ | |
/** | |
* @param {String} tok | |
* @param {AST.Object} labelObject | |
*/ | |
Init: function (tok, labelObject) { | |
this.tok = tok; | |
this.labelObject = labelObject; | |
}, | |
toString: function () { | |
return "{[" + this.tok + "] " + this.labelObject + "}"; | |
} | |
}); | |
// | '{' <nudge> <twocell label entry> '}' | |
AST.Command.Twocell.Arrow.WithPosition = AST.Command.Twocell.Arrow.Subclass({ | |
/** | |
* @param {AST.Command.Twocell.Nudge.*} nudge | |
* @param {AST.Object} labelObject | |
*/ | |
Init: function (nudge, labelObject) { | |
this.nudge = nudge; | |
this.labelObject = labelObject; | |
}, | |
toString: function () { | |
return "{[" + this.nudge + "] " + this.labelObject + "}"; | |
} | |
}); | |
// '\newdir' '{' <main> '}' '{' <composite_object> '}' | |
AST.Command.Newdir = MathJax.Object.Subclass({ | |
/** | |
* @param {String} dirMain | |
* @param {AST.ObjectBox.CompositeObject} compositeObject | |
*/ | |
Init: function (dirMain, compositeObject) { | |
this.dirMain = dirMain; | |
this.compositeObject = compositeObject; | |
}, | |
toString: function () { | |
return "\\newdir{" + this.dirMain + "}{" + this.compositeObject + "}"; | |
} | |
}); | |
// '\xyimport' '(' <factor> ',' <factor> ')' ( '(' <factor> ',' <factor> ')' )? '{' <TeX command> '}' | |
AST.Pos.Xyimport = MathJax.Object.Subclass({}); | |
AST.Pos.Xyimport.TeXCommand = AST.Pos.Xyimport.Subclass({ | |
/** | |
* @param {Number} width the width of the graphics in the coordinate system | |
* @param {Number} height the height of the graphics in the coordinate system | |
* @param {Number} xOffset the distance of the origin of coordinates from left corner | |
* @param {Number} yOffset the distance of the origin of coordinates from bottom corner | |
* @param {AST.Command.*} graphics object | |
*/ | |
Init: function (width, height, xOffset, yOffset, graphics) { | |
this.width = width; | |
this.height = height; | |
this.xOffset = xOffset; | |
this.yOffset = yOffset; | |
this.graphics = graphics; | |
}, | |
toString: function () { | |
return "\\xyimport(" + this.width + ", " + this.height + ")(" + this.xOffset + ", " + this.yOffset + "){" + this.graphics + "}"; | |
} | |
}); | |
// '\xyimport' '(' <factor> ',' <factor> ')' ( '(' <factor> ',' <factor> ')' )? '{' <include graphics> '}' | |
AST.Pos.Xyimport.Graphics = AST.Pos.Xyimport.Subclass({ | |
/** | |
* @param {Number} width the width of the graphics in the coordinate system | |
* @param {Number} height the height of the graphics in the coordinate system | |
* @param {Number} xOffset the distance of the origin of coordinates from left corner | |
* @param {Number} yOffset the distance of the origin of coordinates from bottom corner | |
* @param {AST.Command.Includegraphics} graphics object | |
*/ | |
Init: function (width, height, xOffset, yOffset, graphics) { | |
this.width = width; | |
this.height = height; | |
this.xOffset = xOffset; | |
this.yOffset = yOffset; | |
this.graphics = graphics; | |
}, | |
toString: function () { | |
return "\\xyimport(" + this.width + ", " + this.height + ")(" + this.xOffset + ", " + this.yOffset + "){" + this.graphics + "}"; | |
} | |
}); | |
/* \includegraphics command from the graphicx package */ | |
// '\includegraphics' '*'? '[' ( <includegraphics attr key val> ( ',' <includegraphics attr key val> )* )? ']' '{' <file path> '}' | |
AST.Command.Includegraphics = MathJax.Object.Subclass({ | |
/** | |
* @param {boolean} isClipped whether the graphics is clipped to the size specified or not | |
* @param {List[AST.Command.Includegraphics.Attr]} attributeList attribute key-value list | |
* @param {String} filepath image file path | |
*/ | |
Init: function (isClipped, attributeList, filepath) { | |
this.isClipped = isClipped; | |
this.attributeList = attributeList; | |
this.filepath = filepath; | |
}, | |
isIncludegraphics: true, | |
toString: function () { | |
return "\\includegraphics" + (this.isClipped? "*" : "") + this.attributeList.mkString("[", ",", "]") + "{" + this.filepath + "}"; | |
} | |
}); | |
// TODO: define <includegraphics attr key val> | |
// <includegraphics attr key val> := 'width' '=' <dimen> | |
// | 'height' '=' <dimen> | |
AST.Command.Includegraphics.Attr = MathJax.Object.Subclass({}); | |
AST.Command.Includegraphics.Attr.Width = AST.Command.Includegraphics.Attr.Subclass({ | |
/** | |
* @param {String} dimen | |
*/ | |
Init: function (dimen) { | |
this.dimen = dimen; | |
}, | |
toString: function () { | |
return "width=" + this.dimen; | |
} | |
}); | |
AST.Command.Includegraphics.Attr.Height = AST.Command.Includegraphics.Attr.Subclass({ | |
/** | |
* @param {String} dimen | |
*/ | |
Init: function (dimen) { | |
this.dimen = dimen; | |
}, | |
toString: function () { | |
return "height=" + this.dimen; | |
} | |
}); | |
var fun = FP.Parsers.fun; | |
var elem = FP.Parsers.elem; | |
var felem = function (x) { return fun(FP.Parsers.elem(x)); } | |
var lit = FP.Parsers.literal; | |
var regex = FP.Parsers.regex; | |
var regexLit = FP.Parsers.regexLiteral; | |
var flit = function (x) { return fun(FP.Parsers.literal(x)); } | |
var seq = FP.Parsers.seq; | |
var or = FP.Parsers.or; | |
var rep = function (x) { return FP.Parsers.lazyParser(x)().rep(); } | |
var rep1 = function (x) { return FP.Parsers.lazyParser(x)().rep1(); } | |
var opt = function (x) { return FP.Parsers.lazyParser(x)().opt(); } | |
var not = function (x) { return FP.Parsers.not(FP.Parsers.lazyParser(x)); } | |
var success = FP.Parsers.success; | |
var memo = function (parser) { | |
return function () { | |
var m = parser.memo; | |
if (m === undefined) { | |
m = parser.memo = parser(); | |
} | |
return m; | |
} | |
} | |
var p = FP.Parsers.Subclass({ | |
// <pos-decor> '\end' '{' 'xy' '}' | |
xy: memo(function () { | |
return p.posDecor().into(function (pd) { | |
return FP.Parsers.guard(function() { return lit('\\end').andl(flit('{')).andl(flit('xy')).andl(flit('}')).to(function () { | |
return pd; | |
})}); | |
}); | |
}), | |
// \xyboxの後の | |
// '{' <pos-decor> '}' | |
xybox: memo(function () { | |
return lit("{").andr(p.posDecor).andl(flit("}")).to(function (pd) { | |
return pd; | |
}); | |
}), | |
// \xymatrixの後の | |
// <xymatrix> | |
xymatrixbox: memo(function () { | |
return p.xymatrix().to(function (m) { | |
return AST.PosDecor(AST.Pos.Coord(AST.Coord.C(), FP.List.empty), AST.Decor(FP.List.empty.append(m))); | |
}); | |
}), | |
// <pos-decor> ::= <pos> <decor> | |
posDecor: memo(function () { | |
return seq(p.pos, p.decor).to(function (pd) { | |
return AST.PosDecor(pd.head, pd.tail); | |
}); | |
}), | |
// <pos> ::= <coord> <pos2>* | |
pos: memo(function () { | |
return seq(p.coord, rep(p.pos2)).to(function (cps) { | |
return AST.Pos.Coord(cps.head, cps.tail); | |
}); | |
}), | |
// <nonemptyPos> ::= <coord> <pos2>* | |
nonemptyPos: memo(function () { | |
return or( | |
seq(p.nonemptyCoord, rep(p.pos2)), | |
seq(p.coord, rep1(p.pos2)) | |
).to(function (cps) { | |
return AST.Pos.Coord(cps.head, cps.tail); | |
}); | |
}), | |
// <pos2> ::= '+' <coord> | |
// | '-' <coord> | |
// | '!' <coord> | |
// | '.' <coord> | |
// | ',' <coord> | |
// | ';' <coord> | |
// | '::' <coord> | |
// | ':' <coord> | |
// | '**' <object> | |
// | '*' <object> | |
// | '?' <place> | |
// | '@+' <corrd> | |
// | '@-' <corrd> | |
// | '@=' <corrd> | |
// | '@@' <corrd> | |
// | '@i' | |
// | '@(' | |
// | '@)' | |
// | '=:' '"' <id> '"' | |
// | '=@' '"' <id> '"' | |
// | '=' '"' <id> '"' | |
// | '=' <nonemptyCoord> '"' <id> '"' | |
// | <xyimport> | |
pos2: memo(function () { | |
return or( | |
lit('+').andr(p.coord).to(function (c) { return AST.Pos.Plus(c); }), | |
lit('-').andr(p.coord).to(function (c) { return AST.Pos.Minus(c); }), | |
lit('!').andr(p.coord).to(function (c) { return AST.Pos.Skew(c); }), | |
lit('.').andr(p.coord).to(function (c) { return AST.Pos.Cover(c); }), | |
lit(',').andr(p.coord).to(function (c) { return AST.Pos.Then(c); }), | |
lit(';').andr(p.coord).to(function (c) { return AST.Pos.SwapPAndC(c); }), | |
lit('::').andr(p.coord).to(function (c) { return AST.Pos.SetYBase(c); }), | |
lit(':').andr(p.coord).to(function (c) { return AST.Pos.SetBase(c); }), | |
lit('**').andr(p.object).to(function (o) { return AST.Pos.ConnectObject(o); }), | |
lit('*').andr(p.object).to(function (o) { return AST.Pos.DropObject(o); }), | |
lit('?').andr(p.place).to(function (o) { return AST.Pos.Place(o); }), | |
lit('@+').andr(p.coord).to(function (c) { return AST.Pos.PushCoord(c); }), | |
lit('@-').andr(p.coord).to(function (c) { return AST.Pos.EvalCoordThenPop(c); }), | |
lit('@=').andr(p.coord).to(function (c) { return AST.Pos.LoadStack(c); }), | |
lit('@@').andr(p.coord).to(function (c) { return AST.Pos.DoCoord(c); }), | |
lit('@i').to(function () { return AST.Pos.InitStack(); }), | |
lit('@(').to(function () { return AST.Pos.EnterFrame(); }), | |
lit('@)').to(function () { return AST.Pos.LeaveFrame(); }), | |
lit('=:').andr(flit('"')).andr(p.id).andl(felem('"')).to(function (id) { return AST.Pos.SaveBase(id); }), | |
lit('=@').andr(flit('"')).andr(p.id).andl(felem('"')).to(function (id) { return AST.Pos.SaveStack(id); }), | |
lit('=').andr(flit('"')).andr(p.id).andl(felem('"')).to(function (id) { return AST.Pos.SavePos(id); }), | |
lit('=').andr(p.nonemptyCoord).andl(flit('"')).and(p.id).andl(felem('"')).to(function (mid) { return AST.Pos.SaveMacro(mid.head, mid.tail); }), | |
p.xyimport | |
); | |
}), | |
// <coord> ::= <nonemptyCoord> | <empty> | |
coord: memo(function () { | |
return or( | |
p.nonemptyCoord, | |
success('empty').to(function () { return AST.Coord.C(); }) | |
); | |
}), | |
// <nonemptyCoord> ::= 'c' | 'p' | 'x' | 'y' | |
// | <vector> | |
// | '"' <id> '"' | |
// | '{' <pos> <decor> '}' | |
// | 's' <digit> | |
// | 's' '{' <nonnegative-number> '}' | |
// | '[' ('"'<prefix>'"')? <number> ',' <number> ']' | |
// | '[' ('"'<prefix>'"')? ( 'l' | 'r' | 'u' | 'd' )* ']' | |
// | '[' ('"'<prefix>'"')? ( 'l' | 'r' | 'u' | 'd' )+ <place> ']' | |
nonemptyCoord: memo(function () { | |
return or( | |
lit('c').to(function () { return AST.Coord.C(); }), | |
lit('p').to(function () { return AST.Coord.P(); }), | |
lit('x').to(function () { return AST.Coord.X(); }), | |
lit('y').to(function () { return AST.Coord.Y(); }), | |
p.vector().to(function (v) { return AST.Coord.Vector(v); }), | |
lit('"').andr(p.id).andl(felem('"')).to(function (id) { return AST.Coord.Id(id) }), | |
lit('{').andr(p.posDecor).andl(flit('}')).to(function (pd) { return AST.Coord.Group(pd) }), | |
lit('s').andr(fun(regexLit(/^\d/))).to(function (n) { | |
return AST.Coord.StackPosition(parseInt(n)); | |
}), | |
lit('s').andr(flit('{')).and(p.nonnegativeNumber).andl(flit('}')).to(function (n) { | |
return AST.Coord.StackPosition(n); | |
}), | |
lit('[').andr(fun( | |
opt(lit('"').andr(p.id).andl(felem('"'))).to(function (id) { return id.getOrElse(""); }) ) | |
).and(p.number).andl(flit(",")).and(p.number).andl(flit("]")).to(function (prc) { | |
return AST.Coord.DeltaRowColumn(prc.head.head, prc.head.tail, prc.tail); | |
}), | |
lit('[').andr(fun( | |
opt(lit('"').andr(p.id).andl(felem('"'))).to(function (id) { return id.getOrElse(""); }) ) | |
).and(fun(rep(regex(/^[lrud]/)))).andl(flit("]")).to(function (ph) { | |
return AST.Coord.Hops(ph.head, ph.tail); | |
}), | |
lit('[').andr(fun( | |
opt(lit('"').andr(p.id).andl(felem('"'))).to(function (id) { return id.getOrElse(""); }) ) | |
).and(fun(rep1(regex(/^[lrud]/)))).and(p.place).andl(flit("]")).to(function (php) { | |
return AST.Coord.DeltaRowColumn(php.head.head, php.head.tail, AST.Pos.Place(php.tail)); | |
}) | |
); | |
}), | |
// <vector> ::= '(' <factor> ',' <factor> ')' | |
// | '<' <dimen> ',' <dimen> '>' | |
// | '<' <dimen> '>' | |
// | 'a' '(' <number> ')' | |
// | '/' <direction> <loose-dimen> '/' | |
// | 0 | |
// | <corner> | |
// | <corner> '(' <factor> ')' | |
vector: memo(function () { | |
return or( | |
lit('(').andr(p.factor).andl(flit(',')).and(p.factor).andl(flit(')')).to( | |
function (xy) { | |
return AST.Vector.InCurBase(xy.head, xy.tail); | |
} | |
), | |
lit('<').andr(p.dimen).andl(flit(',')).and(p.dimen).andl(flit('>')).to( | |
function (xy) { | |
return AST.Vector.Abs(xy.head, xy.tail); | |
} | |
), | |
lit('<').andr(p.dimen).andl(flit('>')).to( | |
function (x) { | |
return AST.Vector.Abs(x, x); | |
} | |
), | |
lit('a').andr(flit('(')).andr(p.number).andl(flit(')')).to( | |
function (d) { | |
return AST.Vector.Angle(d); | |
} | |
), | |
lit('/').andr(p.direction).and(p.looseDimen).andl(flit('/')).to( | |
function (dd) { | |
return AST.Vector.Dir(dd.head, dd.tail); | |
} | |
), | |
lit('0').to(function (x) { return AST.Vector.Abs("0mm", "0mm"); }), | |
function () { return p.corner().and(fun(FP.Parsers.opt( | |
fun(lit('(').andr(p.factor).andl(flit(')')))).to(function (f) { | |
return f.getOrElse(1); | |
}))).to(function (cf) { | |
return AST.Vector.Corner(cf.head, cf.tail); | |
}) | |
} | |
); | |
}), | |
// <corner> ::= 'L' | 'R' | 'D' | 'U' | |
// | 'CL' | 'CR' | 'CD' | 'CU' | 'LC' | 'RC' | 'DC' | 'UC' | |
// | 'LD' | 'RD' | 'LU' | 'RU' | 'DL' | 'DR' | 'UL' | 'UR' | |
// | 'E' | 'P' | |
// | 'A' | |
corner: memo(function () { | |
return or( | |
regexLit(/^(CL|LC)/).to(function () { return AST.Corner.CL(); }), | |
regexLit(/^(CR|RC)/).to(function () { return AST.Corner.CR(); }), | |
regexLit(/^(CD|DC)/).to(function () { return AST.Corner.CD(); }), | |
regexLit(/^(CU|UC)/).to(function () { return AST.Corner.CU(); }), | |
regexLit(/^(LD|DL)/).to(function () { return AST.Corner.LD(); }), | |
regexLit(/^(RD|DR)/).to(function () { return AST.Corner.RD(); }), | |
regexLit(/^(LU|UL)/).to(function () { return AST.Corner.LU(); }), | |
regexLit(/^(RU|UR)/).to(function () { return AST.Corner.RU(); }), | |
lit('L').to(function () { return AST.Corner.L(); }), | |
lit('R').to(function () { return AST.Corner.R(); }), | |
lit('D').to(function () { return AST.Corner.D(); }), | |
lit('U').to(function () { return AST.Corner.U(); }), | |
lit('E').to(function () { return AST.Corner.NearestEdgePoint(); }), | |
lit('P').to(function () { return AST.Corner.PropEdgePoint(); }), | |
lit('A').to(function () { return AST.Corner.Axis(); }) | |
); | |
}), | |
// <place> ::= '<' <place> | |
// | '>' <place> | |
// | '(' <factor> ')' <place> | |
// | '!' '{' <pos> '}' <slide> | |
// | <slide> | |
place: memo(function () { | |
return or( | |
lit('<').andr(p.place).to(function (pl) { | |
return AST.Place(1, 0, undefined, undefined).compound(pl); | |
}), | |
lit('>').andr(p.place).to(function (pl) { | |
return AST.Place(0, 1, undefined, undefined).compound(pl); | |
}), | |
lit('(').andr(p.factor).andl(flit(')')).and(p.place).to(function (pl) { | |
return AST.Place(0, 0, AST.Place.Factor(pl.head), undefined).compound(pl.tail); | |
}), | |
lit('!').andr(flit('{')).andr(p.pos).andl(flit('}')).and(p.slide).to(function (ps) { | |
return AST.Place(0, 0, AST.Place.Intercept(ps.head), ps.tail); | |
}), | |
function () { return p.slide().to(function (s) { | |
return AST.Place(0, 0, undefined, s); | |
}) } | |
); | |
}), | |
// <slide> ::= '/' <dimen> '/' | |
// | <empty> | |
slide: memo(function () { | |
return or( | |
lit('/').andr(p.dimen).andl(flit('/')).to(function (d) { | |
return AST.Slide(FP.Option.Some(d)); | |
}), | |
success("no slide").to(function () { | |
return AST.Slide(FP.Option.empty); | |
}) | |
); | |
}), | |
// <factor> | |
factor: memo(fun(regexLit(/^[+\-]?(\d+(\.\d*)?|\d*\.\d+)/).to( | |
function (v) { return parseFloat(v); }) | |
)), | |
// <number> | |
number: memo(fun(regexLit(/^[+\-]?\d+/).to( | |
function (n) { return parseInt(n); }) | |
)), | |
// <nonnegative-number> | |
nonnegativeNumber: memo(fun(regexLit(/^\d+/).to( | |
function (n) { return parseInt(n); }) | |
)), | |
unit: memo(fun(regexLit(/^(em|ex|px|pt|pc|in|cm|mm|mu)/).to(function (d) { | |
return d | |
}))), | |
// <dimen> ::= <factor> ( 'em' | 'ex' | 'px' | 'pt' | 'pc' | 'in' | 'cm' | 'mm' | 'mu' ) | |
dimen: memo(function () { | |
return p.factor().and(p.unit).to(function (x) { | |
return x.head.toString() + x.tail; | |
}) | |
}), | |
// <loose-dimen> ::= <loose-factor> ( 'em' | 'ex' | 'px' | 'pt' | 'pc' | 'in' | 'cm' | 'mm' | 'mu' ) | |
looseDimen: memo(function () { | |
return p.looseFactor().and(p.unit).to(function (x) { | |
return x.head.toString() + x.tail; | |
}) | |
}), | |
// <loose-factor> | |
// makeshift against /^ 3.5mm/ converted to /^ 3 .5mm/ by MathJax.InputJax.TeX.prefilterMath() | |
looseFactor: memo(fun(or( | |
regexLit(/^(\d \d*(\.\d*))/).to(function (v) { | |
return parseFloat(v.replace(/ /, "")); | |
}), | |
regexLit(/^[+\-]?(\d+(\.\d*)?|\d*\.\d+)/).to(function (v) { | |
return parseFloat(v); | |
}) | |
))), | |
// <id> | |
id: memo(fun(regex(/^[^"]+/))), // " | |
// <object> ::= <modifier>* <objectbox> | |
object: memo(function () { | |
return or( | |
rep(p.modifier).and(p.objectbox).to(function (mso) { | |
return AST.Object(mso.head, mso.tail); | |
}) | |
); | |
}), | |
// <objectbox> ::= '{' <text> '}' | |
// | '@' <dir> | |
// | '\dir' <dir> | |
// | '\cir' <cir_radius> '{' <cir> '}' | |
// | '\frm' <frame_radius> '{' <frame_main> '}' | |
// | '\object' <object> | |
// | '\composite' '{' <composite_object> '}' | |
// | '\xybox' '{' <pos> <decor> '}' | |
// | '\xymatrix' <xymatrix> | |
// | <curve> | |
// | <TeX box> '{' <text> '}' | |
objectbox: memo(function () { | |
return or( | |
p.mathText, | |
lit("@").andr(p.dir), | |
lit("\\dir").andr(p.dir), | |
lit("\\cir").andr(p.cirRadius).andl(flit("{")).and(p.cir).andl(flit("}")).to(function (rc) { | |
return AST.ObjectBox.Cir(rc.head, rc.tail); | |
}), | |
lit("\\frm").andr(p.frameRadius).andl(flit("{")).and(p.frameMain).andl(flit("}")).to(function (rm) { | |
return AST.ObjectBox.Frame(rm.head, rm.tail); | |
}), | |
lit("\\object").andr(p.object).to(function (o) { | |
return AST.ObjectBox.WrapUpObject(o); | |
}), | |
lit("\\composite").and(flit("{")).andr(p.compositeObject).andl(flit("}")).to(function (os) { | |
return AST.ObjectBox.CompositeObject(os); | |
}), | |
lit("\\xybox").and(flit("{")).andr(p.posDecor).andl(flit("}")).to(function (pd) { | |
return AST.ObjectBox.Xybox(pd); | |
}), | |
lit("\\xymatrix").andr(p.xymatrix).to(function (m) { | |
return AST.ObjectBox.Xymatrix(m); | |
}), | |
p.txt, | |
p.curve, | |
regex(/^(\\[a-zA-Z@][a-zA-Z0-9@]+)/).andl(flit("{")).and(p.text).andl(flit("}")).to(function (bt) { | |
return p.toMath(bt.head + "{" + bt.tail + "}"); | |
}) | |
); | |
}), | |
// <composite_object> ::= <object> ( '*' <object> )* | |
compositeObject: memo(function () { | |
return p.object().and(fun(rep(lit("*").andr(p.object)))).to(function (oos) { | |
return oos.tail.prepend(oos.head); | |
}); | |
}), | |
// <math-text> ::= '{' <text> '}' | |
mathText: memo(function () { | |
return lit("{").andr(p.text).andl(felem("}")).to(function (text) { | |
return p.toMath("\\hbox{$\\objectstyle{" + text + "}$}"); | |
}); | |
}), | |
toMath: function (math) { | |
var mml = TEX.Parse(math).mml(); | |
if (mml.inferred) { | |
mml = MML.apply(MathJax.ElementJax, mml.data); | |
} else { | |
mml = MML(mml); | |
} | |
TEX.combineRelations(mml.root); | |
return AST.ObjectBox.Text(mml.root); | |
}, | |
// <text> ::= /[^{}\\%]*/ (( '\{' | '\}' | '\%' | '\\' | '{' <text> '}' | /%[^\r\n]*(\r\n|\r|\n)?/ ) /[^{}\\%]*/ )* | |
text: memo(function () { | |
return regex(/^[^{}\\%]*/).and(function () { | |
return ( | |
or( | |
regex(/^(\\\{|\\\}|\\%|\\)/).to(function (x) { | |
return x; | |
}), | |
elem("{").andr(p.text).andl(felem("}")).to(function (x) { | |
return "{" + x + "}"; | |
}), | |
regex(/^%[^\r\n]*(\r\n|\r|\n)?/).to(function (x) { | |
return ' '; // ignore comments | |
}) | |
).and(fun(regex(/^[^{}\\%]*/)))).rep().to(function (xs) { | |
var res = ""; | |
xs.foreach(function (x) { | |
res += x.head + x.tail; | |
}); | |
return res; | |
}) | |
}).to(function (x) { | |
return x.head + x.tail | |
}); | |
}), | |
txt: memo(function () { | |
return lit("\\txt").andr(p.txtWidth).and(fun(regex(/^(\\[a-zA-Z@][a-zA-Z0-9@]+)?/))).andl(flit("{")).and(p.text).andl(flit("}")).to(function (wst) { | |
var width = wst.head.head; | |
var style = wst.head.tail; | |
var text = wst.tail; | |
var math; | |
var lines = text.split("\\\\"); | |
if (lines.length <= 1) { | |
math = style + "{\\hbox{" + text + "}}"; | |
} else { | |
math = "\\hbox{$\\begin{array}{c}\n"; | |
for (var i = 0; i < lines.length; i++) { | |
math += style + "{\\hbox{" + lines[i].replace(/(^[\r\n\s]+)|([\r\n\s]+$)/g, "") + "}}"; | |
if (i != lines.length - 1) { | |
math += "\\\\\n"; | |
} | |
} | |
math += "\\end{array}$}"; | |
} | |
return AST.ObjectBox.Txt(width, p.toMath(math)); | |
}); | |
}), | |
// <txt_width> ::= '<' <dimen> '>' | |
// | <empty> | |
txtWidth: memo(function () { | |
return or( | |
lit('<').andr(p.dimen).andl(flit('>')).to( | |
function (x) { | |
return AST.Vector.Abs(x, x); | |
} | |
).to(function (v) { | |
return AST.ObjectBox.Txt.Width.Vector(v); | |
}), | |
success("default").to(function () { | |
return AST.ObjectBox.Txt.Width.Default(); | |
}) | |
); | |
}), | |
// <dir> ::= <variant> '{' <main> '}' | |
// <variant> ::= '^' | '_' | '0' | '1' | '2' | '3' | <empty> | |
dir: memo(function () { | |
return regexLit(/^[\^_0123]/).opt().andl(flit('{')).and(p.dirMain).andl(flit('}')).to(function (vm) { | |
return AST.ObjectBox.Dir(vm.head.getOrElse(""), vm.tail); | |
}) | |
}), | |
// <main> ::= ('-' | '.' | '~' | '>' | '<' | '(' | ')' | '`' | "'" | '|' | '*' | '+' | 'x' | '/' | 'o' | '=' | ':' | /[a-zA-Z@ ]/)* | |
dirMain: memo(function () { | |
return regex(/^(-|\.|~|>|<|\(|\)|`|'|\||\*|\+|x|\/|o|=|:|[a-zA-Z@ ])+/ /*'*/).opt().to(function (m) { | |
return m.getOrElse(""); | |
}) | |
}), | |
// <cir_radius> ::= <vector> | |
// | <empty> | |
cirRadius: memo(function () { | |
return or( | |
p.vector().to(function (v) { | |
return AST.ObjectBox.Cir.Radius.Vector(v); | |
}), | |
success("default").to(function () { | |
return AST.ObjectBox.Cir.Radius.Default(); | |
}) | |
); | |
}), | |
// <frame_radius> ::= <frame_radius_vector> | |
// | <empty> | |
frameRadius: memo(function () { | |
return or( | |
p.frameRadiusVector().to(function (v) { | |
return AST.ObjectBox.Frame.Radius.Vector(v); | |
}), | |
success("default").to(function () { | |
return AST.ObjectBox.Frame.Radius.Default(); | |
}) | |
); | |
}), | |
// <frame_radius_vector> ::= '<' <dimen> ',' <dimen> '>' | |
// | '<' <dimen> '>' | |
frameRadiusVector: memo(function () { | |
return or( | |
lit('<').andr(p.dimen).andl(flit(',')).and(p.dimen).andl(flit('>')).to( | |
function (xy) { | |
return AST.Vector.Abs(xy.head, xy.tail); | |
} | |
), | |
lit('<').andr(p.dimen).andl(flit('>')).to( | |
function (x) { | |
return AST.Vector.Abs(x, x); | |
} | |
) | |
); | |
}), | |
// <frame_main> ::= ( '-' | '=' | '.' | ',' | 'o' | 'e' | '*' )* | |
// | ( '_' | '^' )? ( '\{' | '\}' | '(' | ')' ) | |
frameMain: memo(function () { | |
return regex(/^(((_|\^)?(\\\{|\\\}|\(|\)))|[\-=oe,\.\*]*)/); | |
}), | |
// <cir> ::= <diag> <orient> <diag> | |
// | <empty> | |
cir: memo(function () { | |
return or( | |
p.nonemptyCir, | |
success("full").to(function () { | |
return AST.ObjectBox.Cir.Cir.Full(); | |
}) | |
); | |
}), | |
nonemptyCir: memo(function () { | |
return p.diag().and(fun(regexLit(/^[_\^]/))).and(p.diag).to(function (dod) { | |
return AST.ObjectBox.Cir.Cir.Segment(dod.head.head, dod.head.tail, dod.tail); | |
}); | |
}), | |
// <curve> ::= '\crv' <curve-modifier> '{' <curve-object> <curve-poslist> '}' | |
curve: memo(function () { | |
return lit("\\crv").andr(p.curveModifier).andl(flit("{")).and(p.curveObject).and(p.curvePoslist).andl(flit("}")).to(function (mop) { | |
return AST.ObjectBox.Curve(mop.head.head, mop.head.tail, mop.tail); | |
}); | |
}), | |
// <curve-modifier> ::= ( '~' <curve-option> )* | |
curveModifier: memo(function () { | |
return rep(fun(lit("~").andr(p.curveOption))); | |
}), | |
// <curve-option> ::= 'p' | 'P' | 'l' | 'L' | 'c' | 'C' | |
// | 'pc' | 'pC' | 'Pc' | 'PC' | |
// | 'lc' | 'lC' | 'Lc' | 'LC' | |
// | 'cC' | |
curveOption: memo(function () { | |
return or( | |
lit("p").to(function () { return AST.ObjectBox.Curve.Modifier.p(); }), | |
lit("P").to(function () { return AST.ObjectBox.Curve.Modifier.P(); }), | |
lit("l").to(function () { return AST.ObjectBox.Curve.Modifier.l(); }), | |
lit("L").to(function () { return AST.ObjectBox.Curve.Modifier.L(); }), | |
lit("c").to(function () { return AST.ObjectBox.Curve.Modifier.c(); }), | |
lit("C").to(function () { return AST.ObjectBox.Curve.Modifier.C(); }), | |
lit("pc").to(function () { return AST.ObjectBox.Curve.Modifier.pc(); }), | |
lit("pC").to(function () { return AST.ObjectBox.Curve.Modifier.pC(); }), | |
lit("Pc").to(function () { return AST.ObjectBox.Curve.Modifier.Pc(); }), | |
lit("PC").to(function () { return AST.ObjectBox.Curve.Modifier.PC(); }), | |
lit("lc").to(function () { return AST.ObjectBox.Curve.Modifier.lc(); }), | |
lit("lC").to(function () { return AST.ObjectBox.Curve.Modifier.lC(); }), | |
lit("Lc").to(function () { return AST.ObjectBox.Curve.Modifier.Lc(); }), | |
lit("LC").to(function () { return AST.ObjectBox.Curve.Modifier.LC(); }), | |
lit("cC").to(function () { return AST.ObjectBox.Curve.Modifier.cC(); }) | |
); | |
}), | |
// <curve-object> ::= <empty> | |
// | '~*' <object> <curve-object> | |
// | '~**' <object> <curve-object> | |
curveObject: memo(function () { | |
return rep(or( | |
lit("~*").andr(p.object).to(function (obj) { | |
return AST.ObjectBox.Curve.Object.Drop(obj); | |
}), | |
lit("~**").andr(p.object).to(function (obj) { | |
return AST.ObjectBox.Curve.Object.Connect(obj); | |
}) | |
)); | |
}), | |
// <curve-poslist> ::= <empty> ^^ Empty List | |
// | '&' <curve-poslist2> ^^ (c, <poslist>) | |
// | <nonemptyPos> ^^ (<nonemptyPos>, Nil) | |
// | <nonemptyPos> '&' <curve-poslist2> ^^ (<nonemptyPos>, <poslist>) | |
// | '~@' ^^ (~@, Nil) | |
// | '~@' '&' <curve-poslist2> ^^ (~@, <poslist>) | |
// <curve-poslist2> ::= <empty> ^^ (c, Nil) | |
// | '&' <curve-poslist2> ^^ (c, <poslist>) | |
// | <nonemptyPos> ^^ (<nonemptyPos>, Nil) | |
// | <nonemptyPos> '&' <curve-poslist2> ^^ (<nonemptyPos>, <poslist>) | |
// | '~@' ^^ (~@, Nil) | |
// | '~@' '&' <curve-poslist2> ^^ (~@, <poslist>) | |
curvePoslist: memo(function () { | |
return or( | |
lit("&").andr(p.curvePoslist2).to(function (ps) { | |
return ps.prepend(AST.ObjectBox.Curve.PosList.CurPos()); | |
}), | |
lit("~@").andr(flit("&")).andr(p.curvePoslist2).to(function (ps) { | |
return ps.prepend(AST.ObjectBox.Curve.PosList.AddStack()); | |
}), | |
lit("~@").to(function () { | |
return FP.List.empty.prepend(AST.ObjectBox.Curve.PosList.AddStack()); | |
}), | |
p.pos().andl(flit("&")).and(p.curvePoslist2).to(function (pps) { | |
return pps.tail.prepend(AST.ObjectBox.Curve.PosList.Pos(pps.head)); | |
}), | |
p.nonemptyPos().to(function (p) { | |
return FP.List.empty.prepend(AST.ObjectBox.Curve.PosList.Pos(p)); | |
}), | |
success("empty").to(function () { | |
return FP.List.empty; | |
}) | |
); | |
}), | |
curvePoslist2: memo(function () { | |
return or( | |
lit("&").andr(p.curvePoslist2).to(function (ps) { | |
return ps.prepend(AST.ObjectBox.Curve.PosList.CurPos()); | |
}), | |
lit("~@").andr(flit("&")).andr(p.curvePoslist2).to(function (ps) { | |
return ps.prepend(AST.ObjectBox.Curve.PosList.AddStack()); | |
}), | |
lit("~@").to(function () { | |
return FP.List.empty.prepend(AST.ObjectBox.Curve.PosList.AddStack()); | |
}), | |
p.nonemptyPos().andl(flit("&")).and(p.curvePoslist2).to(function (pps) { | |
return pps.tail.prepend(AST.ObjectBox.Curve.PosList.Pos(pps.head)); | |
}), | |
p.nonemptyPos().to(function (p) { | |
return FP.List.empty.prepend(AST.ObjectBox.Curve.PosList.Pos(p)); | |
}), | |
success("empty").to(function () { | |
return FP.List.empty.prepend(AST.ObjectBox.Curve.PosList.CurPos()); | |
}) | |
); | |
}), | |
// <modifier> ::= '!' <vector> | |
// | '[' <shape> ']' | |
// | 'i' | |
// | 'h' | |
// | <add-op> <size> | |
// | <nonemptyDirection> | |
modifier: memo(function () { | |
return or( | |
lit("!").andr(p.vector).to(function (v) { | |
return AST.Modifier.Vector(v); | |
}), | |
lit("!").to(function (v) { | |
return AST.Modifier.RestoreOriginalRefPoint(); | |
}), | |
lit("[").andr(p.shape).andl(flit("]")).to(function (s) { | |
return s; | |
}), | |
lit("i").to(function (v) { | |
return AST.Modifier.Invisible(); | |
}), | |
lit("h").to(function (v) { | |
return AST.Modifier.Hidden(); | |
}), | |
p.addOp().and(p.size).to(function (os) { | |
return AST.Modifier.AddOp(os.head, os.tail); | |
}), | |
p.nonemptyDirection().to(function (d) { | |
return AST.Modifier.Direction(d); | |
}) | |
); | |
}), | |
// <add-op> ::= '+' | '-' | '=' | '+=' | '-=' | |
addOp: memo(function () { | |
return or( | |
lit("+=").to(function () { return AST.Modifier.AddOp.GrowTo(); }), | |
lit("-=").to(function () { return AST.Modifier.AddOp.ShrinkTo(); }), | |
lit("+").to(function () { return AST.Modifier.AddOp.Grow(); }), | |
lit("-").to(function () { return AST.Modifier.AddOp.Shrink(); }), | |
lit("=").to(function () { return AST.Modifier.AddOp.Set(); }) | |
); | |
}), | |
// <size> ::= <vector> | <empty> | |
size: memo(function () { | |
return or( | |
function () { return p.vector().to(function (v) { | |
return AST.Modifier.AddOp.VactorSize(v); | |
}) }, | |
success("default size").to(function () { | |
return AST.Modifier.AddOp.DefaultSize(); | |
}) | |
); | |
}), | |
// <shape> ::= '.' | |
// | <frame_shape> | |
// | <alphabets> | |
// | '=' <alphabets> | |
// | <empty> | |
shape: memo(function () { | |
return or( | |
lit(".").to(function () { return AST.Modifier.Shape.Point(); }), | |
p.frameShape, | |
p.alphabets().to(function (name) { | |
return AST.Modifier.Shape.Alphabets(name); | |
}), | |
lit("=").andr(p.alphabets).to(function (name) { | |
return AST.Modifier.Shape.DefineShape(name); | |
}), | |
success("rect").to(function () { return AST.Modifier.Shape.Rect(); }) | |
); | |
}), | |
// <frame_shape> ::= 'F' <frame_main> ( ':' ( <frame_radius_vector> | <color_name> ))* | |
frameShape: memo(function () { | |
return lit("F").andr(p.frameMain).and(fun( | |
rep(lit(":").andr(fun( | |
or( | |
p.frameRadiusVector().to(function (v) { | |
return AST.Modifier.Shape.Frame.Radius(v); | |
}), | |
p.colorName().to(function (c) { | |
return AST.Modifier.Shape.Frame.Color(c); | |
}) | |
) | |
))) | |
)).to(function (mo) { | |
var main = mo.head; | |
if (main === "") { | |
main = "-"; | |
} | |
return AST.Modifier.Shape.Frame(main, mo.tail); | |
}); | |
}), | |
// <alphabets> ::= /[a-zA-Z]+/ | |
alphabets: memo(function () { | |
return regex(/^([a-zA-Z]+)/); | |
}), | |
// <color_name> ::= /[a-zA-Z][a-zA-Z0-9]*/ | |
colorName: memo(function () { | |
return regex(/^([a-zA-Z][a-zA-Z0-9]*)/); | |
}), | |
// <direction> ::= <direction0> <direction1>* | |
// <direction0> ::= <direction2> | |
// | <diag> | |
// <direction1> | ':' <vector> | |
// | '_' | |
// | '^' | |
// <direction2> ::= 'v' <vector> | |
// | 'q' '{' <pos> <decor> '}' | |
direction: memo(function () { | |
return seq(p.direction0, rep(p.direction1)).to(function (drs){ | |
return AST.Direction.Compound(drs.head, drs.tail); | |
}); | |
}), | |
direction0: memo(function () { | |
return or( | |
p.direction2, | |
p.diag().to(function (d) { | |
return AST.Direction.Diag(d); | |
}) | |
); | |
}), | |
direction1: memo(function () { | |
return or( | |
lit(':').andr(p.vector).to(function (v) { | |
return AST.Direction.RotVector(v); | |
}), | |
lit('_').to(function (x) { | |
return AST.Direction.RotAntiCW(); | |
}), | |
lit('^').to(function (x) { | |
return AST.Direction.RotCW(); | |
}) | |
); | |
}), | |
direction2: memo(function () { | |
return or( | |
lit('v').andr(p.vector).to(function (v) { | |
return AST.Direction.Vector(v); | |
}), | |
lit('q').andr(flit('{')).andr(p.posDecor).andl(flit('}')).to(function (pd) { | |
return AST.Direction.ConstructVector(pd); | |
}) | |
); | |
}), | |
// <nonempty-direction> ::= <nonempty-direction0> <direction1>* | |
// | <direction0> <direction1>+ | |
// <nonempty-direction0> ::= <nonempty-diag> | |
// | <direction2> | |
nonemptyDirection: memo(function () { | |
return or( | |
seq(p.nonemptyDirection0, rep(p.direction1)), | |
seq(p.direction0, rep1(p.direction1)) | |
).to(function (drs){ | |
return AST.Direction.Compound(drs.head, drs.tail); | |
}); | |
}), | |
nonemptyDirection0: memo(function () { | |
return or( | |
p.direction2, | |
p.nonemptyDiag().to(function (d) { | |
return AST.Direction.Diag(d); | |
}) | |
); | |
}), | |
// <diag> ::= <nonempty-diag> | <empty> | |
// <nonempty-diag> ::= 'l' | 'r' | 'd' | 'u' | 'ld' | 'rd' | 'lu' | 'ru' | |
diag: memo(function () { | |
return or( | |
p.nonemptyDiag, | |
success("empty").to(function (x) { | |
return AST.Diag.Default(); | |
}) | |
); | |
}), | |
nonemptyDiag: memo(function () { | |
return or( | |
regexLit(/^(ld|dl)/).to(function (x) { return AST.Diag.LD(); }), | |
regexLit(/^(rd|dr)/).to(function (x) { return AST.Diag.RD(); }), | |
regexLit(/^(lu|ul)/).to(function (x) { return AST.Diag.LU(); }), | |
regexLit(/^(ru|ur)/).to(function (x) { return AST.Diag.RU(); }), | |
lit('l').to(function (x) { return AST.Diag.L(); }), | |
lit('r').to(function (x) { return AST.Diag.R(); }), | |
lit('d').to(function (x) { return AST.Diag.D(); }), | |
lit('u').to(function (x) { return AST.Diag.U(); }) | |
); | |
}), | |
// <decor> ::= <command>* | |
decor: memo(function () { | |
return p.command().rep().to(function (cs) { | |
return AST.Decor(cs); | |
}) | |
}), | |
// <command> ::= '\ar' ( <arrow_form> )* <path> | |
// | '\xymatrix' <xymatrix> | |
// | '\PATH' <path> | |
// | '\afterPATH' '{' <decor> '}' <path> | |
// | '\save' <pos> | |
// | '\restore' | |
// | '\POS' <pos> | |
// | '\afterPOS' '{' <decor> '}' <pos> | |
// | '\drop' <object> | |
// | '\connect' <object> | |
// | '\relax' | |
// | '\xyignore' '{' <pos> <decor> '}' | |
// | <twocell command> | |
command: memo(function () { | |
return or( | |
lit("\\ar").andr(fun(rep(p.arrowForm))).and(p.path).to(function (fsp) { | |
return AST.Command.Ar(fsp.head, fsp.tail); | |
}), | |
lit("\\xymatrix").andr(p.xymatrix), | |
lit("\\PATH").andr(p.path).to(function (path) { | |
return AST.Command.Path(path); | |
}), | |
lit("\\afterPATH").andr(flit('{')).andr(p.decor).andl(flit('}')).and(p.path).to(function (dp) { | |
return AST.Command.AfterPath(dp.head, dp.tail); | |
}), | |
lit("\\save").andr(p.pos).to(function (pos) { | |
return AST.Command.Save(pos); | |
}), | |
lit("\\restore").to(function () { | |
return AST.Command.Restore(); | |
}), | |
lit("\\POS").andr(p.pos).to(function (pos) { | |
return AST.Command.Pos(pos); | |
}), | |
lit("\\afterPOS").andr(flit('{')).andr(p.decor).andl(flit('}')).and(p.pos).to(function (dp) { | |
return AST.Command.AfterPos(dp.head, dp.tail); | |
}), | |
lit("\\drop").andr(p.object).to(function (obj) { | |
return AST.Command.Drop(obj); | |
}), | |
lit("\\connect").andr(p.object).to(function (obj) { | |
return AST.Command.Connect(obj); | |
}), | |
lit("\\relax").to(function () { | |
return AST.Command.Relax(); | |
}), | |
lit("\\xyignore").andr(flit('{')).andr(p.pos).and(p.decor).andl(flit('}')).to(function (pd) { | |
return AST.Command.Ignore(pd.head, pd.tail); | |
}), | |
lit("\\xyshowAST").andr(flit('{')).andr(p.pos).and(p.decor).andl(flit('}')).to(function (pd) { | |
return AST.Command.ShowAST(pd.head, pd.tail); | |
}), | |
p.twocellCommand | |
); | |
}), | |
// <arrow_form> ::= '@' <conchar> | |
// | '@' '!' | |
// | '@' '/' <direction> ( <loose-dimen> )? '/' | |
// | '@' '(' <direction> ',' <direction> ')' | |
// | '@' '`' '{' <curve-poslist> '}' | |
// | '@' '[' <shape> ']' | |
// | '@' '*' '{' ( <modifier> )* '}' | |
// | '@' '<' <dimen> '>' | |
// | '|' <anchor> <it> | |
// | '^' <anchor> <it> | |
// | '_' <anchor> <it> | |
// | '@' '?' | |
// | '@' <variant> ( <tip_conn_tip> )? | |
// <conchar> ::= /[\-\.~=:]/ | |
// <variant> ::= /[\^_0123]/ | <empty> | |
arrowForm: memo(function () { | |
return or( | |
lit("@").andr(fun(regex(/^([\-\.~=:])/))).to(function (c) { | |
return AST.Command.Ar.Form.ChangeStem(c); | |
}), | |
lit("@").andr(flit("!")).to(function (c) { | |
return AST.Command.Ar.Form.DashArrowStem(); | |
}), | |
lit("@").andr(flit("/")).andr(p.direction).and(fun(opt(p.looseDimen))).andl(flit("/")).to(function (dd) { | |
return AST.Command.Ar.Form.CurveArrow(dd.head, dd.tail.getOrElse(".5pc")); | |
}), | |
lit("@").andr(flit("(")).andr(p.direction).andl(flit(",")).and(p.direction).andl(flit(")")).to(function (dd) { | |
return AST.Command.Ar.Form.CurveFitToDirection(dd.head, dd.tail); | |
}), | |
lit("@").andr(flit("`")).andr(p.coord).to(function (c) { | |
return AST.Command.Ar.Form.CurveWithControlPoints(c); | |
}), | |
lit("@").andr(flit("[")).andr(p.shape).andl(flit("]")).to(function (s) { | |
return AST.Command.Ar.Form.AddShape(s); | |
}), | |
lit("@").andr(flit("*")).andr(flit("{")).andr(fun(rep(p.modifier))).andl(flit("}")).to(function (ms) { | |
return AST.Command.Ar.Form.AddModifiers(ms); | |
}), | |
lit("@").andr(flit("<")).andr(p.dimen).andl(flit(">")).to(function (d) { | |
return AST.Command.Ar.Form.Slide(d); | |
}), | |
lit("|").andr(p.anchor).and(p.it).to(function (ai) { | |
return AST.Command.Ar.Form.LabelAt(ai.head, ai.tail); | |
}), | |
lit("^").andr(p.anchor).and(p.it).to(function (ai) { | |
return AST.Command.Ar.Form.LabelAbove(ai.head, ai.tail); | |
}), | |
lit("_").andr(p.anchor).and(p.it).to(function (ai) { | |
return AST.Command.Ar.Form.LabelBelow(ai.head, ai.tail); | |
}), | |
lit("@").andr(flit("?")).to(function () { | |
return AST.Command.Ar.Form.ReverseAboveAndBelow(); | |
}), | |
lit("@").andr(fun(regex(/^([\^_0123])/).opt())).and(fun(opt(p.tipConnTip))).to(function (vtct) { | |
var variant = vtct.head.getOrElse(""); | |
if (vtct.tail.isDefined) { | |
var tct = vtct.tail.get; | |
return AST.Command.Ar.Form.BuildArrow(variant, tct.tail, tct.stem, tct.head); | |
} else { | |
return AST.Command.Ar.Form.ChangeVariant(variant); | |
} | |
}) | |
); | |
}), | |
// <tip_conn_tip> ::= '{' <nonempty_tip>? <nonempty_conn>? <nonempty_tip>? '}' | |
tipConnTip: memo(function () { | |
return lit("{").andr(fun(opt(p.nonemptyTip))).and(fun(opt(p.nonemptyConn))).and(fun(opt(p.nonemptyTip))).andl(flit("}")).to(function (pcp) { | |
var maybeTail = pcp.head.head; | |
var maybeStem = pcp.head.tail; | |
var maybeHead = pcp.tail; | |
var emptyTip = AST.Command.Ar.Form.Tip.Tipchars(""); | |
var tail, stem, head; | |
if (!maybeStem.isDefined && !maybeHead.isDefined) { | |
if (!maybeTail.isDefined) { | |
tail = emptyTip; | |
stem = AST.Command.Ar.Form.Conn.Connchars(""); | |
head = emptyTip; | |
} else { | |
tail = emptyTip; | |
stem = AST.Command.Ar.Form.Conn.Connchars("-"); | |
head = maybeTail.getOrElse(emptyTip); | |
} | |
} else { | |
tail = maybeTail.getOrElse(emptyTip); | |
stem = maybeStem.getOrElse(AST.Command.Ar.Form.Conn.Connchars("")); | |
head = maybeHead.getOrElse(emptyTip); | |
} | |
return { | |
tail:tail, | |
stem:stem, | |
head:head | |
}; | |
}); | |
}), | |
// <nonempty_tip> ::= /[<>()|'`+/a-zA-Z ]+/ | |
// | <arrow_dir> | |
// <arrow_dir> ::= '*' <object> | |
// | <dir> | |
nonemptyTip: memo(function () { | |
return or( | |
regex(/^([<>()|'`+\/a-zA-Z ]+)/).to(function (cs) { | |
return AST.Command.Ar.Form.Tip.Tipchars(cs); | |
}), | |
lit("*").andr(p.object).to(function (o) { | |
return AST.Command.Ar.Form.Tip.Object(o); | |
}), | |
p.dir().to(function (d) { | |
return AST.Command.Ar.Form.Tip.Dir(d); | |
}) | |
); | |
}), | |
// <nonempty_conn> ::= /[\-\.~=:]+/ | |
// | <arrow_dir> | |
nonemptyConn: memo(function () { | |
return or( | |
regex(/^([\-\.~=:]+)/).to(function (cs) { | |
return AST.Command.Ar.Form.Conn.Connchars(cs); | |
}), | |
lit("*").andr(p.object).to(function (o) { | |
return AST.Command.Ar.Form.Conn.Object(o); | |
}), | |
p.dir().to(function (d) { | |
return AST.Command.Ar.Form.Conn.Dir(d); | |
}) | |
); | |
}), | |
// <path> ::= <path2>(Nil) | |
path: memo(function () { | |
return p.path2(FP.List.empty /* initial failure continuation */).to(function (ps) { | |
return AST.Command.Path.Path(ps); | |
}) | |
}), | |
// <path2>(fc) ::= '~' <action> '{' <pos> <decor> '}' <path2>(fc) | |
// | '~' <which> '{' <labels> '}' <path2>(fc) | |
// | "'" <segment> <path2>(fc) | |
// | '`' <turn> <segment> <path2>(fc) | |
// | '~' '{' <path2 as fc'> '}' <path2>(fc') | |
// | <segment> | |
// | <empty> | |
// <action> ::= '=' | '/' | |
// <which> ::= '<' | '>' | '+' | |
path2: function (fc) { | |
var q = memo(function () { return p.path2(fc) }); | |
return or( | |
p.path3().and(q).to(function (ep) { | |
return ep.tail.prepend(ep.head); | |
}), | |
seq('~', '{', q, '}').to(function (newFc) { | |
return newFc.head.tail; | |
}).into(function (newFc) { | |
return p.path2(newFc); | |
}), | |
p.segment().to(function (s) { | |
return FP.List.empty.prepend(AST.Command.Path.LastSegment(s)); | |
}), | |
success(fc).to(function (fc) { | |
return fc; | |
}) | |
); | |
}, | |
path3: memo(function () { | |
return or( | |
seq('~', '=', '{', p.posDecor, '}').to(function (pd) { | |
return AST.Command.Path.SetBeforeAction(pd.head.tail); | |
}), | |
seq('~', '/', '{', p.posDecor, '}').to(function (pd) { | |
return AST.Command.Path.SetAfterAction(pd.head.tail); | |
}), | |
seq('~', '<', '{', p.labels, '}').to(function (ls) { | |
return AST.Command.Path.AddLabelNextSegmentOnly(ls.head.tail); | |
}), | |
seq('~', '>', '{', p.labels, '}').to(function (ls) { | |
return AST.Command.Path.AddLabelLastSegmentOnly(ls.head.tail); | |
}), | |
seq('~', '+', '{', p.labels, '}').to(function (ls) { | |
return AST.Command.Path.AddLabelEverySegment(ls.head.tail); | |
}), | |
seq("'", p.segment).to(function (s) { | |
return AST.Command.Path.StraightSegment(s.tail); | |
}), | |
seq('`', p.turn, p.segment).to(function (ts) { | |
return AST.Command.Path.TurningSegment(ts.head.tail, ts.tail); | |
}) | |
); | |
}), | |
// <turn> ::= <diag> <turn-radius> | |
// | <cir> <turnradius> | |
turn: memo(function () { | |
return or( | |
p.nonemptyCir().and(p.turnRadius).to(function (cr) { | |
return AST.Command.Path.Turn.Cir(cr.head, cr.tail); | |
}), | |
p.diag().and(p.turnRadius).to(function (dr) { | |
return AST.Command.Path.Turn.Diag(dr.head, dr.tail); | |
}) | |
); | |
}), | |
// <turn-radius> ::= <empty> | '/' <dimen> | |
turnRadius: memo(function () { | |
return or( | |
lit('/').andr(p.dimen).to(function (d) { | |
return AST.Command.Path.TurnRadius.Dimen(d); | |
}), | |
success("default").to(function () { | |
return AST.Command.Path.TurnRadius.Default(); | |
}) | |
); | |
}), | |
// <segment> ::= <nonempty-pos> <slide> <labels> | |
segment: memo(function () { | |
return p.nonemptyPos().and(p.pathSlide).and(p.labels).to(function (psl) { | |
return AST.Command.Path.Segment(psl.head.head, psl.head.tail, psl.tail); | |
}); | |
}), | |
// <slide> ::= '<' <dimen> '>' | |
// | <empty> | |
pathSlide: memo(function () { | |
return or( | |
lit('<').andr(p.dimen).andl(flit('>')).to(function (d) { | |
return AST.Slide(FP.Option.Some(d)); | |
}), | |
success("no slide").to(function () { | |
return AST.Slide(FP.Option.empty); | |
}) | |
); | |
}), | |
// <labels> ::= <label>* | |
labels: memo(function () { | |
return p.label().rep().to(function (ls) { | |
return AST.Command.Path.Labels(ls); | |
}); | |
}), | |
// <label> ::= '^' <anchor> <it> <alias>? | |
// <label> ::= '_' <anchor> <it> <alias>? | |
// <label> ::= '|' <anchor> <it> <alias>? | |
label: memo(function () { | |
return or( | |
seq('^', p.anchor, p.it, p.alias).to(function (aia) { | |
return AST.Command.Path.Label.Above(AST.Pos.Place(aia.head.head.tail), aia.head.tail, aia.tail); | |
}), | |
seq('_', p.anchor, p.it, p.alias).to(function (aia) { | |
return AST.Command.Path.Label.Below(AST.Pos.Place(aia.head.head.tail), aia.head.tail, aia.tail); | |
}), | |
seq('|', p.anchor, p.it, p.alias).to(function (aia) { | |
return AST.Command.Path.Label.At(AST.Pos.Place(aia.head.head.tail), aia.head.tail, aia.tail); | |
}) | |
); | |
}), | |
// <anchor> ::= '-' <anchor> | <place> | |
anchor: memo(function () { | |
return or( | |
lit('-').andr(p.anchor).to(function (a) { | |
return AST.Place(1, 1, AST.Place.Factor(0.5), undefined).compound(a); | |
}), | |
p.place | |
); | |
}), | |
// <it> ::= ( '[' <shape> ']' )* <it2> | |
it: memo(function () { | |
return rep(lit('[').andr(p.shape).andl(flit(']')).to(function (s) { | |
return s; | |
})).and(p.it2).to(function (si) { | |
return AST.Object(si.head.concat(si.tail.modifiers), si.tail.object); | |
}); | |
}), | |
// <it2> ::= <digit> | <letter> | |
// | '{' <text> '}' | |
// | '\' <letters> | |
// | '*' <object> | |
// | '@' <dir> | |
it2: memo(function () { | |
return or( | |
regexLit(/^[0-9a-zA-Z]/).to(function (c) { | |
return AST.Object(FP.List.empty, p.toMath("\\labelstyle " + c)); | |
}), | |
regexLit(/^(\\[a-zA-Z][a-zA-Z0-9]*)/).to(function (c) { | |
return AST.Object(FP.List.empty, p.toMath("\\labelstyle " + c)); | |
}), | |
lit("{").andr(p.text).andl(felem("}")).to(function (t) { | |
return AST.Object(FP.List.empty, p.toMath("\\labelstyle " + t)); | |
}), | |
lit('*').andr(p.object), | |
lit('@').andr(p.dir).to(function (dir) { | |
return AST.Object(FP.List.empty, dir); | |
}) | |
); | |
}), | |
// <alias> ::= '=' '"' <id> '"' | |
alias: memo(function () { | |
return seq('=', '"', p.id, '"').opt().to(function (optId) { | |
return optId.map(function (id) { return id.head.tail; }); | |
}); | |
}), | |
// <xymatrix> ::= <setup> '{' <rows> '}' | |
xymatrix: memo(function () { | |
return p.setup().andl(flit("{")).and(p.rows).andl(flit("}")).to(function (sr) { | |
return AST.Command.Xymatrix(sr.head, sr.tail); | |
}) | |
}), | |
// <setup> ::= <switch>* | |
// <switch> ::= '"' <prefix> '"' | |
// | '@' <rcchar> <add op> <dimen> | |
// | '@' '!' <rcchar> '0' | |
// | '@' '!' <rcchar> '=' <dimen> | |
// | '@' '!' <rcchar> | |
// | '@' ( 'M' | 'W' | 'H' ) <add op> <dimen> | |
// | '@' '1' | |
// | '@' 'L' <add op> <dimen> | |
// | '@' <nonemptyDirection> | |
// | '@' '*' '[' <shape> ']' | |
// | '@' '*' <add op> <size> | |
// <rcchar> ::= 'R' | 'C' | <empty> | |
// <mwhlchar> ::= 'M' | 'W' | 'H' | 'L' | |
setup: memo(function () { | |
return rep(fun(or( | |
lit('"').andr(fun(regex(/^[^"]+/))).andl(felem('"')).to(function (p) { | |
return AST.Command.Xymatrix.Setup.Prefix(p); | |
}), | |
lit("@!").andr(fun(regex(/^[RC]/).opt().to(function (c) { | |
return c.getOrElse(""); | |
}))).and(fun( | |
or( | |
elem("0").to(function() { return "0em"; }), | |
elem("=").andr(p.dimen) | |
) | |
)).to(function (cd) { | |
var dimen = cd.tail; | |
switch (cd.head) { | |
case "R": return AST.Command.Xymatrix.Setup.PretendEntrySize.Height(dimen); | |
case "C": return AST.Command.Xymatrix.Setup.PretendEntrySize.Width(dimen); | |
default: return AST.Command.Xymatrix.Setup.PretendEntrySize.HeightAndWidth(dimen); | |
} | |
}), | |
lit("@!").andr(fun( | |
or( | |
elem("R").to(function () { return AST.Command.Xymatrix.Setup.FixGrid.Row(); }), | |
elem("C").to(function () { return AST.Command.Xymatrix.Setup.FixGrid.Column(); }) | |
).opt().to(function (rc) { | |
return rc.getOrElse(AST.Command.Xymatrix.Setup.FixGrid.RowAndColumn()); | |
}) | |
)), | |
lit("@").andr(fun(regex(/^[MWHL]/))).and(p.addOp).and(p.dimen).to(function (cod) { | |
var addop = cod.head.tail; | |
var dimen = cod.tail; | |
switch (cod.head.head) { | |
case "M": return AST.Command.Xymatrix.Setup.AdjustEntrySize.Margin(addop, dimen); | |
case "W": return AST.Command.Xymatrix.Setup.AdjustEntrySize.Width(addop, dimen); | |
case "H": return AST.Command.Xymatrix.Setup.AdjustEntrySize.Height(addop, dimen); | |
case "L": return AST.Command.Xymatrix.Setup.AdjustLabelSep(addop, dimen); | |
} | |
}), | |
lit("@").andr(p.nonemptyDirection).to(function (d) { | |
return AST.Command.Xymatrix.Setup.SetOrientation(d); | |
}), | |
lit("@*[").andr(p.shape).andl(flit("]")).to(function (s) { | |
return AST.Command.Xymatrix.Setup.AddModifier(s); | |
}), | |
lit("@*").andr(p.addOp).and(p.size).to(function (os) { | |
return AST.Command.Xymatrix.Setup.AddModifier(AST.Modifier.AddOp(os.head, os.tail)); | |
}), | |
lit("@").andr(fun(regex(/^[RC]/).opt().to(function (c) { | |
return c.getOrElse(""); | |
}))).and(p.addOp).and(p.dimen).to(function (cod) { | |
var addop = cod.head.tail; | |
var dimen = cod.tail; | |
switch (cod.head.head) { | |
case "R": return AST.Command.Xymatrix.Setup.ChangeSpacing.Row(addop, dimen); | |
case "C": return AST.Command.Xymatrix.Setup.ChangeSpacing.Column(addop, dimen); | |
default: return AST.Command.Xymatrix.Setup.ChangeSpacing.RowAndColumn(addop, dimen); | |
} | |
}), | |
lit("@1").to(function () { | |
return AST.Command.Xymatrix.Setup.AdjustEntrySize.Margin(AST.Modifier.AddOp.Set(), "1pc"); | |
}) | |
))); | |
}), | |
// <rows> ::= <row> ( '\\' <row> )* | |
rows: memo(function () { | |
return p.row().and(fun(rep(lit("\\\\").andr(p.row)))).to(function (rrs) { | |
var rows = rrs.tail.prepend(rrs.head); | |
if (!rows.isEmpty) { | |
var lastRow = rows.at(rows.length() - 1); | |
if (lastRow.entries.length() === 1 && lastRow.entries.at(0).isEmpty) { | |
rows = rows.reverse().tail.reverse(); | |
} | |
} | |
return rows; | |
}) | |
}), | |
// <row> ::= <entry> ( '&' <entry> )* | |
row: memo(function () { | |
return p.entry().and(fun(rep(lit("&").andr(p.entry)))).to(function (ees) { | |
return AST.Command.Xymatrix.Row(ees.tail.prepend(ees.head)); | |
}) | |
}), | |
// <entry> ::= '*' <object> <pos> <decor> | |
// | <entry modifier>* <loose objectbox> <decor> | |
entry: memo(function () { | |
return or( | |
lit("*").andr(p.object).and(p.pos).and(p.decor).to(function (opd) { | |
var obj = opd.head.head; | |
var pos = opd.head.tail; | |
var decor = opd.tail; | |
return AST.Command.Xymatrix.Entry.ObjectEntry(obj, pos, decor); | |
}), | |
p.entryModifier().rep().and(p.looseObjectbox).and(p.decor).to(function (mopd) { | |
var modifiers = mopd.head.head.foldLeft(FP.List.empty, function (tmpMs, ms) { | |
return ms.concat(tmpMs); | |
}); | |
var isEmpty = mopd.head.tail.isEmpty; | |
var objbox = mopd.head.tail.object; | |
var decor = mopd.tail; | |
if (isEmpty && modifiers.isEmpty) { | |
return AST.Command.Xymatrix.Entry.EmptyEntry(decor); | |
} | |
return AST.Command.Xymatrix.Entry.SimpleEntry(modifiers, objbox, decor); | |
}) | |
); | |
}), | |
// <entry modifier> ::= '**' '[' <shape> ']' | '**' '{' <modifier>* '}' | |
entryModifier: memo(function () { | |
return or( | |
lit("**").andr(flit("[")).andr(p.shape).andl(flit("]")).to(function (s) { | |
return FP.List.empty.append(s); | |
}), | |
lit("**").andr(flit("{")).andr(fun(rep(p.modifier))).andl(flit("}")) | |
); | |
}), | |
// <loose objectbox> ::= <objectbox> | |
// | /[^\\{}%&]+/* ( ( '\' not( '\' | <decor command names> ) ( '{' | '}' | '%' | '&' ) | '{' <text> '}' | /%[^\r\n]*(\r\n|\r|\n)?/ ) /[^\\{}%&]+/* )* | |
// <decor command names> ::= 'ar' | 'xymatrix' | 'PATH' | 'afterPATH' | |
// | 'save' | 'restore' | 'POS' | 'afterPOS' | 'drop' | 'connect' | 'xyignore' | |
looseObjectbox: memo(function () { | |
return or( | |
p.objectbox().to(function (o) { return { | |
isEmpty:false, object:o | |
} }), | |
regex(/^[^\\{}%&]+/).opt().to(function (rs) { return rs.getOrElse(""); }).and(fun( | |
rep( | |
or( | |
elem("{").andr(p.text).andl(felem("}")).to(function (t) { return "{" + t + "}"; }), | |
elem("\\").andr(fun( | |
not(regex(/^(\\|ar|xymatrix|PATH|afterPATH|save|restore|POS|afterPOS|drop|connect|xyignore|([lrud]+(twocell|uppertwocell|lowertwocell|compositemap))|xtwocell|xuppertwocell|xlowertwocell|xcompositemap)/)) | |
)).andr(fun( | |
regex(/^[{}%&]/).opt().to(function (c) { return c.getOrElse(""); }) | |
)).to(function (t) { | |
return "\\" + t; | |
}), | |
regex(/^%[^\r\n]*(\r\n|\r|\n)?/).to(function (x) { | |
return ' '; // ignore comments | |
}) | |
).and(fun( | |
regex(/^[^\\{}%&]+/).opt().to(function (cs) { return cs.getOrElse(""); }) | |
)).to(function (tt) { | |
return tt.head + tt.tail; | |
}) | |
).to(function (cs) { return cs.mkString("") }) | |
)).to(function (tt) { | |
var text = tt.head + tt.tail; | |
var isEmpty = (text.trim().length === 0); | |
var object = p.toMath("\\hbox{$\\objectstyle{" + text + "}$}"); | |
return { | |
isEmpty:isEmpty, object:object | |
}; | |
}) | |
) | |
}), | |
// <command> ::= <twocell> <twocell switch>* <twocell arrow> | |
twocellCommand: memo(function () { | |
return p.twocell().and(fun(rep(p.twocellSwitch))).and(p.twocellArrow).to(function (tsa) { | |
return AST.Command.Twocell(tsa.head.head, tsa.head.tail, tsa.tail); | |
}); | |
}), | |
// <twocell> ::= '\' /[lrud]+/ 'twocell' | |
// | '\' /[lrud]+/ 'uppertwocell' | |
// | '\' /[lrud]+/ 'lowertwocell' | |
// | '\' /[lrud]+/ 'compositemap' | |
// | '\xtwocell' '[' /[lrud]+/ ']' '{' <text> '}' | |
// | '\xuppertwocell' '[' /[lrud]+/ ']' '{' <text> '}' | |
// | '\xlowertwocell' '[' /[lrud]+/ ']' '{' <text> '}' | |
// | '\xcompositemap' '[' /[lrud]+/ ']' '{' <text> '}' | |
twocell: memo(function () { | |
return or( | |
regexLit(/^\\[lrud]+twocell/).to(function (h) { | |
var hops = h.substring(1, h.length - "twocell".length); | |
return AST.Command.Twocell.Twocell(hops, FP.Option.empty); | |
}), | |
regexLit(/^\\[lrud]+uppertwocell/).to(function (h) { | |
var hops = h.substring(1, h.length - "uppertwocell".length); | |
return AST.Command.Twocell.UpperTwocell(hops, FP.Option.empty); | |
}), | |
regexLit(/^\\[lrud]+lowertwocell/).to(function (h) { | |
var hops = h.substring(1, h.length - "lowertwocell".length); | |
return AST.Command.Twocell.LowerTwocell(hops, FP.Option.empty); | |
}), | |
regexLit(/^\\[lrud]+compositemap/).to(function (h) { | |
var hops = h.substring(1, h.length - "compositemap".length); | |
return AST.Command.Twocell.CompositeMap(hops, FP.Option.empty); | |
}), | |
or( | |
lit("\\xtwocell").to(function () { return AST.Command.Twocell.Twocell; }), | |
lit("\\xuppertwocell").to(function () { return AST.Command.Twocell.UpperTwocell; }), | |
lit("\\xlowertwocell").to(function () { return AST.Command.Twocell.LowerTwocell; }), | |
lit("\\xcompositemap").to(function () { return AST.Command.Twocell.CompositeMap; }) | |
).andl(flit("[")).and(fun(regex(/^[lrud]+/))).andl(flit("]")).andl(flit("{")).and(p.text).andl(flit("}")).to(function (cht) { | |
var textObject = AST.Object(FP.List.empty, p.toMath("\\labelstyle " + cht.tail)); | |
return cht.head.head(cht.head.tail, FP.Option.Some(textObject)); | |
}) | |
); | |
}), | |
// <twocell switch> ::= '^' <twocell label> | |
// | '_' <twocell label> | |
// | '\omit' | |
// | '~!' | |
// | '~' ( '`' | "'" ) '{' <object> '}' | |
// | '~' ( '' | '^' | '_' ) '{' <object> ( '~**' <object> )? '}' | |
// | <nudge> | |
twocellSwitch: memo(function () { | |
return or( | |
lit("^").andr(p.twocellLabel).to(function (l) { | |
return AST.Command.Twocell.Switch.UpperLabel(l); | |
}), | |
lit("_").andr(p.twocellLabel).to(function (l) { | |
return AST.Command.Twocell.Switch.LowerLabel(l); | |
}), | |
lit("\\omit").to(function () { | |
return AST.Command.Twocell.Switch.DoNotSetCurvedArrows(); | |
}), | |
lit("~!").to(function () { | |
return AST.Command.Twocell.Switch.PlaceModMapObject(); | |
}), | |
regexLit(/^(~[`'])/).andl(flit("{")).and(p.object).andl(flit("}")).to(function (wo) { | |
var what = wo.head.substring(1); | |
return AST.Command.Twocell.Switch.ChangeHeadTailObject(what, wo.tail); | |
}), | |
regexLit(/^(~[\^_]?)/).andl(flit("{")).and(p.object).and(fun(opt(lit("~**").andr(p.object)))).andl(flit("}")).to(function (wso) { | |
var what = wso.head.head.substring(1); | |
var spacer = wso.head.tail; | |
var maybeObject = wso.tail; | |
return AST.Command.Twocell.Switch.ChangeCurveObject(what, spacer, maybeObject); | |
}), | |
p.nudge().to(function (n) { | |
return AST.Command.Twocell.Switch.SetCurvature(n); | |
}) | |
); | |
}), | |
// <twocell label> ::= <digit> | <letter> | <cs> | |
// | '{' <nudge>? '*' <object> '}' | |
// | '{' <nudge>? <text> '}' | |
twocellLabel: memo(function () { | |
return or( | |
regexLit(/^[0-9a-zA-Z]/).to(function (c) { | |
var obj = AST.Object(FP.List.empty, p.toMath("\\twocellstyle " + c)); | |
return AST.Command.Twocell.Label(FP.Option.empty, obj); | |
}), | |
regexLit(/^(\\[a-zA-Z][a-zA-Z0-9]*)/).to(function (c) { | |
var obj = AST.Object(FP.List.empty, p.toMath("\\twocellstyle " + c)); | |
return AST.Command.Twocell.Label(FP.Option.empty, obj); | |
}), | |
lit("{").andr(fun(opt(p.nudge))).andl(flit("*")).and(p.object).andl(flit("}")).to(function (no) { | |
return AST.Command.Twocell.Label(no.head, no.tail); | |
}), | |
lit("{").andr(fun(opt(p.nudge))).and(p.text).andl(felem("}")).to(function (nt) { | |
var obj = AST.Object(FP.List.empty, p.toMath("\\twocellstyle " + nt.tail)); | |
return AST.Command.Twocell.Label(nt.head, obj); | |
}) | |
); | |
}), | |
// <nudge> ::= '<' <factor> '>' | |
// | '<\omit>' | |
nudge: memo(function () { | |
return or( | |
lit("<\\omit>").to(function () { | |
return AST.Command.Twocell.Nudge.Omit(); | |
}), | |
lit("<").andr(p.factor).andl(flit(">")).to(function (n) { | |
return AST.Command.Twocell.Nudge.Number(n); | |
}) | |
); | |
}), | |
// <twocell arrow> ::= '{' <twocell tok> (<twocell label entry> '}' | |
// | '{' <nudge> <twocell label entry> '}' | |
// | '{' <twocell label entry> '}' | |
// | <empty> | |
// <twocell tok> ::= '^' | '_' | '=' | |
// | '\omit' | |
// | '`' | "'" | '"' | '!' | |
twocellArrow: memo(function () { | |
return or( | |
lit("{").andr(fun(regexLit(/^([\^_=`'"!]|\\omit)/))).and(p.twocellLabelEntry).andl(flit("}")).to(function (te) { | |
return AST.Command.Twocell.Arrow.WithOrientation(te.head, te.tail); | |
}), | |
lit("{").andr(p.nudge).and(p.twocellLabelEntry).andl(flit("}")).to(function (te) { | |
return AST.Command.Twocell.Arrow.WithPosition(te.head, te.tail); | |
}), | |
lit("{").andr(p.twocellLabelEntry).andl(flit("}")).to(function (e) { | |
return AST.Command.Twocell.Arrow.WithOrientation('', e); | |
}), | |
success("no arrow label").to(function () { | |
// TODO 無駄な空描画処理をなくす。 | |
return AST.Command.Twocell.Arrow.WithOrientation('', AST.Object(FP.List.empty, p.toMath("\\twocellstyle{}"))); | |
}) | |
); | |
}), | |
// <twocell label entry> ::= '*' <object> | |
// | <text> | |
twocellLabelEntry: memo(function () { | |
return or( | |
lit("*").andr(p.object), | |
p.text().to(function (t) { | |
return AST.Object(FP.List.empty, p.toMath("\\twocellstyle " + t)); | |
}) | |
); | |
}), | |
// \newdirの後の | |
// '{' <main> '}' '{' <composite_object> '}' | |
newdir: memo(function () { | |
return lit("{").andr(p.dirMain).andl(felem("}")).andl(flit("{")).and(p.compositeObject).andl(flit("}")).to(function (mc) { | |
return AST.Command.Newdir(mc.head, AST.ObjectBox.CompositeObject(mc.tail)); | |
}); | |
}), | |
// '\xyimport' '(' <factor> ',' <factor> ')' ( '(' <factor> ',' <factor> ')' )? '{' ( <include graphics> | <TeX command> ) '}' | |
xyimport: memo(function () { | |
return lit("\\xyimport").andr(flit("(")).andr(p.factor).andl(flit(",")).and(p.factor).andl(flit(")")).and(fun( | |
opt(lit("(").andr(p.factor).andl(flit(",")).and(p.factor).andl(flit(")"))) | |
)).andl(flit("{")).and(fun( | |
or( | |
lit("\\includegraphics").andr(p.includegraphics), | |
p.text().to(function (t) { return p.toMath("\\hbox{$\\objectstyle{" + t + "}$}"); }) | |
))).andl(flit("}")).to(function (whog) { | |
var w = whog.head.head.head; | |
var h = whog.head.head.tail; | |
var xOffset, yOffset; | |
if (whog.head.tail.isDefined) { | |
xOffset = whog.head.tail.get.head; | |
yOffset = whog.head.tail.get.tail; | |
} else { | |
xOffset = 0; | |
yOffset = 0; | |
} | |
var graphics = whog.tail; | |
if (graphics.isIncludegraphics !== undefined) { | |
return AST.Pos.Xyimport.Graphics(w, h, xOffset, yOffset, graphics); | |
} else { | |
return AST.Pos.Xyimport.TeXCommand(w, h, xOffset, yOffset, graphics); | |
} | |
}); | |
}), | |
// \includegraphicsの後の | |
// '*'? '[' ( <includegraphics attr list> )? ']' '{' <file path> '}' | |
includegraphics: memo(function () { | |
return lit("[").andr(fun(opt(p.includegraphicsAttrList))).andl(flit("]")).andl(flit("{")).and(fun(regexLit(/^[^\s{}]+/))).andl(flit("}")).to(function (af) { | |
var attrList = af.head.getOrElse(FP.List.empty); | |
var file = af.tail; | |
return AST.Command.Includegraphics(false, attrList, file); | |
}); | |
}), | |
// <includegraphics attr list> := <includegraphics attr key val> ( ',' <includegraphics attr key val> )* | |
includegraphicsAttrList: memo(function () { | |
return p.includegraphicsAttr().and(fun(rep(lit(",").andr(p.includegraphicsAttr)))).to(function (aas) { | |
return aas.tail.prepend(aas.head); | |
}); | |
}), | |
// <includegraphics attr key val> := 'width' '=' <dimen> | |
// | 'height' '=' <dimen> | |
includegraphicsAttr: memo(function () { | |
return or( | |
lit("width").andr(flit("=")).andr(p.dimen).to(function (d) { | |
return AST.Command.Includegraphics.Attr.Width(d); | |
}), | |
lit("height").andr(flit("=")).andr(p.dimen).to(function (d) { | |
return AST.Command.Includegraphics.Attr.Height(d); | |
}) | |
); | |
}) | |
})(); | |
MathJax.Hub.Insert(TEXDEF,{ | |
environment: { | |
xy: ['XY', null] | |
} | |
}); | |
xypic.ExecutionError = MathJax.Object.Subclass({ | |
Init: function (message) { | |
this.message = message; | |
}, | |
toMML: function () { | |
return MML.merror(MML.mtext(this.message)); | |
}, | |
texError: true, | |
xyjaxError: true | |
}); | |
xypic.ParseError = MathJax.Object.Subclass({ | |
Init: function (parseResult) { | |
this.parseResult = parseResult; | |
}, | |
toMML: function () { | |
var pos = this.parseResult.next.pos(); | |
var lineContents = pos.lineContents(); | |
return MML.merror(MML.mtext('parse error at or near "' + lineContents + '"')); | |
/* | |
var col = pos.column(); | |
var left = lineContents.substring(0, col-1); | |
var mid = lineContents.substring(col-1, col); | |
var right = lineContents.substring(col); | |
return MML.merror(MML.mtext('parse error at or near "'), MML.mtext(left).With({color:"black"}), MML.mtext(mid).With({color:"red"}), MML.mtext(right).With({color:"black"}), MML.mtext('"')); | |
*/ | |
}, | |
texError: true, | |
xyjaxError: true | |
}); | |
TEX.Parse.Augment({ | |
/* | |
* Handle XY environment | |
*/ | |
XY: function(begin) { | |
try { | |
var parseContext = { | |
lastNoSuccess: undefined, | |
whiteSpaceRegex: xypic.constants.whiteSpaceRegex | |
}; | |
var input = FP.StringReader(this.string, this.i, parseContext); | |
var result = FP.Parsers.parse(p.xy(), input); | |
this.i = result.next.offset; | |
} catch (e) { | |
throw e; | |
} | |
if (result.successful) { | |
if (supportGraphics) { | |
this.Push(AST.xypic(result.result)); | |
} else { | |
this.Push(MML.merror(xypic.unsupportedBrowserErrorMessage)); | |
} | |
} else { | |
throw xypic.ParseError(parseContext.lastNoSuccess); | |
} | |
return begin; | |
}, | |
/** | |
* Handle xybox | |
*/ | |
Xybox: function () { | |
try { | |
var parseContext = { | |
lastNoSuccess: undefined, | |
whiteSpaceRegex: xypic.constants.whiteSpaceRegex | |
}; | |
var input = FP.StringReader(this.string, this.i, parseContext); | |
var result = FP.Parsers.parse(p.xybox(), input); | |
this.i = result.next.offset; | |
} catch (e) { | |
throw e; | |
} | |
if (result.successful) { | |
if (supportGraphics) { | |
this.Push(AST.xypic(result.result)); | |
} else { | |
this.Push(MML.merror(xypic.unsupportedBrowserErrorMessage)); | |
} | |
} else { | |
throw xypic.ParseError(parseContext.lastNoSuccess); | |
} | |
}, | |
/** | |
* Handle xymatrix | |
*/ | |
Xymatrix: function () { | |
try { | |
var parseContext = { | |
lastNoSuccess: undefined, | |
whiteSpaceRegex: xypic.constants.whiteSpaceRegex | |
}; | |
var input = FP.StringReader(this.string, this.i, parseContext); | |
var result = FP.Parsers.parse(p.xymatrixbox(), input); | |
this.i = result.next.offset; | |
} catch (e) { | |
throw e; | |
} | |
if (result.successful) { | |
if (supportGraphics) { | |
this.Push(AST.xypic(result.result)); | |
} else { | |
this.Push(MML.merror(xypic.unsupportedBrowserErrorMessage)); | |
} | |
} else { | |
throw xypic.ParseError(parseContext.lastNoSuccess); | |
} | |
}, | |
/** | |
* Handle newdir | |
*/ | |
XypicNewdir: function () { | |
try { | |
var parseContext = { | |
lastNoSuccess: undefined, | |
whiteSpaceRegex: xypic.constants.whiteSpaceRegex | |
}; | |
var input = FP.StringReader(this.string, this.i, parseContext); | |
var result = FP.Parsers.parse(p.newdir(), input); | |
this.i = result.next.offset; | |
} catch (e) { | |
throw e; | |
} | |
if (result.successful) { | |
if (supportGraphics) { | |
this.Push(AST.xypic.newdir(result.result)); | |
} else { | |
this.Push(MML.merror(xypic.unsupportedBrowserErrorMessage)); | |
} | |
} else { | |
throw xypic.ParseError(parseContext.lastNoSuccess); | |
} | |
}, | |
/** | |
* Handle includegraphics | |
*/ | |
Xyincludegraphics: function () { | |
try { | |
var parseContext = { | |
lastNoSuccess: undefined, | |
whiteSpaceRegex: xypic.constants.whiteSpaceRegex | |
}; | |
var input = FP.StringReader(this.string, this.i, parseContext); | |
var result = FP.Parsers.parse(p.includegraphics(), input); | |
this.i = result.next.offset; | |
} catch (e) { | |
throw e; | |
} | |
if (result.successful) { | |
if (supportGraphics) { | |
this.Push(AST.xypic.includegraphics(result.result)); | |
} else { | |
this.Push(MML.merror(xypic.unsupportedBrowserErrorMessage)); | |
} | |
} else { | |
throw xypic.ParseError(parseContext.lastNoSuccess); | |
} | |
} | |
}); | |
var supportGraphics = false; | |
MathJax.Hub.Browser.Select({ | |
Firefox: function (browser) { | |
supportGraphics = true; | |
}, | |
Safari: function (browser) { | |
supportGraphics = true; | |
}, | |
Chrome: function (browser) { | |
supportGraphics = true; | |
}, | |
Opera: function (browser) { | |
supportGraphics = true; | |
}, | |
MSIE: function (browser) { | |
if (MathJax.Hub.Browser.versionAtLeast("9.0") && document.documentMode >= 9) { | |
supportGraphics = true; | |
} | |
} | |
}); | |
MathJax.Hub.Startup.signal.Post("TeX Xy-pic Ready"); | |
}); | |
MathJax.Hub.Register.StartupHook("HTML-CSS Xy-pic Config Require",function () { | |
MathJax.Hub.Startup.signal.Post("HTML-CSS Xy-pic Config Ready"); | |
}); | |
MathJax.Hub.Register.StartupHook("SVG Xy-pic Config Require",function () { | |
MathJax.Hub.Startup.signal.Post("SVG Xy-pic Config Ready"); | |
}); | |
MathJax.Hub.Register.StartupHook("Device-Independent Xy-pic Require",function () { | |
var FP = MathJax.Extension.fp; | |
var MML = MathJax.ElementJax.mml; | |
var HUB = MathJax.Hub; | |
var xypic = MathJax.Extension.xypic; | |
var AST = xypic.AST; | |
var SVGNS = "http://www.w3.org/2000/svg"; | |
var XHTMLNS = "http://www.w3.org/1999/xhtml"; | |
var XLINKNS = "http://www.w3.org/1999/xlink"; | |
// override MathJax.Hub.formatError function to display runtime error. | |
var hub_formatError = HUB.formatError; | |
HUB.formatError = function (script, err) { | |
if (err.xyjaxError !== undefined) { | |
var origMessage = HUB.config.errorSettings.message; | |
HUB.config.errorSettings.message = "[" + err.message + "]"; | |
hub_formatError.apply(HUB, [script, err]); | |
HUB.config.errorSettings.message = origMessage; | |
} else { | |
throw err; | |
hub_formatError.apply(HUB, [script, err]); | |
} | |
} | |
var memoize = xypic.memoize; | |
AST.xypic.Augment({}, { | |
lengthResolution: 128, | |
interpolationResolution: 5, | |
machinePrecision: 1e-12 | |
}); | |
xypic.DirRepository = MathJax.Object.Subclass({ | |
Init: function () { | |
this.userDirMap = {}; | |
}, | |
get: function (dirMain) { | |
return this.userDirMap[dirMain]; | |
}, | |
put: function (dirMain, compositeObject) { | |
this.userDirMap[dirMain] = compositeObject; | |
} | |
}); | |
xypic.ModifierRepository = MathJax.Object.Subclass({ | |
Init: function () { | |
this.userModifierMap = {}; | |
}, | |
get: function (shapeName) { | |
var modifier = xypic.ModifierRepository.embeddedModifierMap[shapeName]; | |
if (modifier !== undefined) { | |
return modifier; | |
} | |
return this.userModifierMap[shapeName]; | |
}, | |
put: function (shapeName, modifier) { | |
if (xypic.ModifierRepository.embeddedModifierMap[shapeName] === undefined) { | |
this.userModifierMap[shapeName] = modifier; | |
} | |
} | |
}, { | |
embeddedModifierMap: { | |
"o":AST.Modifier.Shape.Circle(), | |
"l":AST.Modifier.Shape.L(), | |
"r":AST.Modifier.Shape.R(), | |
"u":AST.Modifier.Shape.U(), | |
"d":AST.Modifier.Shape.D(), | |
"c":AST.Modifier.Shape.C(), | |
"aliceblue":AST.Modifier.Shape.ChangeColor("aliceblue"), | |
"antiquewhite":AST.Modifier.Shape.ChangeColor("antiquewhite"), | |
"aqua":AST.Modifier.Shape.ChangeColor("aqua"), | |
"aquamarine":AST.Modifier.Shape.ChangeColor("aquamarine"), | |
"azure":AST.Modifier.Shape.ChangeColor("azure"), | |
"beige":AST.Modifier.Shape.ChangeColor("beige"), | |
"bisque":AST.Modifier.Shape.ChangeColor("bisque"), | |
"black":AST.Modifier.Shape.ChangeColor("black"), | |
"blanchedalmond":AST.Modifier.Shape.ChangeColor("blanchedalmond"), | |
"blue":AST.Modifier.Shape.ChangeColor("blue"), | |
"blueviolet":AST.Modifier.Shape.ChangeColor("blueviolet"), | |
"brown":AST.Modifier.Shape.ChangeColor("brown"), | |
"burlywood":AST.Modifier.Shape.ChangeColor("burlywood"), | |
"cadetblue":AST.Modifier.Shape.ChangeColor("cadetblue"), | |
"chartreuse":AST.Modifier.Shape.ChangeColor("chartreuse"), | |
"chocolate":AST.Modifier.Shape.ChangeColor("chocolate"), | |
"coral":AST.Modifier.Shape.ChangeColor("coral"), | |
"cornflowerblue":AST.Modifier.Shape.ChangeColor("cornflowerblue"), | |
"cornsilk":AST.Modifier.Shape.ChangeColor("cornsilk"), | |
"crimson":AST.Modifier.Shape.ChangeColor("crimson"), | |
"cyan":AST.Modifier.Shape.ChangeColor("cyan"), | |
"darkblue":AST.Modifier.Shape.ChangeColor("darkblue"), | |
"darkcyan":AST.Modifier.Shape.ChangeColor("darkcyan"), | |
"darkgoldenrod":AST.Modifier.Shape.ChangeColor("darkgoldenrod"), | |
"darkgray":AST.Modifier.Shape.ChangeColor("darkgray"), | |
"darkgreen":AST.Modifier.Shape.ChangeColor("darkgreen"), | |
"darkgrey":AST.Modifier.Shape.ChangeColor("darkgrey"), | |
"darkkhaki":AST.Modifier.Shape.ChangeColor("darkkhaki"), | |
"darkmagenta":AST.Modifier.Shape.ChangeColor("darkmagenta"), | |
"darkolivegreen":AST.Modifier.Shape.ChangeColor("darkolivegreen"), | |
"darkorange":AST.Modifier.Shape.ChangeColor("darkorange"), | |
"darkorchid":AST.Modifier.Shape.ChangeColor("darkorchid"), | |
"darkred":AST.Modifier.Shape.ChangeColor("darkred"), | |
"darksalmon":AST.Modifier.Shape.ChangeColor("darksalmon"), | |
"darkseagreen":AST.Modifier.Shape.ChangeColor("darkseagreen"), | |
"darkslateblue":AST.Modifier.Shape.ChangeColor("darkslateblue"), | |
"darkslategray":AST.Modifier.Shape.ChangeColor("darkslategray"), | |
"darkslategrey":AST.Modifier.Shape.ChangeColor("darkslategrey"), | |
"darkturquoise":AST.Modifier.Shape.ChangeColor("darkturquoise"), | |
"darkviolet":AST.Modifier.Shape.ChangeColor("darkviolet"), | |
"deeppink":AST.Modifier.Shape.ChangeColor("deeppink"), | |
"deepskyblue":AST.Modifier.Shape.ChangeColor("deepskyblue"), | |
"dimgray":AST.Modifier.Shape.ChangeColor("dimgray"), | |
"dimgrey":AST.Modifier.Shape.ChangeColor("dimgrey"), | |
"dodgerblue":AST.Modifier.Shape.ChangeColor("dodgerblue"), | |
"firebrick":AST.Modifier.Shape.ChangeColor("firebrick"), | |
"floralwhite":AST.Modifier.Shape.ChangeColor("floralwhite"), | |
"forestgreen":AST.Modifier.Shape.ChangeColor("forestgreen"), | |
"fuchsia":AST.Modifier.Shape.ChangeColor("fuchsia"), | |
"gainsboro":AST.Modifier.Shape.ChangeColor("gainsboro"), | |
"ghostwhite":AST.Modifier.Shape.ChangeColor("ghostwhite"), | |
"gold":AST.Modifier.Shape.ChangeColor("gold"), | |
"goldenrod":AST.Modifier.Shape.ChangeColor("goldenrod"), | |
"gray":AST.Modifier.Shape.ChangeColor("gray"), | |
"grey":AST.Modifier.Shape.ChangeColor("grey"), | |
"green":AST.Modifier.Shape.ChangeColor("green"), | |
"greenyellow":AST.Modifier.Shape.ChangeColor("greenyellow"), | |
"honeydew":AST.Modifier.Shape.ChangeColor("honeydew"), | |
"hotpink":AST.Modifier.Shape.ChangeColor("hotpink"), | |
"indianred":AST.Modifier.Shape.ChangeColor("indianred"), | |
"indigo":AST.Modifier.Shape.ChangeColor("indigo"), | |
"ivory":AST.Modifier.Shape.ChangeColor("ivory"), | |
"khaki":AST.Modifier.Shape.ChangeColor("khaki"), | |
"lavender":AST.Modifier.Shape.ChangeColor("lavender"), | |
"lavenderblush":AST.Modifier.Shape.ChangeColor("lavenderblush"), | |
"lawngreen":AST.Modifier.Shape.ChangeColor("lawngreen"), | |
"lemonchiffon":AST.Modifier.Shape.ChangeColor("lemonchiffon"), | |
"lightblue":AST.Modifier.Shape.ChangeColor("lightblue"), | |
"lightcoral":AST.Modifier.Shape.ChangeColor("lightcoral"), | |
"lightcyan":AST.Modifier.Shape.ChangeColor("lightcyan"), | |
"lightgoldenrodyellow":AST.Modifier.Shape.ChangeColor("lightgoldenrodyellow"), | |
"lightgray":AST.Modifier.Shape.ChangeColor("lightgray"), | |
"lightgreen":AST.Modifier.Shape.ChangeColor("lightgreen"), | |
"lightgrey":AST.Modifier.Shape.ChangeColor("lightgrey"), | |
"lightpink":AST.Modifier.Shape.ChangeColor("lightpink"), | |
"lightsalmon":AST.Modifier.Shape.ChangeColor("lightsalmon"), | |
"lightseagreen":AST.Modifier.Shape.ChangeColor("lightseagreen"), | |
"lightskyblue":AST.Modifier.Shape.ChangeColor("lightskyblue"), | |
"lightslategray":AST.Modifier.Shape.ChangeColor("lightslategray"), | |
"lightslategrey":AST.Modifier.Shape.ChangeColor("lightslategrey"), | |
"lightsteelblue":AST.Modifier.Shape.ChangeColor("lightsteelblue"), | |
"lightyellow":AST.Modifier.Shape.ChangeColor("lightyellow"), | |
"lime":AST.Modifier.Shape.ChangeColor("lime"), | |
"limegreen":AST.Modifier.Shape.ChangeColor("limegreen"), | |
"linen":AST.Modifier.Shape.ChangeColor("linen"), | |
"magenta":AST.Modifier.Shape.ChangeColor("magenta"), | |
"maroon":AST.Modifier.Shape.ChangeColor("maroon"), | |
"mediumaquamarine":AST.Modifier.Shape.ChangeColor("mediumaquamarine"), | |
"mediumblue":AST.Modifier.Shape.ChangeColor("mediumblue"), | |
"mediumorchid":AST.Modifier.Shape.ChangeColor("mediumorchid"), | |
"mediumpurple":AST.Modifier.Shape.ChangeColor("mediumpurple"), | |
"mediumseagreen":AST.Modifier.Shape.ChangeColor("mediumseagreen"), | |
"mediumslateblue":AST.Modifier.Shape.ChangeColor("mediumslateblue"), | |
"mediumspringgreen":AST.Modifier.Shape.ChangeColor("mediumspringgreen"), | |
"mediumturquoise":AST.Modifier.Shape.ChangeColor("mediumturquoise"), | |
"mediumvioletred":AST.Modifier.Shape.ChangeColor("mediumvioletred"), | |
"midnightblue":AST.Modifier.Shape.ChangeColor("midnightblue"), | |
"mintcream":AST.Modifier.Shape.ChangeColor("mintcream"), | |
"mistyrose":AST.Modifier.Shape.ChangeColor("mistyrose"), | |
"moccasin":AST.Modifier.Shape.ChangeColor("moccasin"), | |
"navajowhite":AST.Modifier.Shape.ChangeColor("navajowhite"), | |
"navy":AST.Modifier.Shape.ChangeColor("navy"), | |
"oldlace":AST.Modifier.Shape.ChangeColor("oldlace"), | |
"olive":AST.Modifier.Shape.ChangeColor("olive"), | |
"olivedrab":AST.Modifier.Shape.ChangeColor("olivedrab"), | |
"orange":AST.Modifier.Shape.ChangeColor("orange"), | |
"orangered":AST.Modifier.Shape.ChangeColor("orangered"), | |
"orchid":AST.Modifier.Shape.ChangeColor("orchid"), | |
"palegoldenrod":AST.Modifier.Shape.ChangeColor("palegoldenrod"), | |
"palegreen":AST.Modifier.Shape.ChangeColor("palegreen"), | |
"paleturquoise":AST.Modifier.Shape.ChangeColor("paleturquoise"), | |
"palevioletred":AST.Modifier.Shape.ChangeColor("palevioletred"), | |
"papayawhip":AST.Modifier.Shape.ChangeColor("papayawhip"), | |
"peachpuff":AST.Modifier.Shape.ChangeColor("peachpuff"), | |
"peru":AST.Modifier.Shape.ChangeColor("peru"), | |
"pink":AST.Modifier.Shape.ChangeColor("pink"), | |
"plum":AST.Modifier.Shape.ChangeColor("plum"), | |
"powderblue":AST.Modifier.Shape.ChangeColor("powderblue"), | |
"purple":AST.Modifier.Shape.ChangeColor("purple"), | |
"red":AST.Modifier.Shape.ChangeColor("red"), | |
"rosybrown":AST.Modifier.Shape.ChangeColor("rosybrown"), | |
"royalblue":AST.Modifier.Shape.ChangeColor("royalblue"), | |
"saddlebrown":AST.Modifier.Shape.ChangeColor("saddlebrown"), | |
"salmon":AST.Modifier.Shape.ChangeColor("salmon"), | |
"sandybrown":AST.Modifier.Shape.ChangeColor("sandybrown"), | |
"seagreen":AST.Modifier.Shape.ChangeColor("seagreen"), | |
"seashell":AST.Modifier.Shape.ChangeColor("seashell"), | |
"sienna":AST.Modifier.Shape.ChangeColor("sienna"), | |
"silver":AST.Modifier.Shape.ChangeColor("silver"), | |
"skyblue":AST.Modifier.Shape.ChangeColor("skyblue"), | |
"slateblue":AST.Modifier.Shape.ChangeColor("slateblue"), | |
"slategray":AST.Modifier.Shape.ChangeColor("slategray"), | |
"slategrey":AST.Modifier.Shape.ChangeColor("slategrey"), | |
"snow":AST.Modifier.Shape.ChangeColor("snow"), | |
"springgreen":AST.Modifier.Shape.ChangeColor("springgreen"), | |
"steelblue":AST.Modifier.Shape.ChangeColor("steelblue"), | |
"tan":AST.Modifier.Shape.ChangeColor("tan"), | |
"teal":AST.Modifier.Shape.ChangeColor("teal"), | |
"thistle":AST.Modifier.Shape.ChangeColor("thistle"), | |
"tomato":AST.Modifier.Shape.ChangeColor("tomato"), | |
"turquoise":AST.Modifier.Shape.ChangeColor("turquoise"), | |
"violet":AST.Modifier.Shape.ChangeColor("violet"), | |
"wheat":AST.Modifier.Shape.ChangeColor("wheat"), | |
"white":AST.Modifier.Shape.ChangeColor("white"), | |
"whitesmoke":AST.Modifier.Shape.ChangeColor("whitesmoke"), | |
"yellow":AST.Modifier.Shape.ChangeColor("yellow"), | |
"yellowgreen":AST.Modifier.Shape.ChangeColor("yellowgreen") | |
} | |
}); | |
// user defined shapes are global in scope. | |
xypic.repositories = MathJax.Object.Subclass({}); | |
xypic.repositories.modifierRepository = xypic.ModifierRepository(); | |
xypic.repositories.dirRepository = xypic.DirRepository(); | |
xypic.Graphics = MathJax.Object.Subclass({}, { | |
createElement: function (type) { | |
// if (document.createElementNS !== undefined) { | |
return document.createElementNS(SVGNS, type); | |
// } else { | |
// return document.createElement(type); | |
// } | |
} | |
}); | |
xypic.Graphics.SVG = xypic.Graphics.Subclass({ | |
createGroup: function (transform) { | |
return xypic.Graphics.SVG.Group(this, transform); | |
}, | |
createChangeColorGroup: function (color) { | |
return xypic.Graphics.SVG.ChangeColorGroup(this, color); | |
}, | |
createSVGElement: function (type, def) { | |
var obj = xypic.Graphics.createElement(type); | |
if (def) { | |
for (var id in def) { | |
if (def.hasOwnProperty(id)) { | |
if (id === "xlink:href") { | |
obj.setAttributeNS(XLINKNS, id, def[id].toString()); | |
} else { | |
obj.setAttribute(id, def[id].toString()); | |
} | |
} | |
} | |
} | |
this.drawArea.appendChild(obj); | |
return obj; | |
}, | |
appendChild: function (svgElement) { | |
this.drawArea.appendChild(svgElement); | |
return svgElement; | |
}, | |
transformBuilder: function () { | |
return xypic.Graphics.SVG.Transform(); | |
} | |
}); | |
xypic.Graphics.SVG.World = xypic.Graphics.SVG.Subclass({ | |
Init: function (height, depth, width, strokeWidth, color, def) { | |
var svg = xypic.Graphics.createElement("svg"); | |
svg.setAttribute("xmlns", SVGNS); | |
svg.setAttribute("version", "1.1"); | |
if (def) { | |
for (var id in def) { | |
if (def.hasOwnProperty(id)) { | |
svg.setAttribute(id, def[id].toString()); | |
} | |
} | |
} | |
if (svg.style) { | |
svg.style.width = xypic.Em(width); | |
svg.style.height = xypic.Em(height + depth); | |
} | |
var def = { | |
fill:"none", stroke:color, "stroke-linecap":"round", | |
"stroke-width":xypic.em2px(strokeWidth) | |
}; | |
this.drawArea = xypic.Graphics.createElement("g"); | |
for (var id in def) { | |
if (def.hasOwnProperty(id)) { | |
this.drawArea.setAttribute(id, def[id].toString()); | |
} | |
} | |
svg.appendChild(this.drawArea); | |
this.svg = svg; | |
this.boundingBox = undefined; | |
this.color = color; | |
}, | |
setHeight: function (height) { | |
this.svg.style.height = xypic.Em(height); | |
}, | |
setWidth: function (height) { | |
this.svg.style.width = xypic.Em(height); | |
}, | |
setAttribute: function (name, value) { | |
this.svg.setAttribute(name, value.toString()); | |
}, | |
extendBoundingBox: function (boundingBox) { | |
this.boundingBox = xypic.Frame.combineRect(this.boundingBox, boundingBox); | |
}, | |
getOrigin: function () { | |
return { x:0, y:0 }; | |
}, | |
getCurrentColor: function () { | |
return this.color; | |
} | |
}); | |
xypic.Graphics.SVG.Transform = MathJax.Object.Subclass({ | |
Init: function (transform) { | |
this.transform = transform || FP.List.empty; | |
}, | |
translate: function (x, y) { | |
return xypic.Graphics.SVG.Transform( | |
this.transform.append(xypic.Graphics.SVG.Transform.Translate(x, y)) | |
); | |
}, | |
rotateDegree: function (degree) { | |
return xypic.Graphics.SVG.Transform( | |
this.transform.append(xypic.Graphics.SVG.Transform.Rotate(degree / 180 * Math.PI)) | |
); | |
}, | |
rotateRadian: function (radian) { | |
return xypic.Graphics.SVG.Transform( | |
this.transform.append(xypic.Graphics.SVG.Transform.Rotate(radian)) | |
); | |
}, | |
toString: function () { | |
var form = ""; | |
this.transform.foreach(function (tr) { form += tr.toTranslateForm() }); | |
return form; | |
}, | |
apply: function (x, y) { | |
var o = { x:x, y:y }; | |
this.transform.foreach(function (tr) { o = tr.apply(o.x, o.y) }); | |
return o; | |
} | |
}); | |
xypic.Graphics.SVG.Transform.Translate = MathJax.Object.Subclass({ | |
Init: function (dx, dy) { | |
this.dx = dx; | |
this.dy = dy; | |
}, | |
apply: function (x, y) { | |
return { x:x - this.dx, y:y + this.dy }; | |
}, | |
toTranslateForm: function () { | |
return "translate(" + xypic.em2px(this.dx) + "," + xypic.em2px(-this.dy) + ") "; | |
} | |
}); | |
xypic.Graphics.SVG.Transform.Rotate = MathJax.Object.Subclass({ | |
Init: function (radian) { | |
this.radian = radian; | |
}, | |
apply: function (x, y) { | |
var c = Math.cos(this.radian); | |
var s = Math.sin(this.radian); | |
return { x:c * x + s * y, y:-s * x + c * y }; | |
}, | |
toTranslateForm: function () { | |
return "rotate(" + (-180 * this.radian / Math.PI) + ") "; | |
} | |
}); | |
xypic.Graphics.SVG.Group = xypic.Graphics.SVG.Subclass({ | |
Init: function (parent, transform) { | |
this.parent = parent; | |
this.drawArea = parent.createSVGElement("g", | |
transform === undefined? {} : { transform: transform.toString() }); | |
var parentOrigin = parent.getOrigin(); | |
if (transform === undefined) { | |
this.origin = parentOrigin; | |
} else { | |
this.origin = transform.apply(parentOrigin.x, parentOrigin.y); | |
} | |
memoize(this, "getCurrentColor"); | |
}, | |
remove: function () { | |
this.drawArea.parentNode.removeChild(this.drawArea); | |
}, | |
extendBoundingBox: function (boundingBox) { | |
this.parent.extendBoundingBox(boundingBox); | |
}, | |
getOrigin: function () { | |
return this.origin; | |
}, | |
getCurrentColor: function () { | |
return this.parent.getCurrentColor(); | |
} | |
}); | |
xypic.Graphics.SVG.ChangeColorGroup = xypic.Graphics.SVG.Subclass({ | |
Init: function (parent, color) { | |
this.parent = parent; | |
this.drawArea = parent.createSVGElement("g", { | |
stroke: color | |
}); | |
this.color = color; | |
memoize(this, "getOrigin"); | |
}, | |
remove: function () { | |
this.drawArea.parentNode.removeChild(this.drawArea); | |
}, | |
extendBoundingBox: function (boundingBox) { | |
this.parent.extendBoundingBox(boundingBox); | |
}, | |
getOrigin: function () { | |
return this.parent.getOrigin(); | |
}, | |
getCurrentColor: function () { | |
return this.color; | |
} | |
}); | |
xypic.Graphics.Augment({}, { | |
createSVG: function (height, depth, width, strokeWidth, color, def) { | |
return xypic.Graphics.SVG.World(height, depth, width, strokeWidth, color, def); | |
} | |
}); | |
xypic.DrawingContext = MathJax.Object.Subclass({ | |
Init: function (shape, env) { | |
this.shape = shape; | |
this.env = env; | |
}, | |
duplicateEnv: function () { | |
var newEnv = this.env.duplicate(); | |
return xypic.DrawingContext(this.shape, newEnv); | |
}, | |
/** | |
* shapeを最前面に追加する。 | |
* @param {xypic.Shape} shape 追加する図形 | |
*/ | |
appendShapeToFront: function (shape) { | |
if (shape.isNone) { | |
} else if (this.shape.isNone) { | |
this.shape = shape; | |
} else { | |
this.shape = xypic.Shape.CompositeShape(shape, this.shape); | |
} | |
}, | |
/** | |
* shapeを最背面に追加する。 | |
* @param {xypic.Shape} shape 追加する図形 | |
*/ | |
appendShapeToBack: function (shape) { | |
if (shape.isNone) { | |
} else if (this.shape.isNone) { | |
this.shape = shape; | |
} else { | |
this.shape = xypic.Shape.CompositeShape(this.shape, shape); | |
} | |
} | |
}); | |
xypic.Util = MathJax.Object.Subclass({}, { | |
extProd: function (v1, v2) { | |
return [v1[1]*v2[2]-v1[2]*v2[1], v1[2]*v2[0]-v1[0]*v2[2], v1[0]*v2[1]-v1[1]*v2[0]]; | |
}, | |
sign: function (x) { | |
return (x < 0? -1 : (x > 0? 1 : 0)); | |
}, | |
sign2: function (x) { | |
return (x < 0? -1 : 1); | |
}, | |
roundEpsilon: function (x) { | |
if (Math.abs(x) < AST.xypic.machinePrecision) { | |
return 0; | |
} else { | |
return x; | |
} | |
} | |
}); | |
HUB.Browser.Select({ | |
MSIE: function (browser) { | |
if (HUB.Browser.versionAtLeast("9.0") && document.documentMode >= 9) { | |
xypic.useSVG = true; | |
} | |
}, | |
Firefox: function (browser) { | |
xypic.useSVG = true; | |
}, | |
Safari: function (browser) { | |
xypic.useSVG = true; | |
}, | |
Chrome: function (browser) { | |
xypic.useSVG = true; | |
}, | |
Opera: function (browser) { | |
xypic.useSVG = true; | |
} | |
}); | |
xypic.Frame = MathJax.Object.Subclass({ | |
toRect: function (def) { | |
return xypic.Frame.Rect(this.x, this.y, def); | |
}, | |
toPoint: function () { | |
return xypic.Frame.Point(this.x, this.y); | |
}, | |
combineRect: function (that) { | |
return xypic.Frame.combineRect(this, that); | |
} | |
},{ | |
combineRect: function (frame1, frame2) { | |
if (frame1 === undefined) { | |
return frame2; | |
} else if (frame2 === undefined) { | |
return frame1; | |
} else { | |
var l = -(Math.min(frame1.x-frame1.l, frame2.x-frame2.l) - frame1.x); | |
var r = Math.max(frame1.x+frame1.r, frame2.x+frame2.r) - frame1.x; | |
var d = -(Math.min(frame1.y-frame1.d, frame2.y-frame2.d) - frame1.y); | |
var u = Math.max(frame1.y+frame1.u, frame2.y+frame2.u) - frame1.y; | |
return frame1.toRect({l:l, r:r, d:d, u:u}); | |
} | |
} | |
}); | |
xypic.Frame.Point = xypic.Frame.Subclass({ | |
Init: function (x, y) { | |
this.x = x; | |
this.y = y; | |
}, | |
l: 0, | |
r: 0, | |
u: 0, | |
d: 0, | |
isPoint: function () { return true; }, | |
isRect: function () { return false; }, | |
isCircle: function () { return false; }, | |
edgePoint: function (x, y) { return this; }, | |
proportionalEdgePoint: function (x, y) { return this; }, | |
grow: function (xMargin, yMargin) { | |
var xm = Math.max(0, xMargin); | |
var ym = Math.max(0, yMargin); | |
return this.toRect({l:xm, r:xm, u:ym, d:ym}); | |
}, | |
toSize: function (width, height) { | |
return this.toRect({ l:width / 2, r:width / 2, u:height / 2, d:height / 2 }); | |
}, | |
growTo: function (width, height) { | |
var w = Math.max(0, width); | |
var h = Math.max(0, height); | |
return this.toRect({ l:w / 2, r:w / 2, u:h / 2, d:h / 2 }); | |
}, | |
shrinkTo: function (width, height) { | |
return this; | |
}, | |
move: function (x, y) { | |
return xypic.Frame.Point(x, y); | |
}, | |
shiftFrame: function (dx, dy) { | |
return this; | |
}, | |
rotate: function (angle) { | |
return this; | |
}, | |
contains: function (point) { | |
return false; | |
}, | |
toString: function () { | |
return "{x:"+this.x+", y:"+this.y+"}"; | |
} | |
}); | |
xypic.Frame.Rect = xypic.Frame.Subclass({ | |
Init: function (x, y, def) { | |
this.x = x; | |
this.y = y; | |
this.l = (def.l || 0); | |
this.r = (def.r || 0); | |
this.u = (def.u || 0); | |
this.d = (def.d || 0); | |
}, | |
isPoint: function () { | |
return this.l === 0 && this.r === 0 && this.u === 0 && this.d === 0; | |
}, | |
isRect: function () { return !this.isPoint(); }, | |
isCircle: function () { return false; }, | |
edgePoint: function (x, y) { | |
if (this.isPoint()) { | |
return this; | |
} | |
var dx = x - this.x; | |
var dy = y - this.y; | |
if (dx > 0) { | |
var ey = dy * this.r / dx; | |
if (ey > this.u) { | |
return xypic.Frame.Point(this.x + this.u * dx / dy, this.y + this.u); | |
} else if (ey < -this.d) { | |
return xypic.Frame.Point(this.x - this.d * dx / dy, this.y - this.d); | |
} | |
return xypic.Frame.Point(this.x + this.r, this.y + ey); | |
} else if (dx < 0) { | |
var ey = -dy * this.l / dx; | |
if (ey > this.u) { | |
return xypic.Frame.Point(this.x + this.u * dx / dy, this.y + this.u); | |
} else if (ey < -this.d) { | |
return xypic.Frame.Point(this.x - this.d * dx / dy, this.y - this.d); | |
} | |
return xypic.Frame.Point(this.x - this.l, this.y + ey); | |
} else { | |
if (dy > 0) { | |
return xypic.Frame.Point(this.x, this.y + this.u); | |
} | |
return xypic.Frame.Point(this.x, this.y - this.d); | |
} | |
}, | |
proportionalEdgePoint: function (x, y) { | |
if (this.isPoint()) { | |
return this; | |
} | |
var dx = x - this.x; | |
var dy = y - this.y; | |
if (Math.abs(dx) < AST.xypic.machinePrecision && Math.abs(dy) < AST.xypic.machinePrecision) { | |
return xypic.Frame.Point(this.x - this.l, this.y + this.u); | |
} | |
var w = this.l + this.r, h = this.u + this.d; | |
var pi = Math.PI; | |
var angle = Math.atan2(dy, dx); | |
var f; | |
if (-3*pi/4 < angle && angle <= -pi/4) { | |
// d | |
f = (angle + 3*pi/4)/(pi/2); | |
return xypic.Frame.Point(this.x + this.r - f * w, this.y + this.u); | |
} else if (-pi/4 < angle && angle <= pi/4) { | |
// r | |
f = (angle + pi/4)/(pi/2); | |
return xypic.Frame.Point(this.x - this.l, this.y + this.u - f * h); | |
} else if (pi/4 < angle && angle <= 3*pi/4) { | |
// u | |
f = (angle - pi/4)/(pi/2); | |
return xypic.Frame.Point(this.x - this.l + f * w, this.y - this.d); | |
} else { | |
// l | |
f = (angle - (angle > 0? 3*pi/4 : -5*pi/4))/(pi/2); | |
return xypic.Frame.Point(this.x + this.r, this.y - this.d + f * h); | |
} | |
}, | |
grow: function (xMargin, yMargin) { | |
return this.toRect({ | |
l:Math.max(0, this.l + xMargin), | |
r:Math.max(0, this.r + xMargin), | |
u:Math.max(0, this.u + yMargin), | |
d:Math.max(0, this.d + yMargin) | |
}); | |
}, | |
toSize: function (width, height) { | |
var u, d, r, l; | |
var ow = this.l + this.r; | |
var oh = this.u + this.d; | |
if (ow === 0) { | |
l = width / 2; | |
r = width / 2; | |
} else { | |
l = width * this.l / ow; | |
r = width * this.r / ow; | |
} | |
if (oh === 0) { | |
u = height / 2; | |
d = height / 2; | |
} else { | |
u = height * this.u / oh; | |
d = height * this.d / oh; | |
} | |
return this.toRect({ l:l, r:r, u:u, d:d }); | |
}, | |
growTo: function (width, height) { | |
var u = this.u; | |
var d = this.d; | |
var r = this.r; | |
var l = this.l; | |
var ow = l + r; | |
var oh = u + d; | |
if (width > ow) { | |
if (ow === 0) { | |
l = width / 2; | |
r = width / 2; | |
} else { | |
l = width * this.l / ow; | |
r = width * this.r / ow; | |
} | |
} | |
if (height > oh) { | |
if (oh === 0) { | |
u = height / 2; | |
d = height / 2; | |
} else { | |
u = height * this.u / oh; | |
d = height * this.d / oh; | |
} | |
} | |
return this.toRect({ l:l, r:r, u:u, d:d }); | |
}, | |
shrinkTo: function (width, height) { | |
var u = this.u; | |
var d = this.d; | |
var r = this.r; | |
var l = this.l; | |
var ow = l + r; | |
var oh = u + d; | |
if (width < ow) { | |
if (ow === 0) { | |
l = width / 2; | |
r = width / 2; | |
} else { | |
l = width * this.l / ow; | |
r = width * this.r / ow; | |
} | |
} | |
if (height < oh) { | |
if (oh === 0) { | |
u = height / 2; | |
d = height / 2; | |
} else { | |
u = height * this.u / oh; | |
d = height * this.d / oh; | |
} | |
} | |
return this.toRect({ l:l, r:r, u:u, d:d }); | |
}, | |
move: function (x, y) { | |
return xypic.Frame.Rect(x, y, { l:this.l, r:this.r, u:this.u, d:this.d }); | |
}, | |
shiftFrame: function (dx, dy) { | |
return xypic.Frame.Rect(this.x, this.y, { | |
l:Math.max(0, this.l - dx), | |
r:Math.max(0, this.r + dx), | |
u:Math.max(0, this.u + dy), | |
d:Math.max(0, this.d - dy) | |
}); | |
}, | |
rotate: function (angle) { | |
var c = Math.cos(angle), s = Math.sin(angle); | |
var lx = -this.l, rx = this.r, uy = this.u, dy = -this.d; | |
var lu = {x:lx*c-uy*s, y:lx*s+uy*c}; | |
var ld = {x:lx*c-dy*s, y:lx*s+dy*c}; | |
var ru = {x:rx*c-uy*s, y:rx*s+uy*c}; | |
var rd = {x:rx*c-dy*s, y:rx*s+dy*c}; | |
return this.toRect({ | |
l:-Math.min(lu.x, ld.x, ru.x, rd.x), | |
r:Math.max(lu.x, ld.x, ru.x, rd.x), | |
u:Math.max(lu.y, ld.y, ru.y, rd.y), | |
d:-Math.min(lu.y, ld.y, ru.y, rd.y) | |
}); | |
}, | |
contains: function (point) { | |
var x = point.x; | |
var y = point.y; | |
return (x >= this.x - this.l) && (x <= this.x + this.r) && (y >= this.y - this.d) && (y <= this.y + this.u); | |
}, | |
toString: function () { | |
return "{x:"+this.x+", y:"+this.y+", l:"+this.l+", r:"+this.r+", u:"+this.u+", d:"+this.d+"}"; | |
} | |
}); | |
xypic.Frame.Ellipse = xypic.Frame.Subclass({ | |
Init: function (x, y, l, r, u, d) { | |
this.x = x; | |
this.y = y; | |
this.l = l; | |
this.r = r; | |
this.u = u; | |
this.d = d; | |
}, | |
isPoint: function () { return this.r === 0 && this.l ===0 || this.u === 0 && this.d ===0; }, | |
isRect: function () { return false; }, | |
isCircle: function () { return !this.isPoint(); }, | |
isPerfectCircle: function () { | |
return this.l === this.r && this.l === this.u && this.l === this.d; | |
}, | |
edgePoint: function (x, y) { | |
if (this.isPoint()) { | |
return this; | |
} | |
if (this.isPerfectCircle()) { | |
var dx = x - this.x; | |
var dy = y - this.y; | |
var angle; | |
if (Math.abs(dx) < AST.xypic.machinePrecision && Math.abs(dy) < AST.xypic.machinePrecision) { | |
angle = -Math.PI/2; | |
} else { | |
angle = Math.atan2(dy, dx); | |
} | |
return xypic.Frame.Point(this.x + this.r * Math.cos(angle), this.y + this.r * Math.sin(angle)); | |
} else { | |
// ellipse | |
var pi = Math.PI; | |
var l = this.l; | |
var r = this.r; | |
var u = this.u; | |
var d = this.d; | |
var x0 = this.x; | |
var y0 = this.y; | |
var cx = x0 + (r - l) / 2; | |
var cy = y0 + (u - d) / 2; | |
var rx = (l + r) / 2; | |
var ry = (u + d) / 2; | |
var dx = x - x0; | |
var dy = y - y0; | |
var a0 = dy; | |
var b0 = -dx; | |
var c0 = dx * y0 - dy * x0; | |
var a = a0 * rx; | |
var b = b0 * ry; | |
var c = c0 * rx + (rx - ry) * b0 * cy; | |
var aabb = a * a + b * b; | |
var d = a * cx + b * cy + c; | |
var e = -d / aabb; | |
var ff = aabb * rx * rx - d * d; | |
if (ff < 0) { | |
return xypic.Frame.Point(this.x, this.y - this.d); | |
} | |
var f = Math.sqrt(ff) / aabb; | |
var xp = a * e + b * f + cx; | |
var yp = b * e - a * f + cy; | |
var xm = a * e - b * f + cx; | |
var ym = b * e + a * f + cy; | |
var eps = ry / rx; | |
var xp0 = xp; | |
var yp0 = eps * (yp - cy) + cy; | |
var xm0 = xm; | |
var ym0 = eps * (ym - cy) + cy; | |
var sign = xypic.Util.sign; | |
if (sign(xp0 - cx) === sign(x - cx) && sign(yp0 - cy) === sign(y - cy)) { | |
return xypic.Frame.Point(xp0, yp0); | |
} else { | |
return xypic.Frame.Point(xm0, ym0); | |
} | |
} | |
}, | |
proportionalEdgePoint: function (x, y) { | |
if (this.isPoint()) { | |
return this; | |
} | |
if (this.isPerfectCircle()) { | |
var dx = x - this.x; | |
var dy = y - this.y; | |
var angle; | |
if (Math.abs(dx) < AST.xypic.machinePrecision && Math.abs(dy) < AST.xypic.machinePrecision) { | |
angle = -Math.PI/2; | |
} else { | |
angle = Math.atan2(dy, dx); | |
} | |
return xypic.Frame.Point(this.x - this.r * Math.cos(angle), this.y - this.r * Math.sin(angle)); | |
} else { | |
// ellipse | |
var pi = Math.PI; | |
var l = this.l; | |
var r = this.r; | |
var u = this.u; | |
var d = this.d; | |
var x0 = this.x; | |
var y0 = this.y; | |
var cx = x0 + (r - l) / 2; | |
var cy = y0 + (u - d) / 2; | |
var rx = (l + r) / 2; | |
var ry = (u + d) / 2; | |
var dx = x - x0; | |
var dy = y - y0; | |
var a0 = dy; | |
var b0 = -dx; | |
var c0 = dx * y0 - dy * x0; | |
var a = a0 * rx; | |
var b = b0 * ry; | |
var c = c0 * rx + (rx - ry) * b0 * cy; | |
var aabb = a * a + b * b; | |
var d = a * cx + b * cy + c; | |
var e = -d / aabb; | |
var ff = aabb * rx * rx - d * d; | |
if (ff < 0) { | |
return xypic.Frame.Point(this.x, this.y - this.d); | |
} | |
var f = Math.sqrt(ff) / aabb; | |
var xp = a * e + b * f + cx; | |
var yp = b * e - a * f + cy; | |
var xm = a * e - b * f + cx; | |
var ym = b * e + a * f + cy; | |
var eps = ry / rx; | |
var xp0 = xp; | |
var yp0 = eps * (yp - cy) + cy; | |
var xm0 = xm; | |
var ym0 = eps * (ym - cy) + cy; | |
var dxp = xp0 - x; | |
var dyp = yp0 - y; | |
var dxm = xm0 - x; | |
var dym = ym0 - y; | |
if (sign(xp0 - cx) === sign(x - cx) && sign(yp0 - cy) === sign(y - cy)) { | |
return xypic.Frame.Point(xm0, ym0); | |
} else { | |
return xypic.Frame.Point(xp0, yp0); | |
} | |
} | |
}, | |
grow: function (xMargin, yMargin) { | |
return xypic.Frame.Ellipse( | |
this.x, this.y, | |
Math.max(0, this.l + xMargin), | |
Math.max(0, this.r + xMargin), | |
Math.max(0, this.u + yMargin), | |
Math.max(0, this.d + yMargin)); | |
}, | |
toSize: function (width, height) { | |
var u, d, r, l; | |
var ow = this.l + this.r; | |
var oh = this.u + this.d; | |
if (ow === 0) { | |
l = width / 2; | |
r = width / 2; | |
} else { | |
l = width * this.l / ow; | |
r = width * this.r / ow; | |
} | |
if (oh === 0) { | |
u = height / 2; | |
d = height / 2; | |
} else { | |
u = height * this.u / oh; | |
d = height * this.d / oh; | |
} | |
return xypic.Frame.Ellipse(this.x, this.y, l, r, u, d); | |
}, | |
growTo: function (width, height) { | |
var u = this.u; | |
var d = this.d; | |
var r = this.r; | |
var l = this.l; | |
var ow = l + r; | |
var oh = u + d; | |
if (width > ow) { | |
if (ow === 0) { | |
l = width / 2; | |
r = width / 2; | |
} else { | |
l = width * this.l / ow; | |
r = width * this.r / ow; | |
} | |
} | |
if (height > oh) { | |
if (oh === 0) { | |
u = height / 2; | |
d = height / 2; | |
} else { | |
u = height * this.u / oh; | |
d = height * this.d / oh; | |
} | |
} | |
return xypic.Frame.Ellipse(this.x, this.y, l, r, u, d); | |
}, | |
shrinkTo: function (width, height) { | |
var u = this.u; | |
var d = this.d; | |
var r = this.r; | |
var l = this.l; | |
var ow = l + r; | |
var oh = u + d; | |
if (width < ow) { | |
if (ow === 0) { | |
l = width / 2; | |
r = width / 2; | |
} else { | |
l = width * this.l / ow; | |
r = width * this.r / ow; | |
} | |
} | |
if (height < oh) { | |
if (oh === 0) { | |
u = height / 2; | |
d = height / 2; | |
} else { | |
u = height * this.u / oh; | |
d = height * this.d / oh; | |
} | |
} | |
return xypic.Frame.Ellipse(this.x, this.y, l, r, u, d); | |
}, | |
move: function (x, y) { | |
return xypic.Frame.Ellipse(x, y, this.l, this.r, this.u, this.d); | |
}, | |
shiftFrame: function (dx, dy) { | |
return xypic.Frame.Ellipse(this.x, this.y, | |
Math.max(0, this.l - dx), | |
Math.max(0, this.r + dx), | |
Math.max(0, this.u + dy), | |
Math.max(0, this.d - dy) | |
); | |
}, | |
rotate: function (angle) { | |
return this; | |
}, | |
contains: function (point) { | |
var x = point.x; | |
var y = point.y; | |
if (this.isPoint()) { | |
return false; | |
} | |
var l = this.l; | |
var r = this.r; | |
var u = this.u; | |
var d = this.d; | |
var x0 = this.x; | |
var y0 = this.y; | |
var cx = x0 + (r - l) / 2; | |
var cy = y0 + (u - d) / 2; | |
var rx = (l + r) / 2; | |
var ry = (u + d) / 2; | |
var eps = ry / rx; | |
var dx = x - cx; | |
var dy = (y - cy) / eps; | |
return dx * dx + dy * dy <= rx * rx; | |
}, | |
toString: function () { | |
return "{x:" + this.x + ", y:" + this.y + ", l:" + this.l + ", r:" + this.r + ", u:" + this.u + ", d:" + this.d + "}"; | |
} | |
}); | |
xypic.Range = MathJax.Object.Subclass({ | |
Init: function (start, end) { | |
if (start > end) { | |
this.start = end; | |
this.end = start; | |
} else { | |
this.start = start; | |
this.end = end; | |
} | |
}, | |
/** | |
* returns difference ranges between this range and a given range: this range \ a given range. | |
*/ | |
difference: function (range) { | |
var diff = FP.List.empty; | |
var a0 = this.start; | |
var a1 = this.end; | |
var b0 = range.start; | |
var b1 = range.end; | |
if (a1 <= b0) { | |
// a0 < a1 <= b0 < b1 | |
diff = diff.prepend(this); | |
} else if (b1 <= a0) { | |
// b0 < b1 <= a0 < a1 | |
diff = diff.prepend(this); | |
} else if (a0 < b0) { | |
if (a1 <= b1) { | |
// a0 < b0 <= a1 <= b1 | |
diff = diff.prepend(xypic.Range(a0, b0)); | |
} else { | |
// a0 < b0 < b1 < a1 | |
diff = diff.prepend(xypic.Range(a0, b0)); | |
diff = diff.prepend(xypic.Range(b1, a1)); | |
} | |
} else /* if (b0 <= a0) */ { | |
if (b1 < a1) { | |
// b0 <= a0 <= b1 < a1 | |
diff = diff.prepend(xypic.Range(b1, a1)); | |
} /* else { | |
// b0 <= a0 < a1 <= b1 | |
} */ | |
} | |
return diff; | |
}, | |
differenceRanges: function (ranges) { | |
var result = FP.List.empty.prepend(this); | |
ranges.foreach(function (range) { | |
result = result.flatMap(function (remaining) { | |
return remaining.difference(range); | |
}); | |
}); | |
return result; | |
}, | |
toString: function () { | |
return "[" + this.start + ", " + this.end + "]"; | |
} | |
}); | |
xypic.Shape = MathJax.Object.Subclass({ | |
// <<interface>> | |
/** | |
* 図形を描画する。 | |
* @param {xypic.Graphics.SVG} svg SVG | |
*/ | |
// draw: function (svg) {} | |
/** | |
* Bounding Boxを返す。 | |
* @returns {xypic.Frame.Rect} Bounding Box (ない場合はundefined) | |
*/ | |
// getBoundingBox: function () {} | |
/** | |
* 中身が空であるかどうかを返す。 | |
* @returns {boolean} true:空である、false:空でない | |
*/ | |
isNone: false | |
}); | |
xypic.Shape.NoneShape = xypic.Shape.Subclass({ | |
draw: function (svg) { | |
}, | |
getBoundingBox: function () { | |
return undefined; | |
}, | |
toString: function () { | |
return "NoneShape"; | |
}, | |
isNone: true | |
}); | |
xypic.Shape.Augment({}, { | |
none: xypic.Shape.NoneShape() | |
}); | |
xypic.Shape.InvisibleBoxShape = xypic.Shape.Subclass({ | |
Init: function (bbox) { | |
this.bbox = bbox; | |
}, | |
draw: function (svg) { | |
}, | |
getBoundingBox: function () { | |
return this.bbox; | |
}, | |
toString: function () { | |
return "InvisibleBoxShape[bbox:" + this.bbox.toString() + "]"; | |
} | |
}); | |
xypic.Shape.TranslateShape = xypic.Shape.Subclass({ | |
Init: function (dx, dy, shape) { | |
this.dx = dx; | |
this.dy = dy; | |
this.shape = shape; | |
memoize(this, "getBoundingBox"); | |
}, | |
draw: function (svg) { | |
var g = svg.createGroup(svg.transformBuilder().translate(this.dx, this.dy)); | |
this.shape.draw(g); | |
}, | |
getBoundingBox: function () { | |
var bbox = this.shape.getBoundingBox(); | |
if (bbox === undefined) { | |
return undefined; | |
} | |
return xypic.Frame.Rect(bbox.x + this.dx, bbox.y + this.dy, bbox); | |
}, | |
toString: function () { | |
return "TranslateShape[dx:" + this.dx + ", dy:" + this.dy + ", shape:" + this.shape.toString() + "]"; | |
} | |
}); | |
xypic.Shape.CompositeShape = xypic.Shape.Subclass({ | |
Init: function (foregroundShape, backgroundShape) { | |
this.foregroundShape = foregroundShape; | |
this.backgroundShape = backgroundShape; | |
memoize(this, "getBoundingBox"); | |
}, | |
draw: function (svg) { | |
this.backgroundShape.draw(svg); | |
this.foregroundShape.draw(svg); | |
}, | |
getBoundingBox: function () { | |
return xypic.Frame.combineRect(this.foregroundShape.getBoundingBox(), this.backgroundShape.getBoundingBox()); | |
}, | |
toString: function () { | |
return "(" + this.foregroundShape.toString() + ", " + this.backgroundShape.toString() + ")"; | |
} | |
}); | |
xypic.Shape.ChangeColorShape = xypic.Shape.Subclass({ | |
Init: function (color, shape) { | |
this.color = color; | |
this.shape = shape; | |
memoize(this, "getBoundingBox"); | |
}, | |
draw: function (svg) { | |
var g = svg.createChangeColorGroup(this.color); | |
this.shape.draw(g); | |
}, | |
getBoundingBox: function () { | |
return this.shape.getBoundingBox(); | |
}, | |
toString: function () { | |
return "" + this.shape + ", color:" + this.color; | |
} | |
}); | |
xypic.Shape.CircleSegmentShape = xypic.Shape.Subclass({ | |
Init: function (x, y, sx, sy, r, large, flip, ex, ey) { | |
this.x = x; | |
this.y = y; | |
this.sx = sx; | |
this.sy = sy; | |
this.r = r; | |
this.large = large; | |
this.flip = flip; | |
this.ex = ex; | |
this.ey = ey; | |
memoize(this, "getBoundingBox"); | |
}, | |
draw: function (svg) { | |
svg.createSVGElement("path", { | |
d:"M" + xypic.em2px(this.sx) + "," + xypic.em2px(-this.sy) + " A" + xypic.em2px(this.r) + "," + xypic.em2px(this.r) + " 0 " + this.large + "," + this.flip + " " + xypic.em2px(this.ex) + "," + xypic.em2px(-this.ey) | |
}); | |
}, | |
getBoundingBox: function () { | |
return xypic.Frame.Ellipse(this.x, this.y, this.r, this.r, this.r, this.r); | |
}, | |
toString: function () { | |
return "CircleSegmentShape[x:" + this.x + ", y:" + this.y + ", sx:" + this.sx + ", sy:" + this.sy + ", r:" + this.r + ", large:" + this.large + ", flip:" + this.flip + ", ex:" + this.ex + ", ey:" + this.ey + "]"; | |
} | |
}); | |
xypic.Shape.FullCircleShape = xypic.Shape.Subclass({ | |
Init: function (x, y, r) { | |
this.x = x; | |
this.y = y; | |
this.r = r; | |
memoize(this, "getBoundingBox"); | |
}, | |
draw: function (svg) { | |
svg.createSVGElement("circle", { | |
cx:xypic.em2px(this.x), cy:xypic.em2px(-this.y), r:xypic.em2px(this.r) | |
}); | |
}, | |
getBoundingBox: function () { | |
return xypic.Frame.Ellipse(this.x, this.y, this.r, this.r, this.r, this.r); | |
}, | |
toString: function () { | |
return "FullCircleShape[x:" + this.x + ", y:" + this.y + ", r:" + this.r + "]"; | |
} | |
}); | |
xypic.Shape.RectangleShape = xypic.Shape.Subclass({ | |
Init: function (x, y, left, right, up, down, r, isDoubled, color, dasharray, fillColor, hideLine) { | |
this.x = x; | |
this.y = y; | |
this.left = left; | |
this.right = right; | |
this.up = up; | |
this.down = down; | |
this.r = r; | |
this.isDoubled = isDoubled; | |
this.color = color; | |
this.dasharray = dasharray; | |
this.fillColor = fillColor; | |
this.hideLine = hideLine || false; | |
memoize(this, "getBoundingBox"); | |
}, | |
draw: function (svg) { | |
var def; | |
def = { | |
x:xypic.em2px(this.x - this.left), | |
y:-xypic.em2px(this.y + this.up), | |
width:xypic.em2px(this.left + this.right), | |
height:xypic.em2px(this.up + this.down), | |
rx:xypic.em2px(this.r) | |
}; | |
if (this.dasharray !== undefined) { | |
def["stroke-dasharray"] = this.dasharray; | |
} | |
if (this.hideLine) { | |
def["stroke"] = "none"; | |
} else if (this.color !== undefined) { | |
def["stroke"] = this.color; | |
} | |
if (this.fillColor !== undefined) { | |
def["fill"] = this.fillColor; | |
} | |
svg.createSVGElement("rect", def); | |
if (this.isDoubled) { | |
def = { | |
x:xypic.em2px(this.x - this.left + AST.xypic.thickness), | |
y:-xypic.em2px(this.y + this.up - AST.xypic.thickness), | |
width:xypic.em2px(this.left + this.right - 2 * AST.xypic.thickness), | |
height:xypic.em2px(this.up + this.down - 2 * AST.xypic.thickness), | |
rx:xypic.em2px(Math.max(this.r - AST.xypic.thickness, 0)) | |
}; | |
if (this.dasharray !== undefined) { | |
def["stroke-dasharray"] = this.dasharray; | |
} | |
if (this.hideLine) { | |
def["stroke"] = "none"; | |
} else if (this.color !== undefined) { | |
def["stroke"] = this.color; | |
} | |
if (this.fillColor !== undefined) { | |
def["fill"] = this.fillColor; | |
} | |
svg.createSVGElement("rect", def); | |
} | |
}, | |
getBoundingBox: function () { | |
return xypic.Frame.Rect(this.x, this.y, { l:this.left, r:this.right, u:this.up, d:this.down }); | |
}, | |
toString: function () { | |
return "RectangleShape[x:" + this.x + ", y:" + this.y + ", left:" + this.left + ", right:" + this.right + ", up:" + this.up + ", down:" + this.down + ", r:" + this.r + ", isDouble:" + this.isDouble + ", dasharray:" + this.dasharray + "]"; | |
} | |
}); | |
xypic.Shape.EllipseShape = xypic.Shape.Subclass({ | |
Init: function (x, y, rx, ry, isDoubled, color, dasharray, fillColor, hideLine) { | |
this.x = x; | |
this.y = y; | |
this.rx = rx; | |
this.ry = ry; | |
this.isDoubled = isDoubled; | |
this.color = color; | |
this.dasharray = dasharray; | |
this.fillColor = fillColor; | |
this.hideLine = hideLine || false; | |
memoize(this, "getBoundingBox"); | |
}, | |
draw: function (svg) { | |
var def; | |
def = { | |
cx:xypic.em2px(this.x), | |
cy:-xypic.em2px(this.y), | |
rx:xypic.em2px(this.rx), | |
ry:xypic.em2px(this.ry) | |
}; | |
if (this.dasharray !== undefined) { | |
def["stroke-dasharray"] = this.dasharray; | |
} | |
if (this.hideLine) { | |
def["stroke"] = "none"; | |
} else if (this.color !== undefined) { | |
def["stroke"] = this.color; | |
} | |
if (this.fillColor !== undefined) { | |
def["fill"] = this.fillColor; | |
} | |
svg.createSVGElement("ellipse", def); | |
if (this.isDoubled) { | |
def = { | |
cx:xypic.em2px(this.x), | |
cy:-xypic.em2px(this.y), | |
rx:xypic.em2px(Math.max(this.rx - AST.xypic.thickness)), | |
ry:xypic.em2px(Math.max(this.ry - AST.xypic.thickness)) | |
}; | |
if (this.dasharray !== undefined) { | |
def["stroke-dasharray"] = this.dasharray; | |
} | |
if (this.hideLine) { | |
def["stroke"] = "none"; | |
} else if (this.color !== undefined) { | |
def["stroke"] = this.color; | |
} | |
if (this.fillColor !== undefined) { | |
def["fill"] = this.fillColor; | |
} | |
svg.createSVGElement("ellipse", def); | |
} | |
}, | |
getBoundingBox: function () { | |
return xypic.Frame.Rect(this.x, this.y, { l:this.rx, r:this.rx, u:this.ry, d:this.ry }); | |
}, | |
toString: function () { | |
return "EllipseShape[x:" + this.x + ", y:" + this.y + ", rx:" + this.rx + ", ry:" + this.ry + ", isDoubled:" + this.isDoubled + ", dasharray:" + this.dasharray + "]"; | |
} | |
}); | |
xypic.Shape.BoxShadeShape = xypic.Shape.Subclass({ | |
Init: function (x, y, left, right, up, down, depth, color) { | |
this.x = x; | |
this.y = y; | |
this.left = left; | |
this.right = right; | |
this.up = up; | |
this.down = down; | |
this.depth = depth; | |
this.color = color || "currentColor"; | |
memoize(this, "getBoundingBox"); | |
}, | |
draw: function (svg) { | |
var x = xypic.em2px(this.x); | |
var y = xypic.em2px(this.y); | |
var l = xypic.em2px(this.left); | |
var r = xypic.em2px(this.right); | |
var u = xypic.em2px(this.up); | |
var d = xypic.em2px(this.down); | |
var depth = xypic.em2px(this.depth); | |
svg.createSVGElement("path", { | |
d: "M" + (x - l + depth) + "," + (-y + d) + | |
"L" + (x + r) + "," + (-y + d) + | |
"L" + (x + r) + "," + (-y - u + depth) + | |
"L" + (x + r + depth) + "," + (-y - u + depth) + | |
"L" + (x + r + depth) + "," + (-y + d + depth) + | |
"L" + (x - l + depth) + "," + (-y + d + depth) + | |
"Z", | |
stroke: this.color, | |
fill: this.color | |
}); | |
}, | |
getBoundingBox: function () { | |
return xypic.Frame.Rect(this.x, this.y, { l:this.left, r:this.right + this.depth, u:this.up, d:this.down + this.depth }); | |
}, | |
toString: function () { | |
return "RectangleShape[x:" + this.x + ", y:" + this.y + ", left:" + this.left + ", right:" + this.right + ", up:" + this.up + ", down:" + this.down + ", depth:" + this.depth + "]"; | |
} | |
}); | |
xypic.Shape.LeftBrace = xypic.Shape.Subclass({ | |
Init: function (x, y, up, down, degree, color) { | |
this.x = x; | |
this.y = y; | |
this.up = up; | |
this.down = down; | |
this.degree = degree; | |
this.color = color || "currentColor"; | |
memoize(this, "getBoundingBox"); | |
}, | |
draw: function (svg) { | |
var scale = xypic.oneem; | |
var down = Math.max(0.759375 + 0.660375, this.down / scale * 1.125) - 0.660375; | |
var up = - Math.max(0.759375 + 0.660375, this.up / scale * 1.125) + 0.660375; | |
var d; | |
d = "M" + xypic.em2px(-0.0675) + " " + xypic.em2px(down) + | |
"T" + xypic.em2px(-0.068625) + " " + xypic.em2px(0.07875 + down) + | |
"Q" + xypic.em2px(-0.068625) + " " + xypic.em2px(0.190125 + down) + | |
" " + xypic.em2px(-0.0585) + " " + xypic.em2px(0.250875 + down) + | |
"T" + xypic.em2px(-0.01125) + " " + xypic.em2px(0.387 + down) + | |
"Q" + xypic.em2px(0.07425) + " " + xypic.em2px(0.55575 + down) + | |
" " + xypic.em2px(0.2475) + " " + xypic.em2px(0.6525 + down) + | |
"L" + xypic.em2px(0.262125) + " " + xypic.em2px(0.660375 + down) + | |
"L" + xypic.em2px(0.3015) + " " + xypic.em2px(0.660375 + down) + | |
"L" + xypic.em2px(0.30825) + " " + xypic.em2px(0.653625 + down) + | |
"V" + xypic.em2px(0.622125 + down) + | |
"Q" + xypic.em2px(0.30825) + " " + xypic.em2px(0.60975 + down) + | |
" " + xypic.em2px(0.2925) + " " + xypic.em2px(0.60075 + down) + | |
"Q" + xypic.em2px(0.205875) + " " + xypic.em2px(0.541125 + down) + | |
" " + xypic.em2px(0.149625) + " " + xypic.em2px(0.44775 + down) + | |
"T" + xypic.em2px(0.07425) + " " + xypic.em2px(0.239625 + down) + | |
"Q" + xypic.em2px(0.07425) + " " + xypic.em2px(0.2385 + down) + | |
" " + xypic.em2px(0.073125) + " " + xypic.em2px(0.235125 + down) + | |
"Q" + xypic.em2px(0.068625) + " " + xypic.em2px(0.203625 + down) + | |
" " + xypic.em2px(0.0675) + " " + xypic.em2px(0.041625 + down) + | |
"L" + xypic.em2px(0.0675) + " " + xypic.em2px(0.75825) + | |
"Q" + xypic.em2px(0.0675) + " " + xypic.em2px(0.496125) + | |
" " + xypic.em2px(0.066375) + " " + xypic.em2px(0.486) + | |
"Q" + xypic.em2px(0.05625) + " " + xypic.em2px(0.336375) + | |
" " + xypic.em2px(-0.021375) + " " + xypic.em2px(0.212625) + | |
"T" + xypic.em2px(-0.226125) + " " + xypic.em2px(0.010125) + | |
"L" + xypic.em2px(-0.241875) + " 0" + | |
"L" + xypic.em2px(-0.226125) + " " + xypic.em2px(-0.010125) + | |
"Q" + xypic.em2px(-0.106875) + " " + xypic.em2px(-0.084375) + | |
" " + xypic.em2px(-0.025875) + " " + xypic.em2px(-0.207) + | |
"T" + xypic.em2px(0.066375) + " " + xypic.em2px(-0.486) + | |
"Q" + xypic.em2px(0.0675) + " " + xypic.em2px(-0.496125) + | |
" " + xypic.em2px(0.0675) + " " + xypic.em2px(-0.75825) + | |
"L" + xypic.em2px(0.0675) + " " + xypic.em2px(-0.041625 + up) + | |
"Q" + xypic.em2px(0.068625) + " " + xypic.em2px(-0.203625 + up) + | |
" " + xypic.em2px(0.073125) + " " + xypic.em2px(-0.235125 + up) + | |
"Q" + xypic.em2px(0.07425) + " " + xypic.em2px(-0.2385 + up) + | |
" " + xypic.em2px(0.07425) + " " + xypic.em2px(-0.239625 + up) + | |
"Q" + xypic.em2px(0.093375) + " " + xypic.em2px(-0.354375 + up) + | |
" " + xypic.em2px(0.149625) + " " + xypic.em2px(-0.44775 + up) + | |
"T" + xypic.em2px(0.2925) + " " + xypic.em2px(-0.60075 + up) + | |
"Q" + xypic.em2px(0.30825) + " " + xypic.em2px(-0.60975 + up) + | |
" " + xypic.em2px(0.30825) + " " + xypic.em2px(-0.622125 + up) + | |
"L" + xypic.em2px(0.30825) + " " + xypic.em2px(-0.653625 + up) + | |
"L" + xypic.em2px(0.3015) + " " + xypic.em2px(-0.660375 + up) + | |
"L" + xypic.em2px(0.262125) + " " + xypic.em2px(-0.660375 + up) + | |
"L" + xypic.em2px(0.2475) + " " + xypic.em2px(-0.6525 + up) + | |
"Q" + xypic.em2px(0.07425) + " " + xypic.em2px(-0.55575 + up) + | |
" " + xypic.em2px(-0.01125) + " " + xypic.em2px(-0.387 + up) + | |
"Q" + xypic.em2px(-0.048375) + " " + xypic.em2px(-0.311625 + up) + | |
" " + xypic.em2px(-0.0585) + " " + xypic.em2px(-0.250875 + up) + | |
"T" + xypic.em2px(-0.068625) + " " + xypic.em2px(-0.07875 + up) + | |
"Q" + xypic.em2px(-0.0675) + " " + xypic.em2px(up) + | |
" " + xypic.em2px(-0.0675) + " " + xypic.em2px(up) + | |
"L" + xypic.em2px(-0.0675) + " " + xypic.em2px(-0.759375) + | |
"V" + xypic.em2px(-0.5985) + | |
"Q" + xypic.em2px(-0.0675) + " " + xypic.em2px(-0.47925) + | |
" " + xypic.em2px(-0.075375) + " " + xypic.em2px(-0.41175) + | |
"T" + xypic.em2px(-0.11475) + " " + xypic.em2px(-0.27) + | |
"Q" + xypic.em2px(-0.133875) + " " + xypic.em2px(-0.2205) + | |
" " + xypic.em2px(-0.160875) + " " + xypic.em2px(-0.17775) + | |
"T" + xypic.em2px(-0.212625) + " " + xypic.em2px(-0.106875) + | |
"T" + xypic.em2px(-0.25875) + " " + xypic.em2px(-0.06075) + | |
"T" + xypic.em2px(-0.293625) + " " + xypic.em2px(-0.0315) + | |
"T" + xypic.em2px(-0.307125) + " " + xypic.em2px(-0.02025) + | |
"Q" + xypic.em2px(-0.30825) + " " + xypic.em2px(-0.019125) + | |
" " + xypic.em2px(-0.30825) + " 0" + | |
"T" + xypic.em2px(-0.307125) + " " + xypic.em2px(0.02025) + | |
"Q" + xypic.em2px(-0.307125) + " " + xypic.em2px(0.021375) + | |
" " + xypic.em2px(-0.284625) + " " + xypic.em2px(0.03825) + | |
"T" + xypic.em2px(-0.2295) + " " + xypic.em2px(0.091125) + | |
"T" + xypic.em2px(-0.162) + " " + xypic.em2px(0.176625) + | |
"T" + xypic.em2px(-0.10125) + " " + xypic.em2px(0.30825) + | |
"T" + xypic.em2px(-0.068625) + " " + xypic.em2px(0.482625) + | |
"Q" + xypic.em2px(-0.0675) + " " + xypic.em2px(0.496125) + | |
" " + xypic.em2px(-0.0675) + " " + xypic.em2px(0.759375) + | |
"Z"; | |
svg.createSVGElement("path", { | |
d:d, | |
fill:this.color, | |
stroke:this.color, | |
"stroke-width":"0pt", | |
transform:"translate(" + xypic.em2px(this.x) + "," + xypic.em2px(-this.y) +") rotate(" + (-this.degree) + ") scale(" + (scale / 1.125) + ")" | |
}); | |
}, | |
getBoundingBox: function () { | |
var scale = xypic.oneem; | |
return xypic.Frame.Rect(this.x, this.y, { l:0.274 * scale, r:0.274 * scale, u:Math.max((0.759375 + 0.660375) * scale / 1.125, this.up), d:Math.max((0.759375 + 0.660375) * scale / 1.125, this.down) }).rotate(this.degree * Math.PI / 180); | |
}, | |
toString: function () { | |
return "LeftBrace[x:" + this.x + ", y:" + this.y + ", up:" + this.up + ", down:" + this.down + "]"; | |
} | |
}); | |
xypic.Shape.LeftParenthesis = xypic.Shape.Subclass({ | |
Init: function (x, y, height, degree, color) { | |
this.x = x; | |
this.y = y; | |
this.height = height; | |
this.degree = degree; | |
this.color = color || "currentColor"; | |
memoize(this, "getBoundingBox"); | |
}, | |
draw: function (svg) { | |
var scale = xypic.oneem; | |
var down = Math.max(0.660375, this.height / 2 / scale * 1.125) - 0.660375; | |
var up = -down; | |
var d; | |
d = "M" + xypic.em2px(-0.0675) + " " + xypic.em2px(down) + | |
"T" + xypic.em2px(-0.068625) + " " + xypic.em2px(0.07875 + down) + | |
"Q" + xypic.em2px(-0.068625) + " " + xypic.em2px(0.190125 + down) + | |
" " + xypic.em2px(-0.0585) + " " + xypic.em2px(0.250875 + down) + | |
"T" + xypic.em2px(-0.01125) + " " + xypic.em2px(0.387 + down) + | |
"Q" + xypic.em2px(0.07425) + " " + xypic.em2px(0.55575 + down) + | |
" " + xypic.em2px(0.2475) + " " + xypic.em2px(0.6525 + down) + | |
"L" + xypic.em2px(0.262125) + " " + xypic.em2px(0.660375 + down) + | |
"L" + xypic.em2px(0.3015) + " " + xypic.em2px(0.660375 + down) + | |
"L" + xypic.em2px(0.30825) + " " + xypic.em2px(0.653625 + down) + | |
"V" + xypic.em2px(0.622125 + down) + | |
"Q" + xypic.em2px(0.30825) + " " + xypic.em2px(0.60975 + down) + | |
" " + xypic.em2px(0.2925) + " " + xypic.em2px(0.60075 + down) + | |
"Q" + xypic.em2px(0.205875) + " " + xypic.em2px(0.541125 + down) + | |
" " + xypic.em2px(0.149625) + " " + xypic.em2px(0.44775 + down) + | |
"T" + xypic.em2px(0.07425) + " " + xypic.em2px(0.239625 + down) + | |
"Q" + xypic.em2px(0.07425) + " " + xypic.em2px(0.2385 + down) + | |
" " + xypic.em2px(0.073125) + " " + xypic.em2px(0.235125 + down) + | |
"Q" + xypic.em2px(0.068625) + " " + xypic.em2px(0.203625 + down) + | |
" " + xypic.em2px(0.0675) + " " + xypic.em2px(0.041625 + down) + | |
"L" + xypic.em2px(0.0675) + " " + xypic.em2px(-0.041625 + up) + | |
"Q" + xypic.em2px(0.068625) + " " + xypic.em2px(-0.203625 + up) + | |
" " + xypic.em2px(0.073125) + " " + xypic.em2px(-0.235125 + up) + | |
"Q" + xypic.em2px(0.07425) + " " + xypic.em2px(-0.2385 + up) + | |
" " + xypic.em2px(0.07425) + " " + xypic.em2px(-0.239625 + up) + | |
"Q" + xypic.em2px(0.093375) + " " + xypic.em2px(-0.354375 + up) + | |
" " + xypic.em2px(0.149625) + " " + xypic.em2px(-0.44775 + up) + | |
"T" + xypic.em2px(0.2925) + " " + xypic.em2px(-0.60075 + up) + | |
"Q" + xypic.em2px(0.30825) + " " + xypic.em2px(-0.60975 + up) + | |
" " + xypic.em2px(0.30825) + " " + xypic.em2px(-0.622125 + up) + | |
"L" + xypic.em2px(0.30825) + " " + xypic.em2px(-0.653625 + up) + | |
"L" + xypic.em2px(0.3015) + " " + xypic.em2px(-0.660375 + up) + | |
"L" + xypic.em2px(0.262125) + " " + xypic.em2px(-0.660375 + up) + | |
"L" + xypic.em2px(0.2475) + " " + xypic.em2px(-0.6525 + up) + | |
"Q" + xypic.em2px(0.07425) + " " + xypic.em2px(-0.55575 + up) + | |
" " + xypic.em2px(-0.01125) + " " + xypic.em2px(-0.387 + up) + | |
"Q" + xypic.em2px(-0.048375) + " " + xypic.em2px(-0.311625 + up) + | |
" " + xypic.em2px(-0.0585) + " " + xypic.em2px(-0.250875 + up) + | |
"T" + xypic.em2px(-0.068625) + " " + xypic.em2px(-0.07875 + up) + | |
"Q" + xypic.em2px(-0.0675) + " " + xypic.em2px(up) + | |
" " + xypic.em2px(-0.0675) + " " + xypic.em2px(up) + | |
"Z"; | |
svg.createSVGElement("path", { | |
d:d, | |
fill:this.color, | |
stroke:this.color, | |
"stroke-width":"0pt", | |
transform:"translate(" + xypic.em2px(this.x) + "," + xypic.em2px(-this.y) +") rotate(" + (-this.degree) + ") scale(" + (scale / 1.125) + ")" | |
}); | |
}, | |
getBoundingBox: function () { | |
var scale = xypic.oneem; | |
return xypic.Frame.Rect(this.x, this.y, { l:0.06 * scale, r:0.274 * scale, u:Math.max(0.660375 * scale / 1.125, this.height / 2), d:Math.max(0.660375 * scale / 1.125, this.height / 2) }).rotate(this.degree * Math.PI / 180); | |
}, | |
toString: function () { | |
return "LeftBrace[x:" + this.x + ", y:" + this.y + ", up:" + this.up + ", down:" + this.down + "]"; | |
} | |
}); | |
xypic.Shape.TextShape = xypic.Shape.Subclass({ | |
Init: function (c, math, svgForTestLayout) { | |
this.c = c; | |
this.math = math; | |
this.svgForTestLayout = svgForTestLayout; | |
this.originalBBox = undefined; | |
memoize(this, "getBoundingBox"); | |
memoize(this, "getOriginalReferencePoint"); | |
}, | |
draw: function (svg) { | |
this._draw(svg, false); | |
}, | |
getBoundingBox: function () { | |
return this._draw(this.svgForTestLayout, true); | |
}, | |
getOriginalReferencePoint: function () { | |
this.getBoundingBox(); | |
var originalBBox = this.originalBBox; | |
var c = this.c; | |
var H = originalBBox.H; | |
var D = originalBBox.D; | |
return xypic.Frame.Point(c.x, c.y - (H - D) / 2); | |
}, | |
toString: function () { | |
return "TextShape[c:" + this.c.toString() + ", math:" + this.math.toString() + "]"; | |
} | |
}); | |
xypic.Shape.ImageShape = xypic.Shape.Subclass({ | |
Init: function (c, url) { | |
this.c = c; | |
this.url = url; | |
memoize(this, "getBoundingBox"); | |
memoize(this, "getOriginalReferencePoint"); | |
}, | |
draw: function (svg) { | |
var c = this.c; | |
svg.createSVGElement("image", { | |
x: xypic.em2px(c.x - c.l), | |
y: xypic.em2px(-c.y - c.u), | |
width: xypic.em2px(c.l + c.r), | |
height: xypic.em2px(c.u + c.d), | |
preserveAspectRatio: "none", | |
"xlink:href": this.url | |
}); | |
}, | |
getBoundingBox: function () { | |
return this.c; | |
}, | |
getOriginalReferencePoint: function () { | |
return this.c; | |
}, | |
toString: function () { | |
return "ImageShape[c:" + this.c.toString() + ", height:" + this.height + ", width:" + this.width + ", url:" + this.url + "]"; | |
} | |
}); | |
xypic.Shape.ArrowheadShape = xypic.Shape.Subclass({ | |
draw: function (svg) { | |
var g = svg.createGroup(svg.transformBuilder().translate(this.c.x, this.c.y).rotateRadian(this.angle)); | |
this.drawDelegate(g); | |
}, | |
getBoundingBox: function () { | |
return this.c.toRect(this.getBox()).rotate(this.angle); | |
}, | |
toString: function () { | |
return "ArrowheadShape[c:" + this.c.toString() + ", angle:" + this.angle + "]"; | |
} | |
}); | |
// @2{>} | |
xypic.Shape.GT2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.456 * scale, r:0, d:0.229 * scale, u:0.229 * scale }; }, | |
getRadius: function () { | |
var scale = xypic.oneem; | |
return 0.213 * scale; | |
}, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var gu = svg.createGroup(svg.transformBuilder().rotateDegree(-10)); | |
var gd = svg.createGroup(svg.transformBuilder().rotateDegree(10)); | |
gu.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + ","+xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @3{>} | |
xypic.Shape.GT3ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.507 * scale, r:0, d:0.268 * scale, u:0.268 * scale }; }, | |
getRadius: function () { | |
var scale = xypic.oneem; | |
return 0.325 * scale; | |
}, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var gu = svg.createGroup(svg.transformBuilder().rotateDegree(-15)); | |
var gd = svg.createGroup(svg.transformBuilder().rotateDegree(15)); | |
gu.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:xypic.em2px(-0.507 * scale), y2:0 | |
}); | |
gd.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @^{>} | |
xypic.Shape.UpperGTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.489 * scale, r:0, d:0, u:0.147 * scale }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
} | |
}); | |
// @_{>} | |
xypic.Shape.LowerGTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.489 * scale, r:0, d:0.147 * scale, u:0 }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @{>} | |
xypic.Shape.GTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.489 * scale, r:0, d:0.147 * scale, u:0.147 * scale }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
} | |
}); | |
// @2{<} | |
xypic.Shape.LT2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.456 * scale, d:0.229 * scale, u:0.229 * scale }; }, | |
getRadius: function () { | |
var scale = xypic.oneem; | |
return 0.213 * scale; | |
}, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var gu = svg.createGroup(svg.transformBuilder().rotateDegree(10)); | |
var gd = svg.createGroup(svg.transformBuilder().rotateDegree(-10)); | |
gu.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @3{<} | |
xypic.Shape.LT3ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.507 * scale, d:0.268 * scale, u:0.268 * scale }; }, | |
getRadius: function () { | |
var scale = xypic.oneem; | |
return 0.325 * scale; | |
}, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var gu = svg.createGroup(svg.transformBuilder().rotateDegree(15)); | |
var gd = svg.createGroup(svg.transformBuilder().rotateDegree(-15)); | |
gu.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:xypic.em2px(0.507 * scale), y2:0 | |
}); | |
gd.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @^{<} | |
xypic.Shape.UpperLTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.489 * scale, d:0, u:0.147 * scale }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
} | |
}); | |
// @_{<} | |
xypic.Shape.LowerLTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.489 * scale, d:0.147 * scale, u:0 }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @{<} | |
xypic.Shape.LTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.489 * scale, d:0.147 * scale, u:0.147 * scale }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @^{|} | |
xypic.Shape.UpperColumnArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0, u:AST.xypic.lineElementLength, d:0 }; }, | |
drawDelegate: function (svg) { | |
var l = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:0, y2:-l | |
}); | |
} | |
}); | |
// @_{|} | |
xypic.Shape.LowerColumnArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0, u:0, d:AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var l = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:0, y2:l | |
}); | |
} | |
}); | |
// @2{|} | |
xypic.Shape.Column2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0, u:0.5 * (AST.xypic.lineElementLength + AST.xypic.thickness), d:0.5 * (AST.xypic.lineElementLength + AST.xypic.thickness) }; }, | |
drawDelegate: function (svg) { | |
var l = xypic.em2px(0.5 * (AST.xypic.lineElementLength + AST.xypic.thickness)); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
} | |
}); | |
// @3{|} | |
xypic.Shape.Column3ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0, u:0.5 * AST.xypic.lineElementLength + AST.xypic.thickness, d:0.5 * AST.xypic.lineElementLength + AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var l = xypic.em2px(0.5 * AST.xypic.lineElementLength + AST.xypic.thickness); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
} | |
}); | |
// @{|} | |
xypic.Shape.ColumnArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
} | |
}); | |
// @^{(} | |
xypic.Shape.UpperLParenArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0.5 * AST.xypic.lineElementLength, r:0, u:AST.xypic.lineElementLength, d:0 }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var r = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("path", { | |
d:"M0,0 A " + r + "," + r + " 0 0,1 0," + (-2 * r) | |
}); | |
} | |
}); | |
// @_{(} | |
xypic.Shape.LowerLParenArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0.5 * AST.xypic.lineElementLength, r:0, u:0, d:AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var r = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("path", { | |
d:"M0,0 A " + r + "," + r + " 0 0,0 0," + (2 * r) | |
}); | |
} | |
}); | |
// @{(} | |
xypic.Shape.LParenArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0.5 * AST.xypic.lineElementLength, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var r = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("path", { | |
d:"M" + r + "," + (-r) + " A " + r + "," + r + " 0 0,0 " + r + "," + r | |
}); | |
} | |
}); | |
// @^{)} | |
xypic.Shape.UpperRParenArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0.5 * AST.xypic.lineElementLength, u:AST.xypic.lineElementLength, d:0 }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var r = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("path", { | |
d:"M0,0 A " + r + "," + r + " 0 0,0 0," + (-2 * r) | |
}); | |
} | |
}); | |
// @_{)} | |
xypic.Shape.LowerRParenArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0.5 * AST.xypic.lineElementLength, u:0, d:AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var r = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("path", { | |
d:"M0,0 A " + r + "," + r + " 0 0,1 0," + (2 * r) | |
}); | |
} | |
}); | |
// @{)} | |
xypic.Shape.RParenArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0.5 * AST.xypic.lineElementLength, r:0, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var r = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("path", { | |
d:"M" + (-r) + "," + (-r) + " A " + r + "," + r + " 0 0,1 " + (-r) + "," + r | |
}); | |
} | |
}); | |
// @_{`} | |
xypic.Shape.LowerBackquoteArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0.5 * AST.xypic.lineElementLength, r:0, u:0, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var r = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("path", { | |
d:"M0,0 A " + r + "," + r + " 0 0,0 " + (-r) + "," + (r) | |
}); | |
} | |
}); | |
// @{`}, @^{`} | |
xypic.Shape.UpperBackquoteArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0.5 * AST.xypic.lineElementLength, r:0, u:0.5 * AST.xypic.lineElementLength, d:0 }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var r = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("path", { | |
d:"M0,0 A " + r + "," + r + " 0 0,1 " + (-r) + "," + (-r) | |
}); | |
} | |
}); | |
// @_{'} | |
xypic.Shape.LowerQuoteArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0.5 * AST.xypic.lineElementLength, u:0, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var r = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("path", { | |
d:"M0,0 A " + r + "," + r + " 0 0,1 " + r + "," + (r) | |
}); | |
} | |
}); | |
// @{'}, @^{'} | |
xypic.Shape.UpperQuoteArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0.5 * AST.xypic.lineElementLength, u:0.5 * AST.xypic.lineElementLength, d:0 }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var r = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("path", { | |
d:"M0,0 A " + r + "," + r + " 0 0,0 " + r + "," + (-r) | |
}); | |
} | |
}); | |
// @{*} | |
xypic.Shape.AsteriskArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = 0; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:AST.xypic.thickness, r:AST.xypic.thickness, u:AST.xypic.thickness, d:AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
svg.createSVGElement("circle", { | |
cx:0, cy:0, r:xypic.em2px(AST.xypic.thickness), | |
fill: "currentColor" | |
}); | |
} | |
}); | |
// @{o} | |
xypic.Shape.OArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = 0; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:AST.xypic.thickness, r:AST.xypic.thickness, u:AST.xypic.thickness, d:AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
svg.createSVGElement("circle", { | |
cx:0, cy:0, r:xypic.em2px(AST.xypic.thickness) | |
}); | |
} | |
}); | |
// @{+} | |
xypic.Shape.PlusArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0.5 * AST.xypic.lineElementLength, r:0.5 * AST.xypic.lineElementLength, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var halfLen = AST.xypic.lineElementLength / 2; | |
var halfLenPx = xypic.em2px(halfLen); | |
svg.createSVGElement("line", { | |
x1:-halfLenPx, y1:0, x2:halfLenPx, y2:0 | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:halfLenPx, x2:0, y2:-halfLenPx | |
}); | |
} | |
}); | |
// @{x} | |
xypic.Shape.XArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle + Math.PI / 4; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0.5 * AST.xypic.lineElementLength, r:0.5 * AST.xypic.lineElementLength, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var halfLen = AST.xypic.lineElementLength / 2; | |
var halfLenPx = xypic.em2px(halfLen); | |
svg.createSVGElement("line", { | |
x1:-halfLenPx, y1:0, x2:halfLenPx, y2:0 | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:halfLenPx, x2:0, y2:-halfLenPx | |
}); | |
} | |
}); | |
// @{/} | |
xypic.Shape.SlashArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle - Math.PI / 10; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0, u:AST.xypic.lineElementLength / 2, d:AST.xypic.lineElementLength / 2 }; }, | |
drawDelegate: function (svg) { | |
var halfLen = AST.xypic.lineElementLength / 2; | |
var halfLenPx = xypic.em2px(halfLen); | |
svg.createSVGElement("line", { | |
x1:0, y1:halfLenPx, x2:0, y2:-halfLenPx | |
}); | |
} | |
}); | |
// @3{-} | |
xypic.Shape.Line3ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:AST.xypic.lineElementLength, u:AST.xypic.thickness, d:AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var lineLen = xypic.em2px(AST.xypic.lineElementLength); | |
var vshift = xypic.em2px(AST.xypic.thickness); | |
svg.createSVGElement("line", { | |
x1:0, y1:vshift, x2:lineLen, y2:vshift | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:lineLen, y2:0 | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:-vshift, x2:lineLen, y2:-vshift | |
}); | |
} | |
}); | |
// @2{-} | |
xypic.Shape.Line2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:AST.xypic.lineElementLength, u:0.5 * AST.xypic.thickness, d:0.5 * AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var vshift = xypic.em2px(0.5 * AST.xypic.thickness); | |
var lineLen = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:vshift, x2:lineLen, y2:vshift | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:-vshift, x2:lineLen, y2:-vshift | |
}); | |
} | |
}); | |
// @{-} | |
xypic.Shape.LineArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:AST.xypic.lineElementLength, u:0, d:0 }; }, | |
drawDelegate: function (svg) { | |
var lineLen = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:lineLen, y2:0 | |
}); | |
} | |
}); | |
// @3{.} | |
xypic.Shape.Dot3ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0, u:AST.xypic.thickness, d:AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var vshift = xypic.em2px(AST.xypic.thickness); | |
var lineLen = xypic.em2px(AST.xypic.thickness); | |
var dasharray = AST.xypic.dottedDasharray; | |
svg.createSVGElement("line", { | |
x1:0, y1:vshift, x2:lineLen, y2:vshift, | |
"stroke-dasharray": dasharray | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:lineLen, y2:0, | |
"stroke-dasharray": dasharray | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:-vshift, x2:lineLen, y2:-vshift, | |
"stroke-dasharray": dasharray | |
}); | |
} | |
}); | |
// @2{.} | |
xypic.Shape.Dot2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0, u:0.5 * AST.xypic.thickness, d:0.5 * AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var vshift = xypic.em2px(0.5 * AST.xypic.thickness); | |
var lineLen = xypic.em2px(AST.xypic.thickness); | |
var dasharray = AST.xypic.dottedDasharray; | |
svg.createSVGElement("line", { | |
x1:0, y1:vshift, x2:lineLen, y2:vshift, | |
"stroke-dasharray": dasharray | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:-vshift, x2:lineLen, y2:-vshift, | |
"stroke-dasharray": dasharray | |
}); | |
} | |
}); | |
// @{.} | |
xypic.Shape.DotArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:0, u:0, d:0 }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var lineLen = xypic.em2px(AST.xypic.thickness); | |
var dasharray = AST.xypic.dottedDasharray; | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:lineLen, y2:0, | |
"stroke-dasharray": dasharray | |
}); | |
} | |
}); | |
// @3{~} | |
xypic.Shape.Tilde3ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:-2 * AST.xypic.thickness, r:2 * AST.xypic.thickness, u:2 * AST.xypic.thickness, d:2* AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var s = xypic.em2px(AST.xypic.thickness); | |
svg.createSVGElement("path", { | |
d:"M" + (-2 * s) + "," + s + | |
" Q" + (-s) + ",0" + | |
" 0," + s + | |
" T" + (2 * s) + "," + s + | |
"M" + (-2 * s) + ",0" + | |
" Q" + (-s) + "," + (-s) + | |
" 0,0" + | |
" T" + (2 * s) + ",0" + | |
"M" + (-2 * s) + "," + (-s) + | |
" Q" + (-s) + "," + (-2 * s) + | |
" 0," + (-s) + | |
" T" + (2 * s) + "," + (-s) | |
}); | |
} | |
}); | |
// @2{~} | |
xypic.Shape.Tilde2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:-2 * AST.xypic.thickness, r:2 * AST.xypic.thickness, u:1.5 * AST.xypic.thickness, d:1.5 * AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var s = xypic.em2px(AST.xypic.thickness); | |
svg.createSVGElement("path", { | |
d:"M" + (-2 * s) + "," + (0.5 * s) + | |
" Q" + (-s) + "," + (-0.5 * s) + | |
" 0," + (0.5 * s) + | |
" T" + (2 * s) + "," + (0.5 * s) + | |
"M" + (-2 * s) + "," + (-0.5 * s) + | |
" Q" + (-s) + "," + (-1.5 * s) + | |
" 0," + (-0.5 * s) + | |
" T" + (2 * s) + "," + (-0.5 * s) | |
}); | |
} | |
}); | |
// @{~} | |
xypic.Shape.TildeArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:-2 * AST.xypic.thickness, r:2 * AST.xypic.thickness, u:AST.xypic.thickness, d:AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var s = xypic.em2px(AST.xypic.thickness); | |
svg.createSVGElement("path", { | |
d:"M" + (-2 * s) + ",0" + | |
" Q" + (-s) + "," + (-s) + | |
" 0,0" + | |
" T" + (2 * s) + ",0" | |
}); | |
} | |
}); | |
// @{~} | |
xypic.Shape.TildeArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:-2 * AST.xypic.thickness, r:2 * AST.xypic.thickness, u:AST.xypic.thickness, d:AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var s = xypic.em2px(AST.xypic.thickness); | |
svg.createSVGElement("path", { | |
d:"M" + (-2 * s) + ",0" + | |
" Q" + (-s) + "," + (-s) + | |
" 0,0" + | |
" T" + (2 * s) + ",0" | |
}); | |
} | |
}); | |
// @{>>} | |
xypic.Shape.GTGTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.489 * scale + 2 * AST.xypic.thickness, r:0, d:0.147 * scale, u:0.147 * scale }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var hshift = xypic.em2px(2 * t); | |
svg.createSVGElement("path", { | |
d:"M" + (-hshift) + ",0 Q" + (xypic.em2px(-0.222 * scale) - hshift) + "," + xypic.em2px(0.020 * scale) + " " + (xypic.em2px(-0.489 * scale) - hshift) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M" + (-hshift) + ",0 Q" + (xypic.em2px(-0.222 * scale) - hshift) + "," + xypic.em2px(-0.020 * scale) + " " + (xypic.em2px(-0.489 * scale) - hshift) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
} | |
}); | |
// @^{>>} | |
xypic.Shape.UpperGTGTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.489 * scale + 2 * AST.xypic.thickness, r:0, d:0, u:0.147 * scale }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var hshift = xypic.em2px(2 * t); | |
svg.createSVGElement("path", { | |
d:"M" + (-hshift) + ",0 Q" + (xypic.em2px(-0.222 * scale) - hshift) + "," + xypic.em2px(-0.020 * scale) + " " + (xypic.em2px(-0.489 * scale) - hshift) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
} | |
}); | |
// @_{>>} | |
xypic.Shape.LowerGTGTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.489 * scale + 2 * AST.xypic.thickness, r:0, d:0.147 * scale, u:0 }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var hshift = xypic.em2px(2 * t); | |
svg.createSVGElement("path", { | |
d:"M" + (-hshift) + ",0 Q" + (xypic.em2px(-0.222 * scale) - hshift) + "," + xypic.em2px(0.020 * scale) + " " + (xypic.em2px(-0.489 * scale) - hshift) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @2{>>} | |
xypic.Shape.GTGT2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.456 * scale + 2 * AST.xypic.thickness, r:0, d:0.229 * scale, u:0.229 * scale }; }, | |
getRadius: function () { | |
var scale = xypic.oneem; | |
return 0.213 * scale; | |
}, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var gu1 = svg.createGroup(svg.transformBuilder().rotateDegree(-10)); | |
var gd1 = svg.createGroup(svg.transformBuilder().rotateDegree(10)); | |
gu1.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd1.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + ","+xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
var gu2 = svg.createGroup(svg.transformBuilder().translate(-2 * t, 0).rotateDegree(-10)); | |
var gd2 = svg.createGroup(svg.transformBuilder().translate(-2 * t, 0).rotateDegree(10)); | |
gu2.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd2.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + ","+xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @3{>>} | |
xypic.Shape.GTGT3ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.507 * scale + 2 * AST.xypic.thickness, r:0, d:0.268 * scale, u:0.268 * scale }; }, | |
getRadius: function () { | |
var scale = xypic.oneem; | |
return 0.325 * scale; | |
}, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var gu1 = svg.createGroup(svg.transformBuilder().rotateDegree(-15)); | |
var gd1 = svg.createGroup(svg.transformBuilder().rotateDegree(15)); | |
gu1.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd1.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + ","+xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
var gu2 = svg.createGroup(svg.transformBuilder().translate(-2 * t, 0).rotateDegree(-15)); | |
var gd2 = svg.createGroup(svg.transformBuilder().translate(-2 * t, 0).rotateDegree(15)); | |
gu2.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd2.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + ","+xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:xypic.em2px(-0.507 * scale - 2 * t), y2:0 | |
}); | |
} | |
}); | |
// @{<<} | |
xypic.Shape.LTLTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.489 * scale + 2 * AST.xypic.thickness, d:0.147 * scale, u:0.147 * scale }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var hshift = xypic.em2px(2 * t); | |
svg.createSVGElement("path", { | |
d:"M" + hshift + ",0 Q" + (xypic.em2px(0.222 * scale) + hshift) + "," + xypic.em2px(-0.020 * scale) + " " + (xypic.em2px(0.489 * scale) + hshift) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M" + hshift + ",0 Q" + (xypic.em2px(0.222 * scale) + hshift) + "," + xypic.em2px(0.020 * scale) + " " + (xypic.em2px(0.489 * scale) + hshift) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @^{<<} | |
xypic.Shape.UpperLTLTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.489 * scale + 2 * AST.xypic.thickness, d:0, u:0.147 * scale }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var hshift = xypic.em2px(2 * t); | |
svg.createSVGElement("path", { | |
d:"M" + hshift + ",0 Q" + (xypic.em2px(0.222 * scale) + hshift) + "," + xypic.em2px(-0.020 * scale) + " " + (xypic.em2px(0.489 * scale) + hshift) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
} | |
}); | |
// @_{<<} | |
xypic.Shape.LowerLTLTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.489 * scale + 2 * AST.xypic.thickness, d:0.147 * scale, u:0 }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var hshift = xypic.em2px(2 * t); | |
svg.createSVGElement("path", { | |
d:"M" + hshift + ",0 Q" + (xypic.em2px(0.222 * scale) + hshift) + "," + xypic.em2px(0.020 * scale) + " " + (xypic.em2px(0.489 * scale) + hshift) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @2{<<} | |
xypic.Shape.LTLT2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.456 + scale + 2 * AST.xypic.thickness, d:0.229 * scale, u:0.229 * scale }; }, | |
getRadius: function () { | |
var scale = xypic.oneem; | |
return 0.213 * scale; | |
}, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var gu1 = svg.createGroup(svg.transformBuilder().translate(2 * t, 0).rotateDegree(10)); | |
var gd1 = svg.createGroup(svg.transformBuilder().translate(2 * t, 0).rotateDegree(-10)); | |
gu1.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd1.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
var gu2 = svg.createGroup(svg.transformBuilder().rotateDegree(10)); | |
var gd2 = svg.createGroup(svg.transformBuilder().rotateDegree(-10)); | |
gu2.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd2.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @3{<<} | |
xypic.Shape.LTLT3ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.507 * scale + 2 * AST.xypic.thickness, d:0.268 * scale, u:0.268 * scale }; }, | |
getRadius: function () { | |
var scale = xypic.oneem; | |
return 0.325 * scale; | |
}, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var gu1 = svg.createGroup(svg.transformBuilder().translate(2 * t, 0).rotateDegree(15)); | |
var gd1 = svg.createGroup(svg.transformBuilder().translate(2 * t, 0).rotateDegree(-15)); | |
gu1.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd1.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
var gu2 = svg.createGroup(svg.transformBuilder().rotateDegree(15)); | |
var gd2 = svg.createGroup(svg.transformBuilder().rotateDegree(-15)); | |
gu2.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd2.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:xypic.em2px(0.507 * scale + 2 * t), y2:0 | |
}); | |
} | |
}); | |
// @{||} | |
xypic.Shape.ColumnColumnArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:AST.xypic.thickness, r:0, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
svg.createSVGElement("line", { | |
x1:-xypic.em2px(t), y1:l, x2:-xypic.em2px(t), y2:-l | |
}); | |
} | |
}); | |
// @^{||} | |
xypic.Shape.UpperColumnColumnArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:AST.xypic.thickness, r:0, u:AST.xypic.lineElementLength, d:0 }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:0, y2:-l | |
}); | |
svg.createSVGElement("line", { | |
x1:-xypic.em2px(t), y1:0, x2:-xypic.em2px(t), y2:-l | |
}); | |
} | |
}); | |
// @_{||} | |
xypic.Shape.LowerColumnColumnArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:AST.xypic.thickness, r:0, u:0, d:AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:0, y2:l | |
}); | |
svg.createSVGElement("line", { | |
x1:-xypic.em2px(t), y1:0, x2:-xypic.em2px(t), y2:l | |
}); | |
} | |
}); | |
// @2{||} | |
xypic.Shape.ColumnColumn2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:AST.xypic.thickness, r:0, u:0.5 * (AST.xypic.lineElementLength + AST.xypic.thickness), d:0.5 * (AST.xypic.lineElementLength + AST.xypic.thickness) }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(0.5 * (AST.xypic.lineElementLength + AST.xypic.thickness)); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
svg.createSVGElement("line", { | |
x1:-xypic.em2px(t), y1:l, x2:-xypic.em2px(t), y2:-l | |
}); | |
} | |
}); | |
// @3{||} | |
xypic.Shape.ColumnColumn3ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:AST.xypic.thickness, r:0, u:0.5 * AST.xypic.lineElementLength + AST.xypic.thickness, d:0.5 * AST.xypic.lineElementLength + AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(0.5 * AST.xypic.lineElementLength + AST.xypic.thickness); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
svg.createSVGElement("line", { | |
x1:-xypic.em2px(t), y1:l, x2:-xypic.em2px(t), y2:-l | |
}); | |
} | |
}); | |
// @{|-} | |
xypic.Shape.ColumnLineArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:AST.xypic.lineElementLength, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var l = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
var lineLen = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:lineLen, y2:0 | |
}); | |
} | |
}); | |
// @^{|-} | |
xypic.Shape.UpperColumnLineArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:AST.xypic.lineElementLength, u:AST.xypic.lineElementLength, d:0 }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:0, y2:-l | |
}); | |
var lineLen = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:lineLen, y2:0 | |
}); | |
} | |
}); | |
// @_{|-} | |
xypic.Shape.LowerColumnLineArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:AST.xypic.lineElementLength, u:0, d:AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:0, y2:l | |
}); | |
var lineLen = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:lineLen, y2:0 | |
}); | |
} | |
}); | |
// @2{|-} | |
xypic.Shape.ColumnLine2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:AST.xypic.lineElementLength, u:0.5 * (AST.xypic.lineElementLength + AST.xypic.thickness), d:0.5 * (AST.xypic.lineElementLength + AST.xypic.thickness) }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(0.5 * (AST.xypic.lineElementLength + AST.xypic.thickness)); | |
svg.createSVGElement("line", { | |
x1:0, y1:-l, x2:0, y2:l | |
}); | |
var vshift = xypic.em2px(0.5 * t); | |
var lineLen = xypic.em2px(AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:vshift, x2:lineLen, y2:vshift | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:-vshift, x2:lineLen, y2:-vshift | |
}); | |
} | |
}); | |
// @3{|-} | |
xypic.Shape.ColumnLine3ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:0, r:AST.xypic.lineElementLength, u:0.5 * AST.xypic.lineElementLength + AST.xypic.thickness, d:0.5 * AST.xypic.lineElementLength + AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(0.5 * AST.xypic.lineElementLength + AST.xypic.thickness); | |
svg.createSVGElement("line", { | |
x1:0, y1:-l, x2:0, y2:l | |
}); | |
var lineLen = xypic.em2px(AST.xypic.lineElementLength); | |
var vshift = xypic.em2px(t); | |
svg.createSVGElement("line", { | |
x1:0, y1:vshift, x2:lineLen, y2:vshift | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:0, x2:lineLen, y2:0 | |
}); | |
svg.createSVGElement("line", { | |
x1:0, y1:-vshift, x2:lineLen, y2:-vshift | |
}); | |
} | |
}); | |
// @{>|} | |
xypic.Shape.GTColumnArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.489 * scale, r:0, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var l = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
} | |
}); | |
// @{>>|} | |
xypic.Shape.GTGTColumnArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0.489 * scale + 2 * AST.xypic.thickness, r:0, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
var hshift = xypic.em2px(2 * t); | |
svg.createSVGElement("path", { | |
d:"M" + (-hshift) + ",0 Q" + (xypic.em2px(-0.222 * scale) - hshift) + "," + xypic.em2px(0.020 * scale) + " " + (xypic.em2px(-0.489 * scale) - hshift) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M" + (-hshift) + ",0 Q" + (xypic.em2px(-0.222 * scale) - hshift) + "," + xypic.em2px(-0.020 * scale) + " " + (xypic.em2px(-0.489 * scale) - hshift) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
} | |
}); | |
// @{|<} | |
xypic.Shape.ColumnLTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.489 * scale, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @{|<<} | |
xypic.Shape.ColumnLTLTArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:0, r:0.489 * scale + 2 * AST.xypic.thickness, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var t = AST.xypic.thickness; | |
var l = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:l, x2:0, y2:-l | |
}); | |
var hshift = xypic.em2px(2 * t); | |
svg.createSVGElement("path", { | |
d:"M" + hshift + ",0 Q" + (xypic.em2px(0.222 * scale) + hshift) + "," + xypic.em2px(-0.020 * scale) + " " + (xypic.em2px(0.489 * scale) + hshift) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M" + hshift + ",0 Q" + (xypic.em2px(0.222 * scale) + hshift) + "," + xypic.em2px(0.020 * scale) + " " + (xypic.em2px(0.489 * scale) + hshift) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(0.222 * scale) + "," + xypic.em2px(0.020 * scale) + " " + xypic.em2px(0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
} | |
}); | |
// @{//} | |
xypic.Shape.SlashSlashArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle - Math.PI / 10; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { return { l:AST.xypic.thickness, r:0, u:0.5 * AST.xypic.lineElementLength, d:0.5 * AST.xypic.lineElementLength }; }, | |
drawDelegate: function (svg) { | |
var hshift = xypic.em2px(AST.xypic.thickness); | |
var halfLenPx = xypic.em2px(0.5 * AST.xypic.lineElementLength); | |
svg.createSVGElement("line", { | |
x1:0, y1:halfLenPx, x2:0, y2:-halfLenPx | |
}); | |
svg.createSVGElement("line", { | |
x1:-hshift, y1:halfLenPx, x2:-hshift, y2:-halfLenPx | |
}); | |
} | |
}); | |
// @{=>} | |
xypic.Shape.LineGT2ArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:AST.xypic.lineElementLength, r:AST.xypic.lineElementLength, d:0.229 * scale, u:0.229 * scale }; }, | |
getRadius: function () { | |
var scale = xypic.oneem; | |
return 0.213 * scale; | |
}, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var halfLen = AST.xypic.lineElementLength; | |
var hshift = xypic.em2px(halfLen); | |
var v = 0.5 * AST.xypic.thickness; | |
var vshift = xypic.em2px(v); | |
var r = this.getRadius(); | |
var delta = xypic.em2px(Math.sqrt(r * r - v * v)); | |
var gu = svg.createGroup(svg.transformBuilder().translate(halfLen, 0).rotateDegree(-10)); | |
var gd = svg.createGroup(svg.transformBuilder().translate(halfLen, 0).rotateDegree(10)); | |
gu.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + "," + xypic.em2px(-0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(-0.147 * scale) | |
}); | |
gd.createSVGElement("path", { | |
d:"M0,0 Q" + xypic.em2px(-0.222 * scale) + ","+xypic.em2px(0.020 * scale) + " " + xypic.em2px(-0.489 * scale) + "," + xypic.em2px(0.147 * scale) | |
}); | |
svg.createSVGElement("path", { | |
d:"M" + (-hshift) + "," + vshift + " L" + (hshift - delta) + "," + vshift + | |
" M" + (-hshift) + "," + (-vshift) + " L" + (hshift - delta) + "," + (-vshift) | |
}); | |
} | |
}); | |
// twocell equality arrow | |
xypic.Shape.TwocellEqualityArrowheadShape = xypic.Shape.ArrowheadShape.Subclass({ | |
Init: function (c, angle) { | |
this.c = c; | |
this.angle = angle; | |
memoize(this, "getBoundingBox"); | |
}, | |
getBox: function () { var scale = xypic.oneem; return { l:AST.xypic.lineElementLength, r:AST.xypic.lineElementLength, d:0.5 * AST.xypic.thickness, u:0.5 * AST.xypic.thickness }; }, | |
drawDelegate: function (svg) { | |
var scale = xypic.oneem; | |
var hshift = xypic.em2px(AST.xypic.lineElementLength); | |
var vshift = xypic.em2px(0.5 * AST.xypic.thickness); | |
svg.createSVGElement("path", { | |
d:"M" + (-hshift) + "," + vshift + " L" + hshift + "," + vshift + | |
" M" + (-hshift) + "," + (-vshift) + " L" + hshift + "," + (-vshift) | |
}); | |
} | |
}); | |
xypic.Shape.LineShape = xypic.Shape.Subclass({ | |
Init: function (line, object, main, variant, bbox) { | |
this.line = line; | |
this.object = object; | |
this.main = main; | |
this.variant = variant; | |
this.bbox = bbox; | |
this.holeRanges = FP.List.empty; | |
}, | |
sliceHole: function (range) { | |
this.holeRanges = this.holeRanges.prepend(range); | |
}, | |
draw: function (svg) { | |
this.line.drawLine(svg, this.object, this.main, this.variant, this.holeRanges); | |
}, | |
getBoundingBox: function () { | |
return this.bbox; | |
}, | |
toString: function () { | |
return "LineShape[line:" + this.line + ", object:" + this.object + ", main:" + this.main + ", variant:" + this.variant + "]"; | |
} | |
}); | |
xypic.Shape.CurveShape = xypic.Shape.Subclass({ | |
Init: function (curve, objectForDrop, objectForConnect, bbox) { | |
this.curve = curve; | |
this.objectForDrop = objectForDrop; | |
this.objectForConnect = objectForConnect; | |
this.bbox = bbox; | |
this.holeRanges = FP.List.empty; | |
}, | |
sliceHole: function (range) { | |
this.holeRanges = this.holeRanges.prepend(range); | |
}, | |
draw: function (svg) { | |
this.curve.drawCurve(svg, this.objectForDrop, this.objectForConnect, this.holeRanges); | |
}, | |
getBoundingBox: function () { | |
return this.bbox; | |
}, | |
toString: function () { | |
return "CurveShape[curve" + this.curve + ", objectForDrop:" + (this.objectForDrop !== undefined? this.objectForDrop.toString() : "null") + ", objectForConnect:" + (this.objectForConnect !== undefined? this.objectForConnect.toString() : "null") + "]"; | |
} | |
}); | |
xypic.Curve = MathJax.Object.Subclass({ | |
velocity: function (t) { | |
var dx = this.dpx(t); | |
var dy = this.dpy(t); | |
return Math.sqrt(dx*dx+dy*dy); | |
}, | |
length: function (t) { | |
if (t < 0 || t > 1) { | |
throw xypic.ExecutionError("illegal cubic Bezier parameter t:"+t); | |
} | |
this.buildLengthArray(); | |
var n = AST.xypic.lengthResolution; | |
var tn = t*n; | |
var f = Math.floor(tn); | |
var c = Math.ceil(tn); | |
if (f === c) { | |
return this.lengthArray[f]; | |
} | |
var sf = this.lengthArray[f]; | |
var sc = this.lengthArray[c]; | |
return sf + (sc-sf)/(c-f)*(tn-f); // linear interpolation | |
}, | |
tOfLength: function (s) { | |
this.buildLengthArray(); | |
var a = this.lengthArray; | |
if (s < a[0]) { | |
return 0; | |
} else if (s > a[a.length - 1]) { | |
return 1; | |
} | |
var m, al, ah; | |
var l = 0; | |
var r = a.length-2; | |
while (l <= r) { | |
m = (l + r) >> 1; | |
al = a[m]; | |
ah = a[m+1]; | |
if (s >= al && s <= ah) { | |
break; | |
} | |
if (s < al) { | |
r = m-1; | |
} else { | |
l = m+1; | |
} | |
} | |
var n = AST.xypic.lengthResolution; | |
if (al === ah) { | |
return m/n; | |
} | |
var t = (m + (s-al)/(ah-al))/n; | |
return t; | |
}, | |
tOfShavedStart: function (frame) { | |
if (frame.isPoint()) { | |
return 0; // trivial | |
} | |
var ts = this.tOfIntersections(frame); | |
if (ts.length == 0) { | |
return undefined; // No solution. | |
} | |
return Math.min.apply(Math, ts); | |
}, | |
tOfShavedEnd: function (frame) { | |
if (frame.isPoint()) { | |
return 1; // trivial | |
} | |
var ts = this.tOfIntersections(frame); | |
if (ts.length == 0) { | |
return undefined; // No solution. | |
} | |
return Math.max.apply(Math, ts); | |
}, | |
shaveStart: function (frame) { | |
if (frame.isPoint()) { | |
return this; // trivial | |
} | |
var ts = this.tOfIntersections(frame); | |
if (ts.length == 0) { | |
return undefined; // No solution. | |
} | |
var t = Math.min.apply(Math, ts); | |
return this.divide(t)[1]; | |
}, | |
shaveEnd: function (frame) { | |
if (frame.isPoint()) { | |
return this; // trivial | |
} | |
var ts = this.tOfIntersections(frame); | |
if (ts.length == 0) { | |
return undefined; // No solution. | |
} | |
var t = Math.max.apply(Math, ts); | |
return this.divide(t)[0]; | |
}, | |
buildLengthArray: function () { | |
if (this.lengthArray !== undefined) { | |
return; | |
} | |
var n = AST.xypic.lengthResolution; | |
// lengthArray[i]: \int_0^{t_{2i}} v(t) dt with Simpson's rule, (i=0, 1, \cdots, n) | |
// where, t_k=k h, h=1/(2n): step length. | |
var lengthArray = new Array(n+1); | |
var sum = 0; | |
var h = 1/2/n; | |
var i = 0; | |
var delta = h/3; | |
lengthArray[0] = 0; | |
sum = this.velocity(0) + 4*this.velocity(h); | |
lastv = this.velocity(2*h); | |
lengthArray[1] = delta*(sum + lastv); | |
for (i = 2; i <= n; i++) { | |
sum += 2*lastv + 4*this.velocity((2*i-1)*h); | |
lastv = this.velocity(2*i*h); | |
lengthArray[i] = delta*(sum + lastv); | |
} | |
this.lengthArray = lengthArray; | |
}, | |
drawParallelCurve: function (svg, vshift) { | |
var i, n = this.countOfSegments() * AST.xypic.interpolationResolution; | |
var ts = new Array(n+1); | |
var x1s = new Array(n+1); | |
var y1s = new Array(n+1); | |
var x2s = new Array(n+1); | |
var y2s = new Array(n+1); | |
var hpi = Math.PI/2; | |
var d = vshift; | |
var t, angle, p, x, y, dc, ds; | |
for (i = 0; i <= n; i++) { | |
t = i/n; | |
ts[i] = t; // TODO: 高速化。ts[i+1]-ts[i]が定数の場合に特化した作りにする。 | |
angle = this.angle(t); | |
p = this.position(t); | |
x = p.x; | |
y = p.y; | |
dc = d*Math.cos(angle+hpi); | |
ds = d*Math.sin(angle+hpi); | |
x1s[i] = x+dc; | |
y1s[i] = y+ds; | |
x2s[i] = x-dc; | |
y2s[i] = y-ds; | |
} | |
xypic.Curve.CubicBeziers.interpolation(ts, x1s, y1s).drawPrimitive(svg, "none"); | |
xypic.Curve.CubicBeziers.interpolation(ts, x2s, y2s).drawPrimitive(svg, "none"); | |
}, | |
drawParallelDottedCurve: function (svg, spacing, vshift) { | |
var px = 1/xypic.em, hpx = px/2; | |
var sp = px + spacing; | |
var len = this.length(1); | |
var n = Math.floor((len-px)/sp); | |
var d = vshift; | |
if (n >= 0) { | |
var i, hpi = Math.PI/2; | |
var s = this.startPosition(), e = this.endPosition(); | |
for (i = 0; i <= n; i++) { | |
var s = hpx + i*sp; | |
// TODO: 高速化。毎回二分探索せず、端から線形探索・適用するようにする。 | |
var t = this.tOfLength(s); | |
var angle = this.angle(t); | |
var p = this.position(t); | |
var x = p.x, y = p.y | |
var dc = d*Math.cos(angle+hpi), ds = d*Math.sin(angle+hpi); | |
svg.createSVGElement("circle", { | |
cx:xypic.em2px(x+dc), cy:-xypic.em2px(y+ds), r:0.12, | |
fill: "currentColor" | |
}); | |
svg.createSVGElement("circle", { | |
cx:xypic.em2px(x-dc), cy:-xypic.em2px(y-ds), r:0.12, | |
fill: "currentColor" | |
}); | |
} | |
} | |
}, | |
drawParallelDashedCurve: function (svg, dash, vshift) { | |
var len = this.length(1); | |
var n = Math.floor((len-dash)/(2*dash)), m = 2*n+1; | |
var hshift = (len-dash)/2-n*dash; | |
var i; | |
var ts = new Array(n+1); | |
var x1s = new Array(n+1); | |
var y1s = new Array(n+1); | |
var x2s = new Array(n+1); | |
var y2s = new Array(n+1); | |
var hpi = Math.PI/2; | |
var d = vshift; | |
var t, angle, p, x, y, dc, ds; | |
for (i = 0; i <= m; i++) { | |
// TODO: 高速化。毎回二分探索せず、端から線形探索・適用するようにする。 | |
t = this.tOfLength(hshift + i*dash); | |
ts[i] = t; | |
angle = this.angle(t); | |
p = this.position(t); | |
x = p.x; | |
y = p.y; | |
dc = d*Math.cos(angle+hpi); | |
ds = d*Math.sin(angle+hpi); | |
x1s[i] = x+dc; | |
y1s[i] = y+ds; | |
x2s[i] = x-dc; | |
y2s[i] = y-ds; | |
} | |
xypic.Curve.CubicBeziers.interpolation(ts, x1s, y1s).drawSkipped(svg); | |
xypic.Curve.CubicBeziers.interpolation(ts, x2s, y2s).drawSkipped(svg); | |
}, | |
drawSquigCurve: function (svg, variant) { | |
var thickness = xypic.length2em("0.15em"); | |
var len = this.length(1); | |
var wave = 4*thickness; | |
var amp = thickness; | |
if (len >= wave) { | |
var n = Math.floor(len/wave); | |
var shiftLen = (len-n*wave)/2; | |
var s, t, p, angle, nx, ny, hpi = Math.PI/2, d1, d2, d3; | |
switch (variant) { | |
case "3": | |
s = shiftLen; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 = "M"+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 = "M"+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
d3 = "M"+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
for (var i = 0; i < n; i++) { | |
s = shiftLen + wave*i + thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " Q"+xypic.em2px(p.x+2*nx)+","+xypic.em2px(-p.y-2*ny); | |
d2 += " Q"+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d3 += " Q"+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
s = shiftLen + wave*i + 2*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " "+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 += " "+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
d3 += " "+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
s = shiftLen + wave*i + 3*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " Q"+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
d2 += " Q"+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
d3 += " "+xypic.em2px(p.x-2*nx)+","+xypic.em2px(-p.y+2*ny); | |
s = shiftLen + wave*(i+1); | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " "+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 += " "+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
d3 += " "+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
} | |
svg.createSVGElement("path", {"d":d1}); | |
svg.createSVGElement("path", {"d":d2}); | |
svg.createSVGElement("path", {"d":d3}); | |
break; | |
case "2": | |
s = shiftLen; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi)/2; | |
ny = amp*Math.sin(angle+hpi)/2; | |
d1 = "M"+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 = "M"+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
for (var i = 0; i < n; i++) { | |
s = shiftLen + wave*i + thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi)/2; | |
ny = amp*Math.sin(angle+hpi)/2; | |
d1 += " Q"+xypic.em2px(p.x+3*nx)+","+xypic.em2px(-p.y-3*ny); | |
d2 += " Q"+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
s = shiftLen + wave*i + 2*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi)/2; | |
ny = amp*Math.sin(angle+hpi)/2; | |
d1 += " "+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 += " "+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
s = shiftLen + wave*i + 3*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi)/2; | |
ny = amp*Math.sin(angle+hpi)/2; | |
d1 += " Q"+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
d2 += " Q"+xypic.em2px(p.x-3*nx)+","+xypic.em2px(-p.y+3*ny); | |
s = shiftLen + wave*(i+1); | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi)/2; | |
ny = amp*Math.sin(angle+hpi)/2; | |
d1 += " "+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 += " "+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
} | |
svg.createSVGElement("path", {"d":d1}); | |
svg.createSVGElement("path", {"d":d2}); | |
break; | |
default: | |
s = shiftLen; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
d1 = "M"+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
for (var i = 0; i < n; i++) { | |
s = shiftLen + wave*i + thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " Q"+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
s = shiftLen + wave*i + 2*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
d1 += " "+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
s = shiftLen + wave*i + 3*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " Q"+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
s = shiftLen + wave*(i+1); | |
t = this.tOfLength(s); | |
p = this.position(t); | |
d1 += " "+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
} | |
svg.createSVGElement("path", {"d":d1}); | |
} | |
} | |
}, | |
drawDashSquigCurve: function (svg, variant) { | |
var thickness = AST.xypic.thickness; | |
var len = this.length(1); | |
var wave = 4*thickness; | |
var amp = thickness; | |
if (len >= wave) { | |
var n = Math.floor((len-wave)/2/wave); | |
var shiftLen = (len-wave)/2-n*wave; | |
var s, t, p, angle, nx, ny, hpi = Math.PI/2, d1, d2, d3; | |
switch (variant) { | |
case "3": | |
d1 = d2 = d3 = ""; | |
for (var i = 0; i <= n; i++) { | |
s = shiftLen + wave*i*2; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " M"+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 += " M"+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
d3 += " M"+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
s = shiftLen + wave*i*2 + thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " Q"+xypic.em2px(p.x+2*nx)+","+xypic.em2px(-p.y-2*ny); | |
d2 += " Q"+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d3 += " Q"+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
s = shiftLen + wave*i*2 + 2*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " "+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 += " "+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
d3 += " "+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
s = shiftLen + wave*i*2 + 3*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " Q"+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
d2 += " Q"+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
d3 += " "+xypic.em2px(p.x-2*nx)+","+xypic.em2px(-p.y+2*ny); | |
s = shiftLen + wave*(i*2+1); | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " "+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 += " "+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
d3 += " "+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
} | |
svg.createSVGElement("path", {"d":d1}); | |
svg.createSVGElement("path", {"d":d2}); | |
svg.createSVGElement("path", {"d":d3}); | |
break; | |
case "2": | |
d1 = d2 = ""; | |
for (var i = 0; i <= n; i++) { | |
s = shiftLen + wave*i*2; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi)/2; | |
ny = amp*Math.sin(angle+hpi)/2; | |
d1 += " M"+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 += " M"+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
s = shiftLen + wave*i*2 + thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi)/2; | |
ny = amp*Math.sin(angle+hpi)/2; | |
d1 += " Q"+xypic.em2px(p.x+3*nx)+","+xypic.em2px(-p.y-3*ny); | |
d2 += " Q"+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
s = shiftLen + wave*i*2 + 2*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi)/2; | |
ny = amp*Math.sin(angle+hpi)/2; | |
d1 += " "+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 += " "+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
s = shiftLen + wave*i*2 + 3*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi)/2; | |
ny = amp*Math.sin(angle+hpi)/2; | |
d1 += " Q"+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
d2 += " Q"+xypic.em2px(p.x-3*nx)+","+xypic.em2px(-p.y+3*ny); | |
s = shiftLen + wave*(i*2+1); | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi)/2; | |
ny = amp*Math.sin(angle+hpi)/2; | |
d1 += " "+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
d2 += " "+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
} | |
svg.createSVGElement("path", {"d":d1}); | |
svg.createSVGElement("path", {"d":d2}); | |
break; | |
default: | |
d1 = ""; | |
for (var i = 0; i <= n; i++) { | |
s = shiftLen + wave*i*2; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
d1 += " M"+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
s = shiftLen + wave*i*2 + thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " Q"+xypic.em2px(p.x+nx)+","+xypic.em2px(-p.y-ny); | |
s = shiftLen + wave*i*2 + 2*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
d1 += " "+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
s = shiftLen + wave*i*2 + 3*thickness; | |
t = this.tOfLength(s); | |
p = this.position(t); | |
angle = this.angle(t); | |
nx = amp*Math.cos(angle+hpi); | |
ny = amp*Math.sin(angle+hpi); | |
d1 += " Q"+xypic.em2px(p.x-nx)+","+xypic.em2px(-p.y+ny); | |
s = shiftLen + wave*(i*2+1); | |
t = this.tOfLength(s); | |
p = this.position(t); | |
d1 += " "+xypic.em2px(p.x)+","+xypic.em2px(-p.y); | |
} | |
svg.createSVGElement("path", {"d":d1}); | |
} | |
} | |
}, | |
drawCurve: function (svg, objectForDrop, objectForConnect, holeRanges) { | |
if (holeRanges.isEmpty) { | |
this._drawCurve(svg, objectForDrop, objectForConnect); | |
} else { | |
var clippingRanges = xypic.Range(0, 1).differenceRanges(holeRanges); | |
var self = this; | |
clippingRanges.foreach(function (range) { | |
self.slice(range.start, range.end)._drawCurve(svg, objectForDrop, objectForConnect); | |
}); | |
} | |
}, | |
_drawCurve: function (svg, objectForDrop, objectForConnect) { | |
var thickness = xypic.length2em("0.15em"); | |
var vshift; | |
if (objectForConnect !== undefined) { | |
var main = objectForConnect.dirMain(); | |
var variant = objectForConnect.dirVariant(); | |
switch (main) { | |
case "=": | |
main = "-"; | |
variant = "2"; | |
break; | |
case "==": | |
main = "--"; | |
variant = "2"; | |
break; | |
case ':': | |
case '::': | |
main = "."; | |
variant = "2"; | |
break; | |
} | |
switch (main) { | |
case '': | |
// draw nothing. | |
break; | |
case '-': | |
switch (variant) { | |
case "2": | |
vshift = thickness/2; | |
this.drawParallelCurve(svg, vshift); | |
break; | |
case "3": | |
vshift = thickness; | |
this.drawParallelCurve(svg, vshift); | |
this.drawPrimitive(svg, "none"); | |
break; | |
default: | |
vshift = 0; | |
this.drawPrimitive(svg, "none"); | |
} | |
break; | |
case '.': | |
case '..': | |
switch (variant) { | |
case "2": | |
vshift = thickness/2; | |
this.drawParallelDottedCurve(svg, thickness, vshift) | |
break; | |
case "3": | |
vshift = thickness; | |
this.drawParallelDottedCurve(svg, thickness, vshift) | |
this.drawPrimitive(svg, AST.xypic.dottedDasharray); | |
break; | |
default: | |
vshift = 0; | |
this.drawPrimitive(svg, AST.xypic.dottedDasharray); | |
break; | |
} | |
break; | |
case '--': | |
var dash = 3 * thickness; | |
var len = this.length(1); | |
if (len >= dash) { | |
switch (variant) { | |
case "2": | |
vshift = thickness / 2; | |
this.drawParallelDashedCurve(svg, dash, vshift); | |
break; | |
case "3": | |
vshift = thickness; | |
this.drawParallelDashedCurve(svg, dash, vshift); | |
var shiftLen = (len - dash) / 2 - Math.floor((len - dash) / 2 / dash) * dash; | |
var shiftT = this.tOfLength(shiftLen); | |
var shifted = this.divide(shiftT)[1]; | |
shifted.drawPrimitive(svg, xypic.em2px(dash) + " " + xypic.em2px(dash)) | |
break; | |
default: | |
vshift = 0; | |
var shiftLen = (len - dash) / 2 - Math.floor((len - dash) / 2 / dash) * dash; | |
var shiftT = this.tOfLength(shiftLen); | |
var shifted = this.divide(shiftT)[1]; | |
shifted.drawPrimitive(svg, xypic.em2px(dash) + " " + xypic.em2px(dash)); | |
} | |
} | |
break; | |
case '~': | |
this.drawSquigCurve(svg, variant); | |
switch (variant) { | |
case "2": | |
vshift = 1.5 * thickness; | |
break; | |
case "3": | |
vshift = 2 * thickness; | |
break; | |
default: | |
vshift = 0 | |
} | |
break; | |
case '~~': | |
this.drawDashSquigCurve(svg, variant); | |
switch (variant) { | |
case "2": | |
vshift = 1.5 * thickness; | |
break; | |
case "3": | |
vshift = 2 * thickness; | |
break; | |
default: | |
vshift = 0 | |
} | |
break; | |
default: | |
// TODO: ~* と ~** の順序を考慮する。 | |
var dummyEnv = xypic.Env(); | |
dummyEnv.c = xypic.Env.originPosition; | |
var dummyContext = xypic.DrawingContext(xypic.Shape.none, dummyEnv); | |
var conBBox = objectForConnect.boundingBox(dummyContext); | |
if (conBBox == undefined) { | |
return; | |
} | |
var cl = conBBox.l; | |
var conLen = cl + conBBox.r; | |
var dropLen, dl; | |
if (objectForDrop !== undefined) { | |
var dropBBox = objectForDrop.boundingBox(dummyContext); | |
if (dropBBox !== undefined) { | |
dl = dropBBox.l; | |
dropLen = dl + dropBBox.r; | |
} | |
} else { | |
dropLen = 0; | |
} | |
var compositeLen = conLen + dropLen; | |
if (compositeLen == 0) { | |
compositeLen = AST.xypic.strokeWidth; | |
} | |
var len = this.length(1); | |
var n = Math.floor(len / compositeLen); | |
if (n == 0) { | |
return; | |
} | |
var shiftLen = (len - n * compositeLen) / 2; | |
var dummyContext = xypic.DrawingContext(xypic.Shape.none, dummyEnv); | |
var s, t; | |
for (var i = 0; i < n; i++) { | |
s = shiftLen + i * compositeLen; | |
if (objectForDrop !== undefined) { | |
t = this.tOfLength(s + dl); | |
dummyEnv.c = this.position(t); | |
dummyEnv.angle = this.angle(t); | |
objectForDrop.toDropShape(dummyContext).draw(svg); | |
} | |
t = this.tOfLength(s + dropLen + cl); | |
dummyEnv.c = this.position(t); | |
dummyEnv.angle = this.angle(t); | |
bbox = objectForConnect.toDropShape(dummyContext).draw(svg); | |
} | |
} | |
} else { | |
var dummyEnv = xypic.Env(); | |
dummyEnv.c = xypic.Env.originPosition; | |
var dummyContext = xypic.DrawingContext(xypic.Shape.none, dummyEnv); | |
var object = objectForDrop; | |
var objectBBox = object.boundingBox(dummyContext); | |
if (objectBBox === undefined) { | |
return; | |
} | |
var objectWidth = objectBBox.l + objectBBox.r; | |
var objectLen = objectWidth; | |
if (objectLen == 0) { | |
objectLen = AST.xypic.strokeWidth; | |
} | |
var len = this.length(1); | |
var n = Math.floor(len / objectLen); | |
if (n == 0) { | |
return; | |
} | |
var shiftLen = (len - n * objectLen + objectLen - objectWidth) / 2 + objectBBox.l; | |
var dummyContext = xypic.DrawingContext(xypic.Shape.none, dummyEnv); | |
for (var i = 0; i < n; i++) { | |
var s = shiftLen + i * objectLen; | |
var t = this.tOfLength(s); | |
dummyEnv.c = this.position(t); | |
dummyEnv.angle = 0; | |
object.toDropShape(dummyContext).draw(svg); | |
} | |
} | |
}, | |
toShape: function (context, objectForDrop, objectForConnect) { | |
var env = context.env; | |
var thickness = xypic.length2em("0.15em"); | |
var shape = xypic.Shape.none; | |
var vshift; | |
if (objectForConnect !== undefined) { | |
var main = objectForConnect.dirMain(); | |
var variant = objectForConnect.dirVariant(); | |
switch (main) { | |
case "=": | |
main = "-"; | |
variant = "2"; | |
break; | |
case "==": | |
main = "--"; | |
variant = "2"; | |
break; | |
case ':': | |
case '::': | |
main = "."; | |
variant = "2"; | |
break; | |
} | |
switch (main) { | |
case '': | |
vshift = 0; | |
break; | |
case '-': | |
case '.': | |
case '..': | |
switch (variant) { | |
case "2": | |
vshift = thickness / 2; | |
break; | |
case "3": | |
vshift = thickness; | |
break; | |
default: | |
vshift = 0; | |
break; | |
} | |
break; | |
case '--': | |
var dash = 3 * thickness; | |
var len = this.length(1); | |
if (len >= dash) { | |
switch (variant) { | |
case "2": | |
vshift = thickness / 2; | |
break; | |
case "3": | |
vshift = thickness; | |
break; | |
default: | |
vshift = 0; | |
} | |
} | |
break; | |
case '~': | |
case '~~': | |
switch (variant) { | |
case "2": | |
vshift = 1.5 * thickness; | |
break; | |
case "3": | |
vshift = 2 * thickness; | |
break; | |
default: | |
vshift = 0 | |
} | |
break; | |
default: | |
// TODO: ~* と ~** の順序を考慮する。 | |
var conBBox = objectForConnect.boundingBox(context); | |
if (conBBox == undefined) { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
} | |
vshift = Math.max(conBBox.u, conBBox.d); | |
var cl = conBBox.l; | |
var conLen = cl + conBBox.r; | |
var dropLen, dl; | |
if (objectForDrop !== undefined) { | |
var dropBBox = objectForDrop.boundingBox(context); | |
if (dropBBox !== undefined) { | |
dl = dropBBox.l; | |
dropLen = dl + dropBBox.r; | |
vshift = Math.max(vshift, dropBBox.u, dropBBox.d); | |
} | |
} else { | |
dropLen = 0; | |
} | |
var compositeLen = conLen + dropLen; | |
if (compositeLen == 0) { | |
compositeLen = AST.xypic.strokeWidth; | |
} | |
var len = this.length(1); | |
var n = Math.floor(len / compositeLen); | |
if (n == 0) { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
} | |
shape = xypic.Shape.CurveShape(this, objectForDrop, objectForConnect, this.boundingBox(vshift)); | |
context.appendShapeToFront(shape); | |
return shape; | |
} | |
if (vshift === undefined) { | |
return xypic.Shape.none; | |
} else { | |
shape = xypic.Shape.CurveShape(this, objectForDrop, objectForConnect, this.boundingBox(vshift)); | |
context.appendShapeToFront(shape); | |
return shape; | |
} | |
} else if (objectForDrop !== undefined) { | |
var object = objectForDrop; | |
var objectBBox = object.boundingBox(context); | |
if (objectBBox == undefined) { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
} | |
var objectWidth = objectBBox.l + objectBBox.r; | |
var objectLen = objectWidth; | |
if (objectLen == 0) { | |
objectLen = AST.xypic.strokeWidth; | |
} | |
var len = this.length(1); | |
var n = Math.floor(len / objectLen); | |
if (n == 0) { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
} | |
vshift = Math.max(objectBBox.u, objectBBox.d); | |
shape = xypic.Shape.CurveShape(this, objectForDrop, objectForConnect, this.boundingBox(vshift)); | |
context.appendShapeToFront(shape); | |
return shape; | |
} | |
return shape; | |
} | |
}, { | |
sign: function (x) { return x>0? 1 : (x===0? 0 : -1); }, | |
solutionsOfCubicEq: function (a3, a2, a1, a0) { | |
// find solutions t in [0, 1] | |
if (a3 === 0) { | |
return xypic.Curve.solutionsOfQuadEq(a2, a1, a0); | |
} | |
var b2 = a2/3/a3, b1 = a1/a3, b0 = a0/a3; | |
var p = b2*b2-b1/3, q = -b0/2+b1*b2/2-b2*b2*b2; | |
var d = q*q-p*p*p; | |
if (d === 0) { | |
var s = Math.pow(q, 1/3); | |
var t0 = 2*s-b2, t1 = -s-b2; | |
return xypic.Curve.filterByIn0to1([t0, t1]); | |
} else if (d > 0) { | |
var u = q+xypic.Curve.sign(q)*Math.sqrt(d); | |
var r = xypic.Curve.sign(u)*Math.pow(Math.abs(u), 1/3); | |
var s = p/r; | |
var t = r+s-b2; | |
return xypic.Curve.filterByIn0to1([t]); | |
} else { | |
var r = 2*Math.sqrt(p); | |
var s = Math.acos(2*q/p/r); | |
var t0 = r*Math.cos(s/3)-b2; | |
var t1 = r*Math.cos((s+2*Math.PI)/3)-b2; | |
var t2 = r*Math.cos((s+4*Math.PI)/3)-b2; | |
return xypic.Curve.filterByIn0to1([t0, t1, t2]); | |
} | |
}, | |
solutionsOfQuadEq: function (a2, a1, a0) { | |
// find solutions t in [0, 1] | |
if (a2 === 0) { | |
return xypic.Curve.solutionsOfLinearEq(a1, a0); | |
} else { | |
var d = a1 * a1 - 4 * a0 * a2; | |
if (d >= 0) { | |
var s = Math.sqrt(d); | |
var tp = (-a1 + s) / 2 / a2; | |
var tm = (-a1 - s) / 2 / a2; | |
return xypic.Curve.filterByIn0to1([tp, tm]); | |
} else { | |
return []; | |
} | |
} | |
}, | |
solutionsOfLinearEq: function (a1, a0) { | |
// find solution t in [0, 1] | |
if (a1 === 0) { | |
return (a0 === 0? 0 : []); | |
} | |
return xypic.Curve.filterByIn0to1([-a0 / a1]); | |
}, | |
filterByIn0to1: function (ts) { | |
var filterdTs = []; | |
for (var i = 0; i < ts.length; i++) { | |
var t = ts[i]; | |
if (t >= 0 && t <= 1) { | |
filterdTs.push(t); | |
} | |
} | |
return filterdTs; | |
} | |
}); | |
xypic.Curve.QuadBezier = xypic.Curve.Subclass({ | |
Init: function (cp0, cp1, cp2) { | |
this.cp0 = cp0; | |
this.cp1 = cp1; | |
this.cp2 = cp2; | |
var a0x = cp0.x; | |
var a1x = 2*(cp1.x - cp0.x); | |
var a2x = cp2.x - 2*cp1.x + cp0.x; | |
this.px = function(t) { return a0x + t*a1x + t*t*a2x; } | |
this.dpx = function(t) { return a1x + 2*t*a2x; } | |
var a0y = cp0.y; | |
var a1y = 2*(cp1.y - cp0.y); | |
var a2y = cp2.y - 2*cp1.y + cp0.y; | |
this.py = function(t) { return a0y + t*a1y + t*t*a2y; } | |
this.dpy = function(t) { return a1y + 2*t*a2y; } | |
}, | |
startPosition: function () { | |
return this.cp0; | |
}, | |
endPosition: function () { | |
return this.cp2; | |
}, | |
position: function (t) { | |
return xypic.Frame.Point(this.px(t), this.py(t)); | |
}, | |
derivative: function (t) { | |
return xypic.Frame.Point(this.dpx(t), this.dpy(t)); | |
}, | |
angle: function (t) { | |
return Math.atan2(this.dpy(t), this.dpx(t)); | |
}, | |
boundingBox: function (vshift) { | |
var maxMinX = this.maxMin(this.cp0.x, this.cp1.x, this.cp2.x, vshift); | |
var maxMinY = this.maxMin(this.cp0.y, this.cp1.y, this.cp2.y, vshift); | |
if (vshift === 0) { | |
return xypic.Frame.Rect(this.cp0.x, this.cp0.y, { | |
l:this.cp0.x-maxMinX.min, r:maxMinX.max-this.cp0.x, | |
u:maxMinY.max-this.cp0.y, d:this.cp0.y-maxMinY.min | |
}); | |
} else { | |
var hpi = Math.PI/2; | |
var sx = this.cp0.x; | |
var sy = this.cp0.y; | |
var ex = this.cp2.x; | |
var ey = this.cp2.y; | |
var a0 = this.angle(0)+hpi; | |
var a1 = this.angle(1)+hpi; | |
var vc0 = vshift*Math.cos(a0), vs0 = vshift*Math.sin(a0); | |
var vc1 = vshift*Math.cos(a1), vs1 = vshift*Math.sin(a1); | |
var minX = Math.min(maxMinX.min, sx+vc0, sx-vc0, ex+vc1, ex-vc1); | |
var maxX = Math.max(maxMinX.max, sx+vc0, sx-vc0, ex+vc1, ex-vc1); | |
var minY = Math.min(maxMinY.min, sy+vs0, sy-vs0, ey+vs1, ey-vs1); | |
var maxY = Math.max(maxMinY.max, sy+vs0, sy-vs0, ey+vs1, ey-vs1); | |
return xypic.Frame.Rect(sx, sy, { | |
l:sx-minX, r:maxX-sx, u:maxY-sy, d:sy-minY | |
}); | |
} | |
}, | |
maxMin: function (x0, x1, x2, vshift) { | |
var max, min; | |
if (x0 > x2) { | |
max = x0; | |
min = x2; | |
} else { | |
max = x2; | |
min = x0; | |
} | |
var roundEp = xypic.Util.roundEpsilon; | |
var a0 = roundEp(x0); | |
var a1 = roundEp(x1 - x0); | |
var a2 = roundEp(x2 - 2*x1 + x0); | |
var p = function(t) { return a0 + 2*t*a1 + t*t*a2 } | |
var x, t; | |
if (a2 != 0) { | |
t = -a1/a2; | |
if (t > 0 && t < 1) { | |
x = p(t); | |
max = Math.max(max, x + vshift, x - vshift); | |
min = Math.min(min, x + vshift, x - vshift); | |
} | |
} | |
return {min:min, max:max}; | |
}, | |
divide: function (t) { | |
if (t < 0 || t > 1) { | |
throw xypic.ExecutionError("illegal quadratic Bezier parameter t:"+t); | |
} | |
var x0 = this.cp0.x; | |
var x1 = this.cp1.x; | |
var x2 = this.cp2.x; | |
var y0 = this.cp0.y; | |
var y1 = this.cp1.y; | |
var y2 = this.cp2.y; | |
var tx = this.px(t); | |
var ty = this.py(t); | |
var p0 = this.cp0; | |
var p1 = xypic.Frame.Point(x0+t*(x1-x0), y0+t*(y1-y0)); | |
var p2 = xypic.Frame.Point(tx, ty); | |
var q0 = p2; | |
var q1 = xypic.Frame.Point(x1+t*(x2-x1), y1+t*(y2-y1)); | |
var q2 = this.cp2; | |
return [ | |
xypic.Curve.QuadBezier(p0, p1, p2), | |
xypic.Curve.QuadBezier(q0, q1, q2) | |
] | |
}, | |
slice: function (t0, t1) { | |
if (t0 >= t1) { | |
return undefined; | |
} | |
if (t0 < 0) { | |
t0 = 0; | |
} | |
if (t1 > 1) { | |
t1 = 1; | |
} | |
if (t0 === 0 && t1 === 1) { | |
return this; | |
} | |
var x0 = this.cp0.x; | |
var x1 = this.cp1.x; | |
var x2 = this.cp2.x; | |
var y0 = this.cp0.y; | |
var y1 = this.cp1.y; | |
var y2 = this.cp2.y; | |
var q0x = this.px(t0); | |
var q0y = this.py(t0); | |
var q1x = x1 + t0 * (x2 - x1); | |
var q1y = y1 + t0 * (y2 - y1); | |
var p0 = xypic.Frame.Point(q0x, q0y); | |
var p1 = xypic.Frame.Point(q0x + t1 * (q1x - q0x), q0y + t1 * (q1y - q0y)); | |
var p2 = xypic.Frame.Point(this.px(t1), this.py(t1)); | |
return xypic.Curve.QuadBezier(p0, p1, p2); | |
}, | |
tOfIntersections: function (frame) { | |
if (frame.isPoint()) { | |
return []; // CAUTION: Point does not intersect with any curves. | |
} | |
if (frame.isRect()) { | |
// find starting edge point | |
var rx = frame.x + frame.r; | |
var lx = frame.x - frame.l; | |
var uy = frame.y + frame.u; | |
var dy = frame.y - frame.d; | |
var roundEp = xypic.Util.roundEpsilon; | |
var x0 = this.cp0.x; | |
var x1 = this.cp1.x; | |
var x2 = this.cp2.x; | |
var a0x = roundEp(x0); | |
var a1x = roundEp(2*(x1 - x0)); | |
var a2x = roundEp(x2 - 2*x1 + x0); | |
var px = function(t) { return a0x + t*a1x + t*t*a2x; } | |
var y0 = this.cp0.y; | |
var y1 = this.cp1.y; | |
var y2 = this.cp2.y; | |
var a0y = roundEp(y0); | |
var a1y = roundEp(2*(y1 - y0)); | |
var a2y = roundEp(y2 - 2*y1 + y0); | |
var py = function(t) { return a0y + t*a1y + t*t*a2y; } | |
var ts = []; | |
var tsCandidate; | |
tsCandidate = xypic.Curve.solutionsOfQuadEq(a2x, a1x, a0x - rx); | |
tsCandidate = tsCandidate.concat(xypic.Curve.solutionsOfQuadEq(a2x, a1x, a0x - lx)); | |
for (var i = 0; i < tsCandidate.length; i++) { | |
var t = tsCandidate[i]; | |
var y = py(t); | |
if (y >= dy && y <= uy) { | |
ts.push(t); | |
} | |
} | |
tsCandidate = xypic.Curve.solutionsOfQuadEq(a2y, a1y, a0y - uy); | |
tsCandidate = tsCandidate.concat(xypic.Curve.solutionsOfQuadEq(a2y, a1y, a0y - dy)); | |
for (var i = 0; i < tsCandidate.length; i++) { | |
var t = tsCandidate[i]; | |
var x = px(t); | |
if (x >= lx && x <= rx) { | |
ts.push(t); | |
} | |
} | |
return ts; | |
} else if (frame.isCircle()) { | |
var pi = Math.PI; | |
var x = frame.x; | |
var y = frame.y; | |
var l = frame.l; | |
var r = frame.r; | |
var u = frame.u; | |
var d = frame.d; | |
var cx = x + (r - l) / 2; | |
var cy = y + (u - d) / 2; | |
var rx = (l + r) / 2; | |
var ry = (u + d) / 2; | |
var delta = pi / 180; // overlapping | |
var arc0 = xypic.CurveSegment.Arc(cx, cy, rx, ry, -pi - delta, -pi / 2 + delta); | |
var arc1 = xypic.CurveSegment.Arc(cx, cy, rx, ry, -pi / 2 - delta, 0 + delta); | |
var arc2 = xypic.CurveSegment.Arc(cx, cy, rx, ry, 0 - delta, pi / 2 + delta); | |
var arc3 = xypic.CurveSegment.Arc(cx, cy, rx, ry, pi / 2 - delta, pi + delta); | |
var bezier = xypic.CurveSegment.QuadBezier(this, 0, 1); | |
var intersec = []; | |
intersec = intersec.concat(xypic.CurveSegment.findIntersections(arc0, bezier)); | |
intersec = intersec.concat(xypic.CurveSegment.findIntersections(arc1, bezier)); | |
intersec = intersec.concat(xypic.CurveSegment.findIntersections(arc2, bezier)); | |
intersec = intersec.concat(xypic.CurveSegment.findIntersections(arc3, bezier)); | |
var ts = []; | |
for (var i = 0; i < intersec.length; i++) { | |
var t = (intersec[i][1].min + intersec[i][1].max) / 2; | |
ts.push(t); | |
} | |
return ts; | |
} | |
}, | |
countOfSegments: function () { return 1; }, | |
drawPrimitive: function (svg, dasharray) { | |
var cp0 = this.cp0, cp1 = this.cp1, cp2 = this.cp2; | |
svg.createSVGElement("path", { | |
"d":"M"+xypic.em2px(cp0.x)+","+xypic.em2px(-cp0.y)+ | |
" Q"+xypic.em2px(cp1.x)+","+xypic.em2px(-cp1.y)+ | |
" "+xypic.em2px(cp2.x)+","+xypic.em2px(-cp2.y), | |
"stroke-dasharray":dasharray | |
}); | |
}, | |
toString: function () { | |
return "QuadBezier("+this.cp0.x+", "+this.cp0.y+")-("+this.cp1.x+", "+this.cp1.y+")-("+this.cp2.x+", "+this.cp2.y+")" | |
} | |
}); | |
xypic.Curve.CubicBezier = xypic.Curve.Subclass({ | |
Init: function (cp0, cp1, cp2, cp3) { | |
this.cp0 = cp0; | |
this.cp1 = cp1; | |
this.cp2 = cp2; | |
this.cp3 = cp3; | |
var a0x = cp0.x; | |
var a1x = 3*(cp1.x - cp0.x); | |
var a2x = 3*(cp2.x - 2*cp1.x + cp0.x); | |
var a3x = cp3.x - 3*cp2.x + 3*cp1.x - cp0.x; | |
this.px = function(t) { return a0x + t*a1x + t*t*a2x + t*t*t*a3x; } | |
this.dpx = function(t) { return a1x + 2*t*a2x + 3*t*t*a3x; } | |
var a0y = cp0.y; | |
var a1y = 3*(cp1.y - cp0.y); | |
var a2y = 3*(cp2.y - 2*cp1.y + cp0.y); | |
var a3y = cp3.y - 3*cp2.y + 3*cp1.y - cp0.y; | |
this.py = function(t) { return a0y + t*a1y + t*t*a2y + t*t*t*a3y; } | |
this.dpy = function(t) { return a1y + 2*t*a2y + 3*t*t*a3y; } | |
}, | |
startPosition: function () { | |
return this.cp0; | |
}, | |
endPosition: function () { | |
return this.cp3; | |
}, | |
position: function (t) { | |
return xypic.Frame.Point(this.px(t), this.py(t)); | |
}, | |
derivative: function (t) { | |
return xypic.Frame.Point(this.dpx(t), this.dpy(t)); | |
}, | |
angle: function (t) { | |
return Math.atan2(this.dpy(t), this.dpx(t)); | |
}, | |
boundingBox: function (vshift) { | |
var maxMinX = this.maxMin(this.cp0.x, this.cp1.x, this.cp2.x, this.cp3.x, vshift); | |
var maxMinY = this.maxMin(this.cp0.y, this.cp1.y, this.cp2.y, this.cp3.y, vshift); | |
if (vshift === 0) { | |
return xypic.Frame.Rect(this.cp0.x, this.cp0.y, { | |
l:this.cp0.x-maxMinX.min, r:maxMinX.max-this.cp0.x, | |
u:maxMinY.max-this.cp0.y, d:this.cp0.y-maxMinY.min | |
}); | |
} else { | |
var hpi = Math.PI/2; | |
var sx = this.cp0.x; | |
var sy = this.cp0.y; | |
var ex = this.cp3.x; | |
var ey = this.cp3.y; | |
var a0 = this.angle(0)+hpi; | |
var a1 = this.angle(1)+hpi; | |
var vc0 = vshift*Math.cos(a0), vs0 = vshift*Math.sin(a0); | |
var vc1 = vshift*Math.cos(a1), vs1 = vshift*Math.sin(a1); | |
var minX = Math.min(maxMinX.min, sx+vc0, sx-vc0, ex+vc1, ex-vc1); | |
var maxX = Math.max(maxMinX.max, sx+vc0, sx-vc0, ex+vc1, ex-vc1); | |
var minY = Math.min(maxMinY.min, sy+vs0, sy-vs0, ey+vs1, ey-vs1); | |
var maxY = Math.max(maxMinY.max, sy+vs0, sy-vs0, ey+vs1, ey-vs1); | |
return xypic.Frame.Rect(sx, sy, { | |
l:sx-minX, r:maxX-sx, u:maxY-sy, d:sy-minY | |
}); | |
} | |
}, | |
maxMin: function (x0, x1, x2, x3, vshift) { | |
var max, min; | |
if (x0 > x3) { | |
max = x0; | |
min = x3; | |
} else { | |
max = x3; | |
min = x0; | |
} | |
var roundEp = xypic.Util.roundEpsilon; | |
var a0 = roundEp(x0); | |
var a1 = roundEp(x1 - x0); | |
var a2 = roundEp(x2 - 2*x1 + x0); | |
var a3 = roundEp(x3 - 3*x2 + 3*x1 - x0); | |
var p = function(t) { return a0 + 3*t*a1 + 3*t*t*a2 + t*t*t*a3 } | |
var updateMinMax = function (t) { | |
if (t > 0 && t < 1) { | |
x = p(t); | |
max = Math.max(max, x + vshift, x - vshift); | |
min = Math.min(min, x + vshift, x - vshift); | |
} | |
} | |
var t, x; | |
if (a3 == 0) { | |
if (a2 != 0) { | |
t = -a1/a2/2; | |
updateMinMax(t); | |
} | |
} else { | |
var d = a2*a2 - a1*a3; | |
if (d > 0) { | |
t = (-a2 + Math.sqrt(d))/a3; | |
updateMinMax(t); | |
t = (-a2 - Math.sqrt(d))/a3; | |
updateMinMax(t); | |
} else if (d == 0) { | |
t = -a2/a3; | |
updateMinMax(t); | |
} | |
} | |
return {min:min, max:max}; | |
}, | |
divide: function (t) { | |
if (t < 0 || t > 1) { | |
throw xypic.ExecutionError("illegal cubic Bezier parameter t:"+t); | |
} | |
var x0 = this.cp0.x; | |
var x1 = this.cp1.x; | |
var x2 = this.cp2.x; | |
var x3 = this.cp3.x; | |
var y0 = this.cp0.y; | |
var y1 = this.cp1.y; | |
var y2 = this.cp2.y; | |
var y3 = this.cp3.y; | |
var tx = this.px(t); | |
var ty = this.py(t); | |
var p0 = this.cp0; | |
var p1 = xypic.Frame.Point(x0+t*(x1-x0), y0+t*(y1-y0)); | |
var p2 = xypic.Frame.Point( | |
x0+2*t*(x1-x0)+t*t*(x2-2*x1+x0), | |
y0+2*t*(y1-y0)+t*t*(y2-2*y1+y0) | |
); | |
var p3 = xypic.Frame.Point(tx, ty); | |
var q0 = p3; | |
var q1 = xypic.Frame.Point( | |
x1+2*t*(x2-x1)+t*t*(x3-2*x2+x1), | |
y1+2*t*(y2-y1)+t*t*(y3-2*y2+y1) | |
); | |
var q2 = xypic.Frame.Point(x2+t*(x3-x2), y2+t*(y3-y2)); | |
var q3 = this.cp3; | |
return [ | |
xypic.Curve.CubicBezier(p0, p1, p2, p3), | |
xypic.Curve.CubicBezier(q0, q1, q2, q3) | |
] | |
}, | |
slice: function (t0, t1) { | |
if (t0 >= t1) { | |
return undefined; | |
} | |
if (t0 < 0) { | |
t0 = 0; | |
} | |
if (t1 > 1) { | |
t1 = 1; | |
} | |
if (t0 === 0 && t1 === 1) { | |
return this; | |
} | |
var x0 = this.cp0.x; | |
var x1 = this.cp1.x; | |
var x2 = this.cp2.x; | |
var x3 = this.cp3.x; | |
var y0 = this.cp0.y; | |
var y1 = this.cp1.y; | |
var y2 = this.cp2.y; | |
var y3 = this.cp3.y; | |
var q0x = this.px(t0); | |
var q0y = this.py(t0); | |
var q1x = x1 + 2 * t0 * (x2 - x1) + t0 * t0 * (x3 - 2 * x2 + x1); | |
var q1y = y1 + 2 * t0 * (y2 - y1) + t0 * t0 * (y3 - 2 * y2 + y1); | |
var q2x = x2 + t0 * (x3 - x2); | |
var q2y = y2 + t0 * (y3 - y2); | |
var p0 = xypic.Frame.Point(q0x, q0y); | |
var p1 = xypic.Frame.Point(q0x + t1 * (q1x - q0x), q0y + t1 * (q1y - q0y)); | |
var p2 = xypic.Frame.Point( | |
q0x + 2 * t1 * (q1x - q0x) + t1 * t1 * (q2x - 2 * q1x + q0x), | |
q0y + 2 * t1 * (q1y - q0y) + t1 * t1 * (q2y - 2 * q1y + q0y) | |
); | |
var p3 = xypic.Frame.Point(this.px(t1), this.py(t1)); | |
return xypic.Curve.CubicBezier(p0, p1, p2, p3); | |
}, | |
tOfIntersections: function (frame) { | |
if (frame.isPoint()) { | |
return []; // CAUTION: Point does not intersect with any curves. | |
} | |
if (frame.isRect()) { | |
// find starting edge point | |
var rx = frame.x + frame.r; | |
var lx = frame.x - frame.l; | |
var uy = frame.y + frame.u; | |
var dy = frame.y - frame.d; | |
var roundEp = xypic.Util.roundEpsilon; | |
var x0 = this.cp0.x; | |
var x1 = this.cp1.x; | |
var x2 = this.cp2.x; | |
var x3 = this.cp3.x; | |
var y0 = this.cp0.y; | |
var y1 = this.cp1.y; | |
var y2 = this.cp2.y; | |
var y3 = this.cp3.y; | |
var a0x = roundEp(x0); | |
var a1x = roundEp(3*(x1 - x0)); | |
var a2x = roundEp(3*(x2 - 2*x1 + x0)); | |
var a3x = roundEp(x3 - 3*x2 + 3*x1 - x0); | |
var px = function(t) { return a0x + t*a1x + t*t*a2x + t*t*t*a3x } | |
var a0y = roundEp(y0); | |
var a1y = roundEp(3*(y1 - y0)); | |
var a2y = roundEp(3*(y2 - 2*y1 + y0)); | |
var a3y = roundEp(y3 - 3*y2 + 3*y1 - y0); | |
var py = function(t) { return a0y + t*a1y + t*t*a2y + t*t*t*a3y } | |
var ts = []; | |
var tsCandidate; | |
tsCandidate = xypic.Curve.solutionsOfCubicEq(a3x, a2x, a1x, a0x-rx); | |
tsCandidate = tsCandidate.concat(xypic.Curve.solutionsOfCubicEq(a3x, a2x, a1x, a0x-lx)); | |
for (var i = 0; i < tsCandidate.length; i++) { | |
var t = tsCandidate[i]; | |
var y = py(t); | |
if (y >= dy && y <= uy) { | |
ts.push(t); | |
} | |
} | |
tsCandidate = xypic.Curve.solutionsOfCubicEq(a3y, a2y, a1y, a0y-uy); | |
tsCandidate = tsCandidate.concat(xypic.Curve.solutionsOfCubicEq(a3y, a2y, a1y, a0y-dy)); | |
for (var i = 0; i < tsCandidate.length; i++) { | |
var t = tsCandidate[i]; | |
var x = px(t); | |
if (x >= lx && x <= rx) { | |
ts.push(t); | |
} | |
} | |
return ts; | |
} else if (frame.isCircle()) { | |
var pi = Math.PI; | |
var x = frame.x; | |
var y = frame.y; | |
var l = frame.l; | |
var r = frame.r; | |
var u = frame.u; | |
var d = frame.d; | |
var cx = x + (r - l) / 2; | |
var cy = y + (u - d) / 2; | |
var rx = (l + r) / 2; | |
var ry = (u + d) / 2; | |
var delta = pi / 180; // overlapping | |
var arc0 = xypic.CurveSegment.Arc(cx, cy, rx, ry, -pi - delta, -pi / 2 + delta); | |
var arc1 = xypic.CurveSegment.Arc(cx, cy, rx, ry, -pi / 2 - delta, 0 + delta); | |
var arc2 = xypic.CurveSegment.Arc(cx, cy, rx, ry, 0 - delta, pi / 2 + delta); | |
var arc3 = xypic.CurveSegment.Arc(cx, cy, rx, ry, pi / 2 - delta, pi + delta); | |
var bezier = xypic.CurveSegment.CubicBezier(this, 0, 1); | |
var intersec = []; | |
intersec = intersec.concat(xypic.CurveSegment.findIntersections(arc0, bezier)); | |
intersec = intersec.concat(xypic.CurveSegment.findIntersections(arc1, bezier)); | |
intersec = intersec.concat(xypic.CurveSegment.findIntersections(arc2, bezier)); | |
intersec = intersec.concat(xypic.CurveSegment.findIntersections(arc3, bezier)); | |
var ts = []; | |
for (var i = 0; i < intersec.length; i++) { | |
var t = (intersec[i][1].min + intersec[i][1].max) / 2; | |
ts.push(t); | |
} | |
return ts; | |
} | |
}, | |
countOfSegments: function () { return 1; }, | |
drawPrimitive: function (svg, dasharray) { | |
var cp0 = this.cp0, cp1 = this.cp1, cp2 = this.cp2, cp3 = this.cp3; | |
svg.createSVGElement("path", { | |
"d":"M"+xypic.em2px(cp0.x)+","+xypic.em2px(-cp0.y)+ | |
" C"+xypic.em2px(cp1.x)+","+xypic.em2px(-cp1.y)+ | |
" "+xypic.em2px(cp2.x)+","+xypic.em2px(-cp2.y)+ | |
" "+xypic.em2px(cp3.x)+","+xypic.em2px(-cp3.y), | |
"stroke-dasharray":dasharray | |
}); | |
}, | |
toString: function () { | |
return "CubicBezier("+this.cp0.x+", "+this.cp0.y+")-("+this.cp1.x+", "+this.cp1.y+")-("+this.cp2.x+", "+this.cp2.y+")-("+this.cp3.x+", "+this.cp3.y+")" | |
} | |
}); | |
xypic.Curve.CubicBeziers = xypic.Curve.Subclass({ | |
Init: function (cbs) { | |
this.cbs = cbs; | |
var n = this.cbs.length; | |
this.delegate = (n == 0? | |
function (t, succ, fail) { | |
return fail; | |
} : function (t, succ, fail) { | |
var tn = t * n; | |
var i = Math.floor(tn); | |
if (i < 0) { i = 0; } | |
if (i >= n) { i = n - 1; } | |
var s = tn - i; | |
var cb = cbs[i]; | |
return succ(cb, s); | |
} | |
); | |
}, | |
startPosition: function () { | |
return this.cbs[0].cp0; | |
}, | |
endPosition: function () { | |
return this.cbs[this.cbs.length - 1].cp3; | |
}, | |
position: function (t) { | |
return this.delegate(t, function (cb, s) { return cb.position(s) }, undefined); | |
}, | |
derivative: function (t) { | |
return this.delegate(t, function (cb, s) { return cb.derivative(s) }, undefined); | |
}, | |
angle: function (t) { | |
return this.delegate(t, function (cb, s) { return cb.angle(s) }, 0); | |
}, | |
velocity: function (t) { | |
var n = this.cbs.length; | |
return this.delegate(t, function (cb, s) { return n * cb.velocity(s) }, 0); | |
}, | |
boundingBox: function (vshift) { | |
if (this.cbs.length == 0) { | |
return undefined; | |
} | |
var bbox = this.cbs[0].boundingBox(vshift); | |
var i, n = this.cbs.length; | |
for (i = 1; i < n; i++) { | |
bbox = bbox.combineRect(this.cbs[i].boundingBox(vshift)) | |
} | |
return bbox; | |
}, | |
tOfIntersections: function (frame) { | |
var ts = []; | |
var i = 0, n = this.cbs.length; | |
for (i = 0; i < n; i++) { | |
var cb = this.cbs[i]; | |
unnormalizedTs = cb.tOfIntersections(frame); | |
for (j = 0; j < unnormalizedTs.length; j++) { | |
ts.push((unnormalizedTs[j] + i) / n); | |
} | |
} | |
return ts; | |
}, | |
divide: function (t) { | |
if (t < 0 || t > 1) { | |
throw xypic.ExecutionError("illegal cubic Bezier parameter t:"+t); | |
} else if (t === 0) { | |
return [xypic.Curve.CubicBeziers([]), this]; | |
} else if (t === 1) { | |
return [this, xypic.Curve.CubicBeziers([])]; | |
} | |
var n = this.cbs.length; | |
var tn = t * n; | |
var i = Math.floor(tn); | |
if (i === n) { | |
i = n - 1; | |
} | |
var s = tn - i; | |
var divS = this.cbs.slice(0, i); | |
var divE = this.cbs.slice(i + 1); | |
var cb = this.cbs[i]; | |
var divB = cb.divide(s); | |
divS.push(divB[0]); | |
divE.unshift(divB[1]); | |
return [xypic.Curve.CubicBeziers(divS), xypic.Curve.CubicBeziers(divE)]; | |
}, | |
slice: function (t0, t1) { | |
if (t0 >= t1) { | |
return undefined; | |
} | |
if (t0 < 0) { | |
t0 = 0; | |
} | |
if (t1 > 1) { | |
t1 = 1; | |
} | |
if (t0 === 0 && t1 === 1) { | |
return this; | |
} | |
var n = this.cbs.length; | |
var tn0 = t0 * n; | |
var tn1 = t1 * n; | |
var i0 = Math.floor(tn0); | |
var i1 = Math.floor(tn1); | |
if (i0 === n) { | |
i0 = n - 1; | |
} | |
if (i1 === n) { | |
i1 = n - 1; | |
} | |
var s0 = tn0 - i0; | |
var s1 = tn1 - i1; | |
var subBeziers; | |
if (i0 === i1) { | |
subBeziers = [this.cbs[i0].slice(s0, s1)]; | |
} else { | |
subBeziers = this.cbs.slice(i0 + 1, i1); | |
subBeziers.push(this.cbs[i1].slice(0, s1)); | |
subBeziers.unshift(this.cbs[i0].slice(s0, 1)); | |
} | |
return xypic.Curve.CubicBeziers(subBeziers); | |
}, | |
countOfSegments: function () { return this.cbs.length; }, | |
drawPrimitive: function (svg, dasharray) { | |
var n = this.cbs.length; | |
var cbs = this.cbs; | |
var cb = cbs[0]; | |
var cp0 = cb.cp0, cp1 = cb.cp1, cp2 = cb.cp2, cp3 = cb.cp3; | |
var d = ("M"+xypic.em2px(cp0.x)+","+xypic.em2px(-cp0.y)+ | |
" C"+xypic.em2px(cp1.x)+","+xypic.em2px(-cp1.y)+ | |
" "+xypic.em2px(cp2.x)+","+xypic.em2px(-cp2.y)+ | |
" "+xypic.em2px(cp3.x)+","+xypic.em2px(-cp3.y)); | |
for (var i = 1; i < n; i++) { | |
cb = cbs[i]; | |
cp2 = cb.cp2, cp3 = cb.cp3; | |
d += " S"+xypic.em2px(cp2.x)+","+xypic.em2px(-cp2.y)+" "+xypic.em2px(cp3.x)+","+xypic.em2px(-cp3.y); | |
} | |
svg.createSVGElement("path", {"d":d, "stroke-dasharray":dasharray}); | |
}, | |
drawSkipped: function (svg) { | |
var n = this.cbs.length; | |
var cbs = this.cbs; | |
var d = ""; | |
for (var i = 0; i < n; i+=2) { | |
var cb = cbs[i]; | |
var cp0 = cb.cp0, cp1 = cb.cp1, cp2 = cb.cp2, cp3 = cb.cp3; | |
d += ("M"+xypic.em2px(cp0.x)+","+xypic.em2px(-cp0.y)+ | |
" C"+xypic.em2px(cp1.x)+","+xypic.em2px(-cp1.y)+ | |
" "+xypic.em2px(cp2.x)+","+xypic.em2px(-cp2.y)+ | |
" "+xypic.em2px(cp3.x)+","+xypic.em2px(-cp3.y)); | |
} | |
svg.createSVGElement("path", {"d":d}); | |
} | |
},{ | |
interpolation: function (ts, xs, ys) { | |
var x12 = xypic.Curve.CubicBeziers.cubicSplineInterpolation(ts, xs); | |
var x1 = x12[0]; | |
var x2 = x12[1]; | |
var y12 = xypic.Curve.CubicBeziers.cubicSplineInterpolation(ts, ys); | |
var y1 = y12[0]; | |
var y2 = y12[1]; | |
var i, n = ts.length; | |
var beziers = new Array(n-1); | |
for (i = 0; i < n-1; i++) { | |
beziers[i] = xypic.Curve.CubicBezier( | |
xypic.Frame.Point(xs[i], ys[i]), | |
xypic.Frame.Point(x1[i], y1[i]), | |
xypic.Frame.Point(x2[i], y2[i]), | |
xypic.Frame.Point(xs[i+1], ys[i+1]) | |
) | |
} | |
return xypic.Curve.CubicBeziers(beziers); | |
}, | |
cubicSplineInterpolation: function (ts, xs) { | |
var n = ts.length-1; | |
var hs = new Array(n); | |
var i; | |
for (i = 0; i < n; i++) { | |
hs[i] = ts[i+1] - ts[i]; | |
} | |
var as = new Array(n); | |
for (i = 1; i < n; i++) { | |
as[i] = 3*(xs[i+1] - xs[i])/hs[i] - 3*(xs[i] - xs[i-1])/hs[i-1]; | |
} | |
var ls = new Array(n+1); | |
var ms = new Array(n+1); | |
var zs = new Array(n+1); | |
ls[0] = 1; | |
ms[0] = 0; | |
zs[0] = 0; | |
for (i = 1; i < n; i++) { | |
ls[i] = 2*(ts[i+1] - ts[i-1]) - hs[i-1]*ms[i-1]; | |
ms[i] = hs[i]/ls[i]; | |
zs[i] = (as[i] - hs[i-1]*zs[i-1])/ls[i]; | |
} | |
ls[n] = 1; | |
zs[n] = 0; | |
var bs = new Array(n); | |
var cs = new Array(n+1); | |
cs[n] = 0; | |
for (i = n-1; i >= 0; i--) { | |
var h = hs[i], c1 = cs[i+1], c0 = h*h*zs[i] - ms[i]*c1; | |
cs[i] = c0; | |
bs[i] = (xs[i+1] - xs[i]) - (c1 + 2*c0)/3; | |
} | |
var p1s = new Array(n); | |
var p2s = new Array(n); | |
for (i = 0; i < n; i++) { | |
var a = xs[i], b = bs[i], c = cs[i]; | |
p1s[i] = a + b/3; | |
p2s[i] = a + (2*b + c)/3; | |
} | |
return [p1s, p2s]; | |
} | |
}); | |
// xypic.Curve.CubicBeziers factory class | |
xypic.Curve.CubicBSpline = MathJax.Object.Subclass({ | |
Init: function (s, intCps, e) { | |
if (intCps.length < 1) { | |
throw xypic.ExecutionError("the number of internal control points of cubic B-spline must be greater than or equal to 1"); | |
} | |
var controlPoints = []; | |
controlPoints.push(s); | |
for (var i = 0, l = intCps.length; i < l; i++) { | |
controlPoints.push(intCps[i]); | |
} | |
controlPoints.push(e); | |
this.cps = controlPoints; | |
var n = this.cps.length - 1; | |
var cps = function (i) { | |
if (i < 0) { | |
return controlPoints[0]; | |
} else if (i > n) { | |
return controlPoints[n]; | |
} else { | |
return controlPoints[i]; | |
} | |
} | |
var N = function (t) { | |
var s = Math.abs(t); | |
if (s <= 1) { | |
return (3*s*s*s - 6*s*s + 4)/6; | |
} else if (s <= 2) { | |
return -(s-2)*(s-2)*(s-2)/6; | |
} else { | |
return 0; | |
} | |
} | |
this.px = function (t) { | |
var s = (n+2)*t-1; | |
var minj = Math.ceil(s-2); | |
var maxj = Math.floor(s+2); | |
var p = 0; | |
for (var j = minj; j <= maxj; j++) { | |
p += N(s-j)*cps(j).x; | |
} | |
return p; | |
} | |
this.py = function (t) { | |
var s = (n+2)*t-1; | |
var minj = Math.ceil(s-2); | |
var maxj = Math.floor(s+2); | |
var p = 0; | |
for (var j = minj; j <= maxj; j++) { | |
p += N(s-j)*cps(j).y; | |
} | |
return p; | |
} | |
var dN = function (t) { | |
var u = (t>0? 1 : (t<0? -1 : 0)); | |
var s = Math.abs(t); | |
if (s <= 1) { | |
return u*(3*s*s - 4*s)/2; | |
} else if (s <= 2) { | |
return -u*(s-2)*(s-2)/2; | |
} else { | |
return 0; | |
} | |
} | |
this.dpx = function (t) { | |
var s = (n+2)*t-1; | |
var minj = Math.ceil(s-2); | |
var maxj = Math.floor(s+2); | |
var p = 0; | |
for (var j = minj; j <= maxj; j++) { | |
p += dN(s-j)*cps(j).x; | |
} | |
return p; | |
} | |
this.dpy = function (t) { | |
var s = (n+2)*t-1; | |
var minj = Math.ceil(s-2); | |
var maxj = Math.floor(s+2); | |
var p = 0; | |
for (var j = minj; j <= maxj; j++) { | |
p += dN(s-j)*cps(j).y; | |
} | |
return p; | |
} | |
}, | |
position: function (t) { | |
return xypic.Frame.Point(this.px(t), this.py(t)); | |
}, | |
angle: function (t) { | |
return Math.atan2(this.dpy(t), this.dpx(t)); | |
}, | |
toCubicBeziers: function () { | |
var cbs = []; | |
var cps = this.cps; | |
var cp0 = cps[0]; | |
var cp1 = cps[1]; | |
var cp2 = cps[2]; | |
var p0x = cp0.x; | |
var p0y = cp0.y; | |
var p1x = p0x+(cp1.x-p0x)/3; | |
var p1y = p0y+(cp1.y-p0y)/3; | |
var p2x = p0x+(cp1.x-p0x)*2/3; | |
var p2y = p0y+(cp1.y-p0y)*2/3; | |
var n1x = cp1.x+(cp2.x-cp1.x)/3; | |
var n1y = cp1.y+(cp2.y-cp1.y)/3; | |
var p3x = (p2x+n1x)/2; | |
var p3y = (p2y+n1y)/2; | |
var p0 = cp0; | |
var p1 = xypic.Frame.Point(p1x, p1y); | |
var p2 = xypic.Frame.Point(p2x, p2y); | |
var p3 = xypic.Frame.Point(p3x, p3y); | |
var cb = xypic.Curve.CubicBezier(p0, p1, p2, p3); | |
cbs.push(cb); | |
var len = this.cps.length - 1; | |
for (var i=2; i < len; i++) { | |
cp0 = cp1; | |
cp1 = cp2; | |
cp2 = cps[i+1]; | |
p0x = p3x; | |
p0y = p3y; | |
p1x = 2*p3x - p2x; | |
p1y = 2*p3y - p2y; | |
p2x = cp0.x+(cp1.x-cp0.x)*2/3; | |
p2y = cp0.y+(cp1.y-cp0.y)*2/3; | |
n1x = cp1.x+(cp2.x-cp1.x)/3; | |
n1y = cp1.y+(cp2.y-cp1.y)/3; | |
p3x = (p2x+n1x)/2; | |
p3y = (p2y+n1y)/2; | |
p0 = p3; | |
p1 = xypic.Frame.Point(p1x, p1y); | |
p2 = xypic.Frame.Point(p2x, p2y); | |
p3 = xypic.Frame.Point(p3x, p3y); | |
cb = xypic.Curve.CubicBezier(p0, p1, p2, p3); | |
cbs.push(cb); | |
} | |
cp0 = cp1; | |
cp1 = cp2; | |
p0x = p3x; | |
p0y = p3y; | |
p1x = 2*p3x - p2x; | |
p1y = 2*p3y - p2y; | |
p2x = cp0.x+(cp1.x-cp0.x)*2/3; | |
p2y = cp0.y+(cp1.y-cp0.y)*2/3; | |
p3x = cp1.x; | |
p3y = cp1.y; | |
p0 = p3; | |
p1 = xypic.Frame.Point(p1x, p1y); | |
p2 = xypic.Frame.Point(p2x, p2y); | |
p3 = xypic.Frame.Point(p3x, p3y); | |
cb = xypic.Curve.CubicBezier(p0, p1, p2, p3); | |
cbs.push(cb); | |
return cbs; | |
}, | |
countOfSegments: function () { return this.cps.length - 1; } | |
}); | |
xypic.Curve.Line = MathJax.Object.Subclass({ | |
Init: function (s, e) { | |
this.s = s; | |
this.e = e; | |
}, | |
position: function (t) { | |
return xypic.Frame.Point( | |
this.s.x + t * (this.e.x - this.s.x), | |
this.s.y + t * (this.e.y - this.s.y) | |
); | |
}, | |
slice: function (t0, t1) { | |
if (t0 >= t1) { | |
return undefined; | |
} | |
if (t0 < 0) { | |
t0 = 0; | |
} | |
if (t1 > 1) { | |
t1 = 1; | |
} | |
if (t0 === 0 && t1 === 1) { | |
return this; | |
} | |
var s = this.s; | |
var e = this.e; | |
var dx = e.x - s.x; | |
var dy = e.y - s.y; | |
var newS = xypic.Frame.Point(s.x + t0 * dx, s.y + t0 * dy); | |
var newE = xypic.Frame.Point(s.x + t1 * dx, s.y + t1 * dy); | |
return xypic.Curve.Line(newS, newE); | |
}, | |
tOfIntersections: function (frame) { | |
if (frame.isPoint()) { | |
return []; // CAUTION: Point does not intersect with any curves. | |
} | |
var s = this.s; | |
var e = this.e; | |
if (frame.isRect()) { | |
// find starting edge point | |
var rx = frame.x + frame.r; | |
var lx = frame.x - frame.l; | |
var uy = frame.y + frame.u; | |
var dy = frame.y - frame.d; | |
var a0x = s.x; | |
var a0y = s.y; | |
var a1x = e.x - a0x; | |
var a1y = e.y - a0y; | |
var px = function (t) { return a0x + t * a1x; } | |
var py = function (t) { return a0y + t * a1y; } | |
var ts = []; | |
var tsCandidate; | |
tsCandidate = xypic.Curve.solutionsOfLinearEq(a1x, a0x - rx); | |
tsCandidate = tsCandidate.concat(xypic.Curve.solutionsOfLinearEq(a1x, a0x - lx)); | |
for (var i = 0; i < tsCandidate.length; i++) { | |
var t = tsCandidate[i]; | |
var y = py(t); | |
if (y >= dy && y <= uy) { | |
ts.push(t); | |
} | |
} | |
tsCandidate = xypic.Curve.solutionsOfLinearEq(a1y, a0y - uy); | |
tsCandidate = tsCandidate.concat(xypic.Curve.solutionsOfLinearEq(a1y, a0y - dy)); | |
for (var i = 0; i < tsCandidate.length; i++) { | |
var t = tsCandidate[i]; | |
var x = px(t); | |
if (x >= lx && x <= rx) { | |
ts.push(t); | |
} | |
} | |
return ts; | |
} else if (frame.isCircle()) { | |
var pi = Math.PI; | |
var l = frame.l; | |
var r = frame.r; | |
var u = frame.u; | |
var d = frame.d; | |
var x0 = frame.x; | |
var y0 = frame.y; | |
var cx = x0 + (r - l) / 2; | |
var cy = y0 + (u - d) / 2; | |
var rx = (l + r) / 2; | |
var ry = (u + d) / 2; | |
var sx = s.x; | |
var sy = s.y; | |
var ex = e.x; | |
var ey = e.y; | |
var dx = ex - sx; | |
var dy = ey - sy; | |
var a0 = dy; | |
var b0 = -dx; | |
var c0 = dx * sy - dy * sx; | |
var a = a0 * rx; | |
var b = b0 * ry; | |
var c = c0 * rx + (rx - ry) * b0 * cy; | |
var aabb = a * a + b * b; | |
var d = a * cx + b * cy + c; | |
var e = -d / aabb; | |
var ff = aabb * rx * rx - d * d; | |
if (ff < 0) { | |
return []; | |
} | |
var f = Math.sqrt(ff) / aabb; | |
var xp = a * e + b * f + cx; | |
var yp = b * e - a * f + cy; | |
var xm = a * e - b * f + cx; | |
var ym = b * e + a * f + cy; | |
var eps = ry / rx; | |
var xp0 = xp; | |
var yp0 = eps * (yp - cy) + cy; | |
var xm0 = xm; | |
var ym0 = eps * (ym - cy) + cy; | |
var tp, tm; | |
if (Math.abs(dx) > Math.abs(dy)) { | |
tp = (xp0 - sx) / dx; | |
tm = (xm0 - sx) / dx; | |
} else { | |
tp = (yp0 - sy) / dy; | |
tm = (ym0 - sy) / dy; | |
} | |
var ts = []; | |
if (tp >= 0 && tp <= 1) { | |
ts.push(tp); | |
} | |
if (tm >= 0 && tm <= 1) { | |
ts.push(tm); | |
} | |
return ts; | |
} | |
}, | |
toShape: function (context, object, main, variant) { | |
// 多重線の幅、点線・破線の幅の基準 | |
var env = context.env; | |
var thickness = AST.xypic.thickness; | |
var s = this.s; | |
var e = this.e; | |
if (s.x !== e.x || s.y !== e.y) { | |
var dx = e.x - s.x; | |
var dy = e.y - s.y; | |
var angle = Math.atan2(dy, dx); | |
var vshift; | |
var shape = xypic.Shape.none; | |
switch (main) { | |
case "=": | |
main = "-"; | |
variant = "2"; | |
break; | |
case "==": | |
main = "--"; | |
variant = "2"; | |
break; | |
case ':': | |
case '::': | |
main = "."; | |
variant = "2"; | |
break; | |
} | |
switch (main) { | |
case '': | |
// draw invisible line | |
env.angle = angle; | |
env.lastCurve = xypic.LastCurve.Line(s, e, env.p, env.c, undefined); | |
return shape; | |
case '-': | |
case '.': | |
case '..': | |
switch (variant) { | |
case "2": | |
vshift = thickness / 2; | |
break; | |
case "3": | |
vshift = thickness; | |
break; | |
default: | |
vshift = 0; | |
break; | |
} | |
break; | |
case '--': | |
var dash = 3 * thickness; | |
var len = Math.sqrt(dx * dx + dy * dy); | |
if (len >= dash) { | |
switch (variant) { | |
case "2": | |
vshift = thickness / 2; | |
break; | |
case "3": | |
vshift = thickness; | |
break; | |
default: | |
vshift = 0; | |
} | |
} | |
break; | |
case '~': | |
case '~~': | |
switch (variant) { | |
case "2": | |
vshift = 1.5 * thickness; | |
break; | |
case "3": | |
vshift = 2 * thickness; | |
break; | |
default: | |
vshift = 0 | |
} | |
break; | |
default: | |
// connect by arrowheads | |
var arrowBBox = object.boundingBox(context); | |
if (arrowBBox == undefined) { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
} | |
var arrowLen = arrowBBox.l + arrowBBox.r; | |
if (arrowLen == 0) { | |
arrowLen = AST.xypic.strokeWidth; | |
} | |
var len = Math.sqrt(dx * dx + dy * dy); | |
var n = Math.floor(len / arrowLen); | |
if (n == 0) { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
} | |
vshift = Math.max(arrowBBox.u, arrowBBox.d); | |
} | |
if (vshift !== undefined) { | |
var bbox = this.boundingBox(vshift); | |
shape = xypic.Shape.LineShape(this, object, main, variant, bbox); | |
context.appendShapeToFront(shape); | |
env.angle = angle; | |
env.lastCurve = xypic.LastCurve.Line(s, e, env.p, env.c, shape); | |
return shape; | |
} | |
} | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
}, | |
boundingBox: function (vshift) { | |
var s = this.s; | |
var e = this.e; | |
var dx = e.x - s.x; | |
var dy = e.y - s.y; | |
var angle = Math.atan2(dy, dx); | |
var cx = vshift * Math.cos(angle + Math.PI/2); | |
var cy = vshift * Math.sin(angle + Math.PI/2); | |
return xypic.Frame.Rect(s.x, s.y, { | |
l:s.x-Math.min(s.x+cx, s.x-cx, e.x+cx, e.x-cx), | |
r:Math.max(s.x+cx, s.x-cx, e.x+cx, e.x-cx)-s.x, | |
u:Math.max(s.y+cy, s.y-cy, e.y+cy, e.y-cy)-s.y, | |
d:s.y-Math.min(s.y+cy, s.y-cy, e.y+cy, e.y-cy) | |
}); | |
}, | |
drawLine: function (svg, object, main, variant, holeRanges) { | |
if (holeRanges.isEmpty) { | |
this._drawLine(svg, object, main, variant); | |
} else { | |
var clippingRanges = xypic.Range(0, 1).differenceRanges(holeRanges); | |
var self = this; | |
clippingRanges.foreach(function (range) { | |
self.slice(range.start, range.end)._drawLine(svg, object, main, variant); | |
}); | |
} | |
}, | |
_drawLine: function (svg, object, main, variant) { | |
// 多重線の幅、点線・破線の幅の基準 | |
var t = AST.xypic.thickness; | |
var s = this.s; | |
var e = this.e; | |
if (s.x !== e.x || s.y !== e.y) { | |
var dx = e.x - s.x; | |
var dy = e.y - s.y; | |
var angle = Math.atan2(dy, dx); | |
var shift = { x:0, y:0 }; | |
switch (main) { | |
case '': | |
// draw nothing | |
break; | |
case '-': | |
this.drawStraightLine(svg, s, e, shift, angle, t, variant, ""); | |
break; | |
case '=': | |
this.drawStraightLine(svg, s, e, shift, angle, t, "2", ""); | |
break; | |
case '.': | |
case '..': | |
this.drawStraightLine(svg, s, e, shift, angle, t, variant, AST.xypic.dottedDasharray); | |
break; | |
case ':': | |
case '::': | |
this.drawStraightLine(svg, s, e, shift, angle, t, "2", AST.xypic.dottedDasharray); | |
break; | |
case '--': | |
case '==': | |
var len = Math.sqrt(dx * dx + dy * dy); | |
var dash = 3 * t; | |
if (len >= dash) { | |
var shiftLen = (len - dash) / 2 - Math.floor((len - dash) / 2 / dash) * dash; | |
shift = { x:shiftLen * Math.cos(angle), y:shiftLen * Math.sin(angle) }; | |
this.drawStraightLine(svg, s, e, shift, angle, t, (main === "=="? "2" : variant), xypic.em2px(dash) + " " + xypic.em2px(dash)); | |
} | |
break; | |
case '~': | |
var len = Math.sqrt(dx * dx + dy * dy); | |
var wave = 4 * t; | |
if (len >= wave) { | |
var n = Math.floor(len / wave); | |
var shiftLen = (len - n * wave) / 2; | |
shift = { x:shiftLen * Math.cos(angle), y:shiftLen * Math.sin(angle) }; | |
var cx = t * Math.cos(angle + Math.PI / 2); | |
var cy = t * Math.sin(angle + Math.PI / 2); | |
var tx = t * Math.cos(angle); | |
var ty = t * Math.sin(angle); | |
var sx = s.x + shift.x; | |
var sy = -s.y - shift.y; | |
var d = "M" + xypic.em2px(sx) + "," + xypic.em2px(sy) + | |
" Q" + xypic.em2px(sx + tx + cx) + "," + xypic.em2px(sy - ty - cy) + | |
" " + xypic.em2px(sx + 2 * tx) + "," + xypic.em2px(sy - 2 * ty) + | |
" T" + xypic.em2px(sx + 4 * tx) + "," + xypic.em2px(sy - 4 * ty); | |
for (var i = 1; i < n; i++) { | |
d += " T" + xypic.em2px(sx + (4 * i + 2) * tx) + "," + xypic.em2px(sy - (4 * i + 2) * ty) + | |
" T" + xypic.em2px(sx + (4 * i + 4) * tx) + "," + xypic.em2px(sy - (4 * i + 4) * ty); | |
} | |
this.drawSquigglyLineShape(svg, d, s, e, cx, cy, variant); | |
} | |
break; | |
case '~~': | |
var len = Math.sqrt(dx * dx + dy * dy); | |
var wave = 4 * t; | |
if (len >= wave) { | |
var n = Math.floor((len - wave) / 2 / wave); | |
var shiftLen = (len - wave) / 2 - n * wave; | |
shift = { x:shiftLen * Math.cos(angle), y:shiftLen * Math.sin(angle) }; | |
var cx = t * Math.cos(angle + Math.PI / 2); | |
var cy = t * Math.sin(angle + Math.PI / 2); | |
var tx = t * Math.cos(angle); | |
var ty = t * Math.sin(angle); | |
var sx = s.x + shift.x; | |
var sy = -s.y - shift.y; | |
var d = ""; | |
for (var i = 0; i <= n; i++) { | |
d += " M" + xypic.em2px(sx + 8 * i * tx) + "," + xypic.em2px(sy - 8 * i * ty) + | |
" Q" + xypic.em2px(sx + (8 * i + 1) * tx + cx) + "," + xypic.em2px(sy - (8 * i + 1) * ty - cy) + | |
" " + xypic.em2px(sx + (8 * i + 2) * tx) + "," + xypic.em2px(sy - (8 * i + 2) * ty) + | |
" T" + xypic.em2px(sx + (8 * i + 4) * tx) + "," + xypic.em2px(sy - (8 * i + 4) * ty); | |
} | |
this.drawSquigglyLineShape(svg, d, s, e, cx, cy, variant); | |
} | |
break; | |
default: | |
// connect by arrowheads | |
var dummyEnv = xypic.Env(); | |
dummyEnv.c = xypic.Env.originPosition; | |
var dummyContext = xypic.DrawingContext(xypic.Shape.none, dummyEnv); | |
var arrowBBox = object.boundingBox(dummyContext); | |
if (arrowBBox == undefined) { | |
return; | |
} | |
var arrowLen = arrowBBox.l + arrowBBox.r; | |
if (arrowLen == 0) { | |
arrowLen = AST.xypic.strokeWidth; | |
} | |
var len = Math.sqrt(dx * dx + dy * dy); | |
var n = Math.floor(len / arrowLen); | |
if (n == 0) { | |
return; | |
} | |
var shiftLen = (len - n * arrowLen) / 2; | |
var cos = Math.cos(angle), sin = Math.sin(angle); | |
var ac = arrowLen * cos, as = arrowLen * sin; | |
var startX = s.x + (shiftLen + arrowBBox.l) * cos; | |
var startY = s.y + (shiftLen + arrowBBox.l) * sin; | |
var dummyContext = xypic.DrawingContext(xypic.Shape.none, dummyEnv); | |
for (var i = 0; i < n; i++) { | |
dummyEnv.c = xypic.Frame.Point(startX + i * ac, startY + i * as); | |
dummyEnv.angle = angle; | |
object.toDropShape(dummyContext).draw(svg); | |
} | |
} | |
} | |
}, | |
drawStraightLine: function (svg, s, e, shift, angle, t, variant, dasharray) { | |
if (variant === "3") { | |
var cx = t*Math.cos(angle+Math.PI/2); | |
var cy = t*Math.sin(angle+Math.PI/2); | |
svg.createSVGElement("line", { | |
x1:xypic.em2px(s.x+shift.x), y1:-xypic.em2px(s.y+shift.y), | |
x2:xypic.em2px(e.x), y2:-xypic.em2px(e.y), | |
"stroke-dasharray":dasharray | |
}); | |
svg.createSVGElement("line", { | |
x1:xypic.em2px(s.x+cx+shift.x), y1:-xypic.em2px(s.y+cy+shift.y), | |
x2:xypic.em2px(e.x+cx), y2:-xypic.em2px(e.y+cy), | |
"stroke-dasharray":dasharray | |
}); | |
svg.createSVGElement("line", { | |
x1:xypic.em2px(s.x-cx+shift.x), y1:-xypic.em2px(s.y-cy+shift.y), | |
x2:xypic.em2px(e.x-cx), y2:-xypic.em2px(e.y-cy), | |
"stroke-dasharray":dasharray | |
}); | |
} else if (variant === "2") { | |
var cx = t*Math.cos(angle+Math.PI/2)/2; | |
var cy = t*Math.sin(angle+Math.PI/2)/2; | |
svg.createSVGElement("line", { | |
x1:xypic.em2px(s.x+cx+shift.x), y1:-xypic.em2px(s.y+cy+shift.y), | |
x2:xypic.em2px(e.x+cx), y2:-xypic.em2px(e.y+cy), | |
"stroke-dasharray":dasharray | |
}); | |
svg.createSVGElement("line", { | |
x1:xypic.em2px(s.x-cx+shift.x), y1:-xypic.em2px(s.y-cy+shift.y), | |
x2:xypic.em2px(e.x-cx), y2:-xypic.em2px(e.y-cy), | |
"stroke-dasharray":dasharray | |
}); | |
} else { | |
svg.createSVGElement("line", { | |
x1:xypic.em2px(s.x+shift.x), y1:-xypic.em2px(s.y+shift.y), | |
x2:xypic.em2px(e.x), y2:-xypic.em2px(e.y), | |
"stroke-dasharray":dasharray | |
}); | |
} | |
}, | |
drawSquigglyLineShape: function (svg, d, s, e, cx, cy, variant) { | |
var g1, g2; | |
if (variant === "3") { | |
svg.createSVGElement("path", { d:d }); | |
g1 = svg.createGroup(svg.transformBuilder().translate(cx, cy)); | |
g1.createSVGElement("path", { d:d }); | |
g2 = svg.createGroup(svg.transformBuilder().translate(-cx, -cy)); | |
g2.createSVGElement("path", { d:d }); | |
} else if (variant === "2") { | |
g1 = svg.createGroup(svg.transformBuilder().translate(cx / 2, cy / 2)); | |
g1.createSVGElement("path", { d:d }); | |
g2 = svg.createGroup(svg.transformBuilder().translate(-cx / 2, -cy / 2)); | |
g2.createSVGElement("path", { d:d }); | |
} else { | |
svg.createSVGElement("path", { d:d }); | |
} | |
} | |
}); | |
xypic.CurveSegment = MathJax.Object.Subclass({ | |
bezierFatLine: function (n) { | |
var p0 = this.cps[0], pn = this.cps[n]; | |
var a, b, c; | |
if (p0.x !== pn.x || p0.y !== pn.y) { | |
a = p0.y-pn.y; | |
b = pn.x-p0.x; | |
l = Math.sqrt(a*a+b*b); | |
a /= l; | |
b /= l; | |
c = (p0.x*pn.y-p0.y*pn.x)/l; | |
} else { | |
var angle = this.bezier.angle(this.tmin); | |
a = -Math.sin(angle); | |
b = Math.cos(angle); | |
c = -a*this.cp0.x-b*this.cp0.y; | |
} | |
var cmin = c, cmax = c; | |
for (var i = 1; i < n; i++) { | |
var ci = -a*this.cps[i].x-b*this.cps[i].y; | |
if (ci > cmax) { | |
cmax = ci; | |
} else if (ci < cmin) { | |
cmin = ci; | |
} | |
} | |
return {min:[a, b, cmin], max:[a, b, cmax]}; | |
}, | |
clippedLineRange: function (ps, lineMin, lineMax) { | |
var n = ps.length - 1; | |
var es = new Array(n+1); | |
var extProd = xypic.Util.extProd; | |
for (var i = 0; i <= n; i++) { | |
es[i] = [i/n, -lineMin[0]*ps[i].x-lineMin[1]*ps[i].y-lineMin[2], 1]; | |
} | |
var vminAgainstLineMin, vmaxAgainstLineMin, t; | |
if (es[0][1] < 0) { | |
var allLiesBelow = true; | |
for (i = 1; i <= n; i++) { | |
var l0i = extProd(es[0], es[i]); | |
v = -l0i[2]/l0i[0]; | |
if (v > 0 && v < 1 && (vminAgainstLineMin === undefined || v < vminAgainstLineMin)) { | |
vminAgainstLineMin = v; | |
} | |
if (es[i][1] >= 0) { | |
allLiesBelow = false; | |
} | |
} | |
if (allLiesBelow) { | |
// clip away everything. | |
return undefined; | |
} | |
} else { | |
vminAgainstLineMin = 0; | |
} | |
if (es[n][1] < 0) { | |
for (i = 0; i < n; i++) { | |
var lni = extProd(es[n], es[i]); | |
v = -lni[2]/lni[0]; | |
if (v > 0 && v < 1 && (vmaxAgainstLineMin === undefined || v > vmaxAgainstLineMin)) { | |
vmaxAgainstLineMin = v; | |
} | |
} | |
} else { | |
vmaxAgainstLineMin = 1; | |
} | |
for (i = 0; i <= n; i++) { | |
es[i] = [i/n, lineMax[0]*ps[i].x+lineMax[1]*ps[i].y+lineMax[2], 1]; | |
} | |
var vminAgainstLineMax, vmaxAgainstLineMax; | |
if (es[0][1] < 0) { | |
var allLiesAbove = true; | |
for (i = 1; i <= n; i++) { | |
var l0i = extProd(es[0], es[i]); | |
v = -l0i[2]/l0i[0]; | |
if (v > 0 && v < 1 && (vminAgainstLineMax === undefined || v < vminAgainstLineMax)) { | |
vminAgainstLineMax = v; | |
} | |
if (es[i][1] >= 0) { | |
allLiesAbove = false; | |
} | |
} | |
if (allLiesAbove) { | |
// clip away everything. | |
return undefined; | |
} | |
} else { | |
vminAgainstLineMax = 0; | |
} | |
if (es[n][1] < 0) { | |
for (i = 0; i < n; i++) { | |
var lni = extProd(es[n], es[i]); | |
v = -lni[2]/lni[0]; | |
if (v > 0 && v < 1 && (vmaxAgainstLineMax === undefined || v > vmaxAgainstLineMax)) { | |
vmaxAgainstLineMax = v; | |
} | |
} | |
} else { | |
vmaxAgainstLineMax = 1; | |
} | |
var vmin = Math.max(vminAgainstLineMin, vminAgainstLineMax); | |
var vmax = Math.min(vmaxAgainstLineMin, vmaxAgainstLineMax); | |
return {min:this.tmin + vmin*(this.tmax - this.tmin), max:this.tmin + vmax*(this.tmax - this.tmin)}; | |
} | |
}, { | |
findIntersections: function (segment0, segment1) { | |
var n = xypic.CurveSegment.maxIterations; | |
var acc = xypic.CurveSegment.goalAccuracy; | |
var queue = [[segment0, segment1, false]]; | |
var i = 0; | |
var intersections = []; | |
while (i < n && queue.length > 0) { | |
i++; | |
var head = queue.shift(); | |
var segment0 = head[0]; | |
var segment1 = head[1]; | |
var swapped = head[2]; | |
// segment0.drawFatLine(); | |
var fatLine = segment0.fatLine(); | |
var tminMax = segment1.clippedRange(fatLine.min, fatLine.max); | |
if (tminMax == undefined) { | |
// clip away everything | |
continue; | |
} | |
var tmin = tminMax.min; | |
var tmax = tminMax.max; | |
var tlen = tmax - tmin; | |
if (tlen < acc && segment0.paramLength() < acc) { | |
// intersection found | |
if (swapped) { | |
intersections.push([segment1.clip(tmin, tmax).paramRange(), segment0.paramRange()]); | |
} else { | |
intersections.push([segment0.paramRange(), segment1.clip(tmin, tmax).paramRange()]); | |
} | |
continue; | |
} | |
if (tlen <= segment1.paramLength() * 0.8) { | |
queue.push([segment1.clip(tmin, tmax), segment0, !swapped]); | |
} else { | |
// subdivision | |
if (tlen > segment0.paramLength()) { | |
var tmid = (tmax + tmin)/2; | |
queue.push([segment1.clip(tmin, tmid), segment0, !swapped]); | |
queue.push([segment1.clip(tmid, tmax), segment0, !swapped]); | |
} else { | |
var newSegment = segment1.clip(tmin, tmax); | |
var range0 = segment0.paramRange(); | |
var mid0 = (range0.min + range0.max)/2; | |
queue.push([newSegment, segment0.clip(range0.min, mid0), !swapped]); | |
queue.push([newSegment, segment0.clip(mid0, range0.max), !swapped]); | |
} | |
} | |
} | |
return intersections; | |
}, | |
maxIterations: 30, | |
goalAccuracy: 1e-4 | |
}); | |
xypic.CurveSegment.Line = xypic.CurveSegment.Subclass({ | |
Init: function (p0, p1, tmin, tmax) { | |
this.p0 = p0; | |
this.p1 = p1; | |
this.tmin = tmin; | |
this.tmax = tmax; | |
}, | |
paramRange: function () { return {min:this.tmin, max:this.tmax}; }, | |
paramLength: function () { return this.tmax - this.tmin; }, | |
containsParam: function (t) { return t >= this.tmin && t <= this.tmax; }, | |
position: function (t) { | |
return { | |
x:this.p0.x + t*(this.p1.x - this.p0.x), | |
y:this.p0.y + t*(this.p1.y - this.p0.y) | |
}; | |
}, | |
fatLine: function () { | |
var a = (this.p1.y - this.p0.y), b = (this.p0.x - this.p1.x), c = this.p1.x*this.p0.y - this.p0.x*this.p1.y; | |
var l = Math.sqrt(a * a + b * b); | |
if (l === 0) { | |
a = 1; | |
b = 0; | |
} else { | |
a /= l; | |
b /= l; | |
c /= l; | |
} | |
return {min:[a, b, c], max:[a, b, c]}; | |
}, | |
clip: function (tmin, tmax) { | |
return xypic.CurveSegment.Line(this.p0, this.p1, tmin, tmax); | |
}, | |
clippedRange: function (lineMin, lineMax) { | |
var ps = new Array(2); | |
ps[0] = this.position(this.tmin); | |
ps[1] = this.position(this.tmax); | |
return this.clippedLineRange(ps, lineMin, lineMax); | |
}, | |
drawFatLine: function () { | |
var fatLine = this.fatLine(); | |
var lmin = fatLine.min; | |
var y = function (x, l) { | |
return -(x*l[0] + l[2])/l[1]; | |
} | |
var xmin = this.p0.x; | |
var xmax = this.p1.x; | |
xypic.svgForDebug.createSVGElement("line", { | |
x1:xypic.em2px(xmin), y1:-xypic.em2px(y(xmin, lmax)), | |
x2:xypic.em2px(xmax), y2:-xypic.em2px(y(xmax, lmax)), | |
"stroke-width":xypic.em2px(0.02 * xypic.oneem), stroke:"red" | |
}); | |
} | |
}); | |
xypic.CurveSegment.QuadBezier = xypic.CurveSegment.Subclass({ | |
Init: function (bezier, tmin, tmax) { | |
this.bezier = bezier; | |
this.tmin = tmin; | |
this.tmax = tmax; | |
this.cp0 = bezier.position(tmin); | |
this.cp1 = xypic.Frame.Point( | |
(1-tmax)*(1-tmin)*bezier.cp0.x + (tmin+tmax-2*tmin*tmax)*bezier.cp1.x + tmin*tmax*bezier.cp2.x, | |
(1-tmax)*(1-tmin)*bezier.cp0.y + (tmin+tmax-2*tmin*tmax)*bezier.cp1.y + tmin*tmax*bezier.cp2.y | |
); | |
this.cp2 = bezier.position(tmax); | |
this.cps = [this.cp0, this.cp1, this.cp2]; | |
}, | |
paramRange: function () { return {min:this.tmin, max:this.tmax}; }, | |
paramLength: function () { return this.tmax - this.tmin; }, | |
fatLine: function () { return this.bezierFatLine(2); }, | |
clip: function (tmin, tmax) { | |
return xypic.CurveSegment.QuadBezier(this.bezier, tmin, tmax); | |
}, | |
clippedRange: function (lineMin, lineMax) { | |
return this.clippedLineRange(this.cps, lineMin, lineMax); | |
}, | |
drawFatLine: function () { | |
var fatLine = this.fatLine(); | |
var lmin = fatLine.min; | |
var lmax = fatLine.max; | |
var y = function (x, l) { | |
return -(x*l[0] + l[2])/l[1]; | |
} | |
var xmin = this.cp0.x | |
var xmax = this.cp2.x | |
xypic.svgForDebug.createSVGElement("line", { | |
x1:xypic.em2px(xmin), y1:-xypic.em2px(y(xmin, lmin)), | |
x2:xypic.em2px(xmax), y2:-xypic.em2px(y(xmax, lmin)), | |
"stroke-width":xypic.em2px(0.02 * xypic.oneem), stroke:"blue" | |
}); | |
xypic.svgForDebug.createSVGElement("line", { | |
x1:xypic.em2px(xmin), y1:-xypic.em2px(y(xmin, lmax)), | |
x2:xypic.em2px(xmax), y2:-xypic.em2px(y(xmax, lmax)), | |
"stroke-width":xypic.em2px(0.02 * xypic.oneem), stroke:"red" | |
}); | |
} | |
}); | |
xypic.CurveSegment.CubicBezier = xypic.CurveSegment.Subclass({ | |
Init: function (bezier, tmin, tmax) { | |
this.bezier = bezier; | |
this.tmin = tmin; | |
this.tmax = tmax; | |
this.cp0 = bezier.position(tmin); | |
this.cp1 = xypic.Frame.Point( | |
(1-tmax)*(1-tmin)*(1-tmin)*bezier.cp0.x + (1-tmin)*(2*tmin+tmax-3*tmin*tmax)*bezier.cp1.x + tmin*(2*tmax+tmin-3*tmin*tmax)*bezier.cp2.x + tmin*tmin*tmax*bezier.cp3.x, | |
(1-tmax)*(1-tmin)*(1-tmin)*bezier.cp0.y + (1-tmin)*(2*tmin+tmax-3*tmin*tmax)*bezier.cp1.y + tmin*(2*tmax+tmin-3*tmin*tmax)*bezier.cp2.y + tmin*tmin*tmax*bezier.cp3.y | |
); | |
this.cp2 = xypic.Frame.Point( | |
(1-tmin)*(1-tmax)*(1-tmax)*bezier.cp0.x + (1-tmax)*(2*tmax+tmin-3*tmin*tmax)*bezier.cp1.x + tmax*(2*tmin+tmax-3*tmin*tmax)*bezier.cp2.x + tmin*tmax*tmax*bezier.cp3.x, | |
(1-tmin)*(1-tmax)*(1-tmax)*bezier.cp0.y + (1-tmax)*(2*tmax+tmin-3*tmin*tmax)*bezier.cp1.y + tmax*(2*tmin+tmax-3*tmin*tmax)*bezier.cp2.y + tmin*tmax*tmax*bezier.cp3.y | |
); | |
this.cp3 = bezier.position(tmax); | |
this.cps = [this.cp0, this.cp1, this.cp2, this.cp3]; | |
}, | |
paramRange: function () { return {min:this.tmin, max:this.tmax}; }, | |
paramLength: function () { return this.tmax - this.tmin; }, | |
fatLine: function () { return this.bezierFatLine(3); }, | |
clip: function (tmin, tmax) { | |
return xypic.CurveSegment.CubicBezier(this.bezier, tmin, tmax); | |
}, | |
clippedRange: function (lineMin, lineMax) { | |
return this.clippedLineRange(this.cps, lineMin, lineMax); | |
}, | |
drawFatLine: function () { | |
var fatLine = this.fatLine(); | |
var lmin = fatLine.min; | |
var lmax = fatLine.max; | |
var y = function (x, l) { | |
return -(x*l[0] + l[2])/l[1]; | |
} | |
var xmin = this.cp0.x | |
var xmax = this.cp3.x | |
xypic.svgForDebug.createSVGElement("line", { | |
x1:xypic.em2px(xmin), y1:-xypic.em2px(y(xmin, lmin)), | |
x2:xypic.em2px(xmax), y2:-xypic.em2px(y(xmax, lmin)), | |
"stroke-width":xypic.em2px(0.02 * xypic.oneem), stroke:"blue" | |
}); | |
xypic.svgForDebug.createSVGElement("line", { | |
x1:xypic.em2px(xmin), y1:-xypic.em2px(y(xmin, lmax)), | |
x2:xypic.em2px(xmax), y2:-xypic.em2px(y(xmax, lmax)), | |
"stroke-width":xypic.em2px(0.02 * xypic.oneem), stroke:"red" | |
}); | |
} | |
}); | |
xypic.CurveSegment.Arc = xypic.CurveSegment.Subclass({ | |
Init: function (x, y, rx, ry, angleMin, angleMax) { | |
this.x = x; | |
this.y = y; | |
this.rx = rx; | |
this.ry = ry; | |
this.angleMin = angleMin; | |
this.angleMax = angleMax; | |
}, | |
paramRange: function () { return { min:this.angleMin, max:this.angleMax }; }, | |
paramLength: function () { return this.angleMax - this.angleMin; }, | |
normalizeAngle: function (angle) { | |
angle = angle % 2 * Math.PI; | |
if (angle > Math.PI) { | |
return angle - 2 * Math.PI; | |
} | |
if (angle < -Math.PI) { | |
return angle + 2 * Math.PI; | |
} | |
return angle; | |
}, | |
containsParam: function (angle) { return angle >= this.angleMin && angle <= this.angleMax; }, | |
fatLine: function () { | |
var rx = this.rx; | |
var ry = this.ry; | |
var tp = (this.angleMax + this.angleMin) / 2; | |
var tm = (this.angleMax - this.angleMin) / 2; | |
var cosp = Math.cos(tp), sinp = Math.sin(tp); | |
var r = Math.sqrt(rx * rx * sinp * sinp + ry * ry * cosp * cosp); | |
if (r < AST.xypic.machinePrecision) { | |
var Lmin = [1, 0, this.x * ry * cosp + this.y * rx * sinp + rx * ry * Math.cos(tm)]; | |
var Lmax = [1, 0, this.x * ry * cosp + this.y * rx * sinp + rx * ry]; | |
} else { | |
var rrx = rx / r; | |
var rry = ry / r; | |
var Lmin = [-rry * cosp, -rrx * sinp, this.x * rry * cosp + this.y * rrx * sinp + rx * ry / r * Math.cos(tm)]; | |
var Lmax = [-rry * cosp, -rrx * sinp, this.x * rry * cosp + this.y * rrx * sinp + rx * ry / r]; | |
} | |
return { min:Lmin, max:Lmax }; | |
}, | |
clip: function (angleMin, angleMax) { | |
return xypic.CurveSegment.Arc(this.x, this.y, this.rx, this.ry, angleMin, angleMax); | |
}, | |
toCircleLine: function (line, x0, y0, rx, ry) { | |
var a = line[0]; | |
var b = line[1]; | |
var c = line[2]; | |
var a2 = a * rx; | |
var b2 = b * ry; | |
var c2 = c * rx + (rx - ry) * b * y0; | |
var l = Math.sqrt(a2 * a2 + b2 * b2); | |
if (l < AST.xypic.machinePrecision) { | |
a2 = 1; | |
b2 = 0; | |
} else { | |
a2 /= l; | |
b2 /= l; | |
c2 /= l; | |
} | |
return [a2, b2, c2]; | |
}, | |
clippedRange: function (origLineMin, origLineMax) { | |
var x = this.x; | |
var y = this.y; | |
var rx = this.rx; | |
var ry = this.ry; | |
var lineMin = this.toCircleLine(origLineMin, x, y, rx, ry); | |
var lineMax = this.toCircleLine(origLineMax, x, y, rx, ry); | |
var r = rx; | |
var angleMin = this.angleMin; | |
var angleMax = this.angleMax; | |
var d = -(lineMin[0] * x + lineMin[1] * y + lineMin[2]); | |
var sign = xypic.Util.sign2; | |
var angles = []; | |
var det = r * r - d * d; | |
if (det >= 0) { | |
var xp = lineMin[0] * d - lineMin[1] * Math.sqrt(r * r - d * d); | |
var yp = lineMin[1] * d + lineMin[0] * Math.sqrt(r * r - d * d); | |
var xm = lineMin[0] * d + lineMin[1] * Math.sqrt(r * r - d * d); | |
var ym = lineMin[1] * d - lineMin[0] * Math.sqrt(r * r - d * d); | |
var anglep = Math.atan2(yp, xp); | |
var anglem = Math.atan2(ym, xm); | |
if (this.containsParam(anglep)) { | |
angles.push(anglep); | |
} | |
if (this.containsParam(anglem)) { | |
angles.push(anglem); | |
} | |
} | |
var d0 = -(lineMin[0] * (x + r * Math.cos(angleMin)) + lineMin[1] * (y + r * Math.sin(angleMin)) + lineMin[2]); | |
var d1 = -(lineMin[0] * (x + r * Math.cos(angleMax)) + lineMin[1] * (y + r * Math.sin(angleMax)) + lineMin[2]); | |
var angleMinAgainstLineMin, angleMaxAgainstLineMin; | |
if (d0 < 0) { | |
if (angles.length == 0) { | |
// no intersection | |
return undefined; | |
} | |
angleMinAgainstLineMin = Math.min.apply(Math, angles); | |
} else { | |
angleMinAgainstLineMin = this.angleMin; | |
} | |
if (d1 < 0) { | |
if (angles.length == 0) { | |
// no intersection | |
return undefined; | |
} | |
angleMaxAgainstLineMin = Math.max.apply(Math, angles); | |
} else { | |
angleMaxAgainstLineMin = this.angleMax; | |
} | |
var d = lineMax[0] * x + lineMax[1] * y + lineMax[2]; | |
var angles = []; | |
var det = r * r - d * d; | |
if (det >= 0) { | |
var xp = -lineMin[0] * d + lineMin[1] * Math.sqrt(r * r - d * d); | |
var yp = -lineMin[1] * d - lineMin[0] * Math.sqrt(r * r - d * d); | |
var xm = -lineMin[0] * d - lineMin[1] * Math.sqrt(r * r - d * d); | |
var ym = -lineMin[1] * d + lineMin[0] * Math.sqrt(r * r - d * d); | |
var anglep = Math.atan2(yp, xp); | |
var anglem = Math.atan2(ym, xm); | |
if (this.containsParam(anglep)) { | |
angles.push(anglep); | |
} | |
if (this.containsParam(anglem)) { | |
angles.push(anglem); | |
} | |
} | |
var d0 = lineMax[0] * (x + r * Math.cos(angleMin)) + lineMax[1] * (y + r * Math.sin(angleMin)) + lineMax[2]; | |
var d1 = lineMax[0] * (x + r * Math.cos(angleMax)) + lineMax[1] * (y + r * Math.sin(angleMax)) + lineMax[2]; | |
var angleMinAgainstLineMax, angleMaxAgainstLineMax; | |
if (d0 < 0) { | |
if (angles.length == 0) { | |
// no intersection | |
return undefined; | |
} | |
angleMinAgainstLineMax = Math.min.apply(Math, angles); | |
} else { | |
angleMinAgainstLineMax = this.angleMin; | |
} | |
if (d1 < 0) { | |
if (angles.length == 0) { | |
// no intersection | |
return undefined; | |
} | |
angleMaxAgainstLineMax = Math.max.apply(Math, angles); | |
} else { | |
angleMaxAgainstLineMax = this.angleMax; | |
} | |
return { | |
min:Math.max(angleMinAgainstLineMin, angleMinAgainstLineMax), | |
max:Math.min(angleMaxAgainstLineMin, angleMaxAgainstLineMax) | |
}; | |
}, | |
drawFatLine: function () { | |
var fatLine = this.fatLine(); | |
var lmin = fatLine.min; | |
var lmax = fatLine.max; | |
var y = function (x, l) { | |
return -(x * l[0] + l[2]) / l[1]; | |
} | |
var x0 = this.x + this.r * Math.cos(this.angleMin); | |
var x1 = this.x + this.r * Math.cos(this.angleMax); | |
var xmin = x0; | |
var xmax = x1; | |
xypic.svgForDebug.createSVGElement("line", { | |
x1:xypic.em2px(xmin), y1:-xypic.em2px(y(xmin, lmin)), | |
x2:xypic.em2px(xmax), y2:-xypic.em2px(y(xmax, lmin)), | |
"stroke-width":xypic.em2px(0.02 * xypic.oneem), stroke:"blue" | |
}); | |
xypic.svgForDebug.createSVGElement("line", { | |
x1:xypic.em2px(xmin), y1:-xypic.em2px(y(xmin, lmax)), | |
x2:xypic.em2px(xmax), y2:-xypic.em2px(y(xmax, lmax)), | |
"stroke-width":xypic.em2px(0.02 * xypic.oneem), stroke:"red" | |
}); | |
} | |
}); | |
xypic.LastCurve = MathJax.Object.Subclass({}); | |
xypic.LastCurve.None = xypic.LastCurve.Subclass({ | |
Init: function () {}, | |
isDefined: false, | |
segments: function () { return []; }, | |
angle: function () { return 0; } | |
}); | |
xypic.LastCurve.Augment({}, { | |
none: xypic.LastCurve.None() | |
}); | |
xypic.LastCurve.Line = xypic.LastCurve.Subclass({ | |
Init: function (start, end, p, c, lineShape) { | |
this.start = start; | |
this.end = end; | |
this.p = p; | |
this.c = c; | |
this.lineShape = lineShape; // line from start to end. | |
}, | |
isDefined: true, | |
position: function (t) { | |
return xypic.Frame.Point( | |
this.p.x + t*(this.c.x - this.p.x), | |
this.p.y + t*(this.c.y - this.p.y) | |
); | |
}, | |
derivative: function (t) { | |
return xypic.Frame.Point( | |
this.c.x - this.p.x, | |
this.c.y - this.p.y | |
); | |
}, | |
angle: function (t) { | |
var dx = this.c.x - this.p.x; | |
var dy = this.c.y - this.p.y; | |
if (dx === 0 && dy === 0) { | |
return 0; | |
} | |
return Math.atan2(dy, dx); | |
}, | |
tOfPlace: function (shaveP, shaveC, factor, slideEm) { | |
var start = (shaveP? this.start : this.p); | |
var end = (shaveC? this.end : this.c); | |
if (start.x === end.x && start.y === end.y) { | |
return 0; | |
} else { | |
var dx = end.x - start.x; | |
var dy = end.y - start.y; | |
var l = Math.sqrt(dx * dx + dy * dy); | |
var x, y; | |
if (factor > 0.5) { | |
x = end.x - (1 - factor) * dx + slideEm * dx / l; | |
y = end.y - (1 - factor) * dy + slideEm * dy / l; | |
} else { | |
x = start.x + factor * dx + slideEm * dx / l; | |
y = start.y + factor * dy + slideEm * dy / l; | |
} | |
var tx = this.c.x - this.p.x; | |
var ty = this.c.y - this.p.y; | |
if (tx === 0 && ty === 0) { | |
return 0; | |
} | |
if (Math.abs(tx) > Math.abs(ty)) { | |
return (x - this.p.x) / tx; | |
} else { | |
return (y - this.p.y) / ty; | |
} | |
} | |
}, | |
sliceHole: function (holeFrame, t) { | |
if (this.lineShape === undefined || holeFrame.isPoint()) { | |
return; | |
} | |
var shape = this.lineShape; | |
var line = shape.line; | |
var intersections = line.tOfIntersections(holeFrame); // ts of the line from start to end. | |
intersections.push(0); | |
intersections.push(1); | |
intersections.sort(); | |
var t0 = intersections[0], t1; | |
for (var i = 1; i < intersections.length; i++) { | |
var t1 = intersections[i]; | |
var p = line.position((t1 + t0) / 2); | |
if (holeFrame.contains(p)) { | |
var range = xypic.Range(t0, t1); | |
shape.sliceHole(range); | |
} | |
t0 = t1; | |
} | |
}, | |
segments: function () { | |
return [xypic.CurveSegment.Line(this.p, this.c, 0, 1)]; | |
} | |
}); | |
xypic.LastCurve.QuadBezier = xypic.LastCurve.Subclass({ | |
Init: function (origBezier, tOfShavedStart, tOfShavedEnd, curveShape) { | |
this.origBezier = origBezier; // unshaved | |
this.tOfShavedStart = tOfShavedStart; | |
this.tOfShavedEnd = tOfShavedEnd; | |
if (!curveShape.isNone) { | |
this.curveShape = curveShape; | |
if (tOfShavedStart > 0) { curveShape.sliceHole(xypic.Range(0, tOfShavedStart)); } | |
if (tOfShavedEnd < 1) { curveShape.sliceHole(xypic.Range(tOfShavedEnd, 1)); } | |
} | |
}, | |
isDefined: true, | |
position: function (t) { | |
return this.origBezier.position(t); | |
}, | |
derivative: function (t) { | |
return this.origBezier.derivative(t); | |
}, | |
angle: function (t) { | |
return this.origBezier.angle(t); | |
}, | |
tOfPlace: function (shaveP, shaveC, factor, slide) { | |
var offset; | |
var normalizer; | |
if (shaveP) { | |
offset = this.tOfShavedStart; | |
if (shaveC) { | |
normalizer = this.tOfShavedEnd - this.tOfShavedStart; | |
} else { | |
normalizer = 1 - this.tOfShavedStart; | |
} | |
} else { | |
offset = 0; | |
if (shaveC) { | |
normalizer = this.tOfShavedEnd; | |
} else { | |
normalizer = 1; | |
} | |
} | |
var bezier = this.origBezier; | |
var pos, angle; | |
var normalizedFactor = offset + normalizer * factor; | |
if (slide !== 0) { | |
var fd = bezier.length(normalizedFactor); | |
normalizedFactor = bezier.tOfLength(fd + slide); | |
} | |
return normalizedFactor; | |
}, | |
sliceHole: function (holeFrame, t) { | |
var shape = this.curveShape; | |
if (shape === undefined || holeFrame.isPoint()) { | |
return; | |
} | |
var curve = shape.curve; | |
var intersections = curve.tOfIntersections(holeFrame); // ts of the curve from p to c. | |
intersections.push(0); | |
intersections.push(1); | |
intersections.sort(); | |
var t0 = intersections[0], t1; | |
for (var i = 1; i < intersections.length; i++) { | |
var t1 = intersections[i]; | |
if (t0 <= t && t <= t1) { | |
var p = curve.position((t1 + t0) / 2); | |
if (holeFrame.contains(p)) { | |
var range = xypic.Range(t0, t1); | |
shape.sliceHole(range); | |
} | |
} | |
t0 = t1; | |
} | |
}, | |
segments: function () { | |
return [xypic.CurveSegment.QuadBezier(this.origBezier, 0, 1)]; | |
} | |
}); | |
xypic.LastCurve.CubicBezier = xypic.LastCurve.Subclass({ | |
Init: function (origBezier, tOfShavedStart, tOfShavedEnd, curveShape) { | |
this.origBezier = origBezier; // unshaved | |
this.tOfShavedStart = tOfShavedStart; | |
this.tOfShavedEnd = tOfShavedEnd; | |
if (!curveShape.isNone) { | |
this.curveShape = curveShape; | |
if (tOfShavedStart > 0) { curveShape.sliceHole(xypic.Range(0, tOfShavedStart)); } | |
if (tOfShavedEnd < 1) { curveShape.sliceHole(xypic.Range(tOfShavedEnd, 1)); } | |
} | |
}, | |
originalLine: function () { | |
return this.originalLine; | |
}, | |
isDefined: true, | |
position: function (t) { | |
return this.origBezier.position(t); | |
}, | |
derivative: function (t) { | |
return this.origBezier.derivative(t); | |
}, | |
angle: function (t) { | |
return this.origBezier.angle(t); | |
}, | |
tOfPlace: function (shaveP, shaveC, factor, slide) { | |
var offset; | |
var normalizer; | |
if (shaveP) { | |
offset = this.tOfShavedStart; | |
if (shaveC) { | |
normalizer = this.tOfShavedEnd - this.tOfShavedStart; | |
} else { | |
normalizer = 1 - this.tOfShavedStart; | |
} | |
} else { | |
offset = 0; | |
if (shaveC) { | |
normalizer = this.tOfShavedEnd; | |
} else { | |
normalizer = 1; | |
} | |
} | |
var bezier = this.origBezier; | |
var pos, angle; | |
var normalizedFactor = offset + normalizer * factor; | |
if (slide !== 0) { | |
var fd = bezier.length(normalizedFactor); | |
normalizedFactor = bezier.tOfLength(fd + slide); | |
} | |
return normalizedFactor; | |
}, | |
sliceHole: function (holeFrame, t) { | |
var shape = this.curveShape; | |
if (shape === undefined || holeFrame.isPoint()) { | |
return; | |
} | |
var curve = shape.curve; | |
var intersections = curve.tOfIntersections(holeFrame); // ts of the curve from p to c. | |
intersections.push(0); | |
intersections.push(1); | |
intersections.sort(); | |
var t0 = intersections[0], t1; | |
for (var i = 1; i < intersections.length; i++) { | |
var t1 = intersections[i]; | |
if (t0 <= t && t <= t1) { | |
var p = curve.position((t1 + t0) / 2); | |
if (holeFrame.contains(p)) { | |
var range = xypic.Range(t0, t1); | |
shape.sliceHole(range); | |
} | |
} | |
t0 = t1; | |
} | |
}, | |
segments: function () { | |
return [xypic.CurveSegment.CubicBezier(this.origBezier, 0, 1)]; | |
} | |
}); | |
xypic.LastCurve.CubicBSpline = xypic.LastCurve.Subclass({ | |
Init: function (s, e, origBeziers, tOfShavedStart, tOfShavedEnd, curveShape) { | |
this.s = s; | |
this.e = e; | |
this.origBeziers = origBeziers; // unshaved | |
this.tOfShavedStart = tOfShavedStart; | |
this.tOfShavedEnd = tOfShavedEnd; | |
if (!curveShape.isNone) { | |
this.curveShape = curveShape; | |
if (tOfShavedStart > 0) { curveShape.sliceHole(xypic.Range(0, tOfShavedStart)); } | |
if (tOfShavedEnd < 1) { curveShape.sliceHole(xypic.Range(tOfShavedEnd, 1)); } | |
} | |
}, | |
isDefined: true, | |
position: function (t) { | |
return this.origBeziers.position(t); | |
}, | |
derivative: function (t) { | |
return this.origBeziers.derivative(t); | |
}, | |
angle: function (t) { | |
return this.origBeziers.angle(t); | |
}, | |
tOfPlace: function (shaveP, shaveC, factor, slide) { | |
var offset; | |
var normalizer; | |
if (shaveP) { | |
offset = this.tOfShavedStart; | |
if (shaveC) { | |
normalizer = this.tOfShavedEnd - this.tOfShavedStart; | |
} else { | |
normalizer = 1 - this.tOfShavedStart; | |
} | |
} else { | |
offset = 0; | |
if (shaveC) { | |
normalizer = this.tOfShavedEnd; | |
} else { | |
normalizer = 1; | |
} | |
} | |
var beziers = this.origBeziers; | |
var pos, angle; | |
var normalizedFactor = offset + normalizer * factor; | |
if (slide !== 0) { | |
var fd = beziers.length(normalizedFactor); | |
normalizedFactor = beziers.tOfLength(fd + slide); | |
} | |
return normalizedFactor; | |
}, | |
sliceHole: function (holeFrame, t) { | |
var shape = this.curveShape; | |
if (shape === undefined || holeFrame.isPoint()) { | |
return; | |
} | |
var curve = shape.curve; | |
var intersections = curve.tOfIntersections(holeFrame); // ts of the curve from p to c. | |
intersections.push(0); | |
intersections.push(1); | |
intersections.sort(); | |
var t0 = intersections[0], t1; | |
for (var i = 1; i < intersections.length; i++) { | |
var t1 = intersections[i]; | |
if (t0 <= t && t <= t1) { | |
var p = curve.position((t1 + t0) / 2); | |
if (holeFrame.contains(p)) { | |
var range = xypic.Range(t0, t1); | |
shape.sliceHole(range); | |
} | |
} | |
t0 = t1; | |
} | |
}, | |
segments: function () { | |
var segments = new Array(this.origBeziers.length); | |
var n = segments.length; | |
for (var i = 0; i < n; i++) { | |
segments[i] = xypic.CurveSegment.CubicBezier(this.origBezier, i/n, (i+1)/n); | |
} | |
return segments; | |
} | |
}); | |
xypic.Saving = MathJax.Object.Subclass({}); | |
xypic.Saving.Position = MathJax.Object.Subclass({ | |
Init: function (pos) { | |
this.pos = pos; | |
}, | |
position: function (context) { | |
return this.pos; | |
}, | |
toString: function () { | |
return this.pos.toString(); | |
} | |
}); | |
xypic.Saving.Macro = MathJax.Object.Subclass({ | |
Init: function (macro) { | |
this.macro = macro; | |
}, | |
position: function (context) { | |
env.c = this.macro.position(context); | |
return env.c; | |
}, | |
toString: function () { | |
return this.macro.toString(); | |
} | |
}); | |
xypic.Saving.Base = MathJax.Object.Subclass({ | |
Init: function (origin, xBase, yBase) { | |
this.origin = origin; | |
this.xBase = xBase; | |
this.yBase = yBase; | |
}, | |
position: function (context) { | |
var env = context.env; | |
env.origin = this.origin; | |
env.xBase = this.xBase; | |
env.yBase = this.yBase; | |
return env.c; | |
}, | |
toString: function () { | |
return "origin:" + this.origin + ", xBase:" + this.xBase + ", yBase:" + this.yBase; | |
} | |
}); | |
xypic.Saving.Stack = MathJax.Object.Subclass({ | |
Init: function (stack) { | |
this.stack = stack; | |
}, | |
position: function (context) { | |
var env = context.env; | |
if (!this.stack.isEmpty) { | |
this.stack.tail.reverse().foreach(function (p) { | |
env.capturePosition(p); | |
}); | |
env.c = this.stack.head; | |
} | |
return env.c; | |
}, | |
toString: function () { | |
return this.stack.toString(); | |
} | |
}); | |
xypic.Env = MathJax.Object.Subclass({ | |
Init: function () { | |
var onemm = xypic.length2em("1mm"); | |
this.origin = {x:0, y:0}; | |
this.xBase = {x:onemm, y:0}; | |
this.yBase = {x:0, y:onemm}; | |
this.savedPosition = {}; | |
this.stateStack = FP.List.empty; | |
this.stackFrames = FP.List.empty; | |
this.stack = FP.List.empty; | |
this.angle = 0; // radian | |
this.lastCurve = xypic.LastCurve.none; | |
this.p = this.c = xypic.Env.originPosition; | |
this.shouldCapturePos = false; | |
this.capturedPositions = FP.List.empty; | |
this.objectmargin = AST.xypic.objectmargin; | |
this.objectheight = AST.xypic.objectheight; | |
this.objectwidth = AST.xypic.objectwidth; | |
this.labelmargin = AST.xypic.labelmargin; | |
}, | |
duplicate: function () { | |
var newEnv = xypic.Env(); | |
xypic.Env.copyFields(this, newEnv); | |
return newEnv; | |
}, | |
saveState: function () { | |
var currentState = this.duplicate(); | |
this.stateStack = this.stateStack.prepend(currentState); | |
}, | |
restoreState: function () { | |
if (!this.stateStack.isEmpty) { | |
var savedState = this.stateStack.head; | |
this.stateStack = this.stateStack.tail; | |
xypic.Env.copyFields(savedState, this); | |
} | |
}, | |
absVector: function (x, y) { | |
var ax = this.origin.x + x * this.xBase.x + y * this.yBase.x; | |
var ay = this.origin.y + x * this.xBase.y + y * this.yBase.y; | |
return {x:ax, y:ay}; | |
}, | |
inverseAbsVector: function (ax, ay) { | |
var bxx = this.xBase.x; | |
var bxy = this.xBase.y; | |
var byx = this.yBase.x; | |
var byy = this.yBase.y; | |
var det = bxx * byy - bxy * byx; | |
var dx = ax - this.origin.x; | |
var dy = ay - this.origin.y | |
var x = (byy * dx - byx * dy) / det; | |
var y = (-bxy * dx + bxx * dy) / det; | |
return {x:x, y:y}; | |
}, | |
setOrigin: function (x, y) { | |
this.origin = {x:x, y:y}; | |
}, | |
setXBase: function (x, y) { | |
this.xBase = {x:x, y:y}; | |
}, | |
setYBase: function (x, y) { | |
this.yBase = {x:x, y:y}; | |
}, | |
swapPAndC: function () { | |
var t = this.p; | |
this.p = this.c; | |
this.c = t; | |
}, | |
enterStackFrame: function () { | |
this.stackFrames = this.stackFrames.prepend(this.stack); | |
this.initStack(); | |
}, | |
leaveStackFrame: function () { | |
if (!this.stackFrames.isEmpty) { | |
this.stack = this.stackFrames.head; | |
this.stackFrames = this.stackFrames.tail; | |
} else { | |
this.initStack(); | |
} | |
}, | |
savePos: function (id, pos) { | |
this.savedPosition[id] = pos; | |
}, | |
startCapturePositions: function () { | |
this.shouldCapturePos = true; | |
this.capturedPositions = FP.List.empty; | |
}, | |
endCapturePositions: function () { | |
this.shouldCapturePos = false; | |
var positions = this.capturedPositions; | |
this.capturedPositions = FP.List.empty; | |
return positions; | |
}, | |
capturePosition: function (pos) { | |
if (this.shouldCapturePos && pos !== undefined) { | |
this.capturedPositions = this.capturedPositions.prepend(pos); | |
} | |
}, | |
pushPos: function (pos) { | |
if (pos !== undefined) { | |
this.stack = this.stack.prepend(pos); | |
} | |
}, | |
popPos: function () { | |
if (this.stack.isEmpty) { | |
throw xypic.ExecutionError("cannot pop from the empty stack"); | |
} else { | |
var pos = this.stack.head; | |
this.stack = this.stack.tail; | |
return pos; | |
} | |
}, | |
initStack: function () { | |
this.stack = FP.List.empty; | |
}, | |
setStack: function (positions) { | |
this.stack = positions; | |
}, | |
stackAt: function (number) { | |
return this.stack.at(number); | |
}, | |
lookupPos: function (id, errorMessage) { | |
var pos = this.savedPosition[id]; | |
if (pos === undefined) { | |
if (errorMessage !== undefined) { | |
throw xypic.ExecutionError(errorMessage); | |
} else { | |
throw xypic.ExecutionError('<pos> "' + id + '" not defined.'); | |
} | |
} else { | |
return pos; | |
} | |
}, | |
toString: function () { | |
var savedPositionDesc = ""; | |
for (var id in this.savedPosition) { | |
if (this.savedPosition.hasOwnProperty(id)) { | |
if (savedPositionDesc.length > 0) { | |
savedPositionDesc += ", " | |
} | |
savedPositionDesc += id.toString()+":"+this.savedPosition[id]; | |
} | |
} | |
return "Env\n p:"+this.p+"\n c:"+this.c+"\n angle:"+this.angle+"\n lastCurve:"+this.lastCurve+"\n savedPosition:{"+savedPositionDesc+"}\n origin:{x:"+this.origin.x+", y:"+this.origin.y+"}\n xBase:{x:"+this.xBase.x+", y:"+this.xBase.y+"}\n yBase:{x:"+this.yBase.x+", y:"+this.yBase.y+"}\n stackFrames:"+this.stackFrames+"\n stack:"+this.stack+"\n shouldCapturePos:"+this.shouldCapturePos+"\n capturedPositions:"+this.capturedPositions; | |
} | |
}, { | |
originPosition: xypic.Frame.Point(0, 0), | |
copyFields: function (from, to) { | |
for (var attr in from) { | |
if (from.hasOwnProperty(attr)) { | |
to[attr] = from[attr]; | |
} | |
} | |
to.savedPosition = {}; | |
for (var id in from.savedPosition) { | |
if (from.savedPosition.hasOwnProperty(id)) { | |
to.savedPosition[id] = from.savedPosition[id]; | |
} | |
} | |
} | |
}); | |
AST.PosDecor.Augment({ | |
toShape: function (context) { | |
this.pos.toShape(context); | |
this.decor.toShape(context); | |
} | |
}); | |
AST.Pos.Coord.Augment({ | |
toShape: function (context) { | |
context.env.c = this.coord.position(context); | |
this.pos2s.foreach(function (p) { p.toShape(context); }); | |
} | |
}); | |
AST.Pos.Plus.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var pos = this.coord.position(context); | |
env.c = pos.move(env.c.x + pos.x, env.c.y + pos.y); | |
} | |
}); | |
AST.Pos.Minus.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var pos = this.coord.position(context); | |
env.c = pos.move(env.c.x - pos.x, env.c.y - pos.y); | |
} | |
}); | |
AST.Pos.Skew.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var pos = this.coord.position(context); | |
var rp = xypic.Frame.Point(pos.x + env.c.x, pos.y + env.c.y); | |
env.c = rp.combineRect(env.c); | |
} | |
}); | |
AST.Pos.Cover.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var pos = this.coord.position(context); | |
env.c = env.c.combineRect(pos); | |
} | |
}); | |
AST.Pos.Then.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.capturePosition(env.c); | |
env.c = this.coord.position(context); | |
} | |
}); | |
AST.Pos.SwapPAndC.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.swapPAndC(); | |
env.c = this.coord.position(context); | |
} | |
}); | |
AST.Pos.SetBase.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var p = env.p; | |
var x = env.c.x - p.x; | |
var y = env.c.y - p.y; | |
env.setOrigin(p.x, p.y); | |
env.setXBase(x, y); | |
env.setYBase(-y, x); | |
env.c = this.coord.position(context); | |
} | |
}); | |
AST.Pos.SetYBase.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.setYBase(env.c.x - env.origin.x, env.c.y - env.origin.y); | |
env.c = this.coord.position(context); | |
} | |
}); | |
AST.Pos.ConnectObject.Augment({ | |
toShape: function (context) { | |
this.object.toConnectShape(context); | |
} | |
}); | |
AST.Pos.DropObject.Augment({ | |
toShape: function (context) { | |
this.object.toDropShape(context); | |
} | |
}); | |
AST.Pos.Place.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
if (env.lastCurve.isDefined) { | |
var place = this.place; | |
var start, end, f, dimen; | |
var shouldShaveP = (place.shaveP > 0); | |
var shouldShaveC = (place.shaveC > 0); | |
var jotP = (shouldShaveP? place.shaveP - 1 : 0); | |
var jotC = (shouldShaveC? place.shaveC - 1 : 0); | |
if (shouldShaveP) { f = 0; } | |
if (shouldShaveC) { f = 1; } | |
if (shouldShaveP == shouldShaveC) { | |
f = 0.5; | |
} | |
if (place.factor !== undefined) { | |
if (place.factor.isIntercept) { | |
shouldShaveC = shouldShaveP = false; | |
f = place.factor.value(context); | |
if (f === undefined) { | |
return; | |
} | |
} else { | |
f = place.factor.value(context); | |
} | |
} | |
dimen = xypic.length2em(place.slide.dimen.getOrElse("0")); | |
var jot = AST.xypic.jot; | |
var slideEm = dimen + (jotP - jotC) * jot; | |
var t = env.lastCurve.tOfPlace(shouldShaveP, shouldShaveC, f, slideEm); | |
var pos = env.lastCurve.position(t); | |
var angle = env.lastCurve.angle(t); | |
env.c = pos; | |
env.angle = angle; | |
return t; | |
} | |
return undefined; | |
} | |
}); | |
AST.Pos.PushCoord.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var pos = this.coord.position(context); | |
env.pushPos(pos); | |
} | |
}); | |
AST.Pos.EvalCoordThenPop.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.c = this.coord.position(context); | |
env.popPos(); | |
} | |
}); | |
AST.Pos.LoadStack.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.startCapturePositions(); | |
this.coord.position(context); | |
var positions = env.endCapturePositions(); | |
env.setStack(positions); | |
env.pushPos(env.c); | |
} | |
}); | |
AST.Pos.DoCoord.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var coord = this.coord; | |
var pos = env.stack.reverse(); | |
pos.foreach(function (c) { | |
env.c = c; | |
coord.position(context); | |
}); | |
} | |
}); | |
AST.Pos.InitStack.Augment({ | |
toShape: function (context) { | |
context.env.initStack(); | |
} | |
}); | |
AST.Pos.EnterFrame.Augment({ | |
toShape: function (context) { | |
context.env.enterStackFrame(); | |
} | |
}); | |
AST.Pos.LeaveFrame.Augment({ | |
toShape: function (context) { | |
context.env.leaveStackFrame(); | |
} | |
}); | |
AST.Place.Factor.Augment({ | |
value: function (context) { | |
return this.factor; | |
} | |
}); | |
AST.Place.Intercept.Augment({ | |
value: function (context) { | |
var env = context.env; | |
if (!env.lastCurve.isDefined) { | |
return undefined; | |
} | |
var tmpEnv = env.duplicate(); | |
tmpEnv.angle = 0; | |
tmpEnv.lastCurve = xypic.LastCurve.none; | |
tmpEnv.p = tmpEnv.c = xypic.Env.originPosition; | |
var tmpContext = xypic.DrawingContext(xypic.Shape.none, tmpEnv); | |
var box = this.pos.toShape(tmpContext); | |
context.appendShapeToFront(tmpContext.shape); | |
if (!tmpEnv.lastCurve.isDefined) { | |
tmpEnv.lastCurve = xypic.LastCurve.Line(tmpEnv.p, tmpEnv.c, tmpEnv.p, tmpEnv.c, undefined); | |
} | |
var intersec = []; | |
var thisSegs = env.lastCurve.segments(); | |
var thatSegs = tmpEnv.lastCurve.segments(); | |
for (var i = 0; i < thisSegs.length; i++) { | |
for (var j = 0; j < thatSegs.length; j++) { | |
intersec = intersec.concat(xypic.CurveSegment.findIntersections(thisSegs[i], thatSegs[j])); | |
} | |
} | |
if (intersec.length === 0) { | |
// find the nearest point, if no intersection was found. | |
console.log("perhaps no curve intersection."); | |
// Levenberg-Marqardt Method | |
var line0 = env.lastCurve; | |
var line1 = tmpEnv.lastCurve; | |
var n = 100; // maxIterations | |
var goalAccuracy = 1e-5; | |
var tau = 1e-3; | |
var k = 0; | |
var nu = 2; | |
// TODO: 複数個の開始地点から探索し、尤もらしい解を選択する。 | |
var x0 = 0; | |
var x1 = 0; | |
var tx = function (x) { | |
return 1 / (1 + Math.exp(-x)); | |
} | |
var dtx = function (x) { | |
var ex = Math.exp(-x); | |
return ex / (1 + ex) / (1 + ex); | |
} | |
var t0 = tx(x0); | |
var t1 = tx(x1); | |
var dt0 = dtx(x0); | |
var dt1 = dtx(x1); | |
var dp0 = line0.derivative(t0); | |
var dp1 = line1.derivative(t1); | |
var j00 = dp0.x * dt0, j01 = -dp1.x * dt1; | |
var j10 = dp0.y * dt0, j11 = -dp1.y * dt1; | |
var a00 = j00 * j00 + j10 * j10, a01 = j00 * j01 + j10 * j11; | |
var a10 = j01 * j00 + j11 * j10, a11 = j01 * j01 + j11 * j11; | |
var p0 = line0.position(t0); | |
var p1 = line1.position(t1); | |
var f0 = p0.x - p1.x; | |
var f1 = p0.y - p1.y; | |
var g0 = j00 * f0 + j10 * f1; | |
var g1 = j01 * f0 + j11 * f1; | |
var stop = Math.sqrt(g0 * g0 + g1 * g1) < goalAccuracy; | |
var mu = tau * Math.max(a00, a11); | |
while (!stop && k < n) { | |
k++; | |
do { | |
var am00 = a00 + mu, am01 = a01; | |
var am10 = a10, am11 = a11 + mu; | |
var det = am00 * am11 - am01 * am10; | |
var d0 = (am11 * g0 - a01 * g1) / det; | |
var d1 = (-am10 * g0 + a00 * g1) / det; | |
if ((d0 * d0 + d1 * d1) < goalAccuracy * goalAccuracy * (x0 * x0 + x1 * x1)) { | |
stop = true; | |
} else { | |
var newX0 = x0 - d0; | |
var newX1 = x1 - d1; | |
var newT0 = tx(newX0); | |
var newT1 = tx(newX1); | |
var newP0 = line0.position(newT0); | |
var newP1 = line1.position(newT1); | |
var newF0 = newP0.x - newP1.x; | |
var newF1 = newP0.y - newP1.y; | |
var rho = ((f0 * f0 + f1 * f1) - (newF0 * newF0 + newF1 * newF1)) / (d0 * (mu * d0 + g0) + d1 * (mu * d1 + g1)); | |
if (rho > 0) { | |
x0 = newX0; | |
x1 = newX1; | |
t0 = newT0; | |
t1 = newT1; | |
dt0 = dtx(x0); | |
dt1 = dtx(x1); | |
dp0 = line0.derivative(t0); | |
dp1 = line1.derivative(t1); | |
j00 = dp0.x * dt0; j01 = -dp1.x * dt1; | |
j10 = dp0.y * dt0; j11 = -dp1.y * dt1; | |
a00 = j00 * j00 + j10 * j10; a01 = j00 * j01 + j10 * j11; | |
a10 = j01 * j00 + j11 * j10; a11 = j01 * j01 + j11 * j11; | |
f0 = newF0; | |
f1 = newF1; | |
g0 = j00 * f0 + j10 * f1; | |
g1 = j01 * f0 + j11 * f1; | |
stop = Math.sqrt(g0 * g0 + g1 * g1) < goalAccuracy; | |
var sigma = 2 * rho - 1; | |
mu = mu + Math.max(1 / 3, 1 - sigma * sigma * sigma); | |
nu = 2; | |
} else { | |
mu = mu * nu; | |
nu = 2 * nu; | |
} | |
} | |
} while (!stop && !(rho !== undefined && rho > 0)) | |
} | |
return tx(x0); | |
} else { | |
var t = (intersec[0][0].min + intersec[0][0].max)/2; | |
for (var i = 1; i < intersec.length; i++) { | |
var ttmp = (intersec[i][0].min + intersec[i][0].max)/2; | |
if (t > ttmp) { t = ttmp; } | |
} | |
return t; | |
} | |
} | |
}); | |
AST.Pos.SavePos.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.savePos(this.id, xypic.Saving.Position(env.c)); | |
} | |
}); | |
AST.Pos.SaveMacro.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.savePos(this.id, xypic.Saving.Macro(this.macro)); | |
} | |
}); | |
AST.Pos.SaveBase.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.savePos(this.id, xypic.Saving.Base(env.origin, env.xBase, env.yBase)); | |
} | |
}); | |
AST.Pos.SaveStack.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.savePos(this.id, xypic.Saving.Stack(env.stack)); | |
} | |
}); | |
AST.Object.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
if (env.c === undefined) { | |
return xypic.Shape.none; | |
} | |
var modifiers = this.modifiers; | |
if (modifiers.isEmpty) { | |
return this.object.toDropShape(context); | |
} else { | |
var tmpEnv = env.duplicate(); | |
var subcontext = xypic.DrawingContext(xypic.Shape.none, tmpEnv); | |
var reversedProcessedModifiers = FP.List.empty; | |
modifiers.foreach(function (m) { | |
m.preprocess(subcontext, reversedProcessedModifiers); | |
reversedProcessedModifiers = reversedProcessedModifiers.prepend(m); | |
}); | |
var objectShape = this.object.toDropShape(subcontext); | |
var objectBoundingBox = tmpEnv.c; | |
if (objectBoundingBox === undefined) { | |
return xypic.Shape.none; | |
} | |
var originalReferencePoint = tmpEnv.originalReferencePoint; | |
tmpEnv = env.duplicate(); // restore angle | |
tmpEnv.c = objectBoundingBox; | |
tmpEnv.originalReferencePoint = originalReferencePoint; | |
subcontext = xypic.DrawingContext(xypic.Shape.none, tmpEnv); | |
objectShape = modifiers.head.modifyShape(subcontext, objectShape, modifiers.tail); | |
context.appendShapeToFront(objectShape); | |
env.c = tmpEnv.c.move(env.c.x, env.c.y); | |
return objectShape; | |
} | |
}, | |
toConnectShape: function (context) { | |
var env = context.env; | |
if (env.c === undefined) { | |
return xypic.Shape.none; | |
} | |
var modifiers = this.modifiers; | |
if (modifiers.isEmpty) { | |
return this.object.toConnectShape(context); | |
} else { | |
var tmpEnv = env.duplicate(); | |
var subcontext = xypic.DrawingContext(xypic.Shape.none, tmpEnv); | |
var reversedProcessedModifiers = FP.List.empty; | |
modifiers.foreach(function (m) { | |
m.preprocess(subcontext, reversedProcessedModifiers); | |
reversedProcessedModifiers = reversedProcessedModifiers.prepend(m); | |
}); | |
var objectShape = this.object.toConnectShape(subcontext); | |
env.angle = tmpEnv.angle; | |
env.lastCurve = tmpEnv.lastCurve; | |
var objectBoundingBox = tmpEnv.c; | |
if (objectBoundingBox === undefined) { | |
return xypic.Shape.none; | |
} | |
var originalReferencePoint = tmpEnv.originalReferencePoint; | |
tmpEnv = env.duplicate(); // restore angle | |
tmpEnv.c = objectBoundingBox; | |
tmpEnv.originalReferencePoint = originalReferencePoint; | |
subcontext = xypic.DrawingContext(xypic.Shape.none, tmpEnv); | |
objectShape = modifiers.head.modifyShape(subcontext, objectShape, modifiers.tail); | |
context.appendShapeToFront(objectShape); | |
env.c = tmpEnv.c.move(env.c.x, env.c.y); | |
return objectShape; | |
} | |
}, | |
boundingBox: function (context) { | |
var tmpEnvContext = context.duplicateEnv(); | |
var tmpEnv = tmpEnvContext.env; | |
tmpEnv.angle = 0; | |
tmpEnv.p = tmpEnv.c = xypic.Env.originPosition; | |
tmpEnvContext.shape = xypic.Shape.none; | |
var dropShape = this.toDropShape(tmpEnvContext); | |
return dropShape.getBoundingBox(); | |
} | |
}); | |
AST.ObjectBox.Augment({ | |
toConnectShape: function (context) { | |
// 多重線の幅、点線・破線の幅の基準 | |
var env = context.env; | |
var origC = env.c; | |
var env = context.env; | |
var t = AST.xypic.thickness; | |
var s = env.p.edgePoint(env.c.x, env.c.y); | |
var e = env.c.edgePoint(env.p.x, env.p.y); | |
if (s.x !== e.x || s.y !== e.y) { | |
var shape = xypic.Curve.Line(s, e).toShape(context, this, "196883" /* dummy dir name */, ""); | |
env.originalReferencePoint = origC; | |
return shape; | |
} else { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
env.originalReferencePoint = origC; | |
return xypic.Shape.none; | |
} | |
}, | |
boundingBox: function (context) { | |
var tmpEnvContext = context.duplicateEnv(); | |
var tmpEnv = tmpEnvContext.env; | |
tmpEnv.angle = 0; | |
tmpEnv.p = tmpEnv.c = xypic.Env.originPosition; | |
tmpEnvContext.shape = xypic.Shape.none; | |
var dropShape = this.toDropShape(tmpEnvContext); | |
return dropShape.getBoundingBox(); | |
} | |
}); | |
AST.ObjectBox.WrapUpObject.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
var shape = this.object.toDropShape(context); | |
env.originalReferencePoint = env.c; | |
return shape; | |
}, | |
toConnectShape: function (context) { | |
var env = context.env; | |
var shape = this.object.toConnectShape(context); | |
env.originalReferencePoint = env.c; | |
return shape; | |
} | |
}); | |
AST.ObjectBox.CompositeObject.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
var origC = env.c; | |
if (origC === undefined) { | |
return xypic.Shape.none; | |
} | |
var c = origC; | |
var tmpEnv = env.duplicate(); | |
var subcontext = xypic.DrawingContext(xypic.Shape.none, tmpEnv); | |
this.objects.foreach(function (obj) { | |
tmpEnv.c = origC; | |
var tmpShape = obj.toDropShape(subcontext); | |
c = xypic.Frame.combineRect(c, tmpEnv.c); | |
c = xypic.Frame.combineRect(c, tmpShape.getBoundingBox().toPoint()); | |
}); | |
env.c = c; | |
var compositeShape = subcontext.shape; | |
context.appendShapeToFront(compositeShape); | |
env.originalReferencePoint = origC; | |
return compositeShape; | |
} | |
}); | |
AST.ObjectBox.Xybox.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
var c = env.c; | |
if (c === undefined) { | |
return xypic.Shape.none; | |
} | |
var subenv = xypic.Env(); | |
var subcontext = xypic.DrawingContext(xypic.Shape.none, subenv); | |
this.posDecor.toShape(subcontext); | |
var subshape = subcontext.shape; | |
var bbox = subshape.getBoundingBox(); | |
if (bbox === undefined) { | |
return xypic.Shape.none; | |
} | |
var l = Math.max(0, bbox.l - bbox.x); | |
var r = Math.max(0, bbox.r + bbox.x); | |
var u = Math.max(0, bbox.u + bbox.y); | |
var d = Math.max(0, bbox.d - bbox.y); | |
env.c = xypic.Frame.Rect(c.x, c.y, { l:l, r:r, u:u, d:d }); | |
env.originalReferencePoint = c; | |
var objectShape = xypic.Shape.TranslateShape(c.x, c.y, subshape); | |
context.appendShapeToFront(objectShape); | |
return objectShape; | |
} | |
}); | |
AST.ObjectBox.Xymatrix.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
var c = env.c; | |
var shape = this.xymatrix.toShape(context); | |
env.originalReferencePoint = c; | |
return shape; | |
} | |
}); | |
AST.ObjectBox.Text.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
var textShape = xypic.Shape.TextShape(env.c, this.math, xypic.svgForTestLayout); | |
context.appendShapeToFront(textShape); | |
env.c = textShape.getBoundingBox(); | |
env.originalReferencePoint = textShape.getOriginalReferencePoint(); | |
return textShape; | |
} | |
}); | |
AST.ObjectBox.Empty.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
env.originalReferencePoint = env.c; | |
env.c = xypic.Frame.Point(env.c.x, env.c.y); | |
return xypic.Shape.none; | |
} | |
}); | |
AST.ObjectBox.Txt.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
if (env.c === undefined) { | |
return xypic.Shape.none; | |
} | |
// TODO change width | |
var textShape = this.textObject.toDropShape(context); | |
env.originalReferencePoint = env.c; | |
return textShape; | |
} | |
}); | |
AST.ObjectBox.Txt.Width.Vector.Augment({ | |
width: function (context) { | |
return this.vector.xy().x; | |
} | |
}); | |
AST.ObjectBox.Txt.Width.Vector.Augment({ | |
width: function (context) { | |
var c = context.env.c; | |
return c.r + c.l; | |
} | |
}); | |
AST.ObjectBox.Cir.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
if (env.c === undefined) { | |
return xypic.Shape.none; | |
} | |
env.originalReferencePoint = env.c; | |
var r = this.radius.radius(context); | |
var x = env.c.x; | |
var y = env.c.y; | |
var circleShape = this.cir.toDropShape(context, x, y, r); | |
env.c = xypic.Frame.Ellipse(x, y, r, r, r, r); | |
return circleShape; | |
}, | |
toConnectShape: function (context) { | |
// TODO: 何もしなくてよいかTeXの出力結果を確認する。 | |
var env = context.env; | |
env.originalReferencePoint = env.c; | |
return xypic.Shape.none; | |
} | |
}); | |
AST.ObjectBox.Cir.Radius.Vector.Augment({ | |
radius: function (context) { | |
return this.vector.xy(context).x; | |
} | |
}); | |
AST.ObjectBox.Cir.Radius.Default.Augment({ | |
radius: function (context) { | |
return context.env.c.r; | |
} | |
}); | |
AST.ObjectBox.Cir.Cir.Segment.Augment({ | |
toDropShape: function (context, x, y, r) { | |
var env = context.env; | |
var sa = this.startPointDegree(context); | |
var ea = this.endPointDegree(context, sa); | |
var da = ea - sa; | |
da = (da < 0? da + 360 : da); | |
if (da === 0) { | |
return xypic.Shape.none; | |
} | |
var large, flip; | |
if (this.orient === "^") { | |
large = (da > 180? "1" : "0"); | |
flip = "0"; | |
} else { | |
large = (da > 180? "0" : "1"); | |
flip = "1"; | |
} | |
var degToRadCoef = Math.PI / 180; | |
var sx = x + r * Math.cos(sa * degToRadCoef); | |
var sy = y + r * Math.sin(sa * degToRadCoef); | |
var ex = x + r * Math.cos(ea * degToRadCoef); | |
var ey = y + r * Math.sin(ea * degToRadCoef); | |
var circleSegmentShape = xypic.Shape.CircleSegmentShape(x, y, sx, sy, r, large, flip, ex, ey); | |
context.appendShapeToFront(circleSegmentShape); | |
return circleSegmentShape; | |
}, | |
startPointDegree: function (contect) { | |
var sd = this.startDiag.toString(); | |
var sa; | |
if (this.orient === "^") { | |
sa = this.diagToAngleACW(sd); | |
} else { | |
sa = this.diagToAngleCW(sd); | |
} | |
return sa; | |
}, | |
endPointDegree: function (contect, startAngle) { | |
var ed = this.endDiag.toString(); | |
var ea; | |
if (this.orient === "^") { | |
ea = this.diagToAngleACW(ed, startAngle); | |
} else { | |
ea = this.diagToAngleCW(ed, startAngle); | |
} | |
return ea; | |
}, | |
diagToAngleACW: function (diag, angle) { | |
switch (diag) { | |
case "l": return 90; | |
case "r": return -90; | |
case "d": return 180; | |
case "u": return 0; | |
case "dl": | |
case "ld": | |
return 135; | |
case "dr": | |
case "rd": | |
return -135; | |
case "ul": | |
case "lu": | |
return 45; | |
case "ur": | |
case "ru": | |
return -45; | |
default: | |
if (angle !== undefined) { | |
return angle + 180; | |
} else { | |
return 0; | |
} | |
} | |
}, | |
diagToAngleCW: function (diag, angle) { | |
switch (diag) { | |
case "l": return -90; | |
case "r": return 90; | |
case "d": return 0; | |
case "u": return 180; | |
case "dl": | |
case "ld": | |
return -45; | |
case "dr": | |
case "rd": | |
return 45; | |
case "ul": | |
case "lu": | |
return -135; | |
case "ur": | |
case "ru": | |
return 135; | |
default: | |
if (angle !== undefined) { | |
return angle + 180; | |
} else { | |
return 0; | |
} | |
} | |
} | |
}); | |
AST.ObjectBox.Cir.Cir.Full.Augment({ | |
toDropShape: function (context, x, y, r) { | |
var fullCircleShape = xypic.Shape.FullCircleShape(x, y, r); | |
context.appendShapeToFront(fullCircleShape); | |
return fullCircleShape; | |
} | |
}); | |
AST.ObjectBox.Frame.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
env.originalReferencePoint = env.c; | |
return this.toDropFilledShape(context, "currentColor", false) | |
}, | |
toDropFilledShape: function (context, color, convertToEllipse) { | |
var env = context.env; | |
var c = env.c; | |
if (c === undefined) { | |
return xypic.Shape.none; | |
} | |
var t = AST.xypic.thickness; | |
var x = c.x; | |
var y = c.y; | |
var left = c.l; | |
var right = c.r; | |
var up = c.u; | |
var down = c.d; | |
var shape = xypic.Shape.none; | |
switch (this.main) { | |
case '--': | |
var dash = 3 * t; | |
if (convertToEllipse) { | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, false, color, xypic.em2px(dash) + " " + xypic.em2px(dash)); | |
} else { | |
var radius = this.radius.radius(context); | |
shape = xypic.Shape.RectangleShape(x, y, left, right, up, down, radius, false, color, xypic.em2px(dash) + " " + xypic.em2px(dash)); | |
} | |
break; | |
case '==': | |
var dash = 3 * t; | |
if (convertToEllipse) { | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, true, color, xypic.em2px(dash) + " " + xypic.em2px(dash)); | |
} else { | |
var radius = this.radius.radius(context); | |
shape = xypic.Shape.RectangleShape(x, y, left, right, up, down, radius, true, color, xypic.em2px(dash) + " " + xypic.em2px(dash)); | |
} | |
break; | |
case 'o-': | |
var dash = 3 * t; | |
var radius = AST.xypic.lineElementLength; | |
shape = xypic.Shape.RectangleShape(x, y, left, right, up, down, radius, false, color, xypic.em2px(dash) + " " + xypic.em2px(dash)); | |
break; | |
case 'oo': | |
var xy = this.radius.xy(context); | |
var r = xy.x; | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, r, r, true, color, undefined); | |
break; | |
case 'ee': | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, true, color, undefined); | |
break; | |
case '-,': | |
var depth = this.radius.depth(context); | |
var radius = this.radius.radius(context); | |
shape = xypic.Shape.CompositeShape( | |
xypic.Shape.RectangleShape(x, y, left, right, up, down, radius, false, color, undefined), | |
xypic.Shape.BoxShadeShape(x, y, left, right, up, down, depth) | |
); | |
break; | |
case '.o': | |
var xy = this.radius.xy(context); | |
var r = xy.x; | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, r, r, false, color, AST.xypic.dottedDasharray); | |
break; | |
case '-o': | |
var dash = 3 * t; | |
var xy = this.radius.xy(context); | |
var r = xy.x; | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, r, r, false, color, xypic.em2px(dash) + " " + xypic.em2px(dash)); | |
break; | |
case '.e': | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, false, color, AST.xypic.dottedDasharray); | |
break; | |
case '-e': | |
var dash = 3 * t; | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, false, color, xypic.em2px(dash) + " " + xypic.em2px(dash)); | |
break; | |
case '-': | |
if (convertToEllipse) { | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, false, color, undefined); | |
} else { | |
var radius = this.radius.radius(context); | |
shape = xypic.Shape.RectangleShape(x, y, left, right, up, down, radius, false, color, undefined); | |
} | |
break; | |
case '=': | |
if (convertToEllipse) { | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, true, color, undefined); | |
} else { | |
var radius = this.radius.radius(context); | |
shape = xypic.Shape.RectangleShape(x, y, left, right, up, down, radius, true, color, undefined); | |
} | |
break; | |
case '.': | |
if (convertToEllipse) { | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, false, color, AST.xypic.dottedDasharray); | |
} else { | |
var radius = this.radius.radius(context); | |
shape = xypic.Shape.RectangleShape(x, y, left, right, up, down, radius, false, color, AST.xypic.dottedDasharray); | |
} | |
break; | |
case ',': | |
var depth = this.radius.depth(context); | |
shape = xypic.Shape.BoxShadeShape(x, y, left, right, up, down, depth, color); | |
break; | |
case 'o': | |
var xy = this.radius.xy(context); | |
var r = xy.x; | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, r, r, false, color, undefined); | |
break; | |
case 'e': | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, false, color, undefined); | |
break; | |
case '\\{': | |
shape = xypic.Shape.LeftBrace(x - left, y, up, down, 0, color); | |
break; | |
case '\\}': | |
shape = xypic.Shape.LeftBrace(x + right, y, down, up, 180, color); | |
break; | |
case '^\\}': | |
case '^\\{': | |
shape = xypic.Shape.LeftBrace(x, y + up, right, left, 270, color); | |
break; | |
case '_\\{': | |
case '_\\}': | |
shape = xypic.Shape.LeftBrace(x, y - down, left, right, 90, color); | |
break; | |
case '(': | |
shape = xypic.Shape.LeftParenthesis(x - left, y + (up - down) / 2, up + down, 0, color); | |
break; | |
case ')': | |
shape = xypic.Shape.LeftParenthesis(x + right, y + (up - down) / 2, up + down, 180, color); | |
break; | |
case '^(': | |
case '^)': | |
shape = xypic.Shape.LeftParenthesis(x + (right - left) / 2, y + up, left + right, 270, color); | |
break; | |
case '_(': | |
case '_)': | |
shape = xypic.Shape.LeftParenthesis(x + (right - left) / 2, y - down, left + right, 90, color); | |
break; | |
case '*': | |
if (c.isCircle()) { | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, false, "currentColor", undefined, color, true); | |
} else { | |
var radius = this.radius.radius(context); | |
shape = xypic.Shape.RectangleShape(x, y, left, right, up, down, radius, false, "currentColor", undefined, color, true); | |
} | |
break; | |
case '**': | |
if (c.isCircle()) { | |
var xy = this.radius.xy(context); | |
shape = xypic.Shape.EllipseShape(x + (right - left) / 2, y + (up - down) / 2, xy.x, xy.y, false, "currentColor", undefined, color, false); | |
} else { | |
var radius = this.radius.radius(context); | |
shape = xypic.Shape.RectangleShape(x, y, left, right, up, down, radius, false, "currentColor", undefined, color, false); | |
} | |
break; | |
default: | |
return xypic.Shape.none; | |
} | |
context.appendShapeToFront(shape); | |
return shape; | |
}, | |
toConnectShape: function (context) { | |
var env = context.env; | |
var c = env.c; | |
var p = env.p; | |
if (c === undefined || p === undefined) { | |
xypic.Shape.none; | |
} | |
env.originalReferencePoint = c; | |
var tmpEnv = env.duplicate(); | |
tmpEnv.c = p.combineRect(c); | |
var tmpContext = xypic.DrawingContext(xypic.Shape.none, tmpEnv); | |
var shape = this.toDropShape(tmpContext); | |
context.appendShapeToFront(shape); | |
return shape; | |
} | |
}); | |
AST.ObjectBox.Frame.Radius.Vector.Augment({ | |
radius: function (context) { | |
return this.vector.xy(context).x; | |
}, | |
depth: function (context) { | |
return this.vector.xy(context).x; | |
}, | |
xy: function (context) { | |
return this.vector.xy(context); | |
} | |
}); | |
AST.ObjectBox.Frame.Radius.Default.Augment({ | |
radius: function (context) { | |
return 0; | |
}, | |
depth: function (context) { | |
return AST.xypic.thickness / 2; | |
}, | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:(c.l + c.r) / 2, y:(c.u + c.d) / 2 }; | |
} | |
}); | |
AST.ObjectBox.Dir.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
var c = env.c; | |
env.originalReferencePoint = c; | |
var angle = env.angle; | |
if (c === undefined) { | |
return xypic.Shape.none; | |
} | |
env.c = xypic.Frame.Point(c.x, c.y); | |
var t = AST.xypic.thickness; | |
var shape = xypic.Shape.none; | |
switch (this.main) { | |
case "": | |
return xypic.Shape.none; | |
case ">": | |
switch (this.variant) { | |
case "2": | |
shape = xypic.Shape.GT2ArrowheadShape(c, angle); | |
var r = shape.getRadius(); | |
env.c = xypic.Frame.Ellipse(c.x, c.y, r, r, r, r); | |
break; | |
case "3": | |
shape = xypic.Shape.GT3ArrowheadShape(c, angle); | |
var r = shape.getRadius(); | |
env.c = xypic.Frame.Ellipse(c.x, c.y, r, r, r, r); | |
break; | |
default: | |
if (this.variant === "^") { | |
shape = xypic.Shape.UpperGTArrowheadShape(c, angle); | |
} else if (this.variant === "_") { | |
shape = xypic.Shape.LowerGTArrowheadShape(c, angle); | |
} else { | |
shape = xypic.Shape.GTArrowheadShape(c, angle); | |
} | |
} | |
break; | |
case "<": | |
switch (this.variant) { | |
case "2": | |
shape = xypic.Shape.LT2ArrowheadShape(c, angle); | |
var r = shape.getRadius(); | |
env.c = xypic.Frame.Ellipse(c.x, c.y, r, r, r, r); | |
break; | |
case "3": | |
shape = xypic.Shape.LT3ArrowheadShape(c, angle); | |
var r = shape.getRadius(); | |
env.c = xypic.Frame.Ellipse(c.x, c.y, r, r, r, r); | |
break; | |
default: | |
if (this.variant === "^") { | |
shape = xypic.Shape.UpperLTArrowheadShape(c, angle); | |
} else if (this.variant === "_") { | |
shape = xypic.Shape.LowerLTArrowheadShape(c, angle); | |
} else { | |
shape = xypic.Shape.LTArrowheadShape(c, angle); | |
} | |
} | |
break; | |
case "|": | |
switch (this.variant) { | |
case "^": | |
shape = xypic.Shape.UpperColumnArrowheadShape(c, angle); | |
break; | |
case "_": | |
shape = xypic.Shape.LowerColumnArrowheadShape(c, angle); | |
break; | |
case "2": | |
shape = xypic.Shape.Column2ArrowheadShape(c, angle); | |
break; | |
case "3": | |
shape = xypic.Shape.Column3ArrowheadShape(c, angle); | |
break; | |
default: | |
shape = xypic.Shape.ColumnArrowheadShape(c, angle); | |
} | |
break; | |
case "(": | |
switch (this.variant) { | |
case "^": | |
shape = xypic.Shape.UpperLParenArrowheadShape(c, angle); | |
break; | |
case "_": | |
shape = xypic.Shape.LowerLParenArrowheadShape(c, angle); | |
break; | |
default: | |
shape = xypic.Shape.LParenArrowheadShape(c, angle); | |
} | |
break; | |
case ")": | |
switch (this.variant) { | |
case "^": | |
shape = xypic.Shape.UpperRParenArrowheadShape(c, angle); | |
break; | |
case "_": | |
shape = xypic.Shape.LowerRParenArrowheadShape(c, angle); | |
break; | |
default: | |
shape = xypic.Shape.RParenArrowheadShape(c, angle); | |
} | |
break; | |
case "`": | |
switch (this.variant) { | |
case "_": | |
shape = xypic.Shape.LowerBackquoteArrowheadShape(c, angle); | |
break; | |
case "^": | |
default: | |
shape = xypic.Shape.UpperBackquoteArrowheadShape(c, angle); | |
break; | |
} | |
break; | |
case "'": | |
switch (this.variant) { | |
case "_": | |
shape = xypic.Shape.LowerQuoteArrowheadShape(c, angle); | |
break; | |
case "^": | |
default: | |
shape = xypic.Shape.UpperQuoteArrowheadShape(c, angle); | |
break; | |
} | |
break; | |
case '*': | |
shape = xypic.Shape.AsteriskArrowheadShape(c, 0); | |
break; | |
case 'o': | |
shape = xypic.Shape.OArrowheadShape(c, 0); | |
break; | |
case '+': | |
shape = xypic.Shape.PlusArrowheadShape(c, angle); | |
break; | |
case 'x': | |
shape = xypic.Shape.XArrowheadShape(c, angle); | |
break; | |
case '/': | |
shape = xypic.Shape.SlashArrowheadShape(c, angle); | |
break; | |
case '-': | |
case '--': | |
var lineLen = AST.xypic.lineElementLength; | |
if (this.variant === "3") { | |
shape = xypic.Shape.Line3ArrowheadShape(c, angle); | |
} else if (this.variant === "2") { | |
shape = xypic.Shape.Line2ArrowheadShape(c, angle); | |
} else { | |
shape = xypic.Shape.LineArrowheadShape(c, angle); | |
} | |
break; | |
case '=': | |
case '==': | |
shape = xypic.Shape.Line2ArrowheadShape(c, angle); | |
break; | |
case '.': | |
case '..': | |
if (this.variant === "3") { | |
shape = xypic.Shape.Dot3ArrowheadShape(c, angle); | |
} else if (this.variant === "2") { | |
shape = xypic.Shape.Dot2ArrowheadShape(c, angle); | |
} else { | |
shape = xypic.Shape.DotArrowheadShape(c, angle); | |
} | |
break; | |
case ':': | |
case '::': | |
shape = xypic.Shape.Dot2ArrowheadShape(c, angle); | |
break; | |
case '~': | |
case '~~': | |
if (this.variant === "3") { | |
shape = xypic.Shape.Tilde3ArrowheadShape(c, angle); | |
} else if (this.variant === "2") { | |
shape = xypic.Shape.Tilde2ArrowheadShape(c, angle); | |
} else { | |
shape = xypic.Shape.TildeArrowheadShape(c, angle); | |
} | |
break; | |
case '>>': | |
switch (this.variant) { | |
case "^": | |
shape = xypic.Shape.UpperGTGTArrowheadShape(c, angle); | |
break; | |
case "_": | |
shape = xypic.Shape.LowerGTGTArrowheadShape(c, angle); | |
break; | |
case "2": | |
shape = xypic.Shape.GTGT2ArrowheadShape(c, angle); | |
var r = shape.getRadius(); | |
env.c = xypic.Frame.Ellipse(c.x, c.y, r, r, r, r); | |
break; | |
case "3": | |
shape = xypic.Shape.GTGT3ArrowheadShape(c, angle); | |
var r = shape.getRadius(); | |
env.c = xypic.Frame.Ellipse(c.x, c.y, r, r, r, r); | |
break; | |
default: | |
shape = xypic.Shape.GTGTArrowheadShape(c, angle); | |
break; | |
} | |
break; | |
case '<<': | |
switch (this.variant) { | |
case "^": | |
shape = xypic.Shape.UpperLTLTArrowheadShape(c, angle); | |
break; | |
case "_": | |
shape = xypic.Shape.LowerLTLTArrowheadShape(c, angle); | |
break; | |
case "2": | |
shape = xypic.Shape.LTLT2ArrowheadShape(c, angle); | |
var r = shape.getRadius(); | |
env.c = xypic.Frame.Ellipse(c.x, c.y, r, r, r, r); | |
break; | |
case "3": | |
shape = xypic.Shape.LTLT3ArrowheadShape(c, angle); | |
var r = shape.getRadius(); | |
env.c = xypic.Frame.Ellipse(c.x, c.y, r, r, r, r); | |
break; | |
default: | |
shape = xypic.Shape.LTLTArrowheadShape(c, angle); | |
break; | |
} | |
break; | |
case '||': | |
switch (this.variant) { | |
case "^": | |
shape = xypic.Shape.UpperColumnColumnArrowheadShape(c, angle); | |
break; | |
case "_": | |
shape = xypic.Shape.LowerColumnColumnArrowheadShape(c, angle); | |
break; | |
case "2": | |
shape = xypic.Shape.ColumnColumn2ArrowheadShape(c, angle); | |
break; | |
case "3": | |
shape = xypic.Shape.ColumnColumn3ArrowheadShape(c, angle); | |
break; | |
default: | |
shape = xypic.Shape.ColumnColumnArrowheadShape(c, angle); | |
break; | |
} | |
break; | |
case '|-': | |
switch (this.variant) { | |
case "^": | |
shape = xypic.Shape.UpperColumnLineArrowheadShape(c, angle); | |
break; | |
case "_": | |
shape = xypic.Shape.LowerColumnLineArrowheadShape(c, angle); | |
break; | |
case "2": | |
shape = xypic.Shape.ColumnLine2ArrowheadShape(c, angle); | |
break; | |
case "3": | |
shape = xypic.Shape.ColumnLine3ArrowheadShape(c, angle); | |
break; | |
default: | |
shape = xypic.Shape.ColumnLineArrowheadShape(c, angle); | |
break; | |
} | |
break; | |
case '>|': | |
shape = xypic.Shape.GTColumnArrowheadShape(c, angle); | |
break; | |
case ">>|": | |
shape = xypic.Shape.GTGTColumnArrowheadShape(c, angle); | |
break; | |
case "|<": | |
shape = xypic.Shape.ColumnLTArrowheadShape(c, angle); | |
break; | |
case "|<<": | |
shape = xypic.Shape.ColumnLTLTArrowheadShape(c, angle); | |
break; | |
case "//": | |
shape = xypic.Shape.SlashSlashArrowheadShape(c, angle); | |
break; | |
case "=>": | |
shape = xypic.Shape.LineGT2ArrowheadShape(c, angle); | |
break; | |
default: | |
var newdirObj = xypic.repositories.dirRepository.get(this.main); | |
if (newdirObj !== undefined) { | |
shape = newdirObj.toDropShape(context); | |
} else { | |
throw xypic.ExecutionError("\\dir " + this.variant + "{" + this.main + "} not defined."); | |
} | |
} | |
context.appendShapeToFront(shape); | |
return shape; | |
}, | |
toConnectShape: function (context) { | |
// 多重線の幅、点線・破線の幅の基準 | |
var env = context.env; | |
env.originalReferencePoint = env.c; | |
var t = AST.xypic.thickness; | |
var s = env.p.edgePoint(env.c.x, env.c.y); | |
var e = env.c.edgePoint(env.p.x, env.p.y); | |
if (s.x !== e.x || s.y !== e.y) { | |
var shape = xypic.Curve.Line(s, e).toShape(context, this, this.main, this.variant); | |
return shape; | |
} else { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
} | |
} | |
}); | |
AST.ObjectBox.Curve.Augment({ | |
toDropShape: function (context) { | |
var env = context.env; | |
env.originalReferencePoint = env.c; | |
return xypic.Shape.none; | |
}, | |
toConnectShape: function (context) { | |
var env = context.env; | |
env.originalReferencePoint = env.c; | |
// find object for drop and connect | |
var objectForDrop = undefined; | |
var objectForConnect = undefined; | |
this.objects.foreach(function (o) { | |
objectForDrop = o.objectForDrop(objectForDrop); | |
objectForConnect = o.objectForConnect(objectForConnect); | |
}); | |
if (objectForDrop === undefined && objectForConnect === undefined) { | |
objectForConnect = AST.Object(FP.List.empty, AST.ObjectBox.Dir("", "-")); | |
} | |
var thickness = AST.xypic.thickness; | |
var c = env.c; | |
var p = env.p; | |
var controlPoints = []; | |
this.poslist.foreach(function (p) { | |
p.addPositions(controlPoints, context); | |
// svg.createSVGElement("circle", { | |
// cx:xypic.em2px(env.c.x), cy:-xypic.em2px(env.c.y), r:xypic.em2px(thickness/2) | |
// }); | |
}); | |
env.c = c; | |
env.p = p; | |
var shape = xypic.Shape.none; | |
var s = p; | |
var e = c; | |
switch (controlPoints.length) { | |
case 0: | |
if (s.x === e.x && s.y === e.y) { | |
env.lastCurve = xypic.LastCurve.none; | |
env.angle = 0; | |
return xypic.Shape.none; | |
} | |
if (objectForConnect !== undefined) { | |
return objectForConnect.toConnectShape(context); | |
} else { | |
return objectForDrop.toConnectShape(context); | |
} | |
case 1: | |
var origBezier = xypic.Curve.QuadBezier(s, controlPoints[0], e); | |
var tOfShavedStart = origBezier.tOfShavedStart(s); | |
var tOfShavedEnd = origBezier.tOfShavedEnd(e); | |
if (tOfShavedStart === undefined || tOfShavedEnd === undefined || tOfShavedStart >= tOfShavedEnd) { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
} | |
shape = origBezier.toShape(context, objectForDrop, objectForConnect); | |
env.lastCurve = xypic.LastCurve.QuadBezier(origBezier, tOfShavedStart, tOfShavedEnd, shape); | |
env.angle = Math.atan2(e.y - s.y, e.x - s.x); | |
break; | |
case 2: | |
var origBezier = xypic.Curve.CubicBezier(s, controlPoints[0], controlPoints[1], e); | |
var tOfShavedStart = origBezier.tOfShavedStart(s); | |
var tOfShavedEnd = origBezier.tOfShavedEnd(e); | |
if (tOfShavedStart === undefined || tOfShavedEnd === undefined || tOfShavedStart >= tOfShavedEnd) { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
} | |
shape = origBezier.toShape(context, objectForDrop, objectForConnect); | |
env.lastCurve = xypic.LastCurve.CubicBezier(origBezier, tOfShavedStart, tOfShavedEnd, shape); | |
env.angle = Math.atan2(e.y - s.y, e.x - s.x); | |
break; | |
default: | |
var spline = xypic.Curve.CubicBSpline(s, controlPoints, e); | |
var origBeziers = xypic.Curve.CubicBeziers(spline.toCubicBeziers()); | |
var tOfShavedStart = origBeziers.tOfShavedStart(s); | |
var tOfShavedEnd = origBeziers.tOfShavedEnd(e); | |
if (tOfShavedStart === undefined || tOfShavedEnd === undefined || tOfShavedStart >= tOfShavedEnd) { | |
env.angle = 0; | |
env.lastCurve = xypic.LastCurve.none; | |
return xypic.Shape.none; | |
} | |
shape = origBeziers.toShape(context, objectForDrop, objectForConnect); | |
env.lastCurve = xypic.LastCurve.CubicBSpline(s, e, origBeziers, tOfShavedStart, tOfShavedEnd, shape); | |
env.angle = Math.atan2(e.y - s.y, e.x - s.x); | |
break; | |
} | |
// svg.createSVGElement("rect", { | |
// x:xypic.em2px(box.x-box.l), y:xypic.em2px(-box.y-box.u), width:xypic.em2px(box.l+box.r), height:xypic.em2px(box.u+box.d), | |
// "stroke-width":"0.02em", stroke:"green" | |
// }) | |
return shape; | |
} | |
}); | |
AST.ObjectBox.Curve.Object.Drop.Augment({ | |
objectForDrop: function (object) { | |
return this.object; | |
}, | |
objectForConnect: function (object) { | |
return object; | |
} | |
}); | |
AST.ObjectBox.Curve.Object.Connect.Augment({ | |
objectForDrop: function (object) { | |
return object; | |
}, | |
objectForConnect: function (object) { | |
return this.object; | |
} | |
}); | |
AST.ObjectBox.Curve.PosList.CurPos.Augment({ | |
addPositions: function (controlPoints, context) { | |
var env = context.env; | |
controlPoints.push(env.c); | |
} | |
}); | |
AST.ObjectBox.Curve.PosList.Pos.Augment({ | |
addPositions: function (controlPoints, context) { | |
var env = context.env; | |
this.pos.toShape(context); | |
controlPoints.push(env.c); | |
} | |
}); | |
AST.ObjectBox.Curve.PosList.AddStack.Augment({ | |
addPositions: function (controlPoints, context) { | |
context.env.stack.reverse().foreach(function (p) { | |
controlPoints.push(p); | |
}); | |
} | |
}); | |
AST.Coord.C.Augment({ | |
position: function (context) { | |
return context.env.c; | |
} | |
}); | |
AST.Coord.P.Augment({ | |
position: function (context) { | |
return context.env.p; | |
} | |
}); | |
AST.Coord.X.Augment({ | |
position: function (context) { | |
var env = context.env; | |
var p = env.p; | |
var c = env.c; | |
var o = env.origin; | |
var b = env.xBase; | |
var a0 = c.y - p.y, b0 = p.x - c.x, c0 = c.x * p.y - c.y * p.x; | |
var a1 = b.y, b1 = -b.x, c1 = b.x * o.y - b.y * o.x; | |
var d = a0 * b1 - a1 * b0; | |
if (Math.abs(d) < AST.xypic.machinePrecision) { | |
console.log("there is no intersection point."); | |
return xypic.Env.originPosition; | |
} | |
var x = -(b1 * c0 - b0 * c1)/d; | |
var y = (a1 * c0 - a0 * c1)/d; | |
return xypic.Frame.Point(x, y); | |
} | |
}); | |
AST.Coord.Y.Augment({ | |
position: function (context) { | |
var env = context.env; | |
var p = env.p; | |
var c = env.c; | |
var o = env.origin; | |
var b = env.yBase; | |
var a0 = c.y - p.y, b0 = p.x - c.x, c0 = c.x * p.y - c.y * p.x; | |
var a1 = b.y, b1 = -b.x, c1 = b.x * o.y - b.y * o.x; | |
var d = a0 * b1 - a1 * b0; | |
if (Math.abs(d) < AST.xypic.machinePrecision) { | |
console.log("there is no intersection point."); | |
return xypic.Env.originPosition; | |
} | |
var x = -(b1 * c0 - b0 * c1)/d; | |
var y = (a1 * c0 - a0 * c1)/d; | |
return xypic.Frame.Point(x, y); | |
} | |
}); | |
AST.Coord.Vector.Augment({ | |
position: function (context) { | |
var xy = this.vector.xy(context); | |
return xypic.Frame.Point(xy.x, xy.y); | |
} | |
}); | |
AST.Coord.Id.Augment({ | |
position: function (context) { | |
return context.env.lookupPos(this.id).position(context); | |
} | |
}); | |
AST.Coord.Group.Augment({ | |
position: function (context) { | |
var env = context.env; | |
var origin = env.origin; | |
var xBase = env.xBase; | |
var yBase = env.yBase; | |
var p = env.p; | |
// side effect | |
this.posDecor.toShape(context); | |
env.p = p; | |
env.origin = origin; | |
env.xBase = xBase; | |
env.yBase = yBase; | |
return env.c; | |
} | |
}); | |
AST.Coord.StackPosition.Augment({ | |
position: function (context) { | |
return context.env.stackAt(this.number); | |
} | |
}); | |
AST.Coord.DeltaRowColumn.Augment({ | |
position: function (context) { | |
var env = context.env; | |
var row = env.xymatrixRow; | |
var col = env.xymatrixCol; | |
if (row === undefined || col === undefined) { | |
throw xypic.ExecutionError("xymatrix rows and columns not found for " + this.toSring()); | |
} | |
var id = this.prefix + (row + this.dr) + "," + (col + this.dc); | |
return context.env.lookupPos(id, 'in entry "' + env.xymatrixRow + "," + env.xymatrixCol + '": No ' + this + " (is " + id + ") from here.").position(context); | |
} | |
}); | |
AST.Coord.Hops.Augment({ | |
position: function (context) { | |
var env = context.env; | |
var row = env.xymatrixRow; | |
var col = env.xymatrixCol; | |
if (row === undefined || col === undefined) { | |
throw xypic.ExecutionError("xymatrix rows and columns not found for " + this.toSring()); | |
} | |
this.hops.foreach(function (hop) { | |
switch (hop) { | |
case 'u': | |
row -= 1; | |
break; | |
case 'd': | |
row += 1; | |
break; | |
case 'l': | |
col -= 1; | |
break; | |
case 'r': | |
col += 1; | |
break; | |
} | |
}); | |
var id = this.prefix + row + "," + col; | |
return context.env.lookupPos(id, 'in entry "' + env.xymatrixRow + "," + env.xymatrixCol + '": No ' + this + " (is " + id + ") from here.").position(context); | |
} | |
}); | |
AST.Coord.HopsWithPlace.Augment({ | |
position: function (context) { | |
var env = context.env; | |
var row = env.xymatrixRow; | |
var col = env.xymatrixCol; | |
if (row === undefined || col === undefined) { | |
throw xypic.ExecutionError("xymatrix rows and columns not found for " + this.toSring()); | |
} | |
this.hops.foreach(function (hop) { | |
switch (hop) { | |
case 'u': | |
row -= 1; | |
break; | |
case 'd': | |
row += 1; | |
break; | |
case 'l': | |
col -= 1; | |
break; | |
case 'r': | |
col += 1; | |
break; | |
} | |
}); | |
var id = this.prefix + row + "," + col; | |
var pos = context.env.lookupPos(id, 'in entry "' + env.xymatrixRow + "," + env.xymatrixCol + '": No ' + this + " (is " + id + ") from here.").position(context); | |
var c = env.c; | |
var tmpEnv = env.duplicate(); | |
tmpEnv.p = env.c; | |
tmpEnv.c = pos; | |
var dx = tmpEnv.c.x - tmpEnv.p.x; | |
var dy = tmpEnv.c.y - tmpEnv.p.y; | |
var angle; | |
if (dx === 0 && dy === 0) { | |
angle = 0; | |
} else { | |
angle = Math.atan2(dy, dx); | |
} | |
tmpEnv.angle = angle; | |
var s = tmpEnv.p.edgePoint(tmpEnv.c.x, tmpEnv.c.y); | |
var e = tmpEnv.c.edgePoint(tmpEnv.p.x, tmpEnv.p.y); | |
tmpEnv.lastCurve = xypic.LastCurve.Line(s, e, tmpEnv.p, tmpEnv.c, undefined); | |
var tmpContext = xypic.DrawingContext(xypic.Shape.none, tmpEnv); | |
var t = this.place.toShape(tmpContext); | |
return tmpEnv.lastCurve.position(t); | |
} | |
}); | |
AST.Vector.InCurBase.Augment({ | |
xy: function (context) { | |
return context.env.absVector(this.x, this.y); | |
}, | |
angle: function (context) { | |
var xy = context.env.absVector(this.x, this.y); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Vector.Abs.Augment({ | |
xy: function (context) { | |
return { x:xypic.length2em(this.x), y:xypic.length2em(this.y) }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Vector.Angle.Augment({ | |
xy: function (context) { | |
var angle = Math.PI / 180 * this.degree; | |
var xy = context.env.absVector(Math.cos(angle), Math.sin(angle)); | |
return xy; | |
}, | |
angle: function (context) { | |
return Math.PI / 180 * this.degree; | |
} | |
}); | |
AST.Vector.Dir.Augment({ | |
xy: function (context) { | |
var l = xypic.length2em(this.dimen); | |
var angle = this.dir.angle(context); | |
return { x:l * Math.cos(angle), y:l * Math.sin(angle) }; | |
}, | |
angle: function (context) { | |
return this.dir.angle(context); | |
} | |
}); | |
AST.Vector.Corner.Augment({ | |
xy: function (context) { | |
var xy = this.corner.xy(context); | |
return { x:xy.x*this.factor, y:xy.y*this.factor }; | |
}, | |
angle: function (context) { | |
return this.corner.angle(context); | |
} | |
}); | |
AST.Corner.L.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:-c.l, y:0 }; | |
}, | |
angle: function (context) { | |
return Math.PI; | |
} | |
}); | |
AST.Corner.R.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:c.r, y:0 }; | |
}, | |
angle: function (context) { | |
return 0; | |
} | |
}); | |
AST.Corner.D.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:0, y:-c.d }; | |
}, | |
angle: function (context) { | |
return -Math.PI / 2; | |
} | |
}); | |
AST.Corner.U.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:0, y:c.u }; | |
}, | |
angle: function (context) { | |
return Math.PI / 2; | |
} | |
}); | |
AST.Corner.CL.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:-c.l, y:(c.u - c.d) / 2 }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Corner.CR.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:c.r, y:(c.u - c.d) / 2 }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Corner.CD.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:(c.r-c.l)/2, y:-c.d }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Corner.CU.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:(c.r-c.l)/2, y:c.u }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Corner.LU.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:-c.l, y:c.u }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Corner.LD.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:-c.l, y:-c.d }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Corner.RU.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:c.r, y:c.u }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Corner.RD.Augment({ | |
xy: function (context) { | |
var c = context.env.c; | |
return { x:c.r, y:-c.d }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Corner.NearestEdgePoint.Augment({ | |
xy: function (context) { | |
var env = context.env; | |
var c = env.c; | |
var e = c.edgePoint(env.p.x, env.p.y); | |
return { x:e.x - c.x, y:e.y - c.y }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Corner.PropEdgePoint.Augment({ | |
xy: function (context) { | |
var env = context.env; | |
var c = env.c; | |
var e = c.proportionalEdgePoint(env.p.x, env.p.y); | |
return { x:e.x - c.x, y:e.y - c.y }; | |
}, | |
angle: function (context) { | |
var xy = this.xy(context); | |
return Math.atan2(xy.y, xy.x); | |
} | |
}); | |
AST.Corner.Axis.Augment({ | |
xy: function (context) { | |
return { x:0, y:AST.xypic.axisHeightLength }; | |
}, | |
angle: function (context) { | |
return Math.PI / 2; | |
} | |
}); | |
AST.Modifier.Augment({ | |
proceedModifyShape: function (context, objectShape, restModifiers) { | |
if (restModifiers.isEmpty) { | |
return objectShape; | |
} else { | |
return restModifiers.head.modifyShape(context, objectShape, restModifiers.tail); | |
} | |
} | |
}); | |
AST.Modifier.Vector.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var d = this.vector.xy(context); | |
var env = context.env; | |
env.c = env.c.shiftFrame(-d.x, -d.y); | |
objectShape = xypic.Shape.TranslateShape(-d.x, -d.y, objectShape); | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.RestoreOriginalRefPoint.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var env = context.env; | |
var origRefPoint = env.originalReferencePoint; | |
if (origRefPoint !== undefined) { | |
var dx = env.c.x - origRefPoint.x; | |
var dy = env.c.y - origRefPoint.y; | |
env.c = env.c.shiftFrame(dx, dy); | |
objectShape = xypic.Shape.TranslateShape(dx, dy, objectShape); | |
} | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Shape.Point.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var c = context.env.c; | |
context.env.c = xypic.Frame.Point(c.x, c.y); | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Shape.Rect.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var c = context.env.c; | |
context.env.c = xypic.Frame.Rect(c.x, c.y, { l:c.l, r:c.r, u:c.u, d:c.d }); | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Shape.Circle.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var c = context.env.c; | |
context.env.c = xypic.Frame.Ellipse(c.x, c.y, c.l, c.r, c.u, c.d); | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Shape.L.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var env = context.env; | |
var c = env.c; | |
if (c !== undefined) { | |
var width = c.r + c.l; | |
var height = c.u + c.d; | |
var dx, dy; | |
if (width < height) { | |
dx = (c.l - c.r) / 2; | |
dy = (c.d - c.u) / 2; | |
} else { | |
dx = -c.r + height / 2; | |
dy = (c.d - c.u) / 2; | |
} | |
env.c = env.c.shiftFrame(dx, dy); | |
objectShape = xypic.Shape.TranslateShape(dx, dy, objectShape); | |
} | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Shape.R.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var env = context.env; | |
var c = env.c; | |
if (c !== undefined) { | |
var width = c.r + c.l; | |
var height = c.u + c.d; | |
var dx, dy; | |
if (width < height) { | |
dx = (c.l - c.r) / 2; | |
dy = (c.d - c.u) / 2; | |
} else { | |
dx = c.l - height / 2; | |
dy = (c.d - c.u) / 2; | |
} | |
env.c = env.c.shiftFrame(dx, dy); | |
objectShape = xypic.Shape.TranslateShape(dx, dy, objectShape); | |
} | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Shape.U.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var env = context.env; | |
var c = env.c; | |
if (c !== undefined) { | |
var width = c.r + c.l; | |
var height = c.u + c.d; | |
var dx, dy; | |
if (width > height) { | |
dx = (c.l - c.r) / 2; | |
dy = (c.d - c.u) / 2; | |
} else { | |
dx = (c.l - c.r) / 2; | |
dy = c.d - width / 2; | |
} | |
env.c = env.c.shiftFrame(dx, dy); | |
objectShape = xypic.Shape.TranslateShape(dx, dy, objectShape); | |
} | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Shape.D.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var env = context.env; | |
var c = env.c; | |
if (c !== undefined) { | |
var width = c.r + c.l; | |
var height = c.u + c.d; | |
var dx, dy; | |
if (width > height) { | |
dx = (c.l - c.r) / 2; | |
dy = (c.d - c.u) / 2; | |
} else { | |
dx = (c.l - c.r) / 2; | |
dy = -c.u + width / 2; | |
} | |
env.c = env.c.shiftFrame(dx, dy); | |
objectShape = xypic.Shape.TranslateShape(dx, dy, objectShape); | |
} | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Shape.C.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var env = context.env; | |
var c = env.c; | |
if (c !== undefined) { | |
var dx, dy; | |
dx = (c.l - c.r) / 2; | |
dy = (c.d - c.u) / 2; | |
env.c = env.c.shiftFrame(dx, dy); | |
objectShape = xypic.Shape.TranslateShape(dx, dy, objectShape); | |
} | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Shape.ChangeColor.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
objectShape = this.proceedModifyShape(context, objectShape, restModifiers); | |
return xypic.Shape.ChangeColorShape(this.colorName, objectShape); | |
} | |
}); | |
AST.Modifier.Shape.Alphabets.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
var modifier = xypic.repositories.modifierRepository.get(this.alphabets); | |
if (modifier !== undefined) { | |
return modifier.preprocess(context, reversedProcessedModifiers); | |
} else { | |
// TODO 存在しないshape名が指定されたらエラーを発生させる。 | |
} | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var modifier = xypic.repositories.modifierRepository.get(this.alphabets); | |
if (modifier !== undefined) { | |
return modifier.modifyShape(context, objectShape, restModifiers); | |
} | |
} | |
}); | |
AST.Modifier.Shape.DefineShape.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
var processedModifiers = reversedProcessedModifiers.reverse(); | |
xypic.repositories.modifierRepository.put(this.shape, AST.Modifier.Shape.CompositeModifiers(processedModifiers)); | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
// ユーザ定義されたshape | |
AST.Modifier.Shape.CompositeModifiers.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
this.modifiers.foreach(function (m) { | |
m.preprocess(context, reversedProcessedModifiers); | |
reversedProcessedModifiers = reversedProcessedModifiers.prepend(m); | |
}); | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
objectShape = this.proceedModifyShape(context, objectShape, this.modifiers); | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Invisible.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
objectShape = this.proceedModifyShape(context, objectShape, restModifiers); | |
return xypic.Shape.none; | |
} | |
}); | |
AST.Modifier.Hidden.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
// TODO implement hidden modifier | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Direction.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
context.env.angle = this.direction.angle(context); | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
context.env.angle = this.direction.angle(context); | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.AddOp.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var c = context.env.c; | |
context.env.c = this.op.apply(this.size, c, context); | |
context.appendShapeToFront(xypic.Shape.InvisibleBoxShape(context.env.c)); | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.AddOp.Grow.Augment({ | |
apply: function (size, c, context) { | |
var env = context.env; | |
var margin = (size.isDefault? | |
{ x:2 * env.objectmargin, y:2 * env.objectmargin }: | |
size.vector.xy(context)); | |
var xMargin = Math.abs(margin.x / 2); | |
var yMargin = Math.abs(margin.y / 2); | |
return c.grow(xMargin, yMargin); | |
}, | |
applyToDimen: function (lhsEm, rhsEm) { | |
return lhsEm + rhsEm; | |
} | |
}); | |
AST.Modifier.AddOp.Shrink.Augment({ | |
apply: function (size, c, context) { | |
var env = context.env; | |
var margin = (size.isDefault? | |
{ x:2 * env.objectmargin, y:2 * env.objectmargin }: | |
size.vector.xy(context)); | |
var xMargin = -Math.abs(margin.x / 2); | |
var yMargin = -Math.abs(margin.y / 2); | |
return c.grow(xMargin, yMargin); | |
}, | |
applyToDimen: function (lhsEm, rhsEm) { | |
return lhsEm - rhsEm; | |
} | |
}); | |
AST.Modifier.AddOp.Set.Augment({ | |
apply: function (size, c, context) { | |
var env = context.env; | |
var margin = (size.isDefault? | |
{ x:env.objectwidth, y:env.objectheight }: | |
size.vector.xy(context)); | |
var width = Math.abs(margin.x); | |
var height = Math.abs(margin.y); | |
return c.toSize(width, height); | |
}, | |
applyToDimen: function (lhsEm, rhsEm) { | |
return rhsEm; | |
} | |
}); | |
AST.Modifier.AddOp.GrowTo.Augment({ | |
apply: function (size, c, context) { | |
var l = Math.max(c.l + c.r, c.u + c.d); | |
var margin = (size.isDefault? { x:l, y:l } : size.vector.xy(context)); | |
var width = Math.abs(margin.x); | |
var height = Math.abs(margin.y); | |
return c.growTo(width, height); | |
}, | |
applyToDimen: function (lhsEm, rhsEm) { | |
return Math.max(Math.max(lhsEm, rhsEm), 0); | |
} | |
}); | |
AST.Modifier.AddOp.ShrinkTo.Augment({ | |
apply: function (size, c, context) { | |
var l = Math.min(c.l + c.r, c.u + c.d); | |
var margin = (size.isDefault? { x:l, y:l } : size.vector.xy(context)); | |
var width = Math.abs(margin.x); | |
var height = Math.abs(margin.y); | |
return c.shrinkTo(width, height); | |
}, | |
applyToDimen: function (lhsEm, rhsEm) { | |
return Math.max(Math.min(lhsEm, rhsEm), 0); | |
} | |
}); | |
AST.Modifier.Shape.Frame.Augment({ | |
preprocess: function (context, reversedProcessedModifiers) { | |
}, | |
modifyShape: function (context, objectShape, restModifiers) { | |
var env = context.env; | |
if (env.c !== undefined) { | |
var main = this.main; | |
var radius = AST.ObjectBox.Frame.Radius.Default(); | |
var colorName = "currentColor"; | |
this.options.foreach(function (op) { radius = op.getRadius(radius); }); | |
this.options.foreach(function (op) { colorName = op.getColorName(colorName); }); | |
var dummyEnv = env.duplicate(); | |
var dummyContext = xypic.DrawingContext(xypic.Shape.none, dummyEnv); | |
var frameObject = AST.ObjectBox.Frame(radius, this.main); | |
var frameShape = frameObject.toDropFilledShape(dummyContext, colorName, env.c.isCircle()); | |
objectShape = xypic.Shape.CompositeShape(objectShape, frameShape); | |
} | |
return this.proceedModifyShape(context, objectShape, restModifiers); | |
} | |
}); | |
AST.Modifier.Shape.Frame.Radius.Augment({ | |
getRadius: function (radius) { | |
return AST.ObjectBox.Frame.Radius.Vector(this.vector); | |
}, | |
getColorName: function (colorName) { | |
return colorName; | |
} | |
}); | |
AST.Modifier.Shape.Frame.Color.Augment({ | |
getRadius: function (radius) { | |
return radius; | |
}, | |
getColorName: function (colorName) { | |
return this.colorName; | |
} | |
}); | |
AST.Direction.Compound.Augment({ | |
angle: function (context) { | |
var angle = this.dir.angle(context); | |
this.rots.foreach(function (rot) { angle = rot.rotate(angle, context); }); | |
return angle; | |
} | |
}); | |
AST.Direction.Diag.Augment({ | |
angle: function (context) { | |
return this.diag.angle(context); | |
} | |
}); | |
AST.Direction.Vector.Augment({ | |
angle: function (context) { | |
return this.vector.angle(context); | |
} | |
}); | |
AST.Direction.ConstructVector.Augment({ | |
angle: function (context) { | |
var env = context.env; | |
var origin = env.origin; | |
var xBase = env.xBase; | |
var yBase = env.yBase; | |
var p = env.p; | |
var c = env.c; | |
// side effect | |
this.posDecor.toShape(context); | |
var angle = Math.atan2(env.c.y - env.p.y, env.c.x - env.p.x); | |
env.c = c; | |
env.p = p; | |
env.origin = origin; | |
env.xBase = xBase; | |
env.yBase = yBase; | |
return angle; | |
} | |
}); | |
AST.Direction.RotVector.Augment({ | |
rotate: function (angle, context) { | |
return angle + this.vector.angle(context); | |
} | |
}); | |
AST.Direction.RotCW.Augment({ | |
rotate: function (angle, context) { | |
return angle + Math.PI /2; | |
} | |
}); | |
AST.Direction.RotAntiCW.Augment({ | |
rotate: function (angle, context) { | |
return angle - Math.PI / 2; | |
} | |
}); | |
AST.Diag.Default.Augment({ | |
isEmpty: true, | |
angle: function (context) { | |
return context.env.angle; | |
} | |
}); | |
AST.Diag.Angle.Augment({ | |
isEmpty: false, | |
angle: function (context) { | |
return this.ang; | |
} | |
}); | |
AST.Decor.Augment({ | |
toShape: function (context) { | |
this.commands.foreach(function (c) { | |
c.toShape(context); | |
}); | |
} | |
}); | |
AST.Command.Save.Augment({ | |
toShape: function (context) { | |
context.env.saveState(); | |
this.pos.toShape(context); | |
} | |
}); | |
AST.Command.Restore.Augment({ | |
toShape: function (context) { | |
context.env.restoreState(); | |
} | |
}); | |
AST.Command.Pos.Augment({ | |
toShape: function (context) { | |
this.pos.toShape(context); | |
} | |
}); | |
AST.Command.AfterPos.Augment({ | |
toShape: function (context) { | |
this.pos.toShape(context); | |
this.decor.toShape(context); | |
} | |
}); | |
AST.Command.Drop.Augment({ | |
toShape: function (context) { | |
this.object.toDropShape(context); | |
} | |
}); | |
AST.Command.Connect.Augment({ | |
toShape: function (context) { | |
this.object.toConnectShape(context); | |
} | |
}); | |
AST.Command.Relax.Augment({ | |
toShape: function (context) { | |
// do nothing | |
} | |
}); | |
AST.Command.Ignore.Augment({ | |
toShape: function (context) { | |
// do nothing | |
} | |
}); | |
AST.Command.ShowAST.Augment({ | |
toShape: function (context) { | |
console.log(this.pos.toString() + " " + this.decor); | |
} | |
}); | |
AST.Command.Ar.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var origin = env.origin; | |
var xBase = env.xBase; | |
var yBase = env.yBase; | |
var p = env.p; | |
var c = env.c; | |
env.pathActionForBeforeSegment = FP.Option.empty; | |
env.pathActionForAfterSegment = FP.Option.empty; | |
env.labelsForNextSegmentOnly = FP.Option.empty; | |
env.labelsForLastSegmentOnly = FP.Option.empty; | |
env.labelsForEverySegment = FP.Option.empty; | |
env.segmentSlideEm = FP.Option.empty; | |
env.lastTurnDiag = FP.Option.empty; | |
env.arrowVariant = ""; | |
env.tailTip = AST.Command.Ar.Form.Tip.Tipchars(""); | |
env.headTip = AST.Command.Ar.Form.Tip.Tipchars(">"); | |
env.stemConn = AST.Command.Ar.Form.Conn.Connchars("-"); | |
env.reverseAboveAndBelow = false; | |
env.arrowObjectModifiers = FP.List.empty; | |
this.forms.foreach(function (f) { f.toShape(context); }); | |
if (!env.pathActionForBeforeSegment.isDefined) { | |
// the following AST means **\dir{stem}. | |
env.pathActionForBeforeSegment = FP.Option.Some( | |
AST.PosDecor( | |
AST.Pos.Coord( | |
AST.Coord.C(), | |
FP.List.empty.append( | |
AST.Pos.ConnectObject( | |
AST.Object( | |
env.arrowObjectModifiers, | |
env.stemConn.getObject(context) | |
) | |
) | |
) | |
), | |
AST.Decor(FP.List.empty) | |
) | |
); | |
} | |
env.labelsForNextSegmentOnly = FP.Option.Some( | |
AST.Command.Path.Labels( | |
FP.List.empty.append( | |
AST.Command.Path.Label.At( | |
AST.Pos.Place(AST.Place(1, 1, AST.Place.Factor(0), AST.Slide(FP.Option.empty))), | |
env.tailTip.getObject(context), | |
FP.Option.empty | |
) | |
) | |
) | |
); | |
// arrow head | |
env.labelsForLastSegmentOnly = FP.Option.Some( | |
AST.Command.Path.Labels( | |
FP.List.empty.append( | |
AST.Command.Path.Label.At( | |
AST.Pos.Place(AST.Place(1, 1, AST.Place.Factor(1), AST.Slide(FP.Option.empty))), | |
env.headTip.getObject(context), | |
FP.Option.empty | |
) | |
) | |
) | |
); | |
this.path.toShape(context); | |
env.c = c; | |
env.p = p; | |
env.origin = origin; | |
env.xBase = xBase; | |
env.yBase = yBase; | |
} | |
}); | |
AST.Command.Ar.Form.BuildArrow.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.arrowVariant = this.variant; | |
env.tailTip = this.tailTip; | |
env.stemConn = this.stemConn; | |
env.headTip = this.headTip; | |
} | |
}); | |
AST.Command.Ar.Form.ChangeVariant.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.arrowVariant = this.variant; | |
} | |
}); | |
AST.Command.Ar.Form.ChangeStem.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.stemConn = AST.Command.Ar.Form.Conn.Connchars(this.connchar); | |
} | |
}); | |
AST.Command.Ar.Form.DashArrowStem.Augment({ | |
toShape: function (context) { | |
// TODO impl | |
} | |
}); | |
AST.Command.Ar.Form.CurveArrow.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var cpDist = xypic.em2length(xypic.length2em(this.dist) * 2); | |
// the following AST means **\crv{{**@{} ?+/d 2l/}}. too long... | |
env.pathActionForBeforeSegment = FP.Option.Some( | |
AST.PosDecor( | |
AST.Pos.Coord( | |
AST.Coord.C(), | |
FP.List.empty.append( | |
AST.Pos.ConnectObject(AST.Object(env.arrowObjectModifiers, AST.ObjectBox.Curve( | |
FP.List.empty, | |
FP.List.empty.append( | |
AST.ObjectBox.Curve.Object.Connect( | |
env.stemConn.getObject(context) | |
) | |
), | |
FP.List.empty.append( | |
AST.ObjectBox.Curve.PosList.Pos( | |
AST.Pos.Coord( | |
AST.Coord.Group( | |
AST.PosDecor( | |
AST.Pos.Coord( | |
AST.Coord.C(), | |
FP.List.empty.append( | |
AST.Pos.ConnectObject( | |
AST.Object( | |
FP.List.empty, | |
AST.ObjectBox.Dir("", "") | |
) | |
) | |
).append( | |
AST.Pos.Place( | |
AST.Place(0, 0, undefined, AST.Slide(FP.Option.empty)) | |
) | |
).append( | |
AST.Pos.Plus( | |
AST.Coord.Vector( | |
AST.Vector.Dir(this.direction, cpDist) | |
) | |
) | |
) | |
), | |
AST.Decor(FP.List.empty) | |
) | |
), | |
FP.List.empty | |
) | |
) | |
) | |
))) | |
) | |
), | |
AST.Decor(FP.List.empty) | |
) | |
); | |
} | |
}); | |
AST.Command.Ar.Form.CurveFitToDirection.Augment({ | |
toShape: function (context) { | |
// the following AST means **\crv{;+/outdir 3pc/ & ;+/indir 3pc/}. | |
var env = context.env; | |
env.pathActionForBeforeSegment = FP.Option.Some( | |
AST.PosDecor( | |
AST.Pos.Coord( | |
AST.Coord.C(), | |
FP.List.empty.append( | |
AST.Pos.ConnectObject(AST.Object(env.arrowObjectModifiers, AST.ObjectBox.Curve( | |
FP.List.empty, | |
FP.List.empty.append( | |
AST.ObjectBox.Curve.Object.Connect( | |
env.stemConn.getObject(context) | |
) | |
), | |
FP.List.empty.append( | |
AST.ObjectBox.Curve.PosList.Pos( | |
AST.Pos.Coord( | |
AST.Coord.C(), | |
FP.List.empty.append( | |
AST.Pos.SwapPAndC( | |
AST.Coord.C() | |
) | |
).append( | |
AST.Pos.Plus( | |
AST.Coord.Vector(AST.Vector.Dir(this.outDirection, "3pc")) | |
) | |
) | |
) | |
) | |
).append( | |
AST.ObjectBox.Curve.PosList.Pos( | |
AST.Pos.Coord( | |
AST.Coord.C(), | |
FP.List.empty.append( | |
AST.Pos.SwapPAndC( | |
AST.Coord.C() | |
) | |
).append( | |
AST.Pos.Plus( | |
AST.Coord.Vector(AST.Vector.Dir(this.inDirection, "3pc")) | |
) | |
) | |
) | |
) | |
) | |
))) | |
) | |
), | |
AST.Decor(FP.List.empty) | |
) | |
); | |
} | |
}); | |
AST.Command.Ar.Form.CurveWithControlPoints.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
tmpEnv = env.duplicate(); | |
tmpEnv.startCapturePositions(); | |
var tmpContext = xypic.DrawingContext(xypic.Shape.none, tmpEnv); | |
this.coord.position(tmpContext); | |
var positions = tmpEnv.endCapturePositions(); | |
positions = positions.append(tmpEnv.c); | |
var points = FP.List.empty; | |
positions.reverse().foreach(function (pos) { | |
var xy = env.inverseAbsVector(pos.x, pos.y); | |
points = points.prepend(AST.ObjectBox.Curve.PosList.Pos( | |
AST.Pos.Coord( | |
AST.Coord.Vector(AST.Vector.InCurBase(xy.x, xy.y)), | |
FP.List.empty | |
) | |
)); | |
}); | |
// the following AST means **\crv{ control points }. | |
env.pathActionForBeforeSegment = FP.Option.Some( | |
AST.PosDecor( | |
AST.Pos.Coord( | |
AST.Coord.C(), | |
FP.List.empty.append( | |
AST.Pos.ConnectObject(AST.Object(env.arrowObjectModifiers, AST.ObjectBox.Curve( | |
FP.List.empty, | |
FP.List.empty.append( | |
AST.ObjectBox.Curve.Object.Connect( | |
env.stemConn.getObject(context) | |
) | |
), | |
points | |
))) | |
) | |
), | |
AST.Decor(FP.List.empty) | |
) | |
); | |
} | |
}); | |
AST.Command.Ar.Form.AddShape.Augment({ | |
toShape: function (context) { | |
context.env.arrowObjectModifiers = FP.List.empty.append(this.shape); | |
} | |
}); | |
AST.Command.Ar.Form.AddModifiers.Augment({ | |
toShape: function (context) { | |
context.env.arrowObjectModifiers = this.modifiers; | |
} | |
}); | |
AST.Command.Ar.Form.Slide.Augment({ | |
toShape: function (context) { | |
context.env.segmentSlideEm = FP.Option.Some(xypic.length2em(this.slideDimen)); | |
} | |
}); | |
AST.Command.Ar.Form.LabelAt.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.labelsForEverySegment = FP.Option.Some( | |
AST.Command.Path.Labels( | |
FP.List.empty.append( | |
AST.Command.Path.Label.At( | |
AST.Pos.Place(this.anchor), this.it, FP.Option.empty | |
) | |
) | |
) | |
); | |
} | |
}); | |
AST.Command.Ar.Form.LabelAbove.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var label; | |
if (env.reverseAboveAndBelow) { | |
label = AST.Command.Path.Label.Below( | |
AST.Pos.Place(this.anchor), this.it, FP.Option.empty | |
); | |
} else { | |
label = AST.Command.Path.Label.Above( | |
AST.Pos.Place(this.anchor), this.it, FP.Option.empty | |
); | |
} | |
env.labelsForEverySegment = FP.Option.Some( | |
AST.Command.Path.Labels(FP.List.empty.append(label)) | |
); | |
} | |
}); | |
AST.Command.Ar.Form.LabelBelow.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var label; | |
if (env.reverseAboveAndBelow) { | |
label = AST.Command.Path.Label.Above( | |
AST.Pos.Place(this.anchor), this.it, FP.Option.empty | |
); | |
} else { | |
label = AST.Command.Path.Label.Below( | |
AST.Pos.Place(this.anchor), this.it, FP.Option.empty | |
); | |
} | |
env.labelsForEverySegment = FP.Option.Some( | |
AST.Command.Path.Labels(FP.List.empty.append(label)) | |
); | |
} | |
}); | |
AST.Command.Ar.Form.ReverseAboveAndBelow.Augment({ | |
toShape: function (context) { | |
context.env.reverseAboveAndBelow = true; | |
} | |
}); | |
AST.Command.Ar.Form.Conn.Connchars.Augment({ | |
getObject: function (context) { | |
var env = context.env; | |
var dir = AST.ObjectBox.Dir(env.arrowVariant, this.connchars); | |
return AST.Object(env.arrowObjectModifiers, dir); | |
} | |
}); | |
AST.Command.Ar.Form.Conn.Object.Augment({ | |
getObject: function (context) { | |
var modifiers = context.env.arrowObjectModifiers.concat(this.object.modifiers); | |
return AST.Object(modifiers, this.object.object); | |
} | |
}); | |
AST.Command.Ar.Form.Conn.Dir.Augment({ | |
getObject: function (context) { | |
var env = context.env; | |
var thisDir = this.dir; | |
var dir = thisDir; | |
if (thisDir.variant === "" && env.arrowVariant !== "") { | |
dir = AST.ObjectBox.Dir(env.arrowVariant, thisDir.main); | |
} | |
return AST.Object(env.arrowObjectModifiers, dir); | |
} | |
}); | |
AST.Command.Ar.Form.Tip.Tipchars.Augment({ | |
getObject: function (context) { | |
var env = context.env; | |
var dir = AST.ObjectBox.Dir(env.arrowVariant, this.tipchars); | |
return AST.Object(env.arrowObjectModifiers, dir); | |
} | |
}); | |
AST.Command.Ar.Form.Tip.Object.Augment({ | |
getObject: function (context) { | |
var modifiers = context.env.arrowObjectModifiers.concat(this.object.modifiers); | |
return AST.Object(modifiers, this.object.object); | |
} | |
}); | |
AST.Command.Ar.Form.Tip.Dir.Augment({ | |
getObject: function (context) { | |
var env = context.env; | |
var thisDir = this.dir; | |
var dir = thisDir; | |
if (thisDir.variant === "" && env.arrowVariant !== "") { | |
dir = AST.ObjectBox.Dir(env.arrowVariant, thisDir.main); | |
} | |
return AST.Object(env.arrowObjectModifiers, dir); | |
} | |
}); | |
AST.Command.Path.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var origin = env.origin; | |
var xBase = env.xBase; | |
var yBase = env.yBase; | |
var p = env.p; | |
var c = env.c; | |
env.pathActionForBeforeSegment = FP.Option.empty; | |
env.pathActionForAfterSegment = FP.Option.empty; | |
env.labelsForNextSegmentOnly = FP.Option.empty; | |
env.labelsForLastSegmentOnly = FP.Option.empty; | |
env.labelsForEverySegment = FP.Option.empty; | |
env.segmentSlideEm = FP.Option.empty; | |
env.lastTurnDiag = FP.Option.empty; | |
this.path.toShape(context); | |
env.c = c; | |
env.p = p; | |
env.origin = origin; | |
env.xBase = xBase; | |
env.yBase = yBase; | |
} | |
}); | |
AST.Command.AfterPath.Augment({ | |
toShape: function (context) { | |
this.path.toShape(context); | |
this.decor.toShape(context); | |
} | |
}); | |
AST.Command.Path.Path.Augment({ | |
toShape: function (context) { | |
this.pathElements.foreach(function (e) { | |
e.toShape(context); | |
}); | |
} | |
}); | |
AST.Command.Path.SetBeforeAction.Augment({ | |
toShape: function (context) { | |
context.env.pathActionForBeforeSegment = FP.Option.Some(this.posDecor); | |
} | |
}); | |
AST.Command.Path.SetAfterAction.Augment({ | |
toShape: function (context) { | |
context.env.pathActionForAfterSegment = FP.Option.Some(this.posDecor); | |
} | |
}); | |
AST.Command.Path.AddLabelNextSegmentOnly.Augment({ | |
toShape: function (context) { | |
context.env.labelsForNextSegmentOnly = FP.Option.Some(this.labels); | |
} | |
}); | |
AST.Command.Path.AddLabelLastSegmentOnly.Augment({ | |
toShape: function (context) { | |
context.env.labelsForLastSegmentOnly = FP.Option.Some(this.labels); | |
} | |
}); | |
AST.Command.Path.AddLabelEverySegment.Augment({ | |
toShape: function (context) { | |
context.env.labelsForEverySegment = FP.Option.Some(this.labels); | |
} | |
}); | |
AST.Command.Path.StraightSegment.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
this.segment.setupPositions(context); | |
var c = env.c; | |
env.pathActionForBeforeSegment.foreach(function (action) { | |
action.toShape(context); | |
}); | |
env.labelsForNextSegmentOnly.foreach(function (labels) { | |
labels.toShape(context); | |
env.labelsForNextSegmentOnly = FP.Option.empty; | |
}); | |
env.labelsForEverySegment.foreach(function (labels) { | |
labels.toShape(context); | |
}); | |
env.c = c; | |
env.pathActionForAfterSegment.foreach(function (action) { | |
action.toShape(context); | |
}); | |
this.segment.toLabelsShape(context); | |
} | |
}); | |
AST.Command.Path.LastSegment.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
this.segment.setupPositions(context); | |
var c = env.c; | |
env.pathActionForBeforeSegment.foreach(function (action) { | |
action.toShape(context); | |
}); | |
env.labelsForNextSegmentOnly.foreach(function (labels) { | |
labels.toShape(context); | |
env.labelsForNextSegmentOnly = FP.Option.empty; | |
}); | |
env.labelsForLastSegmentOnly.foreach(function (labels) { | |
labels.toShape(context); | |
env.labelsForNextSegmentOnly = FP.Option.empty; | |
}); | |
env.labelsForEverySegment.foreach(function (labels) { | |
labels.toShape(context); | |
}); | |
env.c = c; | |
env.pathActionForAfterSegment.foreach(function (action) { | |
action.toShape(context); | |
}); | |
this.segment.toLabelsShape(context); | |
} | |
}); | |
AST.Command.Path.TurningSegment.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var p = env.c; | |
this.segment.pos.toShape(context); | |
env.p = p; | |
var circle = this.turn.explicitizedCircle(context); | |
var r = this.turn.radius.radius(context); | |
env.lastTurnDiag = FP.Option.Some(circle.endDiag); | |
var sv = circle.startVector(context); | |
var ev = circle.endVector(context); | |
var slideEm = env.segmentSlideEm.getOrElse(0); | |
this.segment.slide.dimen.foreach(function (d) { | |
slideEm = xypic.length2em(d); | |
env.segmentSlideEm = FP.Option.Some(slideEm); | |
}); | |
if (slideEm !== 0) { | |
env.p = env.p.move( | |
env.p.x - slideEm * sv.y, | |
env.p.y + slideEm * sv.x); | |
env.c = env.c.move( | |
env.c.x - slideEm * ev.y, | |
env.c.y + slideEm * ev.x); | |
if (circle.orient === "^") { | |
r = Math.max(0, r - slideEm); | |
} else { | |
r = Math.max(0, r + slideEm); | |
} | |
} | |
var s = env.p.edgePoint(env.p.x + sv.x, env.p.y + sv.y); | |
var e = env.c; | |
var ds = circle.relativeStartPoint(context, r); | |
var de = circle.relativeEndPoint(context, r); | |
var deo = circle.relativeEndPoint(context, r + (circle.orient === "^"? slideEm : -slideEm)); | |
var t; | |
var det = sv.x * ev.y - sv.y * ev.x; | |
if (Math.abs(det) < AST.xypic.machinePrecision) { | |
t = 0; | |
} else { | |
var dx = e.x - s.x + ds.x - de.x; | |
var dy = e.y - s.y + ds.y - de.y; | |
t = (ev.y * dx - ev.x * dy)/det; | |
if (t < 0) { t = 0; } | |
} | |
var x = s.x - ds.x + t * sv.x; | |
var y = s.y - ds.y + t * sv.y; | |
var circleShape = circle.toDropShape(context, x, y, r); | |
var c = xypic.Frame.Point(x + deo.x, y + deo.y); | |
env.c = xypic.Frame.Point(x + ds.x, y + ds.y); | |
env.pathActionForBeforeSegment.foreach(function (action) { | |
action.toShape(context); | |
}); | |
env.labelsForNextSegmentOnly.foreach(function (labels) { | |
labels.toShape(context); | |
env.labelsForNextSegmentOnly = FP.Option.empty; | |
}); | |
env.labelsForEverySegment.foreach(function (labels) { | |
labels.toShape(context); | |
}); | |
env.c = c; | |
env.pathActionForAfterSegment.foreach(function (action) { | |
action.toShape(context); | |
}); | |
this.segment.toLabelsShape(context); | |
} | |
}); | |
AST.Command.Path.Turn.Cir.Augment({ | |
explicitizedCircle: function (context) { | |
var env = context.env; | |
var startDiag, orient, endDiag; | |
if (this.cir.startDiag.isEmpty) { | |
startDiag = env.lastTurnDiag.getOrElse(AST.Diag.R()); | |
} else { | |
startDiag = this.cir.startDiag; | |
} | |
orient = this.cir.orient; | |
if (this.cir.endDiag.isEmpty) { | |
endDiag = startDiag.turn(orient); | |
} else { | |
endDiag = this.cir.endDiag; | |
} | |
return AST.ObjectBox.Cir.Cir.Segment(startDiag, orient, endDiag); | |
} | |
}); | |
AST.ObjectBox.Cir.Cir.Segment.Augment({ | |
startVector: function (context) { | |
var angle = this.startDiag.angle(context); | |
return { x:Math.cos(angle), y:Math.sin(angle) }; | |
}, | |
endVector: function (context) { | |
var angle = this.endDiag.angle(context); | |
return { x:Math.cos(angle), y:Math.sin(angle) }; | |
}, | |
relativeStartPointAngle: function (context) { | |
return this.startPointDegree(context) / 180 * Math.PI; | |
}, | |
relativeStartPoint: function (context, r) { | |
var angle = this.startPointDegree(context) / 180 * Math.PI; | |
return { x:r * Math.cos(angle), y:r * Math.sin(angle) }; | |
}, | |
relativeEndPoint: function (context, r) { | |
var angle; | |
angle = this.endPointDegree(context, this.relativeStartPointAngle(context)) / 180 * Math.PI; | |
return { x:r * Math.cos(angle), y:r * Math.sin(angle) }; | |
} | |
}); | |
AST.Command.Path.Turn.Diag.Augment({ | |
explicitizedCircle: function (context) { | |
var env = context.env; | |
var startDiag, orient, endDiag; | |
if (this.diag.isEmpty) { | |
startDiag = env.lastTurnDiag.getOrElse(AST.Diag.R()); | |
} else { | |
startDiag = this.diag; | |
} | |
var angle = startDiag.angle(context); | |
var det = (env.c.x - env.p.x) * Math.sin(angle) - (env.c.y - env.p.y) * Math.cos(angle); | |
orient = (det < 0? "^" : "_"); | |
endDiag = startDiag.turn(orient); | |
return AST.ObjectBox.Cir.Cir.Segment(startDiag, orient, endDiag); | |
} | |
}); | |
AST.Command.Path.TurnRadius.Default.Augment({ | |
radius: function (context) { | |
return AST.xypic.turnradius; | |
} | |
}); | |
AST.Command.Path.TurnRadius.Dimen.Augment({ | |
radius: function (context) { | |
return xypic.length2em(this.dimen); | |
} | |
}); | |
AST.Command.Path.Segment.Augment({ | |
setupPositions: function (context) { | |
var env = context.env; | |
env.p = env.c; | |
this.pos.toShape(context); | |
var p = env.p; | |
var c = env.c; | |
var tx = c.x - p.x; | |
var ty = c.y - p.y; | |
var angle = Math.atan2(ty, tx) + Math.PI / 2; | |
var slideEm = env.segmentSlideEm.getOrElse(0); | |
this.slide.dimen.foreach(function (d) { | |
slideEm = xypic.length2em(d); | |
env.segmentSlideEm = FP.Option.Some(slideEm); | |
}); | |
if (slideEm !== 0) { | |
p = p.move(p.x + slideEm * Math.cos(angle), p.y + slideEm * Math.sin(angle)); | |
c = c.move(c.x + slideEm * Math.cos(angle), c.y + slideEm * Math.sin(angle)); | |
} | |
env.p = p; | |
env.c = c; | |
}, | |
toLabelsShape: function (context) { | |
var env = context.env; | |
var c = env.c, p = env.p; | |
this.labels.toShape(context); | |
env.c = c; | |
env.p = p; | |
} | |
}); | |
AST.Command.Path.Labels.Augment({ | |
toShape: function (context) { | |
this.labels.foreach(function (label) { | |
label.toShape(context); | |
}); | |
} | |
}); | |
AST.Command.Path.Label.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var p = env.p; | |
var c = env.c; | |
var t = this.anchor.toShape(context); | |
var labelmargin = this.getLabelMargin(context); | |
if (labelmargin !== 0) { | |
var lastCurve = env.lastCurve; | |
var angle; | |
if (!lastCurve.isNone) { | |
angle = lastCurve.angle(t) + Math.PI/2 + (labelmargin > 0? 0 : Math.PI); | |
} else { | |
angle = Math.atan2(c.y - p.y, c.x - p.x) + Math.PI/2; | |
} | |
var c = env.c; | |
var subcontext = xypic.DrawingContext(xypic.Shape.none, env); | |
this.it.toDropShape(subcontext); | |
var labelShape = subcontext.shape; | |
var bbox = labelShape.getBoundingBox(); | |
if (bbox !== undefined) { | |
var x = bbox.x - c.x; | |
var y = bbox.y - c.y; | |
var l = bbox.l; | |
var r = bbox.r; | |
var u = bbox.u; | |
var d = bbox.d; | |
var cos = Math.cos(angle); | |
var sin = Math.sin(angle); | |
var delta = Math.min( | |
(x - l) * cos + (y - d) * sin, | |
(x - l) * cos + (y + u) * sin, | |
(x + r) * cos + (y - d) * sin, | |
(x + r) * cos + (y + u) * sin | |
); | |
var margin = Math.abs(labelmargin) - delta; | |
env.c = env.c.move(c.x + margin * cos, c.y + margin * sin); | |
context.appendShapeToFront(xypic.Shape.TranslateShape(margin * cos, margin * sin, labelShape)); | |
} | |
} else { | |
this.it.toDropShape(context); | |
} | |
var lastCurve = env.lastCurve; | |
if (this.shouldSliceHole && lastCurve.isDefined && t !== undefined) { | |
lastCurve.sliceHole(env.c, t); | |
} | |
this.aliasOption.foreach(function (alias) { | |
env.savePos(alias, xypic.Saving.Position(env.c)); | |
}); | |
} | |
}); | |
AST.Command.Path.Label.Above.Augment({ | |
getLabelMargin: function (context) { | |
return context.env.labelmargin; | |
}, | |
shouldSliceHole: false | |
}); | |
AST.Command.Path.Label.Below.Augment({ | |
getLabelMargin: function (context) { | |
return -context.env.labelmargin; | |
}, | |
shouldSliceHole: false | |
}); | |
AST.Command.Path.Label.At.Augment({ | |
getLabelMargin: function (context) { | |
return 0; | |
}, | |
shouldSliceHole: true | |
}); | |
AST.Command.Xymatrix.Augment({ | |
toShape: function (context) { | |
var origEnv = context.env; | |
if (origEnv.c === undefined) { | |
return xypic.Shape.none; | |
} | |
var subEnv = origEnv.duplicate(); | |
var subcontext = xypic.DrawingContext(xypic.Shape.none, subEnv); | |
subEnv.xymatrixPrefix = ""; | |
subEnv.xymatrixRowSepEm = xypic.length2em("2pc"); | |
subEnv.xymatrixColSepEm = xypic.length2em("2pc"); | |
subEnv.xymatrixPretendEntryHeight = FP.Option.empty; | |
subEnv.xymatrixPretendEntryWidth = FP.Option.empty; | |
subEnv.xymatrixFixedRow = false; | |
subEnv.xymatrixFixedCol = false; | |
subEnv.xymatrixOrientationAngle = 0; | |
subEnv.xymatrixEntryModifiers = FP.List.empty; | |
this.setup.foreach(function (sw) { sw.toShape(subcontext); }); | |
var orientation = subEnv.xymatrixOrientationAngle; | |
var rowCount; | |
var columnCount = 0; | |
var rownum = 0, colnum; | |
var matrix = xypic.Xymatrix( | |
this.rows.map(function (row) { | |
rownum += 1; | |
colnum = 0; | |
var rowModel = xypic.Xymatrix.Row( | |
row.entries.map(function (entry) { | |
colnum += 1; | |
var localEnv = subEnv.duplicate(); | |
localEnv.origin = {x:0, y:0}; | |
localEnv.p = localEnv.c = xypic.Env.originPosition; | |
localEnv.angle = 0; | |
localEnv.lastCurve = xypic.LastCurve.none; | |
localEnv.xymatrixRow = rownum; // = \the\Row | |
localEnv.xymatrixCol = colnum; // = \the\Col | |
var localContext = xypic.DrawingContext(xypic.Shape.none, localEnv); | |
var shape = entry.toShape(localContext); | |
var c = localEnv.c; | |
var l, r, u, d; | |
if (subEnv.xymatrixPretendEntryHeight.isDefined) { | |
var h = subEnv.xymatrixPretendEntryHeight.get; | |
u = h / 2; | |
d = h / 2; | |
} else { | |
u = c.u; | |
d = c.d; | |
} | |
if (subEnv.xymatrixPretendEntryWidth.isDefined) { | |
var w = subEnv.xymatrixPretendEntryWidth.get; | |
l = w / 2; | |
r = w / 2; | |
} else { | |
l = c.l; | |
r = c.r; | |
} | |
var frame = xypic.Frame.Rect(0, 0, { l:l, r:r, u:u, d:d }); | |
return xypic.Xymatrix.Entry(localEnv.c, shape, entry.decor, frame); | |
}), | |
orientation | |
); | |
columnCount = Math.max(columnCount, colnum); | |
return rowModel; | |
}), | |
orientation | |
); | |
rowCount = rownum; | |
if (rowCount === 0) { | |
return xypic.Shape.none; | |
} | |
var colnum; | |
matrix.rows.foreach(function (row) { | |
colnum = 0; | |
row.entries.foreach (function (entry) { | |
colnum += 1; | |
var column = matrix.getColumn(colnum); | |
column.addEntry(entry); | |
}); | |
}); | |
/* | |
console.log(matrix.toString()); | |
var rownum = 0; | |
matrix.rows.foreach(function (row) { | |
rownum += 1; | |
console.log("row[" + rownum + "] #" + row.entries.length() + " u:" + row.getU() + ", d:" + row.getD()); | |
}) | |
var colnum = 0; | |
matrix.columns.foreach(function (col) { | |
colnum += 1; | |
console.log("column[" + colnum + "] #" + col.entries.length() + " l:" + col.getL() + ", r:" + col.getR()); | |
}) | |
*/ | |
var colsep = subEnv.xymatrixColSepEm; | |
var xs = []; | |
var x = origEnv.c.x; | |
xs.push(x); | |
if (subEnv.xymatrixFixedCol) { | |
var maxL = 0; | |
var maxR = 0; | |
matrix.columns.foreach(function (col) { | |
maxL = Math.max(maxL, col.getL()); | |
maxR = Math.max(maxR, col.getR()); | |
}); | |
matrix.columns.tail.foreach(function (col) { | |
x = x + maxR + colsep + maxL; | |
xs.push(x); | |
}); | |
l = maxL; | |
r = xs[xs.length - 1] + maxR; | |
} else { | |
var prevCol = matrix.columns.head; | |
matrix.columns.tail.foreach(function (col) { | |
x = x + prevCol.getR() + colsep + col.getL(); | |
xs.push(x); | |
prevCol = col; | |
}); | |
l = matrix.columns.head.getL(); | |
r = x + matrix.columns.at(columnCount - 1).getR() - xs[0]; | |
} | |
var rowsep = subEnv.xymatrixRowSepEm; | |
var ys = []; | |
var y = origEnv.c.y; | |
ys.push(y); | |
if (subEnv.xymatrixFixedRow) { | |
var maxU = 0; | |
var maxD = 0; | |
matrix.rows.foreach(function (row) { | |
maxU = Math.max(maxU, row.getU()); | |
maxD = Math.max(maxD, row.getD()); | |
}); | |
matrix.rows.tail.foreach(function (row) { | |
y = y - (maxD + rowsep + maxU); | |
ys.push(y); | |
}); | |
u = maxU; | |
d = ys[0] - ys[ys.length - 1] + maxD; | |
} else { | |
var prevRow = matrix.rows.head; | |
matrix.rows.tail.foreach(function (row) { | |
y = y - (prevRow.getD() + rowsep + row.getU()); | |
ys.push(y); | |
prevRow = row; | |
}); | |
u = matrix.rows.head.getU(); | |
d = ys[0] - y + matrix.rows.at(rowCount - 1).getD(); | |
} | |
origEnv.c = xypic.Frame.Rect(origEnv.c.x, origEnv.c.y, { l:l, r:r, u:u, d:d }); | |
var prefix = subEnv.xymatrixPrefix; | |
var cos = Math.cos(orientation); | |
var sin = Math.sin(orientation); | |
var rowIndex = 0; | |
matrix.rows.foreach(function (row) { | |
colIndex = 0; | |
row.entries.foreach (function (entry) { | |
var x0 = xs[colIndex]; | |
var y0 = ys[rowIndex]; | |
var x = x0 * cos - y0 * sin; | |
var y = x0 * sin + y0 * cos; | |
var colnum = colIndex + 1; | |
var rownum = rowIndex + 1; | |
var pos = xypic.Saving.Position(entry.c.move(x, y)); | |
subEnv.savePos("" + rownum + "," + colnum, pos); | |
subEnv.savePos(prefix + rownum + "," + colnum, pos); | |
colIndex += 1; | |
}); | |
rowIndex += 1; | |
}); | |
subcontext = xypic.DrawingContext(xypic.Shape.none, subEnv); | |
var rowIndex = 0; | |
matrix.rows.foreach(function (row) { | |
colIndex = 0; | |
row.entries.foreach (function (entry) { | |
var x0 = xs[colIndex]; | |
var y0 = ys[rowIndex]; | |
var x = x0 * cos - y0 * sin; | |
var y = x0 * sin + y0 * cos; | |
var colnum = colIndex + 1; | |
var rownum = rowIndex + 1; | |
var objectShape = xypic.Shape.TranslateShape(x, y, entry.objectShape); | |
subcontext.appendShapeToFront(objectShape); | |
// draw decor | |
subEnv.c = entry.c.move(x, y); | |
subEnv.xymatrixRow = rownum; // = \the\Row | |
subEnv.xymatrixCol = colnum; // = \the\Col | |
entry.decor.toShape(subcontext); | |
colIndex += 1; | |
}); | |
rowIndex += 1; | |
}); | |
var matrixShape = subcontext.shape; | |
context.appendShapeToFront(matrixShape); | |
origEnv.savedPosition = subEnv.savedPosition; | |
return matrixShape; | |
} | |
}); | |
// xymatrix data models | |
xypic.Xymatrix = MathJax.Object.Subclass({ | |
Init: function (rows, orientation) { | |
this.rows = rows; | |
this.columns = FP.List.empty; | |
this.orientation = orientation; | |
}, | |
getColumn: function (colnum /* >= 1 */) { | |
if (this.columns.length() >= colnum) { | |
return this.columns.at(colnum - 1); | |
} else { | |
var column = xypic.Xymatrix.Column(this.orientation); | |
this.columns = this.columns.append(column); | |
return column; | |
} | |
}, | |
toString: function () { | |
return "Xymatrix{\n" + this.rows.mkString("\\\\\n") + "\n}"; | |
} | |
}); | |
xypic.Xymatrix.Row = MathJax.Object.Subclass({ | |
Init: function (entries, orientation) { | |
this.entries = entries; | |
this.orientation = orientation; | |
memoize(this, "getU"); | |
memoize(this, "getD"); | |
}, | |
getU: function () { | |
var orientation = this.orientation; | |
var maxU = 0; | |
this.entries.foreach(function (e) { maxU = Math.max(maxU, e.getU(orientation)); }) | |
return maxU; | |
}, | |
getD: function () { | |
var orientation = this.orientation; | |
var maxD = 0; | |
this.entries.foreach(function (e) { maxD = Math.max(maxD, e.getD(orientation)); }) | |
return maxD; | |
}, | |
toString: function () { | |
return this.entries.mkString(" & "); | |
} | |
}); | |
xypic.Xymatrix.Column = MathJax.Object.Subclass({ | |
Init: function (orientation) { | |
this.entries = FP.List.empty; | |
this.orientation = orientation; | |
memoize(this, "getL"); | |
memoize(this, "getR"); | |
}, | |
addEntry: function (entry) { | |
this.entries = this.entries.append(entry); | |
this.getL.reset; | |
this.getR.reset; | |
}, | |
getL: function () { | |
var orientation = this.orientation; | |
var maxL = 0; | |
this.entries.foreach(function (e) { maxL = Math.max(maxL, e.getL(orientation)); }) | |
return maxL; | |
}, | |
getR: function () { | |
var orientation = this.orientation; | |
var maxR = 0; | |
this.entries.foreach(function (e) { maxR = Math.max(maxR, e.getR(orientation)); }) | |
return maxR; | |
}, | |
toString: function () { | |
return this.entries.mkString(" \\\\ "); | |
} | |
}); | |
xypic.Xymatrix.Entry = MathJax.Object.Subclass({ | |
Init: function (c, objectShape, decor, frame) { | |
this.c = c; | |
this.objectShape = objectShape; | |
this.decor = decor; | |
this.frame = frame; | |
}, | |
getDistanceToEdgePoint: function (frame, angle) { | |
var edgePoint = frame.edgePoint(frame.x + Math.cos(angle), frame.y + Math.sin(angle)); | |
var dx = edgePoint.x - frame.x; | |
var dy = edgePoint.y - frame.y; | |
return Math.sqrt(dx * dx + dy * dy); | |
}, | |
getU: function (orientation) { | |
if (orientation === 0) { | |
return this.frame.u; | |
} | |
return this.getDistanceToEdgePoint(this.frame, orientation + Math.PI / 2); | |
}, | |
getD: function (orientation) { | |
if (orientation === 0) { | |
return this.frame.d; | |
} | |
return this.getDistanceToEdgePoint(this.frame, orientation - Math.PI / 2); | |
}, | |
getL: function (orientation) { | |
if (orientation === 0) { | |
return this.frame.l; | |
} | |
return this.getDistanceToEdgePoint(this.frame, orientation + Math.PI); | |
}, | |
getR: function (orientation) { | |
if (orientation === 0) { | |
return this.frame.r; | |
} | |
return this.getDistanceToEdgePoint(this.frame, orientation); | |
}, | |
toString: function () { | |
return this.objectShape.toString() + " " + this.decor; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.Prefix.Augment({ | |
toShape: function (context) { | |
context.env.xymatrixPrefix = this.prefix; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.ChangeSpacing.Row.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.xymatrixRowSepEm = this.addop.applyToDimen(env.xymatrixRowSepEm, xypic.length2em(this.dimen)); | |
} | |
}); | |
AST.Command.Xymatrix.Setup.ChangeSpacing.Column.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.xymatrixColSepEm = this.addop.applyToDimen(env.xymatrixColSepEm, xypic.length2em(this.dimen)); | |
} | |
}); | |
AST.Command.Xymatrix.Setup.ChangeSpacing.RowAndColumn.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var sepEm = this.addop.applyToDimen(env.xymatrixRowSepEm, xypic.length2em(this.dimen)); | |
env.xymatrixRowSepEm = sepEm; | |
env.xymatrixColSepEm = sepEm; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.PretendEntrySize.Height.Augment({ | |
toShape: function (context) { | |
context.env.xymatrixPretendEntryHeight = FP.Option.Some(xypic.length2em(this.dimen)); | |
} | |
}); | |
AST.Command.Xymatrix.Setup.PretendEntrySize.Width.Augment({ | |
toShape: function (context) { | |
context.env.xymatrixPretendEntryWidth = FP.Option.Some(xypic.length2em(this.dimen)); | |
} | |
}); | |
AST.Command.Xymatrix.Setup.PretendEntrySize.HeightAndWidth.Augment({ | |
toShape: function (context) { | |
var len = FP.Option.Some(xypic.length2em(this.dimen)); | |
context.env.xymatrixPretendEntryHeight = len; | |
context.env.xymatrixPretendEntryWidth = len; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.FixGrid.Row.Augment({ | |
toShape: function (context) { | |
context.env.xymatrixFixedRow = true; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.FixGrid.Column.Augment({ | |
toShape: function (context) { | |
context.env.xymatrixFixedCol = true; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.FixGrid.RowAndColumn.Augment({ | |
toShape: function (context) { | |
context.env.xymatrixFixedRow = true; | |
context.env.xymatrixFixedCol = true; | |
} | |
}); | |
AST.Command.Xymatrix.Setup.AdjustEntrySize.Margin.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.objectmargin = this.addop.applyToDimen(env.objectmargin, xypic.length2em(this.dimen)); | |
} | |
}); | |
AST.Command.Xymatrix.Setup.AdjustEntrySize.Width.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.objectwidth = this.addop.applyToDimen(env.objectwidth, xypic.length2em(this.dimen)); | |
} | |
}); | |
AST.Command.Xymatrix.Setup.AdjustEntrySize.Height.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.objectheight = this.addop.applyToDimen(env.objectheight, xypic.length2em(this.dimen)); | |
} | |
}); | |
AST.Command.Xymatrix.Setup.AdjustLabelSep.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.labelmargin = this.addop.applyToDimen(env.labelmargin, xypic.length2em(this.dimen)); | |
} | |
}); | |
AST.Command.Xymatrix.Setup.SetOrientation.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.xymatrixOrientationAngle = this.direction.angle(context); | |
} | |
}); | |
AST.Command.Xymatrix.Setup.AddModifier.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
env.xymatrixEntryModifiers = env.xymatrixEntryModifiers.prepend(this.modifier); | |
} | |
}); | |
AST.Command.Xymatrix.Entry.SimpleEntry.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var defaultWidth = xypic.em2length(env.objectmargin + env.objectwidth); | |
var defaultHeight = xypic.em2length(env.objectmargin + env.objectheight); | |
var defaultSizeModifier = AST.Modifier.AddOp(AST.Modifier.AddOp.GrowTo(), AST.Modifier.AddOp.VactorSize(AST.Vector.Abs( | |
defaultWidth, defaultHeight | |
))); | |
var margin = xypic.em2length(env.objectmargin); | |
var marginModifier = AST.Modifier.AddOp(AST.Modifier.AddOp.Grow(), AST.Modifier.AddOp.VactorSize(AST.Vector.Abs( | |
margin, margin | |
))); | |
var modifiers = this.modifiers.concat(env.xymatrixEntryModifiers).prepend(defaultSizeModifier).prepend(marginModifier); | |
return AST.Object(modifiers, this.objectbox).toDropShape(context); | |
} | |
}); | |
AST.Command.Xymatrix.Entry.EmptyEntry.Augment({ | |
toShape: function (context) { | |
var env = context.env; | |
var defaultWidth = xypic.em2length(env.objectmargin + env.objectwidth); | |
var defaultHeight = xypic.em2length(env.objectmargin + env.objectheight); | |
var defaultSizeModifier = AST.Modifier.AddOp(AST.Modifier.AddOp.GrowTo(), AST.Modifier.AddOp.VactorSize(AST.Vector.Abs( | |
defaultWidth, defaultHeight | |
))); | |
var margin = xypic.em2length(env.objectmargin); | |
var marginModifier = AST.Modifier.AddOp(AST.Modifier.AddOp.Grow(), AST.Modifier.AddOp.VactorSize(AST.Vector.Abs( | |
margin, margin | |
))); | |
var modifiers = env.xymatrixEntryModifiers.prepend(defaultSizeModifier).prepend(marginModifier); | |
return AST.Object(modifiers, AST.ObjectBox.Empty()).toDropShape(context); | |
} | |
}); | |
AST.Command.Xymatrix.Entry.ObjectEntry.Augment({ | |
toShape: function (context) { | |
return this.object.toDropShape(context); | |
} | |
}); | |
AST.Command.Twocell.Augment({ | |
toShape: function (context) { | |
var origEnv = context.env; | |
if (origEnv.c === undefined) { | |
return xypic.Shape.none; | |
} | |
var subEnv = origEnv.duplicate(); | |
var subcontext = xypic.DrawingContext(xypic.Shape.none, subEnv); | |
subEnv.twocellmodmapobject = origEnv.twocellmodmapobject || AST.Object(FP.List.empty, AST.ObjectBox.Dir("", "|")); | |
subEnv.twocellhead = origEnv.twocellhead || AST.Object(FP.List.empty, AST.ObjectBox.Dir("", ">")); | |
subEnv.twocelltail = origEnv.twocelltail || AST.Object(FP.List.empty, AST.ObjectBox.Dir("", "")); | |
subEnv.twocellarrowobject = origEnv.twocellarrowobject || AST.Object(FP.List.empty, AST.ObjectBox.Dir("", "=>")); | |
subEnv.twocellUpperCurveObjectSpacer = origEnv.twocellUpperCurveObjectSpacer; | |
subEnv.twocellUpperCurveObject = origEnv.twocellUpperCurveObject; | |
subEnv.twocellLowerCurveObjectSpacer = origEnv.twocellLowerCurveObjectSpacer; | |
subEnv.twocellLowerCurveObject = origEnv.twocellLowerCurveObject; | |
// temporary attributes | |
subEnv.twocellUpperLabel = FP.Option.empty; | |
subEnv.twocellLowerLabel = FP.Option.empty; | |
subEnv.twocellCurvatureEm = FP.Option.empty; | |
subEnv.twocellShouldDrawCurve = true; | |
subEnv.twocellShouldDrawModMap = false; | |
this.switches.foreach(function (sw) { sw.setup(subcontext); }); | |
this.twocell.toShape(subcontext, this.arrow); | |
context.appendShapeToFront(subcontext.shape); | |
} | |
}); | |
AST.Command.Twocell.Hops2cell.Augment({ | |
toShape: function (context, arrow) { | |
var env = context.env; | |
var c = env.c; | |
var angle = env.angle; | |
var s = env.c; | |
var e = this.targetPosition(context); | |
if (s === undefined || e === undefined) { | |
return; | |
} | |
var dx = e.x - s.x; | |
var dy = e.y - s.y; | |
if (dx === 0 && dy === 0) { | |
return; | |
} | |
var m = xypic.Frame.Point( | |
s.x + dx * 0.5, | |
s.y + dy * 0.5 | |
); | |
var tangle = Math.atan2(dy, dx); | |
var antiClockwiseAngle = tangle + Math.PI / 2; | |
var curvatureEm = env.twocellCurvatureEm.getOrElse(this.getDefaultCurvature()); | |
var ncos = Math.cos(antiClockwiseAngle); | |
var nsin = Math.sin(antiClockwiseAngle); | |
var ucp = this.getUpperControlPoint(s, e, m, curvatureEm, ncos, nsin); | |
var lcp = this.getLowerControlPoint(s, e, m, curvatureEm, ncos, nsin); | |
if (env.twocellShouldDrawCurve) { | |
// upper curve | |
var objectForDrop = env.twocellUpperCurveObjectSpacer; | |
var objectForConnect; | |
if (objectForDrop === undefined) { | |
objectForConnect = AST.Object(FP.List.empty, AST.ObjectBox.Dir("", "-")); | |
} else { | |
if (env.twocellUpperCurveObject !== undefined) { | |
objectForConnect = env.twocellUpperCurveObject.getOrElse(undefined); | |
} else { | |
objectForConnect = undefined; | |
} | |
} | |
this.toUpperCurveShape(context, s, ucp, e, objectForDrop, objectForConnect); | |
if (env.lastCurve.isDefined) { | |
env.angle = tangle; | |
var ucmp = this.getUpperLabelPosition(s, e, m, curvatureEm, ncos, nsin); | |
var uangle = this.getUpperLabelAngle(antiClockwiseAngle, s, e, m, curvatureEm, ncos, nsin); | |
env.twocellUpperLabel.foreach(function (l) { | |
l.toShape(context, ucmp, Math.cos(uangle), Math.sin(uangle), tangle); | |
}); | |
if (this.hasUpperTips) { | |
arrow.toUpperTipsShape(context); | |
} | |
} | |
// lower curve | |
var objectForDrop = env.twocellLowerCurveObjectSpacer; | |
var objectForConnect; | |
if (objectForDrop === undefined) { | |
objectForConnect = AST.Object(FP.List.empty, AST.ObjectBox.Dir("", "-")); | |
} else { | |
if (env.twocellLowerCurveObject !== undefined) { | |
objectForConnect = env.twocellLowerCurveObject.getOrElse(undefined); | |
} else { | |
objectForConnect = undefined; | |
} | |
} | |
this.toLowerCurveShape(context, s, lcp, e, objectForDrop, objectForConnect); | |
if (env.lastCurve.isDefined) { | |
env.angle = tangle; | |
var lcmp = this.getLowerLabelPosition(s, e, m, curvatureEm, ncos, nsin); | |
var langle = this.getLowerLabelAngle(antiClockwiseAngle, s, e, m, curvatureEm, ncos, nsin); | |
env.twocellLowerLabel.foreach(function (l) { | |
l.toShape(context, lcmp, Math.cos(langle), Math.sin(langle), tangle); | |
}); | |
if (this.hasLowerTips) { | |
arrow.toLowerTipsShape(context); | |
} | |
} | |
} | |
env.c = this.getDefaultArrowPoint(s, e, m, curvatureEm, ncos, nsin); | |
env.angle = antiClockwiseAngle + Math.PI; | |
var labelOrigin = m; | |
arrow.toArrowShape(context, labelOrigin); | |
env.c = c; | |
env.angle = angle; | |
}, | |
_toCurveShape: function (context, s, cp, e, objectForDrop, objectForConnect) { | |
var env = context.env; | |
var origBezier = xypic.Curve.QuadBezier(s, cp, e); | |
var tOfShavedStart = origBezier.tOfShavedStart(s); | |
var tOfShavedEnd = origBezier.tOfShavedEnd(e); | |
if (tOfShavedStart === undefined || tOfShavedEnd === undefined || tOfShavedStart >= tOfShavedEnd) { | |
env.lastCurve = xypic.LastCurve.none; | |
return; | |
} | |
var curveShape = origBezier.toShape(context, objectForDrop, objectForConnect); | |
env.lastCurve = xypic.LastCurve.QuadBezier(origBezier, tOfShavedStart, tOfShavedEnd, curveShape); | |
}, | |
targetPosition: function (context) { | |
var env = context.env; | |
var row = env.xymatrixRow; | |
var col = env.xymatrixCol; | |
if (row === undefined || col === undefined) { | |
throw xypic.ExecutionError("rows and columns not found for hops [" + this.hops + "]"); | |
} | |
for (var i = 0; i < this.hops.length; i++) { | |
switch (this.hops[i]) { | |
case 'u': | |
row -= 1; | |
break; | |
case 'd': | |
row += 1; | |
break; | |
case 'l': | |
col -= 1; | |
break; | |
case 'r': | |
col += 1; | |
break; | |
} | |
} | |
var id = "" + row + "," + col; | |
return context.env.lookupPos(id, 'in entry "' + env.xymatrixRow + "," + env.xymatrixCol + '": No ' + this + " (is " + id + ") from here.").position(context); | |
} | |
}); | |
AST.Command.Twocell.Twocell.Augment({ | |
getUpperControlPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return xypic.Frame.Point( | |
midPoint.x + curvatureEm * ncos, | |
midPoint.y + curvatureEm * nsin | |
); | |
}, | |
getLowerControlPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return xypic.Frame.Point( | |
midPoint.x - curvatureEm * ncos, | |
midPoint.y - curvatureEm * nsin | |
); | |
}, | |
getUpperLabelPosition: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return xypic.Frame.Point( | |
midPoint.x + 0.5 * curvatureEm * ncos, | |
midPoint.y + 0.5 * curvatureEm * nsin | |
); | |
}, | |
getLowerLabelPosition: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return xypic.Frame.Point( | |
midPoint.x - 0.5 * curvatureEm * ncos, | |
midPoint.y - 0.5 * curvatureEm * nsin | |
); | |
}, | |
getUpperLabelAngle: function (antiClockwiseAngle, s, e, midPoint, curvatureEm, ncos, nsin) { | |
var rot = (curvatureEm < 0? Math.PI : 0); | |
return antiClockwiseAngle + rot; | |
}, | |
getLowerLabelAngle: function (antiClockwiseAngle, s, e, midPoint, curvatureEm, ncos, nsin) { | |
var rot = (curvatureEm < 0? 0 : Math.PI); | |
return antiClockwiseAngle + rot; | |
}, | |
getDefaultArrowPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return midPoint; | |
}, | |
toUpperCurveShape: function (context, s, cp, e, objectForDrop, objectForConnect) { | |
this._toCurveShape(context, s, cp, e, objectForDrop, objectForConnect); | |
}, | |
toLowerCurveShape: function (context, s, cp, e, objectForDrop, objectForConnect) { | |
this._toCurveShape(context, s, cp, e, objectForDrop, objectForConnect); | |
}, | |
getDefaultCurvature: function () { return 3.5 * AST.xypic.lineElementLength; }, | |
hasUpperTips: true, | |
hasLowerTips: true | |
}); | |
AST.Command.Twocell.UpperTwocell.Augment({ | |
getUpperControlPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return xypic.Frame.Point( | |
midPoint.x + curvatureEm * ncos, | |
midPoint.y + curvatureEm * nsin | |
); | |
}, | |
getLowerControlPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return midPoint; | |
}, | |
getUpperLabelPosition: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return xypic.Frame.Point( | |
midPoint.x + 0.5 * curvatureEm * ncos, | |
midPoint.y + 0.5 * curvatureEm * nsin | |
); | |
}, | |
getLowerLabelPosition: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return midPoint; | |
}, | |
getUpperLabelAngle: function (antiClockwiseAngle, s, e, midPoint, curvatureEm, ncos, nsin) { | |
var rot = (curvatureEm < 0? Math.PI : 0); | |
return antiClockwiseAngle + rot; | |
}, | |
getLowerLabelAngle: function (antiClockwiseAngle, s, e, midPoint, curvatureEm, ncos, nsin) { | |
var rot = (curvatureEm < 0? 0 : Math.PI); | |
return antiClockwiseAngle + rot; | |
}, | |
getDefaultArrowPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return xypic.Frame.Point( | |
midPoint.x + 0.25 * curvatureEm * ncos, | |
midPoint.y + 0.25 * curvatureEm * nsin | |
); | |
}, | |
toUpperCurveShape: function (context, s, cp, e, objectForDrop, objectForConnect) { | |
this._toCurveShape(context, s, cp, e, objectForDrop, objectForConnect); | |
}, | |
toLowerCurveShape: function (context, s, cp, e, objectForDrop, objectForConnect) { | |
var shavedS = s.edgePoint(e.x, e.y); | |
var shavedE = e.edgePoint(s.x, s.y); | |
if (shavedS.x !== shavedE.x || shavedS.y !== shavedE.y) { | |
context.env.lastCurve = xypic.LastCurve.Line(shavedS, shavedE, s, e, undefined); | |
} else { | |
context.env.lastCurve = xypic.LastCurve.none; | |
} | |
}, | |
getDefaultCurvature: function () { return 7 * AST.xypic.lineElementLength; }, | |
hasUpperTips: true, | |
hasLowerTips: false | |
}); | |
AST.Command.Twocell.LowerTwocell.Augment({ | |
getUpperControlPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return midPoint; | |
}, | |
getLowerControlPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return xypic.Frame.Point( | |
midPoint.x + curvatureEm * ncos, | |
midPoint.y + curvatureEm * nsin | |
); | |
}, | |
getUpperLabelPosition: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return midPoint; | |
}, | |
getLowerLabelPosition: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return xypic.Frame.Point( | |
midPoint.x + 0.5 * curvatureEm * ncos, | |
midPoint.y + 0.5 * curvatureEm * nsin | |
); | |
}, | |
getUpperLabelAngle: function (antiClockwiseAngle, s, e, midPoint, curvatureEm, ncos, nsin) { | |
var rot = (curvatureEm < 0? 0 : Math.PI); | |
return antiClockwiseAngle + rot; | |
}, | |
getLowerLabelAngle: function (antiClockwiseAngle, s, e, midPoint, curvatureEm, ncos, nsin) { | |
var rot = (curvatureEm < 0? Math.PI : 0); | |
return antiClockwiseAngle + rot; | |
}, | |
getDefaultArrowPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return xypic.Frame.Point( | |
midPoint.x + 0.25 * curvatureEm * ncos, | |
midPoint.y + 0.25 * curvatureEm * nsin | |
); | |
}, | |
toUpperCurveShape: function (context, s, cp, e, objectForDrop, objectForConnect) { | |
var shavedS = s.edgePoint(e.x, e.y); | |
var shavedE = e.edgePoint(s.x, s.y); | |
if (shavedS.x !== shavedE.x || shavedS.y !== shavedE.y) { | |
context.env.lastCurve = xypic.LastCurve.Line(shavedS, shavedE, s, e, undefined); | |
} else { | |
context.env.lastCurve = xypic.LastCurve.none; | |
} | |
}, | |
toLowerCurveShape: function (context, s, cp, e, objectForDrop, objectForConnect) { | |
this._toCurveShape(context, s, cp, e, objectForDrop, objectForConnect); | |
}, | |
getDefaultCurvature: function () { return -7 * AST.xypic.lineElementLength; }, | |
hasUpperTips: false, | |
hasLowerTips: true | |
}); | |
AST.Command.Twocell.CompositeMap.Augment({ | |
getUpperControlPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
var midBoxSize = this.getMidBoxSize(); | |
return xypic.Frame.Ellipse( | |
midPoint.x + curvatureEm * ncos, | |
midPoint.y + curvatureEm * nsin, | |
midBoxSize, midBoxSize, midBoxSize, midBoxSize | |
); | |
}, | |
getLowerControlPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
var midBoxSize = this.getMidBoxSize(); | |
return xypic.Frame.Ellipse( | |
midPoint.x + curvatureEm * ncos, | |
midPoint.y + curvatureEm * nsin, | |
midBoxSize, midBoxSize, midBoxSize, midBoxSize | |
); | |
}, | |
getUpperLabelPosition: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
var dx = midPoint.x + curvatureEm * ncos - e.x; | |
var dy = midPoint.y + curvatureEm * nsin - e.y; | |
var l = Math.sqrt(dx * dx + dy * dy); | |
return xypic.Frame.Point( | |
e.x + 0.5 * dx, | |
e.y + 0.5 * dy | |
); | |
}, | |
getLowerLabelPosition: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
var dx = midPoint.x + curvatureEm * ncos - s.x; | |
var dy = midPoint.y + curvatureEm * nsin - s.y; | |
var l = Math.sqrt(dx * dx + dy * dy); | |
return xypic.Frame.Point( | |
s.x + 0.5 * dx, | |
s.y + 0.5 * dy | |
); | |
}, | |
getUpperLabelAngle: function (antiClockwiseAngle, s, e, midPoint, curvatureEm, ncos, nsin) { | |
var dx = e.x - midPoint.x + curvatureEm * ncos; | |
var dy = e.y - midPoint.y + curvatureEm * nsin; | |
var angle = Math.atan2(dy, dx); | |
var rot = (curvatureEm < 0? Math.PI : 0); | |
return angle + Math.PI / 2 + rot; | |
}, | |
getLowerLabelAngle: function (antiClockwiseAngle, s, e, midPoint, curvatureEm, ncos, nsin) { | |
var dx = midPoint.x + curvatureEm * ncos - s.x; | |
var dy = midPoint.y + curvatureEm * nsin - s.y; | |
var angle = Math.atan2(dy, dx); | |
var rot = (curvatureEm < 0? Math.PI : 0); | |
return angle + Math.PI / 2 + rot; | |
}, | |
getDefaultArrowPoint: function (s, e, midPoint, curvatureEm, ncos, nsin) { | |
return midPoint; | |
}, | |
toUpperCurveShape: function (context, s, cp, e, objectForDrop, objectForConnect) { | |
var env = context.env; | |
var start = s; | |
var end = cp; | |
var shavedS = start.edgePoint(end.x, end.y); | |
var shavedE = end.edgePoint(start.x, start.y); | |
var p = env.p; | |
var c = env.c; | |
env.p = start; | |
env.c = end; | |
xypic.Curve.Line(shavedS, shavedE).toShape(context, undefined, "-", ""); | |
env.p = p; | |
env.c = c; | |
}, | |
toLowerCurveShape: function (context, s, cp, e, objectForDrop, objectForConnect) { | |
var env = context.env; | |
var start = cp; | |
var end = e; | |
var shavedS = start.edgePoint(end.x, end.y); | |
var shavedE = end.edgePoint(start.x, start.y); | |
var p = env.p; | |
var c = env.c; | |
env.p = start; | |
env.c = end; | |
xypic.Curve.Line(shavedS, shavedE).toShape(context, undefined, "-", ""); | |
env.p = p; | |
env.c = c; | |
}, | |
getMidBoxSize: function () { return 0.5 * AST.xypic.lineElementLength; }, | |
getDefaultCurvature: function () { return 3.5 * AST.xypic.lineElementLength; }, | |
hasUpperTips: true, | |
hasLowerTips: true | |
}); | |
AST.Command.Twocell.Switch.UpperLabel.Augment({ | |
setup: function (context) { | |
var env = context.env; | |
env.twocellUpperLabel = FP.Option.Some(this); | |
}, | |
toShape: function (context, curveMidPos, ncos, nsin, tangle) { | |
this.label.toShape(context, curveMidPos, ncos, nsin, tangle); | |
} | |
}); | |
AST.Command.Twocell.Switch.LowerLabel.Augment({ | |
setup: function (context) { | |
var env = context.env; | |
env.twocellLowerLabel = FP.Option.Some(this); | |
}, | |
toShape: function (context, curveMidPos, ncos, nsin, tangle) { | |
this.label.toShape(context, curveMidPos, ncos, nsin, tangle); | |
} | |
}); | |
AST.Command.Twocell.Switch.SetCurvature.Augment({ | |
setup: function (context) { | |
var env = context.env; | |
if (this.nudge.isOmit) { | |
env.twocellShouldDrawCurve = false; | |
} else { | |
env.twocellCurvatureEm = FP.Option.Some(this.nudge.number * AST.xypic.lineElementLength); | |
} | |
} | |
}); | |
AST.Command.Twocell.Switch.DoNotSetCurvedArrows.Augment({ | |
setup: function (context) { | |
var env = context.env; | |
env.twocellShouldDrawCurve = false; | |
} | |
}); | |
AST.Command.Twocell.Switch.PlaceModMapObject.Augment({ | |
setup: function (context) { | |
var env = context.env; | |
env.twocellShouldDrawModMap = true; | |
} | |
}); | |
AST.Command.Twocell.Switch.ChangeHeadTailObject.Augment({ | |
setup: function (context) { | |
var env = context.env; | |
switch (this.what) { | |
case '`': | |
env.twocelltail = this.object; | |
break; | |
case "'": | |
env.twocellhead = this.object; | |
break; | |
} | |
} | |
}); | |
AST.Command.Twocell.Switch.ChangeCurveObject.Augment({ | |
setup: function (context) { | |
var env = context.env; | |
switch (this.what) { | |
case '': | |
env.twocellUpperCurveObjectSpacer = this.spacer; | |
env.twocellUpperCurveObject = this.maybeObject; | |
env.twocellLowerCurveObjectSpacer = this.spacer; | |
env.twocellLowerCurveObject = this.maybeObject; | |
break; | |
case '^': | |
env.twocellUpperCurveObjectSpacer = this.spacer; | |
env.twocellUpperCurveObject = this.maybeObject; | |
break; | |
case '_': | |
env.twocellLowerCurveObjectSpacer = this.spacer; | |
env.twocellLowerCurveObject = this.maybeObject; | |
break; | |
} | |
} | |
}); | |
AST.Command.Twocell.Label.Augment({ | |
toShape: function (context, curveMidPos, ncos, nsin, tangle) { | |
var maybeNudge = this.maybeNudge; | |
var offset; | |
if (maybeNudge.isDefined) { | |
var nudge = maybeNudge.get; | |
if (nudge.isOmit) { | |
return; | |
} else { | |
offset = nudge.number * AST.xypic.lineElementLength; | |
} | |
} else { | |
offset = this.getDefaultLabelOffset(); | |
} | |
var env = context.env; | |
var c = env.c; | |
env.c = xypic.Frame.Point( | |
curveMidPos.x + offset * ncos, | |
curveMidPos.y + offset * nsin | |
); | |
var labelObject = this.labelObject; | |
labelObject.toDropShape(context); | |
env.c = c; | |
}, | |
getDefaultLabelOffset: function () { return AST.xypic.lineElementLength; } | |
}); | |
AST.Command.Twocell.Nudge.Number.Augment({ | |
isOmit: false | |
}); | |
AST.Command.Twocell.Nudge.Omit.Augment({ | |
isOmit: true | |
}); | |
AST.Command.Twocell.Arrow.Augment({ | |
toTipsShape: function (context, reversed, doubleHeaded) { | |
var env = context.env; | |
var lastCurve = env.lastCurve; | |
var c = env.c; | |
var angle = env.angle; | |
var rot = (reversed? Math.PI : 0); | |
var t = lastCurve.tOfPlace(true, true, (reversed? 0 : 1), 0); | |
env.c = lastCurve.position(t); | |
env.angle = lastCurve.angle(t) + rot; | |
env.twocellhead.toDropShape(context); | |
var t = lastCurve.tOfPlace(true, true, (reversed? 1 : 0), 0); | |
env.c = lastCurve.position(t); | |
env.angle = lastCurve.angle(t) + rot; | |
if (doubleHeaded) { | |
env.twocellhead.toDropShape(context); | |
} else { | |
env.twocelltail.toDropShape(context); | |
} | |
if (env.twocellShouldDrawModMap) { | |
var t = lastCurve.tOfPlace(false, false, 0.5, 0); | |
env.c = lastCurve.position(t); | |
env.angle = lastCurve.angle(t) + rot; | |
env.twocellmodmapobject.toDropShape(context); | |
} | |
env.c = c; | |
env.angle = angle; | |
} | |
}); | |
AST.Command.Twocell.Arrow.WithOrientation.Augment({ | |
toUpperTipsShape: function (context) { | |
switch (this.tok) { | |
case '': | |
case '^': | |
case '_': | |
case '=': | |
case '\\omit': | |
case "'": | |
this.toTipsShape(context, false, false); | |
break; | |
case '`': | |
this.toTipsShape(context, true, false); | |
break; | |
case '"': | |
this.toTipsShape(context, false, true); | |
break; | |
case '!': | |
break; | |
} | |
}, | |
toLowerTipsShape: function (context) { | |
switch (this.tok) { | |
case '': | |
case '^': | |
case '_': | |
case '=': | |
case '\\omit': | |
case '`': | |
this.toTipsShape(context, false, false); | |
break; | |
case "'": | |
this.toTipsShape(context, true, false); | |
break; | |
case '"': | |
this.toTipsShape(context, false, true); | |
break; | |
case '!': | |
break; | |
} | |
}, | |
toArrowShape: function(context, labelOrigin) { | |
var env = context.env; | |
var c = env.c; | |
switch (this.tok) { | |
case '^': | |
var angle = env.angle; | |
env.angle = angle + Math.PI; | |
env.twocellarrowobject.toDropShape(context); | |
env.c = xypic.Frame.Point( | |
c.x + AST.xypic.lineElementLength * Math.cos(angle - Math.PI / 2), | |
c.y + AST.xypic.lineElementLength * Math.sin(angle - Math.PI / 2) | |
); | |
this.labelObject.toDropShape(context); | |
env.angle = angle; | |
break; | |
case '': | |
case '_': | |
var angle = env.angle; | |
env.twocellarrowobject.toDropShape(context); | |
env.c = xypic.Frame.Point( | |
c.x + AST.xypic.lineElementLength * Math.cos(angle + Math.PI / 2), | |
c.y + AST.xypic.lineElementLength * Math.sin(angle + Math.PI / 2) | |
); | |
this.labelObject.toDropShape(context); | |
break; | |
case '=': | |
var angle = env.angle; | |
var shape = xypic.Shape.TwocellEqualityArrowheadShape(env.c, env.angle); | |
context.appendShapeToFront(shape); | |
env.c = xypic.Frame.Point( | |
c.x + AST.xypic.lineElementLength * Math.cos(angle + Math.PI / 2), | |
c.y + AST.xypic.lineElementLength * Math.sin(angle + Math.PI / 2) | |
); | |
this.labelObject.toDropShape(context); | |
break; | |
default: | |
this.labelObject.toDropShape(context); | |
break; | |
} | |
env.c = c; | |
} | |
}); | |
AST.Command.Twocell.Arrow.WithPosition.Augment({ | |
toUpperTipsShape: function (context) { | |
this.toTipsShape(context, false, false); | |
}, | |
toLowerTipsShape: function (context) { | |
this.toTipsShape(context, false, false); | |
}, | |
toArrowShape: function(context, labelOrigin) { | |
var env = context.env; | |
var c = env.c; | |
var angle = env.angle; | |
var arrowPos; | |
var nudge = this.nudge; | |
if (nudge.isOmit) { | |
arrowPos = c; | |
} else { | |
var offset = nudge.number * AST.xypic.lineElementLength; | |
arrowPos = xypic.Frame.Point( | |
labelOrigin.x + offset * Math.cos(angle), | |
labelOrigin.y + offset * Math.sin(angle) | |
); | |
} | |
env.c = arrowPos; | |
env.twocellarrowobject.toDropShape(context); | |
if (!nudge.isOmit) { | |
env.c = xypic.Frame.Point( | |
arrowPos.x + AST.xypic.lineElementLength * Math.cos(angle + Math.PI / 2), | |
arrowPos.y + AST.xypic.lineElementLength * Math.sin(angle + Math.PI / 2) | |
); | |
this.labelObject.toDropShape(context); | |
} | |
env.c = c; | |
} | |
}); | |
AST.Pos.Xyimport.TeXCommand.Augment({ | |
toShape: function (context) { | |
var origEnv = context.env; | |
if (origEnv.c === undefined) { | |
return xypic.Shape.none; | |
} | |
var subEnv = origEnv.duplicate(); | |
var subcontext = xypic.DrawingContext(xypic.Shape.none, subEnv); | |
var shape = this.graphics.toDropShape(subcontext); | |
var xyWidth = this.width; | |
var xyHeight = this.height; | |
if (xyWidth === 0 || xyHeight === 0) { | |
throw xypic.ExecutionError("the 'width' and 'height' attributes of the \\xyimport should be non-zero."); | |
} | |
var c = subEnv.c; | |
var imageWidth = c.l + c.r; | |
var imageHeight = c.u + c.d; | |
if (imageWidth === 0 || imageHeight === 0) { | |
throw xypic.ExecutionError("the width and height of the graphics to import should be non-zero."); | |
} | |
var xOffset = this.xOffset; | |
var yOffset = this.yOffset; | |
origEnv.c = c.toRect({ | |
u:imageHeight / xyHeight * (xyHeight - yOffset), | |
d:imageHeight / xyHeight * yOffset, | |
l:imageWidth / xyWidth * xOffset, | |
r:imageWidth / xyWidth * (xyWidth - xOffset) | |
}); | |
origEnv.setXBase(imageWidth / xyWidth, 0); | |
origEnv.setYBase(0, imageHeight / xyHeight); | |
var dx = c.l - origEnv.c.l; | |
var dy = c.d - origEnv.c.d; | |
var shape = xypic.Shape.TranslateShape(dx, dy, subcontext.shape); | |
context.appendShapeToFront(shape); | |
} | |
}); | |
AST.Pos.Xyimport.Graphics.Augment({ | |
toShape: function (context) { | |
var origEnv = context.env; | |
if (origEnv.c === undefined) { | |
return xypic.Shape.none; | |
} | |
var subEnv = origEnv.duplicate(); | |
var subcontext = xypic.DrawingContext(xypic.Shape.none, subEnv); | |
var xyWidth = this.width; | |
var xyHeight = this.height; | |
if (xyWidth === 0 || xyHeight === 0) { | |
throw xypic.ExecutionError("the 'width' and 'height' attributes of the \\xyimport should be non-zero."); | |
} | |
var graphics = this.graphics; | |
graphics.setup(subcontext); | |
if (!subEnv.includegraphicsWidth.isDefined || !subEnv.includegraphicsHeight.isDefined) { | |
throw xypic.ExecutionError("the 'width' and 'height' attributes of the \\includegraphics are required."); | |
} | |
var imageWidth = subEnv.includegraphicsWidth.get; | |
var imageHeight = subEnv.includegraphicsHeight.get; | |
if (imageWidth === 0 || imageHeight === 0) { | |
throw xypic.ExecutionError("the 'width' and 'height' attributes of the \\includegraphics should be non-zero."); | |
} | |
var xOffset = this.xOffset; | |
var yOffset = this.yOffset; | |
origEnv.c = subEnv.c.toRect({ | |
u:imageHeight / xyHeight * (xyHeight - yOffset), | |
d:imageHeight / xyHeight * yOffset, | |
l:imageWidth / xyWidth * xOffset, | |
r:imageWidth / xyWidth * (xyWidth - xOffset) | |
}); | |
origEnv.setXBase(imageWidth / xyWidth, 0); | |
origEnv.setYBase(0, imageHeight / xyHeight); | |
var imageShape = xypic.Shape.ImageShape(origEnv.c, graphics.filepath); | |
context.appendShapeToFront(imageShape); | |
} | |
}); | |
AST.Command.Includegraphics.Augment({ | |
setup: function (context) { | |
var env = context.env; | |
env.includegraphicsWidth = FP.Option.empty; | |
env.includegraphicsHeight = FP.Option.empty; | |
this.attributeList.foreach(function (attr) { | |
attr.setup(context); | |
}); | |
} | |
}); | |
AST.Command.Includegraphics.Attr.Width.Augment({ | |
setup: function (context) { | |
var env = context.env; | |
env.includegraphicsWidth = FP.Option.Some(xypic.length2em(this.dimen)); | |
} | |
}); | |
AST.Command.Includegraphics.Attr.Height.Augment({ | |
setup: function (context) { | |
var env = context.env; | |
env.includegraphicsHeight = FP.Option.Some(xypic.length2em(this.dimen)); | |
} | |
}); | |
MathJax.Hub.Startup.signal.Post("Device-Independent Xy-pic Ready"); | |
}); | |
MathJax.Hub.Register.StartupHook("HTML-CSS Xy-pic Require",function () { | |
var FP = MathJax.Extension.fp; | |
var MML = MathJax.ElementJax.mml; | |
var HTMLCSS = MathJax.OutputJax["HTML-CSS"]; | |
var HUB = MathJax.Hub; | |
var xypic = MathJax.Extension.xypic; | |
var AST = xypic.AST; | |
var SVGNS = "http://www.w3.org/2000/svg"; | |
var XHTMLNS = "http://www.w3.org/1999/xhtml"; | |
var XLINKNS = "http://www.w3.org/1999/xlink"; | |
var setupHTMLCSSMeasure = function () { | |
xypic.length2em = function (len) { return HTMLCSS.length2em(len); } | |
xypic.oneem = xypic.length2em("1em"); | |
xypic.em2length = function (len) { return (len / xypic.oneem) + "em"; } | |
xypic.Em = function (x) { return HTMLCSS.Em(x); } | |
xypic.em = HTMLCSS.em; | |
xypic.em2px = function (n) { return Math.round(n * HTMLCSS.em * 100) / 100; } | |
xypic.axis_height = HTMLCSS.TeX.axis_height; | |
AST.xypic.strokeWidth = xypic.length2em("0.04em"); | |
AST.xypic.thickness = xypic.length2em("0.15em"); | |
AST.xypic.jot = xypic.length2em("3pt"); | |
AST.xypic.objectmargin = xypic.length2em("3pt"); | |
AST.xypic.objectwidth = xypic.length2em("0pt"); | |
AST.xypic.objectheight = xypic.length2em("0pt"); | |
AST.xypic.labelmargin = xypic.length2em("2.5pt"); | |
AST.xypic.turnradius = xypic.length2em("10pt"); | |
AST.xypic.lineElementLength = xypic.length2em("5pt"); | |
AST.xypic.axisHeightLength = xypic.axis_height * xypic.length2em("10pt"); | |
AST.xypic.dottedDasharray = "" + xypic.oneem + " " + xypic.em2px(AST.xypic.thickness); | |
}; | |
AST.xypic.Augment({ | |
toHTML: function (span) { | |
if (!xypic.useSVG) { | |
return span; | |
} | |
setupHTMLCSSMeasure(); | |
// HTML-CSS Text Objects | |
var textObjects = []; | |
var p = xypic.length2em("0.2em"); | |
var t = AST.xypic.strokeWidth; | |
span = this.HTMLcreateSpan(span); | |
var svgStack = HTMLCSS.createStack(span); | |
xypic.Shape.TextShape.Augment({ | |
_draw: function (svg, test) { | |
var math = this.math; | |
var span, stack, base; | |
math.setTeXclass(); | |
// padding | |
var p = xypic.length2em("0.1em"); | |
var mathSpan = HTMLCSS.Element("span", { | |
className:"MathJax", | |
style:{ "text-align":"center", "role":"textbox", "aria-readonly":"true", "position":"absolute", color:svg.getCurrentColor() /*, "border":"0.1px dashed" */ } | |
}); | |
svgStack.appendChild(mathSpan); | |
// clear spanID for connecting objects. | |
var clearSpanId = function (mml) { | |
if (mml) { | |
if (mml.hasOwnProperty("spanID")) { delete mml.spanID; } | |
if (mml.data) { | |
for (var i = 0, n = mml.data.length; i < n; i++) { | |
clearSpanId(mml.data[i]); | |
} | |
} | |
} | |
} | |
clearSpanId(math); | |
var span = math.HTMLcreateSpan(mathSpan); | |
stack = HTMLCSS.createStack(span); | |
base = HTMLCSS.createBox(stack); | |
math.HTMLmeasureChild(0, base); | |
var H = base.bbox.h + p, D = base.bbox.d + p, W = base.bbox.w + 2 * p; | |
var frame = HTMLCSS.createFrame(stack, H + D, 0, W, 0, "none"); | |
frame.id = "MathJax-frame-" + math.spanID + HTMLCSS.idPostfix; | |
// stack.style.border = "solid 0.1px pink"; | |
// base.style.border = "solid 0.1px pink"; | |
// frame.style.border = "solid 0.1px pink"; | |
HTMLCSS.addBox(stack, frame); | |
stack.insertBefore(frame, base); | |
frame.style.width = xypic.em2px(W); | |
frame.style.height = xypic.em2px(H + D); | |
HTMLCSS.placeBox(frame, 0, -D, true); | |
HTMLCSS.placeBox(base, p, 0); | |
math.HTMLhandleSpace(span); | |
math.HTMLhandleColor(span); | |
var spanHeight = span.offsetHeight; | |
var halfHD = (H + D) / 2; | |
var halfW = W / 2; | |
var c = this.c; | |
this.originalBBox = { H:H, D:D, W:W }; | |
if (!test) { | |
var origin = svg.getOrigin(); | |
mathSpan.setAttribute("x", c.x - halfW - origin.x); | |
mathSpan.setAttribute("y", -c.y - halfHD - origin.y - stack.offsetTop / HTMLCSS.em + H); | |
textObjects.push(mathSpan); | |
/* | |
svg.createSVGElement("rect", { | |
x:xypic.em2px(c.x - halfW), | |
y:-xypic.em2px(c.y - (H - D) / 2), | |
width:xypic.em2px(W), | |
height:0.1, | |
stroke:"green", "stroke-width":0.3 | |
}); | |
console.log("span.top:" + span.offsetTop + ", " + (span.offsetTop / HTMLCSS.em) + "em"); | |
console.log("span.height:" + span.offsetHeight + ", " + (span.offsetHeight / HTMLCSS.em) + "em"); | |
console.log("stack.top:" + stack.offsetTop + ", " + (stack.offsetTop / HTMLCSS.em) + "em"); | |
console.log("stack.height:" + stack.offsetHeight + ", " + (stack.offsetHeight / HTMLCSS.em) + "em"); | |
console.log("frame.top:" + frame.offsetTop + ", " + (frame.offsetTop / HTMLCSS.em) + "em"); | |
console.log("frame.height:" + frame.offsetHeight + ", " + (frame.offsetHeight / HTMLCSS.em) + "em"); | |
console.log("base.top:" + base.offsetTop + ", " + (base.offsetTop / HTMLCSS.em) + "em"); | |
console.log("base.height:" + base.offsetHeight + ", " + (base.offsetHeight / HTMLCSS.em) + "em"); | |
console.log("p:" + xypic.em2px(p) + ", " + p + "em"); | |
console.log("D:" + xypic.em2px(D) + ", " + D + "em"); | |
console.log("H:" + xypic.em2px(H) + ", " + H + "em"); | |
console.log("d:" + xypic.em2px(base.bbox.d) + ", " + base.bbox.d + "em"); | |
console.log("h:" + xypic.em2px(base.bbox.h) + ", " + base.bbox.h + "em"); | |
svg.createSVGElement("rect", { | |
x:xypic.em2px(c.x - halfW), | |
y:-xypic.em2px(c.y + halfHD), | |
width:xypic.em2px(W), | |
height:xypic.em2px(H + D), | |
stroke:"green", "stroke-width":0.5 | |
}); | |
*/ | |
} else { | |
svgStack.removeChild(mathSpan); | |
} | |
return c.toRect({ u:halfHD, d:halfHD, l:halfW, r:halfW }); | |
} | |
}); | |
var bbox = { h:1, d:0, w:1, lw:0, rw:1 }; | |
var H = bbox.h, D = bbox.d, W = bbox.w; | |
var frame = HTMLCSS.createFrame(svgStack, H + D, 0, W, t, "none"); | |
frame.id = "MathJax-frame-" + this.spanID + HTMLCSS.idPostfix; | |
var svg; | |
var color = "black"; | |
svg = xypic.Graphics.createSVG(H, D, W, t, color, { | |
viewBox:[0, -xypic.em2px(H + D), xypic.em2px(W), xypic.em2px(H + D)].join(" "), | |
overflow:"visible" | |
}); | |
xypic.svgForDebug = svg; | |
xypic.svgForTestLayout = svg; | |
var scale = HTMLCSS.createBox(svgStack); | |
scale.appendChild(svg.svg); | |
var xypicData = this.cmd; | |
if (xypicData) { | |
var env = xypic.Env(); | |
var context = xypic.DrawingContext(xypic.Shape.none, env); | |
xypicData.toShape(context); | |
var shape = context.shape; | |
shape.draw(svg); | |
var box = shape.getBoundingBox(); | |
if (box !== undefined) { | |
box = xypic.Frame.Rect( | |
0, 0, | |
{ | |
l:Math.max(0, -(box.x - box.l)), | |
r:Math.max(0, box.x + box.r), | |
u:Math.max(0, box.y + box.u), | |
d:Math.max(0, -(box.y - box.d)) | |
} | |
); | |
svg.setWidth(box.l + box.r + 2 * p); | |
svg.setHeight(box.u + box.d + 2 * p); | |
svg.setAttribute("viewBox", [ xypic.em2px(box.x - box.l - p), -xypic.em2px(box.y + box.u + p), xypic.em2px(box.l + box.r + 2 * p), xypic.em2px(box.u + box.d + 2 * p) ].join(" ")); | |
var c = textObjects.length; | |
for (var i = 0; i < c; i++) { | |
var to = textObjects[i]; | |
var x = parseFloat(to.getAttribute("x")); | |
var y = parseFloat(to.getAttribute("y")); | |
to.style.left = "" + xypic.em2px(x + box.l + p * xypic.oneem) + "px"; | |
to.style.top = "" + xypic.em2px(y - xypic.axis_height) + "px"; | |
} | |
bbox = { h:(box.u + p), d:(box.d + p), w:(box.l + box.r + 2 * p), lw:0, rw:(box.l + box.r + 2 * p)} | |
span.bbox = bbox; | |
D = box.d + p; | |
W = box.l + box.r + 2 * p; | |
H = box.h + p; | |
HTMLCSS.placeBox(scale, 0, xypic.axis_height - D, true); | |
frame.style.width = xypic.Em(W); | |
frame.style.height = xypic.Em(H + D); | |
HTMLCSS.addBox(svgStack, frame); | |
HTMLCSS.placeBox(frame, W - 1, -D, true); | |
this.HTMLhandleSpace(span); | |
this.HTMLhandleColor(span); | |
} else { | |
// there is no contents | |
span = span.parentNode; | |
span.removeChild(span.firstChild); | |
} | |
} else { | |
// there is no contents | |
span = span.parentNode; | |
span.removeChild(span.firstChild); | |
} | |
return span; | |
} | |
}); | |
AST.xypic.newdir.Augment({ | |
toHTML: function (span) { | |
var newdir = this.cmd; | |
xypic.repositories.dirRepository.put(newdir.dirMain, newdir.compositeObject); | |
return span; | |
} | |
}); | |
AST.xypic.includegraphics.Augment({ | |
toHTML: function (span) { | |
setupHTMLCSSMeasure(); | |
var graphics = this.cmd; | |
var env = xypic.Env(); | |
var context = xypic.DrawingContext(xypic.Shape.none, env); | |
graphics.setup(context); | |
if (!env.includegraphicsWidth.isDefined || !env.includegraphicsHeight.isDefined) { | |
throw xypic.ExecutionError("the 'width' and 'height' attributes of the \\includegraphics are required."); | |
} | |
var imageWidth = env.includegraphicsWidth.get; | |
var imageHeight = env.includegraphicsHeight.get; | |
span = this.HTMLcreateSpan(span); | |
var stack = HTMLCSS.createStack(span); | |
var base = HTMLCSS.createBox(stack); | |
var img = new Image(); | |
img.src = graphics.filepath; | |
img.style.width = HTMLCSS.Em(imageWidth); | |
img.style.height = HTMLCSS.Em(imageHeight); | |
base.appendChild(img); | |
var bbox = {h:imageHeight, d:0, w:imageWidth, rw:imageWidth, lw:0, exactW:true}; | |
img.bbox = bbox; | |
var H = imageHeight, D = 0, W = imageWidth; | |
HTMLCSS.Measured(img); | |
var frame = HTMLCSS.createFrame(stack, H+D, 0, W, 0, "none"); | |
frame.id = "MathJax-frame-" + this.spanID; | |
HTMLCSS.addBox(stack, frame); | |
stack.insertBefore(frame, base); | |
var T = 0, B = 0, R = 0, L = 0, dx = 0, dy = 0; | |
frame.style.width = HTMLCSS.Em(W-L-R); | |
frame.style.height = HTMLCSS.Em(H+D-T-B); | |
HTMLCSS.placeBox(frame, 0, dy-D, true); | |
HTMLCSS.placeBox(base, dx, 0); | |
this.HTMLhandleSpace(span); | |
this.HTMLhandleColor(span); | |
return span; | |
} | |
}); | |
MathJax.Hub.Startup.signal.Post("HTML-CSS Xy-pic Ready"); | |
}); | |
MathJax.Hub.Register.StartupHook("SVG Xy-pic Require",function () { | |
var FP = MathJax.Extension.fp; | |
var MML = MathJax.ElementJax.mml; | |
var SVG = MathJax.OutputJax.SVG; | |
var BBOX = SVG.BBOX; | |
var HUB = MathJax.Hub; | |
var xypic = MathJax.Extension.xypic; | |
var AST = xypic.AST; | |
var SVGNS = "http://www.w3.org/2000/svg"; | |
var XHTMLNS = "http://www.w3.org/1999/xhtml"; | |
var XLINKNS = "http://www.w3.org/1999/xlink"; | |
var memoize = xypic.memoize; | |
BBOX.PPATH = BBOX.Subclass({ | |
type: "path", removeable: false, | |
Init: function (h,d,w,p,t,color,def) { | |
if (def == null) {def = {}}; def.fill = "none"; | |
if (color) {def.stroke = color} | |
def["stroke-width"] = t.toFixed(2).replace(/\.?0+$/,""); | |
def.d = p; | |
this.SUPER(arguments).Init.call(this,def); | |
this.w = this.r = w; this.h = this.H = h+d; | |
this.d = this.D = this.l = 0; this.y = -d; | |
} | |
}); | |
BBOX.XYPIC = BBOX.Subclass({ | |
type: "g", removeable: false, | |
Init: function (bbox, x, y, svg) { | |
this.element = svg; | |
this.x = x; | |
this.y = y; | |
this.r = bbox.r; | |
this.l = bbox.l; | |
this.h = bbox.h; | |
this.d = bbox.d; | |
this.w = bbox.w; | |
this.H = bbox.h; | |
this.D = bbox.d; | |
this.scale = 1; | |
this.n = 1; | |
} | |
}); | |
var setupSVGMeasure = function (mu, scale) { | |
xypic.length2em = function (len) { return SVG.length2em(len, mu, 1/SVG.em) * scale; } | |
xypic.oneem = xypic.length2em("1em"); | |
xypic.em2length = function (len) { return (len / xypic.oneem) + "em"; } | |
xypic.Em = function (x) { return SVG.Em(x); } | |
xypic.em = SVG.em; | |
xypic.em2px = function (n) { return Math.round(n * SVG.em * 100) / 100; } | |
xypic.axis_height = SVG.TeX.axis_height; | |
AST.xypic.strokeWidth = xypic.length2em("0.04em"); | |
AST.xypic.thickness = xypic.length2em("0.15em"); | |
AST.xypic.jot = xypic.length2em("3pt"); | |
AST.xypic.objectmargin = xypic.length2em("3pt"); | |
AST.xypic.objectwidth = xypic.length2em("0pt"); | |
AST.xypic.objectheight = xypic.length2em("0pt"); | |
AST.xypic.labelmargin = xypic.length2em("2.5pt"); | |
AST.xypic.turnradius = xypic.length2em("10pt"); | |
AST.xypic.lineElementLength = xypic.length2em("5pt"); | |
AST.xypic.axisHeightLength = xypic.axis_height * xypic.length2em("1em") / 1000; | |
AST.xypic.dottedDasharray = "" + xypic.oneem + " " + xypic.em2px(AST.xypic.thickness); | |
}; | |
AST.xypic.Augment({ | |
toSVG: function (HW, DD) { | |
this.SVGgetStyles(); | |
var svg = this.SVG(); | |
this.SVGhandleSpace(svg); | |
var mu = this.SVGgetMu(svg); | |
var scale = this.SVGgetScale(); | |
setupSVGMeasure(mu, scale); | |
var p = xypic.length2em("0.2em"); | |
var t = AST.xypic.strokeWidth; | |
var jaxSVG = svg; | |
xypic.Shape.TextShape.Augment({ | |
_draw: function (svg, test) { | |
var math = this.math; | |
// padding | |
var p = xypic.length2em("0.1em"); | |
var c = this.c; | |
math.setTeXclass(); | |
math.SVGgetStyles(); | |
math.SVGhandleSpace(jaxSVG); | |
var box = math.data[0].toSVG(); | |
var x = c.x - box.w / 2; | |
var y = c.y - (box.h + box.d) / 2 + box.d + xypic.axis_height; | |
var H = box.h + p; | |
var D = box.d + p; | |
var W = box.w + 2 * p; | |
this.originalBBox = { H:H, D:D, W:W }; | |
var halfHD = (H + D) / 2; | |
var halfW = W / 2; | |
if (!test) { | |
var origin = svg.getOrigin(); | |
var color = svg.getCurrentColor(); | |
var localSVG = BBOX.G({ stroke:color, fill:color, "stroke-thickness":0, transform:"scale(" + SVG.em + ") matrix(1 0 0 -1 0 0) translate(" + xypic.em2px(x / SVG.em) + ", " + xypic.em2px((c.y - (H - D) / 2) / SVG.em) + ")" }).With({removeable: false}); | |
localSVG.Add(box, 0, 0, true, true); | |
localSVG.ic = box.ic; | |
localSVG.Clean(); | |
math.SVGhandleColor(localSVG); | |
math.SVGsaveData(localSVG); | |
svg.appendChild(localSVG.element); | |
} | |
return c.toRect({ u:halfHD, d:halfHD, l:halfW, r:halfW }); | |
} | |
}); | |
var bbox = { h:xypic.oneem, d:0, w:xypic.oneem, lw:0, rw:xypic.oneem }; | |
var H = bbox.h, D = bbox.d, W = bbox.w; | |
var color = "black"; | |
var xypicSVG = xypic.Graphics.createSVG(H, D, W, t, color, { | |
viewBox:[0, -xypic.em2px(H + D), xypic.em2px(W), xypic.em2px(H + D)].join(" "), | |
overflow:"visible" | |
}); | |
xypic.svgForDebug = xypicSVG; | |
xypic.svgForTestLayout = xypicSVG; | |
var xypicData = this.cmd; | |
if (xypicData) { | |
var env = xypic.Env(); | |
var context = xypic.DrawingContext(xypic.Shape.none, env); | |
xypicData.toShape(context); | |
var shape = context.shape; | |
shape.draw(xypicSVG); | |
var shapeBBox = shape.getBoundingBox(); | |
if (shapeBBox !== undefined) { | |
var box = xypic.Frame.Rect( | |
0, 0, | |
{ | |
l:Math.max(0, -(shapeBBox.x - shapeBBox.l)), | |
r:Math.max(0, shapeBBox.x + shapeBBox.r), | |
u:Math.max(0, shapeBBox.y + shapeBBox.u), | |
d:Math.max(0, -(shapeBBox.y - shapeBBox.d)) | |
} | |
); | |
bbox = { h:(box.u + p + xypic.axis_height), d:(box.d + p - xypic.axis_height), w:(box.r + box.l + 2*p), l:(- box.l - p), r:(box.r + p)} | |
this.SVGhandleSpace(svg); | |
var xypicBBOX = BBOX.XYPIC(bbox, 0, 0, xypicSVG.drawArea); | |
xypicBBOX.element.setAttribute("transform", "scale(" + (1 / SVG.em) + ") matrix(1 0 0 -1 0 0) translate(0," + xypic.em2px(- xypic.axis_height) + ")"); | |
svg.Add(xypicBBOX); | |
// FIXME | |
svg.x += box.l + p; | |
svg.w -= box.l + p; | |
this.SVGhandleColor(svg); | |
this.SVGsaveData(svg); | |
} | |
} | |
return svg; | |
} | |
}); | |
AST.xypic.newdir.Augment({ | |
toSVG: function () { | |
var newdir = this.cmd; | |
xypic.repositories.dirRepository.put(newdir.dirMain, newdir.compositeObject); | |
return this.SVG(); | |
} | |
}); | |
AST.xypic.includegraphics.Augment({ | |
toSVG: function (HW, DD) { | |
this.SVGgetStyles(); | |
var svg = this.SVG(); | |
this.SVGhandleSpace(svg); | |
var mu = this.SVGgetMu(svg); | |
var scale = this.SVGgetScale(); | |
setupSVGMeasure(mu, scale); | |
var t = AST.xypic.strokeWidth; | |
var bbox = { h:xypic.oneem, d:0, w:xypic.oneem, lw:0, rw:xypic.oneem }; | |
var H = bbox.h, D = bbox.d, W = bbox.w; | |
var color = "black"; | |
var xypicSVG = xypic.Graphics.createSVG(H, D, W, t, color, { | |
viewBox:[0, -xypic.em2px(H + D), xypic.em2px(W), xypic.em2px(H + D)].join(" "), | |
overflow:"visible" | |
}); | |
xypic.svgForDebug = xypicSVG; | |
xypic.svgForTestLayout = xypicSVG; | |
var env = xypic.Env(); | |
var context = xypic.DrawingContext(xypic.Shape.none, env); | |
var graphics = this.cmd; | |
graphics.setup(context); | |
if (!env.includegraphicsWidth.isDefined || !env.includegraphicsHeight.isDefined) { | |
throw xypic.ExecutionError("the 'width' and 'height' attributes of the \\includegraphics are required."); | |
} | |
var imageWidth = env.includegraphicsWidth.get; | |
var imageHeight = env.includegraphicsHeight.get; | |
var c = env.c; | |
c = c.toRect({ u:imageHeight - xypic.axis_height, d:xypic.axis_height, l:0, r:imageWidth }); | |
var imageShape = xypic.Shape.ImageShape(c, graphics.filepath); | |
imageShape.draw(xypicSVG); | |
var shapeBBox = imageShape.getBoundingBox(); | |
var box = xypic.Frame.Rect( | |
0, 0, | |
{ | |
l:Math.max(0, -(shapeBBox.x - shapeBBox.l)), | |
r:Math.max(0, shapeBBox.x + shapeBBox.r), | |
u:Math.max(0, shapeBBox.y + shapeBBox.u), | |
d:Math.max(0, -(shapeBBox.y - shapeBBox.d)) | |
} | |
); | |
var bbox = { h:(box.u + xypic.axis_height), d:(box.d - xypic.axis_height), w:(box.r + box.l), l:(- box.l), r:(box.r)} | |
this.SVGhandleSpace(svg); | |
var xypicBBOX = BBOX.XYPIC(bbox, 0, 0, xypicSVG.drawArea); | |
xypicBBOX.element.setAttribute("transform", "scale(" + (1 / SVG.em) + ") matrix(1 0 0 -1 0 0) translate(0," + xypic.em2px(- xypic.axis_height) + ")"); | |
svg.Add(xypicBBOX); | |
svg.x += box.l; | |
svg.w -= box.l; | |
this.SVGhandleColor(svg); | |
this.SVGsaveData(svg); | |
return svg; | |
} | |
}); | |
MathJax.Hub.Startup.signal.Post("SVG Xy-pic Ready"); | |
}); | |
MathJax.Ajax.loadComplete("http://bit.ly/youqadXyJax"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment