Last active
June 20, 2017 13:20
-
-
Save youqad/c2f734f54f5a2e3176e7a998a229b51f to your computer and use it in GitHub Desktop.
This file contains hidden or 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 <sonoisa@gmail.com>. | |
| * | |
| * 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