网页版几何画板开发笔记(十七) 增强版本的作图检测

过去实现的作图检测有了新的发展的需求, 因此需要对此功能进行增强/升级. 主要的增强是提供了
简单表达式计算(含简单对象字段获取,变量), 扩展/增加了判断函数, 自定义判断提示信息几个方面.

变量和表达式

需要进行一些简单计算的场合, 因此判断脚本需要支持变量和简单表达式.

变量通常是以$开头的标识符, 标识符中可使用 字母,数字和下划线. 例如 $a, $x, $1, $long_name 等.
使用 $ 开头是为了避免和几何对象的标记相混淆和冲突, 如几何中点通常标记为大写字母, 线,圆
标记为小写字母, 角有时候标记为数字.

简单表达式计算中支持 +, -, *, / (加减乘除), 比较. 下面简单列出, 设 $a, $b 是两个量:
   $a + $b : 求两个量的和, 数字可以相加, 两个字符串也可以加.
   $a - $b: 减.
   $a * $b: 乘.
   $a / $b: 除.
   $a % $b: 求模, 一般此计算对整数才有意义.
   $a == $b:  相等比较. 由于 js 中使用浮点数, 浮点数计算后通常不能保证一定精确相等.
   $a ~= $b:  近似相等, 两者的差的绝对值小于 0.000001 (EPSILON) 就认为是近似相等.
   $a != $b:  不相等.
   $a < $b:  比较 a 小于 b.
   $a > $b:  比较 a 大于 b.
   $a <= $b: 小于等于.
   $a >= $b: 大于等于.
   $a & $b:  逻辑与(and), 两值都为真才为真.
   $a | $b: 逻辑或(or), a,b有任何一值为真结果即为真.

还支持用 . (句点) 访问对象的简单属性, 例如设 $a 获得一个点对象时:
   $a = point(A);
   $a.x, $a.y 得到该点的 x,y 坐标. 它们可用于计算中, 如:
   $r = sqrt($a.x * $a.x + $a.y * $a.y);
不同的对象有不同的属性. 在下面获得对象的地方有简单说明.

 

函数调用

在新的检测脚本中提供了很多检测,获取值,计算的函数, 调用方式是:
   funame(arg1, arg2, ...);

有些(大部分)函数有返回值, 如:
   $p = point(P);  --- 得到点 P 的对象.

函数也能被嵌套调用:
   $val = px2cm(dist(A,B)) + sin(log(x));

在每个表达式后面, 分号的前面, 可以使用错误信息子句, 最常用的地方是函数调用之后:
   $m = line(m) error '获取线 m 时发生某种错误';
错误信息子句被设计用来提供自定义的错误信息, 根据题意, 教师选择合适的错误信息, 能够给学生
更恰当的指导.

错误信息子句可使用多种错误类型, 如:
   $x = point(X)  unlabel '没有找到标记为 X 的点'
                         unexist '点 X 不存在'
                         invisible '点 X 不可见'
                         errtype '有标记为 X 的对象, 但不是点'
                         multi  '有多个点被标记为 X, 所以指代不明确.'
                         error '错误总类' ;

注意表达式最后一定要有 ';' 分号结束. 现在程序需要有这个分号做为表达式结束标志.

错误子句实际上是加在表达式最后的, 所以下面写也是可以的:
   $not_care = line(m) & point(B) & point(C) & line(n) error '错误子句' ;
这个表达式一次检测了线 m, 点 B,C, 线 n, 并使用最后的错误子句报告错误信息.

抑制错误报告: 有时候调用某个函数只为判断点,线,圆等对象是否存在, 而不是报告错误(然后终止了),
   此时可以使用 @func(...) 形式来调用函数, 即在函数调用前面加上 @ 符号, 该符号的作用是
   抑制错误报告和终止, 如果有错误仍然返回, 但返回的对象为 null 或 判定返回 false(假).

例子: $x = @point(X);  --- 假设没有点 X (或别的错误情况), 则该调用返回 $x 为 null.
   实际错误信息保存在变量 $check_result 中, 错误数量保存在变量 $error_count 中.
例如: print($x) 打印为 null, print($check_result) 打印为 '请标记出点 X.'
   如果自定义了 error/false 子句, 则该错误信息是自定义的子句值.

 

辅助函数

print (a, b, ...);   --- 在浏览器 console (调试控制台)打印出参数, 参数数量不限制. 通常用于调试.
judge(cond) false '错误信息';  ---  给出一个条件值 cond, 如果为假则输出后面的错误信息, 并终止程序.

判断函数

保留了一些和前一版本兼容(有少量改动会标记出来)的判断函数, 并增加了一些新的判断函数. 判断函数比较容易增加.
有的函数有两种(或更多)形式, 程序是根据参数数量判断的, 因此请确保参数数量是对的.

下面的判定函数, 参数为大写字母的大多表示一个点, 小写字母一般表示是数字或对象, $开头的一般表示变量.

print(arg1, arg2, ...) 在浏览器 console 上输出 arg1, arg2,... 的信息, 这里参数数量不限.
这个函数一般用于调试输出一些信息, 帮助查看相应信息. 下面的示例中就常用到.
 point(A)
point(A,B,C, ...)

判定和得到点 A 对象. 形式2 point(A,B,C ...) 可一次判断多个点, 但只返回最后一个点对象.
例子:
   $a = point(A);    --- 得到点 A.
   print ($a.x, $a.y);  ---  输出点 A 的坐标 (x,y) 于浏览器 console.
   $a.name --- 此点的名字, 这个例子中为 'A'. 注意: 有些点可能(学生)没有标记名字.
   $a.type --- 对象类型, 对于点总是 'point'
   $a.sub_type --- 点的子类型, 当前主要有 'freept' (自由点), 'midpt' (中点), 'oopt' (线或圆上的点), ...
   $a.exist --- 点是否存在, 在数学意义上. 如两线段交点, 线段不交的时候, 则原来构造的交点对象有, 但其
        exist 为 false.
   $a = point(A) unlabel '没有标记为 A 的点.'      --- 画板中没有找到标记为 A 的点.
                       errtype '有标记为 A 的别的对象, 但不是点.'
                       multi    '有多个点被标记为 A, 指代不明确.'
                       invisible '点 A 被隐藏, 而不可见.'
                       unexist  '点 A 不存在.'
                       error   '发生上述某种错误.' ;

在对象判定和获取函数的后面可以使用 unlabel, errtype, multi, invisible, unexist 等错误信息自定义子句, 给出学生更准确的错误信息.

vpoint(x, y, name) 创建一个虚的点, 其坐标为 (x,y), 这个点可参与各种判定函数的计算, 但不对应到画板中的点 (也许画板中该位置的确有一个点, 但不和这个对象关联).
可选给出一个名字 name. 可帮助输出信息的时候使用. 例子:
   --- 假设 $a 是另一个点.
   $x = vpoint($a.y, $b.x);   ---- 点 $x 位置等于是 $a 点的 y=x 线的对称点.
   dist($a, $x);  --- 计算两个点的距离.
   $y = vpoint(100, 40, 'Y');  --- 虚拟点 Y, 位置在 (100,40)
line(A, B)
line(m)
any_line(A,B)

形式1 判断并得到过点 A,B 的线对象(含各种线, 如 seg线段, ray射线, sline直线, paral 平行线, perpl 垂线, bisl 角平分线)
形式2 判断并得到标记为 m 的线.  any_line() 是 line() 的过去的名字, 为兼容过去的脚本而保留.
  $m = line(m)  unlabel '未标记' 
              errtype '类型不对' 
              multi '多线同名' 
              invisible '不可见

              unexist '不存在'
              error '上述各种错误总类';

  可用的错误子句同 point() 函数.

线对象保证可以获得构成此线的两个点 p1 ,p2, 如:
   print ($m.p1, $m.p2);
要注意的是 部分线类型构成该线的点 p1 或和 p2 只有 (x,y) 坐标位置(如构造的平行线), p1,p2不是真正的点对象.

seg(A,B)
seg(m)
类似于 line() 函数, 限定线的类型是 'seg', 即线段. 
ray(A, B)
ray(m)
类似于 line() 函数, 限定线的类型是 'ray','bisl', 即射线. 这里构造的角平分线(bisl)也被认为是一种射线.
sline(A, B)
sline(m)
类似于 line() 函数, 限定线的类型是 'sline','paral','perpl' 即直线. 这里构造的平行线(paral)和垂线(perpl) 也被认为是一种直线.
paral(A, B)
paral(m)
类似于 line() 函数, 限定线的类型是 'paral', 即构造时为平行线.
perpl(A, B)
perpl(m)
类似于 line() 函数, 限定线的类型是 'perpl', 即构造时为垂线.
bisl(A,B)
bisl(m)
类似于 line() 函数, 限定线的类型是 'bisl', 即在构造时为角平分线.
circ(c)
circ(O, A)
circ(A,B,C)

形式1 判断并得到标记为 c 的圆对象. 如果标记为 c 的圆没有, 则尝试将 c 当做是一个点, 并判断是否有以该点为圆心的圆.
形式2 判断并得到圆心为 O, 圆上有一点 A 的圆对象.
形式3 判断并得到一个圆对象, 此圆过三点 A,B,C.
例子:
   $c = circ(c);   --- 找标记为 c 的圆, 或圆心为 c 的圆.
   $c = circ(O);   --- 设O 为点, 则找圆心为 O 的圆.
   $c = circ(O, A);   --- 找圆心为 O, 圆上一点为 A 的圆.

在 circ(c) 后面可使用 unlabel, unexist, invisible, multi 等子句自定义错误提示信息.
每个圆对象一定有圆心点, 为 $c.op, 其中过三点圆可能圆心是一个只有 (x,y) 坐标的假点.
每个圆对象一定有半径属性, 如 print ($c.r), 单位是像素.

 

判断 △ABC≌△PQR. 三角形全等.
 coll(A,B,C)  判断点A,B,C 是否共线.
 not_coll(A,B,C)  判断点A,B,C 不共线, 也即这三个点可构成三角形.

para(A,B,C,D)
para(m, n)

形式1判断AB 是否平行(∥)于CD, 其中A,B,C,D 都是点, 不要求有任何线.
形式2判断线 m,n 是否平行.  
例子:
   $m = line(A, B);   --- 得到过点 A,B 的线, 注意也含判定.
   $n = line(n
);    --- 得到标记为 n 的线. 
   para($m, $n) false 'AB 不平行线 n';   --- 进行判定.

perp(A,B,C,D)
perp(m, n)
形式1 判断 AB 是否垂直(⊥)于CD.
形式2判断线 m,n 是否垂直.
intpt_ll(X,A,B,C,D)
intpt_ll(X, m, n)
形式1 判断点 X 是否在 AB, CD 两线的交点位置.
形式2 判断点 X 是否在 m, n 两线的交点位置.
实际实现上来说, 如果 X,A,B 共线, 且X,C,D 共线, 则X 是 AB,CD 的交点.
cycl(A,B,C,D) 判断 A,B,C,D 四点共圆.
eqdist(A,B,C,D) 判断距离 AB=CD.
现在还可以写为:
  $ab = dist(A,B);       --- 求 A,B 间距离.
  $cd = dist(C,D);       --- 求 C,D 间距离.
  judge ($ab == $cd);   --- 判断两值相等, 由于浮点计算有天然的细小的误差, 这个判定几乎不会成立.
  judge ($ab ~= $cd);   --- 两个值近似相等, 程序中近似指两值差绝对值小于 0.000001
  judge (abs($ab - $cd) < 0.001);   --- 判断近似相等, 差小于 0.001, 比上面的比较宽松一些.
eqang(A,B,C, P,Q,R) 判断∠ABC=∠PQR. 角相等.
现在也可以写作:
  $b = angle(A,B,C);   --- 得到∠ABC 的值, 单位是弧度.
  $q = angle(P,Q,R);   --- 得到∠PQR 的值, 单位是弧度.
  judge ($b ~= $q);    --- 判断两值近似相等.
con_tri(A,B,C, P,Q,R)
sim_tri(A,B,C, P,Q,R) 判断 △ABC∽△PQR. 三角形相似.
equ_tri(A,B,C) 判断 △ABC 是等边三角形.
ang_is(A,B,C, degree) 判断 ∠ABC=指定度数 degree. (如 90°, 注意这里单位不是弧度)
可以使用rad2d(x) 函数转换弧度为角度.
angle_v(A,B,C) 得到∠ABC 的值, 该值为弧度.
可以使用 rad2d(x) 函数转换弧度为角度.
angle(A,B,C) 判断存在角 ∠ABC, 其中 B 是顶点, BA,BC 是两条边(即存在任意的线在 BA,BC)
tri(A,B,C, opt) 判断 A,B,C 是一个三角形. 如果 opt 给出为字符串 'seg', 则要求 AB,BC,CA 之间有线段.
如果 opt 为字符串 'line', 则AB,BC,CA 之间只要有任何种类的线即可. opt 不给出则不限制是否有线段.
也即此判断函数可调用为 tri(A,B,C) --- 不用给出 opt 参数. 
acute_tri(A,B,C, opt) 判断 A,B,C 是一个锐角三角形. 选项参数 opt 含义同 tri() 判定函数.
right_tri(A,B,C, opt) 判断 A,B,C 是一个直角三角形, 其中角 A 是直角. 选项参数 opt 含义同 tri() 判定函数.
obtuse_tri(A,B,C,opt) 判断 A,B,C 是一个钝角三角形. 选项参数 opt 含义同 tri() 判定函数.
amark(A,O,B)
amark(n)
形式1 判断∠AOB 有一个标记, 并返回该角标记对象.
形式2 判断有一个标记为 n 的角标记, 并返回该角标记对象.
调用示例(假设已经画了一个角ABC, 并标记为 1):
$1 = amark('1');  --- 得到该角标记, 此对象在画板中是一个 AngleMark 类的实例.
print ($1);   --- 在浏览器的 console 中打印出这个角标记对象.
print ($1.value, $1.value_d);   --- 输出这个角的弧度值, 度数(°)值.
print ($1.style);  --- 这个标记样式, 值为1,2,3,4, 分别表示标记是1-4个弧线.
lmark(A,B) 判断线段A,B 之间有线标记, 并返回线标记对象, 在画板中是一个 LineMark 类的实例.
todo: 实现形式2: lmark(name), 根据名字得到线标记.
$1 = lmark(A,B);
print($1.style);  --- 标记样式, 取值1-4 表示由几个小线段构成.
mk_ss(m1, m2) 判断标记对象 $m1, $m2 有相同的样式, 也即 $m1.style == $m2.style.
ratio(A,B,C,D, E,F,G,H) 判断 AB:CD = EF:GH, 即线段构成比例.
现在也可以用 dist(A,B)/dist(CD) 和 dist(E,F)/dist(G,H) 计算出其比例, 然后用 judge(b) 进行判断.
ratio_2(A,B,C,D,n1,n2) 判断 AB:CD=n1:n2 线段构成比例, 其中 n1,n2 是数字.
现在可以自己计算长度和比例, 如 dist(A,B)/dist(C,D).
intpt(X)

判定点 X 是被构造为交点的类型(点对象的 sub_type == 'intpt'), 并返回该点.
现在可以写为:
  $x = point(X);
  judge($x.sub_type == 'intpt') false '请构造两线的交点X.';

 

 is_square(A,B,C,D,opt) 判断A,B,C,D 构成正方形. 选项 opt 取值可为 'seg', 'line', 含义同 tri() 函数中的 opt 参数.
 is_rect(A,B,C,D,opt) 判断A,B,C,D 构成矩形(长方形). opt 参数同上. 正方形也是矩形. 
 is_diam(A,B,C,D,opt) 判断A,B,C,D 构成菱形. opt 参数同上. 正方形也是菱形. 
is_paralg(A,B,C,D,opt) 判断A,B,C,D 构成平行四边形. 正方形, 长方形, 菱形也是(特殊)平行四边形.
is_trapz(A,B,C,D,opt) 判断 A,B,C,D 构成梯形, 其中 AB//CD, 梯形两腰不平行.
quad(A,B,C,D,opt) 判断存在任意 A,B,C,D 构成的四边形. opt 参数同上.
at_ray(A, B, C) 判断点 A 在射线 B->C 上.
at_seg(A, B, C) 判断点 A 在线段 B, C 上(在线段之内).
pt_at(x, y) 已知坐标 x,y, 找到差异在 EPSILON 之内的点对象, 如果没有找到则返回 null.
is_refl(A, B, m) 判断点 A,B 是否关于直线 m 对称.
ln_intp(m, n) 计算两线 m, n 的交点位置. 如果线是线段或射线, 则交点在线段内或射线上才算交点.
返回为一个 vpoint.
cc_intp(c1, c2, which) 计算两个圆的交点. which 如果为 1 则返回第一个交点, 为 2 则返回第二个交点; 否则同时返回两个交点.
lc_intp(ln, cr, which) 计算线 ln 和圆 cr 的交点. which 含义同上.
cr_rel(cr1, cr2) 计算两个圆 cr1, cr2 的关系.
返回 0:圆不存在; 1:两圆相外离; 2:外切; 3:相交; 4:内切; 5:cr1含cr2; 6:cr2含cr1.
cr_devi(cr1, cr2) 判断圆 cr1, cr2 外离. 即 cr_rel(cr1, cr2) == 1
cr_xtang(cr1, cr2) 是否两圆外切.
cr_itang(cr1, cr2) 是否两圆内切.
cr_intp(cr1, cr2) 判断圆 cr1,cr2 相交.
cr_inc(cr1, cr2) 判断圆 cr1 内含于 cr2.
xpoly(opt, A, B, C, ...) 判断 A,B,C,D ... 多个点(数量可任意指定) 可构成多边形, 注意:至少要给出四个点.
opt 是 'seg', 'line', 'convex' 的任意组合, 或没有.
选项 'seg' 表示要求判断多边形各边必须有线段连接, 如 AB, BC, CD, DA 线段.
   'line' 表示要求判断各边必须有线(任意线)连接.
   'convex' 表示判断是否是 凸多边形.
例子: xpoly('seg,convex', A,B,C,D,E);  --- 判断存在凸五边形ABCDE, 且各边有线段.

 

数学函数

abs,acos, asin, atan, atan2, ceil, cos, exp, floor, log, max, min, pow, random, round, sin, sqrt, tan.

这些数学函数是直接引用 javascript Math 对象中的相应数学函数.
另在程序中可使用 _PI, _E 两个常量, 为避免和几何图中 PI,E 名字冲突, 前面加了 _ 下划线符号.

 

单位转换

px2cm(x) --- 像素转为厘米.
cm2px(x) --- 厘米转为像素.
rad2d(x)  --- 弧度转为度数, 弧度值 π 对应 180°.
d2rad(x)  --- 度数转为弧度.

判断点线的颜色等:

对于点, 如 $a =point(A); print($a); --- 得到一个点, 打印该点对象. 我们可以访问点对象的信息有:

1. 点的坐标: $a.x, $a.y  --- 点的像素坐标, 像素坐标系以画板的左上角为 (0,0), X轴向右, Y轴向下.
   (注意Y轴向下是与一般坐标系的区别)

2. 点的颜色: $a.color --- 例如红色的值为 'red' 或 '#ff0000'.
   judge($a.color == 'red' | $a.color == '#ff0000') false '请将点 A 设置为红色';

3. 点的大小: $a.point_size  --- 标准点大小该值为 3.5, 小的点该值为 2.5, 最小的点为 1.2, 大点为 5.

对于线, 如 $m = line(A,B); print($m);  --- 得到一条线, 打印该线对象. 则有:

1. 确定该线的两个点: $m.p1, $m.p2, 这种点有时候只有 x,y 的值, 不保证一定是用户画出的点, 可能是程序
   计算出的绘制该线的两个点.

2. 线型: $m.line_style , 取值 0 为实线, 1 为点划线, 2 为点线.

3. 线宽: $m.line_width, 取值 2 为标准线宽(中细), 取值 0.3 为极细, 0.8 为细线, 4 为粗线.

4. 线颜色: $m.color , 含义同点的颜色.

对于圆, 如 $c = circ(O, A); print($c); 

1. $c.op 为圆心点, $c.r 为圆的半径.   $c.rp 为圆上一点(不保证一定有)

2. $c.line_width 线宽, 含义同线的说明. $c.line_style 线型, 对圆不支持.

3. $c.color 圆的颜色, 含义同点的颜色.

 =========================================================

新的判定函数 (2015-05-15)

 vpoly(A,B,C ...) 根据所给的任意点数量创建一个虚拟的多边形, 此多边形可用于各种计算. 至少要给出三个点.
 in_poly(A, $poly)

判定点 A 是否在多边形 $poly 内部, 返回 true 在内部, 返回 false 在外部.

 ln_xk(l)  用于得到(任意)线ln 与 x 轴之间的夹角 a, 并规范到锐角范围内, 取值为度数, 即值为 [0, 90] 之间. 如果是 0°表示与 x 轴平行, 90°表示与 x 轴垂直.
tri_centroid(A,B,C), 给出三角形的三个点 A,B,C, 返回一个虚拟的点, 其坐标为 A,B,C 的重心.
tri_orthocentre(A, B, C) 求三角形垂心.
tri_circumcentre(A, B, C) 求三角形外心.
tri_incentre(A, B, C) 求三角形内心.
foot(x, y, ln) 求取点 A(x,y) 到任意的线 ln 的垂足, 返回为一个虚拟点.
ang_r2(a1, a2) 函数 ang_r2(a1, a2) 用于判定两个角 ∠a1, ∠a2 的位置关系.
返回 1,  表示等角关系(角相等, 边所在射线相同)
返回 2,  表示互补角关系. 同样对 (1,4) (2,3) (3,4) 也是互补关系.
返回 3,  表示对顶角关系. 同样对 (2,4) 也是对顶角关系.
返回 -1 表示所给对象不正确, 其它负值表示其它错误.
ang_rel(l1, l2, l3, a1, a2)

判定由线 l3 截l1,l2 构成的两个角a1,a2 的位置关系.
返回 1, 表示是同旁内角.
返回 2, 表示是内错角.
返回 3 表示是同位角.
返回 4 表示是 (没名字), 一个在内,一个在外,且异侧.
返回 5 是同旁外角.
返回 6 是异旁外角.
返回负值表示无法判定, 一般是所给对象不对.

sm_side(A, B, l)  判定点 A,B 是否在直线 l 的同侧或异侧.
返回: 1 表示在同侧, -1 表示在异侧; 返回 0 表示无法判定(点不存在, 或在线 l 上)
refl_pt(A, l) 计算点 A 以直线 l 为镜面的反射点(对称点)
返回为一个虚拟点. 如果参数有错, 则返回 null (空).
is_sel(A, B, C ...) 判断几何对象 A,B,C ... 等是否被选中了. 参数数量任意.
sel_tool(tool_name)

判定当前选择的工具是 tool_name.
其中工具名字分别为 'select' (选择工具,箭头), 'point'(点工具), 'circle'(圆工具), 'segment'(线段工具),
   'ray'(射线工具), 'line'(直线工具), 'any_line'(前三种线工具统称), 'mark'(标记工具), 'text'(文本工具).
可能以后还会添加别的工具, 如 polygon,macro 等.

obj_num(obj_type) 得到指定对象类型为 obj_type 的对象数量. 如 obj_num('point') 得到点的数量. obj_num('segment') 得到线段数量. obj_num('line') 得到任意线的数量.
obj_num() 得到所有对象数量.

 

 

转载于:https://my.oschina.net/u/232554/blog/368393

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值