tslediter/funcext/tvclib/utvclgraphics.tsf

4798 lines
148 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

unit utvclgraphics;
interface
uses utslvclauxiliary;
//tsl绘图库
//20240126
//20240204 添加说明
//20240220 三维绘图功能
//20240614 添加消息
{
tg_const 常量类型,作为所有类型的基类,提供常量别名
tg_canvas 绘图画布对象该对象以窗口中的canvas为父类并增加了辅助函数
axesclip() 限定到坐标系区域
axesunclip() 取消坐标系区域限定
axesrec 坐标系的范围
tg_line_info 画笔线型信息
Style 线型 tgc_PS_DOT tgc_PS_DASH tgc_PS_NULL tgc_PS_SOLID tgc_PS_DASHDOT tgc_PS_DASHDOTDOT
size 线宽度,像素
color 线颜色
bkcolor 线型封闭后的背景
tg_font_info 系统信息
size 字号,宽度的像素
color 字颜色
bkcolor 背景色
tg_mark_info 点标记信息
size 标记大小,像素
color 线颜色
bkcolor 背景色
tg_base 做个绘图类基类,提供一些基础功能,以及层次关系
层次关系:
parent: 设置或者父节点
nodecount 获取子节点数量
GetNodeByIndex 通过序号获取子节点
set_node_index(nd,idx) 设置子节点的序号
基础功能:
markinfo 标记信息 tg_mark_info 类型
lineinfo 画笔信息 tg_line_info 类型
line_mode 是否画线
mark_mode 是否画点的标记
clip_state 是否裁剪区域
zoom_to_xyz(x,y,z,var _x,var _y) 通过坐标点计算画布点位置
xyz_to_zoom(x,y,z,var x_,var y_,var z_) 通过画布点计算坐标点
set_lineinfo_to_canvas(cvs,peninfo) 设置当前画笔信息到画布
set_fontinfo_to_canvas(cvs,info) 设置当前字体信息到画布
paint(cvs);virtual;该函数由tg_figure的管理者在适当时候发起并送入tg_canvas对象
addEventListener(etype,fun(e),ifCapture) //添加消息处理
removeEventListener(etype,fun(e),ifCapture) //移除消息处理
dispatchEvent(evt) ;//分发消息
tg_figure //坐标容器类,可以在上面放坐标系,设置坐标系的位置信息
add_axes(axes) 添加坐标系
del_axes(axes) 删除坐标系
executecommand(cmd,p); //命令行执行
paint(cvs); 送入画布绘制各个图形如果是窗口在onpaint消息中调用该函数
属性:
rec_getter function() 返回画布区域 array(左上右下)
fresh_caller: function() //刷新回调
tg_axes 坐标系类型,作为绘图的基础载体,以及位置关系的基准
属性:
title 标题 tg_label 类型
y_label y轴标签 tg_label 类型
x_label x轴标签 tg_label 类型
axises(idx) 0,1,2 分别获取对应的xy轴 tg_axis 类型
axes_reverse(idx) 坐标轴是否反向,默认正向
auto_ticks(idx) 设置坐标轴刻度自动计算
margins 空白array(左上右下)设置上下左右空白tg_figure区域的百分比
axes_bounds(idx) 坐标系的大小 array((x,width),(y,heigt))以margins为基准点安百分比
data_bounds(idx) 获取或者设置数据范围 array((x0,x1),(y0,y1),(z0,z1))
zoom_box(idx) 设置显示的数据的区域 array((x0,x1),(y0,y1),(z0,z1))
x_location 坐标轴方向tgc_bottom tgc_top,tgc_middle ,tgc_origin
y_location 坐标轴方向tgc_left tgc_right,tgc_middle ,tgc_origin
box 是否有边框
grid(idx) 背景网格线属性 tg_line_info 对象size为0的时候网格线消失
tg_axis 坐标轴,可以在坐标系中放置任意多个坐标轴
tics_direction 坐标轴方向 tgc_direct_asc(坐标轴指向的左手方向) , tgc_direct_desc
tics_style 刻度类型 tgc_tics_v (设置值) tgc_tics_r ([x0,x1,inteval])
tics_coord 刻度根据tics_style 确定 [2,3,4,5,6,7] 计算 [start,end,interval]
ytics_coord 位置,设置在另一个方向的位置,相对坐标系的数据位置,array(x,y,z),为对应三维坐标,x,y,z中为非数字的值表示该坐标轴在对应维度上面
tics_segment 是否有轴线
tics_color 刻度线颜色
sub_tics 子刻度个数
tics_labels 刻度值对应的标签,一维字符串数组
tg_label 标签以axes作为父节点
text 文本
position 坐标系位置
auto_position 自动位置,在坐标轴标签中使用
font_angle 设置角度
其他字体相关的通过 fontinfo设置
tg_graph_base 图基类
get_data_bounds();virtual; //获取数据边界
tg_graph 图类型
get_data_tips(); //获得数据提示对象
get_legend_size(var w,var h);virtual; 获取图例中的大小
paint_legend(cvs,rec);virtual; //绘制图例
get_graph_data_by_idx(idx); //通过数据序号获取数据
graph_data 绘图数据;
tg_Polyline 线图以tg_graph为父类
closed 是否封闭的图像
polyline_style 线类型, tgc_LS_interpolated tgc_LS_bar tgc_LS_filled tgc_LS_arrowed tgc_LS_barplot tgc_LS_staircase
bar_width 柱状图类型时候的宽度
tg_legend 图例
location 位置 tgc_in_upper_left tgc_in_lower_left ..... tgc_by_coordinates
postion 定位为tgc_by_coordinates设置具体位置 array(x,y)
line_mode 边框线
links 关联的绘图tg_graph 数组
text 文本内容,字符串数组
tg_tips 数据点提示父节点为tg_graph 对象
text 文本数组
data_idx 绑定数据序号
tg_text 文本展示
text 字符串数组
font_angle 角度
data array(x,y,z) 相对于坐标系的位置
tg_WinControl:绘图展示窗口对象,管理了一个 tg_figure 对象在paint消息的时候构造tg_canvas 对象并调用tg_figrue的paint函数实现图形的绘制
其仅仅作为一个案例,用户可以按照其原理构造自己的画布对象,驱动绘制,得到图形
消息对象
tg_evt 基类
create(typename,pms) //构造函数
bubbles //是否冒泡,只读
currentTarget //当前绑定的对象,只读
target //目标对象,只读
stoppropagationed 否//已经调用 stoppropagation,只读
stopImmediatePropagationed //是否已经调用 stopImmediatePropagation,只读
eventPhase //只读,1,捕获,2到达目标,3,冒泡
timeStamp //只读,加载完成到现在的时间
eventtype //只读类型
isTrusted //true表示用户触发,false表示代码触发
init_params //初始化参数 数组
tg_evt_mouse
cvsx ,cvsy //画布位置
double 是否双击
button 左右,中 按键
ctrl ,shift //功能按键
tg_evt_custom
detail
目前提供 evt_mouse_up ,evt_mouse_down evt_mouse_move 三个消息
消息传播方式采用类似html对象的捕获和冒泡方式
捕获阶段,从figure对象向下一直传递到当目标对象
冒泡阶段,从目标对象向上传递到figure对象
}
{
//////////////////线图范例//////////////////////////
uses tslvcl,utvclgraphics;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm = class(tvcform)
function create(aowner);
begin
inherited;
Caption := "line";
fg := new tg_WinControl(self);
fg.Caption := "hello1";
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
axs.figure := fg.figure;
axs.title.text := "你好 plot ";
axs.title.fontinfo.size := 15;
axs.title.fontinfo.color := 0xff0000;
axs.x_label.text := "x fanli ";
axs.axises(1).tics_color := 0x0000ff;
axs.axises(1).fontinfo.size := 8;
axs.axises(1).lineinfo.color := 0x00ff00;
axs.grid(0).Width := 2;
axs.grid(0).color := 0x0ff0f0;
//设置线型属性
line := new tg_Polyline();
line.lineinfo.style := 4;
line.lineinfo.color := 0xff0000;
line.markinfo.bkcolor := 0x00ff00;
line.markinfo.color := 0x0000ff;
line.mark_mode := "on";
line.markinfo.size := 30;
line.markinfo.style := "pentagram";
line.polyline_style := "staircase";
d := array();
idx := 0;
for i:= -pi() to pi() step 0.2 do
begin
d[idx] := array(i,sin(i));
idx++;
end
line.graph_data := d;
line.parent := axs;
end
fg;
end
//////////////////表面图范例///////////////////////////////////////
uses tslvcl,utvclgraphics;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm = class(tvcform)
function create(aowner);
begin
inherited;
Caption := "surface";
fg := new tg_WinControl(self);
fg.Caption := "hello1";
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
t := pi()*60/180;
a := pi()*70/180;
axs.set_trans(a,t);
axs.box := true;
axs.figure := fg.figure;
axs.title.text := "你好 surface ";
axs.title.fontinfo.size := 15;
axs.title.fontinfo.color := 0xff0000;
axs.axises(1).tics_color := 0x0000ff;
axs.axises(1).fontinfo.size := 8;
axs.axises(1).lineinfo.color := 0x00ff00;
sf := new tg_my_surf();
sf.lineinfo.color := 0x0000ff;
sf.lineinfo.style := tgc_BS_SOLID;
sf.graph_data := get_surf_data();
sf.parent := axs;
return ;
end
fg;
function c_3(x,y);
begin
return X - 3*X*sin(X)*cos(Y-4) ;
end
function get_surf_data();
begin
st1 := (12)/50;
vs1 := array(-10,st1)->2;
st2 := 10/50;
vs2 := array(-5,st2)->5;
d := array();
dlen := 0;
for i,vi in vs1 do
begin
for j,vj in vs2 do
begin
r := array();
x0 := vi;
y0 := vj;
x1 := vi+st1;
y1 := vj+st2;
v1 := array(x0,y0,c_3(x0,y0));
v2 := array(x1,y0,c_3(x1,y0));
v3 := array(x1,y1,c_3(x1,y1));
v4 := array(x0,y1,c_3(x0,y1));
d[dlen++] := array(v1,v2,v3,v4,v1);
end
end
return d;
end
end
type tg_my_surf = class(tg_graph) //绘图对象,包括数据,提示等内容
function create(pms);
begin
inherited;
lineinfo.bkcolor := 0x00f0f0;
end
function get_data_bounds();override;
begin
d := graph_data;
r := array((inf,-inf),(inf,-inf),(inf,-inf));
for i ,v in d do
begin
for j,vj in v do
begin
for k := 0 to 2 do
begin
r[k,0] := min(r[k,0],vj[k]);
r[k,1] := max(r[k,1],vj[k]);
end
end
end
for k := 0 to 2 do
begin
r[k,0] -= abs(r[k,0]*0.1);
r[k,1] += abs(r[k,1]*0.1);
end
return r;
end
function paint_legend(cvs,rec);virtual; //绘制图例
begin
end
function paint(cvs);override;
begin
d := graph_data;
cvs.axesclip();
set_lineinfo_to_canvas(cvs);
dp := cvs.draw_polygon();
bx := axes.zoom_box;
//cvs.pen.color := 0xff0000;
for i,v in d do
begin
ps := array();
flg := false;
zz := 0;
for j,vj in v do
begin
if vj[0]<bx[0,0] or vj[1]<bx[1,0] or vj[2]<bx[2,0] or vj[0]>bx[0,1] or vj[1]>bx[1,1] or vj[2]>bx[2,1] then
begin
flg := true;
break;
end
//zz:=vj[2];
zoom_to_xyz(vj[0],vj[1],vj[2],_x,_y,_z);
zz := vj[2];
ps[j] := array(_x,_y);
end
if flg then continue;
if zz>0 then cvs.brush.color := 0x00ff00;
else
cvs.brush.color := 0xff0000;
dp.points(ps).requiregdi().draw();
end
cvs.axesunclip();
end
end
//////////////////饼图范例///////////////////////////////////////////
uses tslvcl,utvclgraphics;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm = class(tvcform)
function create(aowner);
begin
inherited;
caption := "pie";
width := 800;
Height := 800;
fg := new tg_WinControl(self);
fg.Caption := "hello1";
fg.parent := self;
fg.Align := alClient;
//////////设置坐标轴属性////////////////////////
axs := new tg_axes();
axs.box := true;
axs.figure := fg.figure;
axs.title.text := "hello pie ";
axs.axises(1).tics_color := 0x0000ff;
axs.axises(1).fontinfo.size := 8;
axs.data_bounds(0) := array(-0.1,2.1);
axs.data_bounds(1) := array(-0.1,2.1);
axs.data_bounds(2) := array(-0.5,0.5);
args := array(
(pi()/4,pi()/3,0x0000ff),
(pi()/3,pi()/2,0x00ff00),
(pi()/2,pi()*3/2,0xff0000),
(pi()*3/2,pi()*9/4,0xff00ff)
);
prominentidx := 0; //凸显的块
prominentrate := 0.1; //凸显的块
for i,v in args do
begin
line := new tg_Polyline();
line.polyline_style := line.tgc_LS_filled;
line.closed := true;
c := (i=2)?1.1:1;
line.graph_data := 1+get_pie_lines(v[0],v[1],i=prominentidx,prominentrate);
line.lineinfo.bkcolor := v[2];
line.parent := axs;
end
end
function get_pie_lines(arg1,arg2,prominent,prominentrate);
begin
stp := pi()/180;
d := 1;
r := array();
r[0] := array(0,0);
idx := 1;
for i:= arg1+(prominent?stp:0) to arg2-(prominent?stp:0) step stp do
begin
r[idx++] := array(sin(i),cos(i));
end
r[idx] :=array(0,0);
if prominent then
begin
rx := r[integer(idx/2)]*prominentrate;
for i := 0 to idx do
begin
r[i]+=rx;
end
end
return r;
end
fg;
end
///////////////////////////消息处理///////////////////////////////////////////////////
uses tslvcl,utvclgraphics;
app := initializeapplication();
app.createform(class(tfm),fm);
fm.show();
app.run();
type tfm = class(tvcform)
function create(aowner);
begin
inherited;
fgwnd := new tg_WinControl(self);
fgwnd.Caption := "hello event";
fgwnd.parent := self;
fgwnd.Align := alClient;
fg := fgwnd.figure;
axs := new tg_axes();
axs.figure := fg;
axs.title.text := "你好 event ";
line := new tg_Polyline();
line.parent := axs;
line.lineinfo.Width := 3;
line.lineinfo.bkcolor := 0xff00f0;
line.lineinfo.color := 0xff0000;
line.markinfo.bkcolor := 0x00ff00;
line.markinfo.color := 0x0000ff;
line.line_mode := 1;
line.markinfo.size := 20;
line.mark_mode := true;
line.markinfo.style := line.tgc_mks_pentagram;
line.polyline_style := line.tgc_LS_interpolated;//"bar";
d2 := array();
idx := 0;
for i:= -pi() to pi() step 0.3 do
begin
d2[idx++] := array(i,sin(i+pi()/2));
end
line.graph_data := d2;
gtx := new tg_text();
gtx.font_angle := pi()/4;
//////////////命中处理///////////////
gtx.onhit_at := function(o,d)begin
x := d["cvsx"];
y := d["cvsy"];
rgn := o.ExecuteCommand("text_rgn");
return rgn and point_in_rgn(array(x,y),rgn);
end
gtx.lineinfo.bkcolor := 0x00ff00;
gtx.parent :=line;
gtx.text := array("按住鼠标左键","移动我");
gtx.data := array(0.3,0.2);
//处理鼠标按下
gtx.addEventListener("mouse_down",function(e)begin
fdragtext := e.target;
ftextinitpos := fdragtext.data;
x := e.cvsx;y := e.cvsy;
fdragtext.xyz_to_zoom(x,y,0,x1,y1);
fmousedownpos := array(x1,y1);
end);
//移动标签
fg.addEventListener("mouse_move",function(e)begin
if fdragtext then
begin
e.stoppropagation();
x := e.cvsx;
y := e.cvsy;
fdragtext.xyz_to_zoom(x,y,0,x1,y1);
dxdata := ftextinitpos+ array(x1-fmousedownpos[0],y1-fmousedownpos[1]);
fdragtext.data := dxdata;
end
end ,true);
//处理鼠标松开
fg.addEventListener("mouse_up",function(e)begin
if fdragtext then
begin
e.stoppropagation();
fdragtext := nil;
end
end );
//构造提示标签
fmovetip := new tg_tips();
fmovetip.Visible := false;
fmovetip.clip_state := 0;
fmovetip.parent := line;
fmovetip.data_idx := 5;
fmovetip.fontinfo.size := 12;
fmovetip.box_mode := true;//false;
fmovetip.fontinfo.color := 0xff00ff;
//设置提示数据点
line.onhit_at := function(o,d)begin
x := d["cvsx"];
y := d["cvsy"];
for i,v in o.ExecuteCommand("points_in_canvas") do
begin
if abs(v[0]-x)<10 and abs(v[1]-y)<10 then
begin
return true;
end
end
end
line.addEventListener("mouse_out",function(e)begin
if e.eventPhase<>2 then return ;
fmovetip.Visible := false;
e.stoppropagation();
end,true);
line.addEventListener("mouse_move",function(e)
begin
if e.eventPhase<>2 then return ;
e.stoppropagation();
x := e.cvsx;
y := e.cvsy;
for i,v in e.target.ExecuteCommand("points_in_canvas") do
begin
if abs(v[0]-x)<10 and abs(v[1]-y)<10 then
begin
fmovetip.Visible := true;
return fmovetip.data_idx := i;
end
end
end,true);
end
fdragtext;
ftextinitpos;
fmousedownpos;
fmovetip;
fgwnd;
fg;
end
}
function point_in_rgn(p,rgn_); //判断点是否在区域中
type tg_WinControl = class(tcustomcontrol,tg_const) //绘图窗口
function create(AOwner);
begin
inherited;
ffigure := new tg_figure();
fg_timer := new unit(utslvclstdctl).tcustomtimer(self);
fg_timer.Interval := 200;
fg_timer.Ontimer := thisfunction(figure_need_fresh);
ffigureprepared := false;
ffigure.rec_getter := function()begin
return clientrect;
end
ffigure.fresh_caller := thisfunction(flushfigure);
end
function flushfigure();
begin
if not ffigureprepared then return ;
if Fneed_invaliate then return ;
if not HandleAllocated() then return ;
Fneed_invaliate := true;
fg_timer.start();
end
function paint();override; //绘制
begin
cvs := canvas;
ffigure.paint(cvs);
ffigureprepared := true;
end
function DestroyHandle();override;
begin
ffigureprepared := false;
inherited;
end
function MouseUp(o,e);override;
begin
if ffigure then
begin
d := e_2_array(e);
if ffigure.executecommand(evt_mouse_up,d)=1 then e.skip := true;
end
end
function MouseDown(o,e);override;
begin
if ffigure then
begin
d := e_2_array(e);
if ffigure.executecommand(evt_mouse_down,d)=1 then e.skip := true;
end
//echo "\r\n",functionname(),tostn(array(xy,bt,sh));
end
function MouseMove(o,e);override;
begin
if ffigure then
begin
fmovecnt++;
if fmovecnt>4 then fmovecnt := 0;
if fmovecnt<>2 then return ;
d := e_2_array(e);
if ffigure.executecommand(evt_mouse_move,d)=1 then e.skip := true;
end
end
function DoMouseWheel(o,e);override;
begin
p := ScreenToClient(e.xpos,e.ypos);
if ffigure then
begin
ffigure.executecommand(cmd_zoom_inc,array("delta":e.delta,"x":p[0],"y":p[1]));
end
end
function DoWMSIZE(o,e);override;
begin
inherited;
if ffigure then
ffigure.executecommand(cmd_figure_changed);
end
function Recycling();override;
begin
ffigure:=nil;
inherited;
end
property figure read ffigure;
private
function figure_need_fresh(o,e); //定时刷新
begin
o.stop();
InvalidateRect(nil,false);
Fneed_invaliate := false;
end
function e_2_array(e);
begin
d := array();
st := e.shiftstate();
sft := 0x0 in st;
sctl := 0x2 in st;
d := array(
"cvsx":e.xpos,
"cvsy":e.ypos,
"shift":sft,
"ctrl":sctl,
"button":e.button(),
);
return d;
end
private
fmovecnt;
ffigure;
fg_timer;
Fneed_invaliate;
ffigureprepared;
end
type tg_figure = class(tg_evet_conainter) /////////
function create();
begin
inherited;
faxeses := new tnumindexarray();
end
function paint(cvs); //绘制
begin
cvs := new tg_canvas(cvs.Handle);
for i,v in faxeses.data do
begin
v.paint_pre(cvs);
end
end
function executecommand(cmd,p);
begin
case cmd of
"figure_need_fresh":
begin
fresh();
return ;
end
cmd_zoom_inc:
begin
for i,v in faxeses.data do
begin
v.executecommand(cmd_zoom_inc,p);
end
end
evt_mouse_move:
begin
return cmd_mouse_event(evt_mouse_move,p);
end
evt_mouse_up:
begin
return cmd_mouse_event(evt_mouse_up,p);
end
evt_mouse_down:
begin
return cmd_mouse_event(evt_mouse_down,p);
end
cmd_figure_changed:
begin
for i,v in faxeses.data do
begin
v.executecommand(cmd_figure_changed);
end
end
end ;
end
function add_axes(axs);//添加
begin
if get_axes_idx(axs)>=0 then return ;
if fwilladdaxs and fwilladdaxs=axs then
begin
faxeses.unshift(axs);
fwilladdaxs := nil;
axs.figure := self(true);
return ;
end
if not(axs is class(tg_axes)) then return ;
fwilladdaxs := axs;
axs.figure := self(true);
end
function del_axes(axs); //移除
begin
idx := get_axes_idx(axs);
if not(idx>=0) then return ;
if fwilldelaxs and fwilldelaxs = axs then
begin
fwilldelaxs := nil;
faxeses.splice(idx,1);
axs.figure := nil;
return ;
end
fwilldelaxs := axs;
axs.figure := nil;
end
function fresh(); ///////////////////////////
begin
if ffresh_caller then call(ffresh_caller);
end
function rect(); //////////////////////////////////
begin
r := array(0,0,200,200);
if frect_getter then r := call(frect_getter);
return r;
end
property rec_getter read frect_getter write frect_getter; //区域获取
property fresh_caller read ffresh_caller write ffresh_caller; //刷新回调
public
function dispatchEvent(evt,nd);
begin
bs := evt.bubbles;
if ifarray(nd) then
begin
nds := nd;
end else
begin
nds := array();
p := nd;
while p do
begin
nds[idx] := p;
idx++;
p := p.parent;
end
end
tg := nds[0];
nds[length(nds)] := self(true);
for i := length(nds)-1 downto 0 do
begin
it := nds[i];
ph := (i=0)?2:1;
d := array("eventphase":ph,
"target":tg,
"currenttarget":it,
);
e := evt.clone(d);
it.dealevent(e,true);
if e.stoppropagationed then
begin
evt.stoppropagation();
return true;
end
end
if not bs then return true;
for i := 0 to length(nds)-1 do
begin
it := nds[i];
ph := (i=0)?2:3;
d := array("eventphase":ph,
"target":tg,
"currenttarget":it,
);
e := evt.clone(d);
it.dealevent(e);
if e.stoppropagationed then
begin
evt.stoppropagation();
return true;
end
end
end
private
function get_axes_idx(axs);
begin
for i ,v in faxeses.data do
begin
if v=axs then
begin
return i;
end
end
return -1;
end
function inverse_array(d);
begin
r := array();
len := length(d)-1;
for i,v in d do
begin
r[len-i] := v;
end
return r;
end
function cmd_mouse_event(evtname,p);
begin
d := p;
for i,v in inverse_array(faxeses.data) do
begin
nds := node_hit_list(v,d);
if nds then
begin
break;
end
end
d["istrusted"] := true;
d["bubbles"] := true;
case evtname of
evt_mouse_move :
begin
ninnode := nds[0];
if ninnode then
begin
if fMouseOnOBJ<> ninnode then //鼠标进入不同的控件
begin
if fMouseOnOBJ then //旧控件 处理move out
begin
onds := array();
nnd := fMouseOnOBJ;
while nnd do
begin
onds[length(onds)] := nnd;
nnd := nnd.parent;
end
evt := new tg_evt_mouse(evt_mouse_out,d);
dispatchEvent(evt,onds);
end
fMouseOnOBJ := ninnode;
evt := new tg_evt_mouse(evt_mouse_in,d); //处理mouse in
dispatchEvent(evt,nds);
end
end
end
end
evt := new tg_evt_mouse(evtname,d);
dispatchEvent(evt,nds);
return evt.stoppropagationed;
end
private
[weakref] frect_getter;
[weakref] ffresh_caller;
[weakref] fMouseOnOBJ;
fwilladdaxs;
fwilldelaxs;
faxeses;
end
type tg_axes = class(tg_base) //坐标系
private
[weakref]fFigure;
///////////////坐标辅助计算/////////////////////////
p_left;
p_top;
p_width;
p_height;
f_changed;
static const c_g_data_changed=1;
static const c_g_paint_rect=2;
static const c_g_data_zoombox=4;
static const c_g_rote_changed=8;
///////////////////////////////////////////
public //zoom-xyz
function executecommand(cmd,pm);override;
begin
ochanged := f_changed;
case cmd of
"title_rgn": return ftitle.executecommand("label_rgn");
"x_label_rgn": return (fx_label.visible=tgc_on)?faxes_objects[0].executecommand("label_rgn"):nil;
"y_label_rgn": return (fy_label.visible=tgc_on)?faxes_objects[1].executecommand("label_rgn"):nil;
"z_label_rgn": return (fz_label.visible=tgc_on)?faxes_objects[2].executecommand("label_rgn"):nil;
"x_tics_recs": return (fx_label.visible=tgc_on)?faxes_objects[0].executecommand("tics_recs"):nil;
"y_tics_recs": return (fy_label.visible=tgc_on)?faxes_objects[1].executecommand("tics_recs"):nil;
"z_tics_recs": return (fz_label.visible=tgc_on)?faxes_objects[2].executecommand("tics_recs"):nil;
cmd_zoom_inc:
begin
if not ifarray(pm) then return ;
p0 := pm["x"];
p1 := pm["y"];
for i := 0 to 2 do
begin
a0 := fzoom_box[i,0];
b0 := fzoom_box[i,1];
if not xy_in_paint_rect(p0,p1) then
begin
continue;
end
if not xyz_to_zoom(p0,p1,fzoom_box[2,0],x,y,z) then continue ;
dx := ((pm["delta"]>0)?(1.05):(1/1.05));
if not zoom_bound_op(a0,b0,dx,array(x,y,z)[i],a,b) then continue ;
rt := 1.1;
cg := 0;
if a<fdata_bounds[i,0]*rt then
begin
cg++;
a := fdata_bounds[i,0]*rt ;
end
if b>fdata_bounds[i,1]*rt then
begin
cg++;
b := fdata_bounds[i,1]*rt;
end
if cg=2 then continue;
fzoom_box[i] := array(a,b);
f_changed .|= c_g_data_zoombox;
end
end
cmd_node_add_in:
begin
if pm is class(tg_graph_base) then
begin
f_changed .|= c_g_data_changed;
f_changed .|= c_g_data_zoombox;
end
end
cmd_figure_changed:
begin
f_changed .|= c_g_paint_rect;
f_changed .|= c_g_data_zoombox;
end
cmd_data_changed:
begin
f_changed .|= c_g_data_changed;
f_changed .|= c_g_data_zoombox;
end
end ;
if ochanged<>f_changed then prop_changed(cmd_data_changed,f_changed);
end
function axes_mapping(x,y,z,_x,_y);override;//坐标系相对位置到画布
begin
if not(fFigure ) then return false;
_x := p_left+p_width*x ;
_y := p_top +p_height*y;
return true;
end
function axes_unmapping(x,y,_x,_y,_z);override;//画布位置到坐标系相对位置
begin
if not(fFigure ) then return false;
_x := (x-p_left)/p_width;
_y := (y-p_top)/p_height;
return true;
end
function zoom_to_xyz(x,y,z,_x,_y,_z); //----------
begin
if not(fFigure ) then return false;
if faxes_reverse[0]=tgc_on then x0 := fcoordinate_sizes[0]/2-(x-fzoom_bounds[0,0])/fzoom_coordinate_rates[0];
else
x0 := (x-fzoom_bounds[0,0])/fzoom_coordinate_rates[0] -fcoordinate_sizes[0]/2;
if faxes_reverse[1]=tgc_on then y0 := fcoordinate_sizes[1]/2-(y-fzoom_bounds[1,0])/fzoom_coordinate_rates[1];
else y0 := (y-fzoom_bounds[1,0])/fzoom_coordinate_rates[1] -fcoordinate_sizes[1]/2;
if faxes_reverse[2]=tgc_on then z0 := fcoordinate_sizes[2]/2-(z-fzoom_bounds[2,0])/fzoom_coordinate_rates[2];
else z0 := (z-fzoom_bounds[2,0])/fzoom_coordinate_rates[2] -fcoordinate_sizes[2]/2;
transxyz(x0,y0,z0,_x,_y,_z);
_x +=fbounds_center[0];
_y +=fbounds_center[1];
_z +=fbounds_center[2];
return true;
end
function xyz_to_zoom(x,y,z,_x,_y,_z);
begin
if not(fFigure ) then return false;
x1 := x;y1 := y;z1 := z;
x1 -=fbounds_center[0];
y1 -=fbounds_center[1];
z1 -=fbounds_center[2];
untransxyz(x1,y1,z1,x0,y0,z0);
if faxes_reverse[0]=tgc_on then
begin
_x := (fcoordinate_sizes[0]/2-x0)*fzoom_coordinate_rates[0]+fzoom_bounds[0,0];
end
else
begin
_x := (x0+fcoordinate_sizes[0]/2)*fzoom_coordinate_rates[0]+fzoom_bounds[0,0];
end
if faxes_reverse[1]=tgc_on then
begin
_y := (fcoordinate_sizes[1]/2-y0)*fzoom_coordinate_rates[1]+fzoom_bounds[1,0];
end
else
begin
_y := (y0+fcoordinate_sizes[1]/2)*fzoom_coordinate_rates[1]+fzoom_bounds[1,0];
end
if faxes_reverse[2]=tgc_on then
begin
_z := (fcoordinate_sizes[2]/2-z0)*fzoom_coordinate_rates[2]+fzoom_bounds[2,0];
end
else
begin
_z := (z0+fcoordinate_sizes[2]/2)*fzoom_coordinate_rates[2]+fzoom_bounds[2,0];
end
return true;
end
function paint_pre(cvs);
begin
if visible<>tgc_on then return ;
axes_changed();
modify_coordinate_position();
r := array(p_left-1,p_top-1,p_left+p_width+1,p_top+p_height+1);
cvs.axesrec := r;
paint(cvs);
cvs.axesunclip();
end
function paint(cvs);override;
begin
paint_grid(cvs);
inherited;
cvs.axesunclip();
for i,v in faxes_objects do //绘制坐标
begin
v.paint(cvs);
end
modify_label_postion();
ftitle.paint(cvs);
if fbox = tgc_on then
begin
set_lineinfo_to_canvas(cvs);
paint_box(cvs);
end
end
function axes_changed();//改变
begin
if not fFigure then return ;
if f_changed then
begin
change_locked := true;
fr := fFigure.rect();
w := fr[2]-fr[0];
h := fr[3]-fr[1];
p_left := fr[0]+w*fmargins[0]+faxes_bounds[0];
p_top := fr[1]+h*fmargins[1]+faxes_bounds[1];
p_width := w*(1-fmargins[0]-fmargins[2])*faxes_bounds[2];
p_height := h*(1-fmargins[1]-fmargins[3])*faxes_bounds[3];
fcvs_bounds := array(p_left,p_top,p_left+p_width,p_top+p_height);
if (f_changed .& c_g_data_changed)=c_g_data_changed then
begin
tbds := fdata_bounds;
for i,v in get_node_data_bounds(self(true)) do
begin
if not fdata_bounds_locked[i] then
begin
new_bounds(v[0],v[1],a_,b_);
tbds[i] := array(a_,b_);//v*1.05;
end
end
fdata_bounds := tbds;
fzoom_box := tbds*1.05;
fzoom_bounds := fzoom_box;
end
/////////////计算旋转矩阵//////////////////////////
if (f_changed .& c_g_rote_changed)=c_g_rote_changed then
begin
c := cos(falpha);
s := sin(falpha);
c1 := cos(ftheta);
s1 := sin(ftheta);
frote_mt := array((0,1,0),(1,0,0),(0,0,1)):*array((c,s,0),(-s,c,0),(0,0,1)):*array((1,0,0),(0,c1,s1),(0,-s1,c1));
end
////////////////////////////////////////
if (f_changed .& c_g_data_zoombox)=c_g_data_zoombox then
begin
fzoom_bounds := fzoom_box;
end
recalc_size();
auto_set_axis();
change_locked := false;
end
f_changed := 0;
end
private
//////////长宽高////////////////////
fbounds_center; //中心
//////////////////////
fface_v_indexs; //定点次序
flines_index;//
ftheta;
ftheta_a;
falpha;
falpha_a;
frote_mt;
fcvs_bounds;
fzoom_bounds;
fbox_vertexs;
fzoom_coordinate_rates;
fcoordinate_sizes;
frevers;
public //create
function set_trans(t,a); //设置转换角度
begin
if (t=ftheta) and (falpha=a) then return ;
if ifnumber(t) then
begin
ftheta_a := (r_2_a(t) mod 360);
ftheta := a_2_r(ftheta_a);
end
if ifnumber(a) then
begin
falpha_a := r_2_a(a) mod 360;
falpha := a_2_r(falpha_a);
end
if ifnumber(t) or ifnumber(a) then f_changed .|=8;
prop_changed();
return ;
end
function create(pms);
begin
inherited;
f_changed := 0;
ftheta := 0;
falpha := 0;
flines_index := array(
(0,1),
(1,2),
(2,3),
(3,0),
(4,5),
(5,6),
(6,7),
(7,4),
(0,4),
(1,5),
(2,6),
(3,7)
);
fface_v_indexs := array(
(0,1,2,3),
(0,4,7,3),
(0,1,5,4),
(1,5,6,2),
(2,6,7,3),
(4,5,6,7)
);
fcvs_bounds := array(0,0,200,200);
fcoordinate_sizes := array(200,200,200);
frote_mt := array((0,1,0),(1,0,0),(0,0,1));
fbounds_center := array(100,100,100);
fzoom_bounds := array((0,200),(0,200),(0,200));
set_trans(0,pi()*1.5);
fzoom_coordinate_rates := array(1,1,1);
fdata_bounds_locked := array(0,0,0);
fgrid := array();
for i:= 0 to 1 do
begin
gd := new tg_line_info();
gd.width := 0;
gd.Style := tgc_PS_DOT;
fgrid[i] := gd;
end
faxes_reverse := array(tgc_off,tgc_off,tgc_off);
fbox := tgc_off;
ffilled := tgc_off;
fx_location := tgc_bottom;
fz_location := tgc_right;
fy_location := tgc_left;
faxes_objects := array();
for i := 0 to 2 do
begin
axi := new tg_axis_main();
axi.tics_style := tgc_tics_v;//tgc_tics_r;
lbl := new tg_label_axis();
case i of
0:
begin
fx_label := lbl;
axi.tics_direction := tgc_bottom;
axi.ytics_coord := array("x",0,0);
axi.tag := "+x+";
end
1:
begin
fy_label := lbl;
axi.tics_direction := tgc_left;
axi.ytics_coord := array(0,"y",0);
axi.tag := "+y+";
end
2:
begin
fz_label := lbl;
//axi.visible := false;
axi.ytics_coord := array(0,0,"z");
axi.tag := "+z+";
end
end ;
axi.axis_label := lbl;
faxes_objects[i] := axi;
axi.axes := self(true);
end
ftitle := new tg_label_axes();
ftitle.axes := self(true);
ftitle.location := tgc_by_axes;
fauto_ticks := array(tgc_on,tgc_on,tgc_on);
fmargins := array(0.125,0.125,0.125,0.125);
faxes_bounds := array( 0,0,1,1);
fdata_bounds := array((0,1),(0,1),(0,1));
fzoom_box := fdata_bounds;
//FA vector containing the handles of all graphics objects children of the
//axes These graphics objects are of type
//"Compound", "Rectangle", "Polyline", "Segs", "Arc", "Grayplot",.. (see Compound_properties,
//rectangle_properties, champ_properties, axis_properties, polyline_properties, segs_properties,
//grayplot_properties, surface_properties, fec_properties, text_properties, legend_properties)
end
published
property figure read fFigure write SetFigure; //窗口
property axises read get_axises;//axes_visible ;//= ["on","on","on"]
property axes_reverse read gs_axes_reverse write gs_axes_reverse;//axes_reverse ;//= ["off","off","off"]
property x_location read fx_location write set_x_location;//'bottom
property y_location read fy_location write set_y_location;//'left
property z_location read fz_location write set_z_location;//'left
property title read ftitle;
property x_label read fx_label;
property y_label read fy_label;
property z_label read fz_label;
property auto_ticks read gs_auto_ticks write gs_auto_ticks;
property box read fbox write set_box;
property filled read ffilled write set_filled;
property sub_ticks read gs_sub_ticks write gs_sub_ticks;
//上下左右空白
property margins read gs_margins write gs_margins;
property axes_bounds read gs_axes_bounds write gs_axes_bounds;
property data_bounds read gs_data_bounds write gs_data_bounds;
property zoom_box read gs_zoom_box write gs_zoom_box;
//在窗口中的区域
//网格线
property grid read get_grid;
//grid ;//= [-1,-1]
//grid_position ;//= "background"
//grid_thickness ;//= [1,1]
//grid_style ;//= [7,7]
//x_ticks.locations ;//= matrix 21x1
//y_ticks.locations ;//= matrix 11x1
//z_ticks.locations ;//= []
//x_ticks.labels ;//= matrix 21x1
//y_ticks.labels ;//= matrix 11x1
//z_ticks.labels ;//= []
//ticks_format ;//= ["","",""]
//ticks_st ;//= [1,1,1;0,0,0]
//sub_ticks ;//= [1,1]
font_style ;//= 6
font_size ;//= 1
font_color ;//= -1
fractional_font ;//= "off"
//isoview ;//= "off"
//cube_scaling ;//= "off"
//rotation_angles ;//= [0,270]
//log_flags ;//= "nnn"
//tight_limits ;//= ["off","off","off"]
//zoom_box ;//= []
//auto_margins ;//= "on"
//auto_clear ;//= "off"
//auto_scale ;//= "on"
//auto_stretch ;//= "on"
//hidden_axis_color ;//= 4
//hiddencolor ;//= 4
//line_mode ;//= "on"
//line_style ;//= 1
//thickness ;//= 1
//mark_mode ;//= "off"
//mark_style ;//= 0
//mark_size_unit ;//= "tabulated"
//mark_size ;//= 0
//mark_foreground ;//= -1
//mark_background ;//= -2
//foreground ;//= -1
//background ;//= -2
//arc_drawing_method ;//= "lines"
//clip_state ;//= "clipgrf"
//clip_box ;//= []
protected
function get_axes();override;
begin
return self(true);
end
private //variable
fgrid;
faxes_objects;
fzoom_box;
fmargins;
faxes_bounds ;//= [0,0,1,1]
fdata_bounds;
fdata_bounds_locked;
ffilled;
fauto_ticks;
ftitle;
fx_label;
fy_label;
fz_label;
fx_location;
fy_location;
fz_location;
fbox;
faxes_reverse;
private
fwilldelfigure;
fwilladdfigure;
function paint_grid(cvs);//绘制表格
begin
xg := fgrid[0];
if xg.width>0 and ifnumber(xg.color) then
begin
set_lineinfo_to_canvas(cvs,xg);
//y1 := p_top;
//y2 := p_top+p_height;
for i,v in faxes_objects[0].executecommand("get_tics_value") do
begin
if v<fzoom_box[0,0] or v>fzoom_box[0,1] then continue;
if zoom_to_xyz(v,fzoom_box[1,0],0,_x1,_y1) then
begin
zoom_to_xyz(v,fzoom_box[1,1],0,_x2,_y2);
cvs.moveto(array(_x1,_y1));
cvs.lineto(array(_x2,_y2));
end
end
end
xg := fgrid[1];
if xg.width>0 and ifnumber(xg.color) then
begin
set_lineinfo_to_canvas(cvs,xg);
for i,v in faxes_objects[1].executecommand("get_tics_value") do
begin
if v<fzoom_box[1,0] or v>fzoom_box[1,1] then continue;
if zoom_to_xyz(fzoom_box[0,0],v,0,_x1,_y1) then
begin
zoom_to_xyz(fzoom_box[0,1],v,0,_x2,_y2);
cvs.moveto(array(_x1,_y1));
cvs.lineto(array(_x2,_y2));
end
end
end
end
function paint_box(cvs);
begin
r := array();
ls := array();
ps2 := array();
inpoints := array();
tf := get_top_face(); //获得顶部的3个面
for i,fc in tf do
begin
for ii in fbox_vertexs do //判断点是否在面的阴影中
begin
if (ii in fc) then continue;
if point_in_rgn(fbox_vertexs[ii],fbox_vertexs[fc]) then
begin
inpoints[length(inpoints)] := ii;
end
end
end
hd := array();
for i,v in flines_index do //判断线是否需要隐藏
begin
ps := fbox_vertexs[v];
if (inpoints intersect v) then hd[i] := true;
for j,vj in ps do
ls[i,j] := vj[0:1]+fbounds_center;
end
for i,v in ls do //绘制线
begin
ps1 := v;
if hd[i] then cvs.pen.style := 1;
else cvs.pen.style := 0;
cvs.draw_polyline().points(ps1).draw();
end
end
function auto_set_axis();//自动计算坐标
begin
for i:=0 to 2 do
begin
axi :=faxes_objects[i];
axi.executecommand("set_bounds",fzoom_box[i]);
if axi.visible<>tgc_on then continue;
fsz := axi.fontinfo.size;
if fauto_ticks[i] = tgc_on then
begin
[arg,ifx,sz] := axi.executecommand("get_angleofhoriz");
if ifx then
begin
n := integer(sz/(fsz*12));
end else
begin
n := integer(sz/(fsz*4));
end
xcd := array();
xcdls := array();
if n>0 then
begin
rt := new_bounds(fzoom_box[i,0],fzoom_box[i,1],a_,b_);
bs :=ceil((b_-a_)/(rt)/n);
axi.sub_tics := min(bs,5);
stp := bs*rt;
vi := a_;
ii := 0;
while vi<=b_ do
begin
xcd[ii++] := vi;
vi+=stp;
end
end
axi.tics_coord := xcd;
end
end
end
function xy_in_paint_rect(x,y);//鼠标是否在坐标内
begin
if not ifnumber(x) then return false;
if not ifnumber(y) then return false;
if x<p_left or x>(p_left+p_width) then return false;
if y<p_top or y>(p_top+p_height) then return false;
return true;
end
function zoom_bound_op(a,b,dx,x,a1,b1);//缩放
begin
if x<a or x>b then return false;
if not(ifnumber(dx)) then return false ;
len := (b-a)/dx;
rt := (x-a)/(b-a);
a1 := x-len*rt;
b1 := a1+len;
return true;
end
function modify_label_postion(); //修正标签位置
begin
if ftitle and (ftitle.visible=tgc_on) and (ftitle.auto_position=tgc_on) then
begin
s := ftitle.text;
if s then
begin
ax := faxes_objects[0];
//y := p_top-20-(ftitle.fontinfo.size*2);
fr := fFigure.rect();
y := fr[1]+10;
{if (ax.visible=tgc_on) and (ax.tics_direction = tgc_top) then
begin
y -=(ax.fontinfo.size*2);
end}
x := p_left+(p_width-length(s)*10)/2;
if ftitle.location=tgc_by_coordinates then
xyz_to_zoom(x,y,0,_x,_y,_z);
else axes_unmapping(x,y,_x,_y,_z);
ftitle.executecommand("auto_position_value",array(_x,_y));
end
end
end
function get_axis_index(p);
begin
r := array();
for i,v in p do
begin
zoom_to_xyz(v[0],v[1],v[2],_x0,_y0,_z0);
r[i] := array(_x0,_y0,_z0);
end
return sselect thisrowindex from r order by [1] asc end;
end
function get_duan_dian(x0,y0,z0,x1,y1,z1,x2,y2,z2);
begin
x0 := fzoom_box[0,0];
y0 := fzoom_box[1,0];
z0 := fzoom_box[2,0];
x1 := fzoom_box[0,1];
y1 := fzoom_box[1,1];
z1 := fzoom_box[2,1];
x2 := (x0+x1)/2;
y2 := (y0+y1)/2;
z2 := (z0+z1)/2;
end
function modify_x_position(loc);
begin
get_duan_dian(x0,y0,z0,x1,y1,z1,x2,y2,z2);
//////bottom
px := array();
px[0] := array(x2,y0,z0);
px[1] := array(x2,y0,z1);
///top
px[2] := array(x2,y1,z0);
px[3] := array(x2,y1,z1);
r := array();
for i,v in px do
begin
zoom_to_xyz(v[0],v[1],v[2],_x0,_y0,_z0);
r[i] := array(_x0,_y0,_z0);
end
axx := faxes_objects[0];
case loc of
tgc_bottom:
begin
if like_0(ftheta) then
begin
if faxes_reverse[1]=tgc_on then idx := 2;
else
idx := 0;
end else
begin
idxs := sselect thisrowindex from r order by [1] asc end;
if faxes_reverse[1]=tgc_on then idx := idxs[3];
else
idx := idxs[0];
end
idxv := px[idx];
zoom_to_xyz(x2,y2,z2,_x0,_y0,_z0);//中间点
zoom_to_xyz(x0,idxv[1],idxv[2],_x00,_y00,_z00);//轴线0点
v1 := array(_x0-r[idx,0],_y0-r[idx,1]);//射线方向
v2 := array(r[idx,0]-_x00,r[idx,1]-_y00); //轴方向
p_trans(v2[0],v2[1],-pi()/2.01,_x,_y);
jj := r_2_a( d2angle(array(_x,_y),v1));
axx.ytics_coord := array("x",idxv[1],idxv[2]);
if jj>90 then axx.tics_direction := tgc_direct_desc ;
else axx.tics_direction := tgc_direct_asc;
return ;
axx.ytics_coord := array("x",fzoom_box[1,(faxes_reverse[1]= tgc_on)],fzoom_box[2,(faxes_reverse[1]= tgc_on)]);
if faxes_reverse[0]=tgc_on then axx.tics_direction := tgc_direct_asc;
else
axx.tics_direction := tgc_direct_desc;
end
tgc_top:
begin
if like_0(ftheta) then
begin
if faxes_reverse[1]=tgc_on then idx := 0;
else
idx := 2;
end else
begin
idxs := sselect thisrowindex from r order by [1] desc end;
if faxes_reverse[1]=tgc_on then idx := idxs[3];
else
idx := idxs[0];
end
idxv := px[idx];
zoom_to_xyz(x2,y2,z2,_x0,_y0,_z0);//中间点
zoom_to_xyz(x0,idxv[1],idxv[2],_x00,_y00,_z00);//轴线0点
v1 := array(_x0-r[idx,0],_y0-r[idx,1]);//射线方向
v2 := array(r[idx,0]-_x00,r[idx,1]-_y00); //轴方向
p_trans(v2[0],v2[1],-pi()/2.01,_x,_y);
jj := r_2_a( d2angle(array(_x,_y),v1));
axx.ytics_coord := array("x",idxv[1],idxv[2]);
if jj>90 then axx.tics_direction := tgc_direct_desc ;
else axx.tics_direction := tgc_direct_asc;
return ;
axx.ytics_coord := array("x",fzoom_box[1,(faxes_reverse[1]<> tgc_on)],fzoom_box[2,(faxes_reverse[1]= tgc_on)]);
if faxes_reverse[0]=tgc_on then axx.tics_direction := tgc_direct_desc;
else
axx.tics_direction := tgc_direct_asc;
end
tgc_middle:
begin
axx.ytics_coord := array("x",fzoom_box[1,0]+(fzoom_box[1,1]-fzoom_box[1,0])/2,0);
end
tgc_origin:
begin
if fzoom_box[1,0]<0 and fzoom_box[1,1]>0 then
axx.ytics_coord := array("x",0,0);
else
begin
return modify_x_position(tgc_bottom);
//axx.ytics_coord := array("x",fzoom_box[1,(faxes_reverse[1]= tgc_on)],0);
end
axx.tics_direction := tgc_direct_desc;
end
end ;
end
function modify_y_postion(loc);
begin
get_duan_dian(x0,y0,z0,x1,y1,z1,x2,y2,z2);
//////left
py := array();
py[0] := array(x0,y2,z0);
py[1] := array(x0,y2,z1);
///right
py[2] := array(x1,y2,z0);
py[3] := array(x1,y2,z1);
r := array();
for i,v in py do
begin
zoom_to_xyz(v[0],v[1],v[2],_x0,_y0,_z0);
r[i] := array(_x0,_y0,_z0);
end
axy := faxes_objects[1];
case loc of
tgc_left:
begin
if like_0(ftheta) then
begin
if faxes_reverse[0]=tgc_on then idx := 2;
else
idx := 0;
end else
begin
idxs := sselect thisrowindex from r order by [1] desc end;
if faxes_reverse[0]=tgc_on then idx := idxs[3];
else
idx := idxs[0];
end
idxv := py[idx];
zoom_to_xyz(x2,y2,z2,_x0,_y0,_z0);//中间点
zoom_to_xyz(idxv[0],y0,idxv[2],_x00,_y00,_z00);//轴线0点
v1 := array(_x0-r[idx,0],_y0-r[idx,1]);//射线方向
v2 := array(r[idx,0]-_x00,r[idx,1]-_y00); //轴方向
p_trans(v2[0],v2[1],-pi()/2.01,_x,_y);
jj := r_2_a( d2angle(array(_x,_y),v1));
axy.ytics_coord := array(py[idx,0],"y",py[idx,2]);
if jj>90 then axy.tics_direction := tgc_direct_desc ;
else axy.tics_direction := tgc_direct_asc;
return ;
axy.ytics_coord := array(fzoom_box[0,(faxes_reverse[0] = tgc_on)],"y",fzoom_box[2,(faxes_reverse[1]= tgc_on)]);
if faxes_reverse[1]=tgc_on then axy.tics_direction := tgc_direct_desc ;
else
axy.tics_direction := tgc_direct_asc;
end
tgc_right:
begin
if like_0(ftheta) then
begin
if faxes_reverse[0]=tgc_on then idx := 0;
else
idx := 2;
end else
begin
idxs := sselect thisrowindex from r order by [1] asc end;
if faxes_reverse[0]=tgc_on then idx := idxs[3];
else
idx := idxs[0];
end
idxv := py[idx];
zoom_to_xyz(x2,y2,z2,_x0,_y0,_z0);//中间点
zoom_to_xyz(idxv[0],y0,idxv[2],_x00,_y00,_z00);//轴线0点
v1 := array(_x0-r[idx,0],_y0-r[idx,1]);//射线方向
v2 := array(r[idx,0]-_x00,r[idx,1]-_y00); //轴方向
p_trans(v2[0],v2[1],-pi()/2.01,_x,_y);
jj := r_2_a( d2angle(array(_x,_y),v1));
axy.ytics_coord := array(py[idx,0],"y",py[idx,2]);
if jj>90 then axy.tics_direction := tgc_direct_desc ;
else axy.tics_direction := tgc_direct_asc;
return ;
axy.ytics_coord := array(fzoom_box[0,(faxes_reverse[0]<> tgc_on)],"y",fzoom_box[2,(faxes_reverse[1]= tgc_on)]);
if faxes_reverse[1]=tgc_on then axy.tics_direction := tgc_direct_asc;
else
axy.tics_direction := tgc_direct_desc;
end
tgc_middle:
begin
axy.ytics_coord := array(fzoom_box[0,0]+(fzoom_box[0,1]-fzoom_box[0,0])/2,"y",0);
end
tgc_origin:
begin
if fzoom_box[0,0]<0 and fzoom_box[0,1]>0 then
begin
axy.ytics_coord := array(0,"y",0);
end
else
begin
return modify_y_postion(tgc_left);
//axy.ytics_coord := array(fzoom_box[0,(faxes_reverse[0] = tgc_on)],"y",0);
end
axy.tics_direction := tgc_direct_asc;
end
end;
end
function modify_z_position(loc);
begin
if like_0(ftheta_a) then return ;
get_duan_dian(x0,y0,z0,x1,y1,z1,x2,y2,z2);
axz := faxes_objects[2];
pz := array();
pz[0] := array(x0,y0,z2);
pz[1] := array(x1,y0,z2);
pz[2] := array(x1,y1,z2);
pz[3] := array(x0,y1,z2);
r := array();
for i,v in pz do
begin
zoom_to_xyz(v[0],v[1],v[2],_x0,_y0,_z0);
r[i] := array(_x0,_y0,_z0);
end
case loc of
tgc_right:
begin
idxs := sselect thisrowindex from r order by [0] desc end;
end
else
begin
idxs := sselect thisrowindex from r order by [0] asc end;
end
end;
idx := idxs[0];
idxv := pz[idx];
zoom_to_xyz(x2,y2,z2,_x0,_y0,_z0);//中间点
zoom_to_xyz(idxv[0],idxv[1],z0,_x00,_y00,_z00);//轴线0点
v1 := array(_x0-r[idx,0],_y0-r[idx,1]);//射线方向
v2 := array(r[idx,0]-_x00,r[idx,1]-_y00); //轴方向
p_trans(v2[0],v2[1],-pi()/2.01,_x,_y);
jj := r_2_a( d2angle(array(_x,_y),v1));
axz.ytics_coord := array(pz[idx,0],pz[idx,1],"z");
if jj>90 then axz.tics_direction := tgc_direct_desc ;
else axz.tics_direction := tgc_direct_asc;
return ;
axz.ytics_coord := array(idxv[0],idxv[1],"z");
if ftheta_a>180 or ftheta_a<0 then axz.tics_direction :=tgc_direct_asc ;
else axz.tics_direction := tgc_direct_desc ;
end
function modify_coordinate_position();//修正坐标轴位置
begin
////////////////y轴///////////////////////////////////
modify_y_postion(fy_location);
///////////////x///////////////////////////////
modify_x_position(fx_location);
//////z-axis
modify_z_position(fz_location);
end
function SetFigure(v); //添加窗口
begin
if v=fFigure then return ;
if fwilladdfigure and fwilladdfigure=v then
begin
fwilladdfigure := nil;
fFigure := v;
v.add_axes(self(true));
f_changed .|= c_g_paint_rect;
return ;
end
if fwilldelfigure and fwilldelfigure=tp then
begin
fwilldelfigure := nil;
fFigure := nil;
v.del_axes(self(true));
return ;
end
tp := fFigure;
if tp then //删除
begin
fwilldelfigure := tp;
tp.del_axes(self(true));
fwilldelfigure := nil;
end
if v is class(tg_figure) then //添加
begin
fwilladdfigure := v;
v.add_axes(self(true));
fwilladdfigure := nil;
end else
begin
fFigure := nil;
end
end
function set_filled(v);
begin
if not tg_boolen_value(v,nv) then return ;
if nv<>fbox then
begin
ffilled := nv;
prop_changed("ffilled",nv);
end
end
function set_box(v);
begin
if not tg_boolen_value(v,nv) then
begin
nv := v;
end
if (nv in array(tgc_box_on,tgc_box_off,tgc_box_half,tgc_box_hidden_axes)) and v<>fbox then
begin
fbox := nv;
prop_changed("box",v);
end
end
function set_x_location(v);
begin
if v<>fx_location and ( v in array(tgc_bottom,tgc_top,tgc_middle,tgc_origin)) then
begin
fx_location := v;
prop_changed("x_location",v);
end
end
function set_y_location(v);
begin
if v<>fy_location and ( v in array(tgc_left,tgc_right,tgc_middle,tgc_origin)) then
begin
fy_location := v;
prop_changed("y_location",v);
end
end
function set_z_location(v);
begin
if v<>fz_location and ( v in array(tgc_left,tgc_right)) then
begin
fz_location := v;
prop_changed("z_location",v);
end
end
function get_grid(idx);
begin
if idx=0 or idx=1 then return fgrid[idx];
end
function set_view(v);
begin
return ;
end
function gs_auto_ticks(vidx,v);//自动更新坐标标签
begin
tg_boolen_value(v,nv);
idx := tg_get_true_idx(vidx);
if nv=tgc_on or nv=tgc_off then
begin
if idx in array(0,1,2) then
begin
if fauto_ticks[idx]<>nv then
begin
fauto_ticks[idx] := nv;
if nv=tgc_on then faxes_objects[i].tics_style := tgc_tics_v;//faxes_objects[i].tics_style := tgc_tics_r;
//else faxes_objects[i].tics_style := tgc_tics_v;
prop_changed("auto_ticks",idx);
end
end
end else //get
begin
if idx in array(0,1,2) then return fauto_ticks[idx];
return fauto_ticks;
end
end
function get_axises(vidx);
begin
idx := tg_get_true_idx(vidx);
if idx in array(0,1,2) then
begin
return faxes_objects[idx];
end
end
function gs_axes_bounds(idx,v);
begin
if ifarray(v) and ifnumber(v[0]) and ifnumber(v[1]) then
begin
if idx in array(0,1,2,3) then
begin
faxes_bounds[idx] := array(v[0],v[1]);
f_changed .|=c_g_paint_rect ;
prop_changed("axes_bounds",idx);
end
end else //get
begin
if idx in array(0,1,2,3) then return faxes_bounds[idx];
return faxes_bounds;
end
end
function gs_data_bounds(vidx,v);
begin
idx := tg_get_true_idx(vidx);
if v=-1 then
begin
if idx in array(0,1,2) then
begin
fdata_bounds_locked[idx] := false;
end
end else
if ifarray(v) and ifnumber(v[0]) and ifnumber(v[1]) then
begin
if idx in array(0,1,2) then
begin
fdata_bounds[idx] := v;
fdata_bounds_locked[idx] := true;
prop_changed("data_bounds",idx);
end
end else //get
begin
if idx in array(0,1,2) then return fdata_bounds[idx];
return fdata_bounds;
end
end
function gs_zoom_box(vidx,v);
begin
idx := tg_get_true_idx(vidx);
if ifarray(v) and ifnumber(v[0]) and ifnumber(v[1]) then
begin
if idx in array(0,1,2) then
begin
fzoom_box[idx] := v;
prop_changed("zoom_box",idx);
end
end else //get
begin
if idx in array(0,1,2) then return fzoom_box[idx];
return fzoom_box;
end
end
function gs_axes_reverse(vidx,v); //反向
begin
if not tg_boolen_value(v,nv) then return ;
idx := tg_get_true_idx(vidx);
if nv=tgc_off or nv=tgc_on then
begin
if idx in array(0,1) then
begin
faxes_reverse[idx] := nv;
prop_changed("axes_reverse",idx);
end
end else //get
begin
if idx in array(0,1) then return faxes_reverse[idx];
return faxes_reverse;
end
end
function gs_margins(idx,v); //空白
begin
if ifnumber(v) then
begin
if idx in array(0,1,2,3) then
begin
fmargins[idx] := v;
f_changed .|= c_g_paint_rect;
prop_changed("margins",idx);
end
end else //get
begin
if idx in array(0,1,2,3) then return fmargins[idx];
return fmargins;
end
end
function gs_sub_ticks(vidx,v); //小刻度线
begin
idx := tg_get_true_idx(vidx);
if ifnumber(v) and (v>=0) then
begin
if idx in array(0,1,2) then
begin
faxes_objects[idx].sub_tics := v;
end
end else //get
begin
if idx in array(0,1,2) then return faxes_objects[idx].sub_tics;
return array(faxes_objects[0].sub_tics,faxes_objects[1].sub_tics,faxes_objects[2].sub_tics);
end
end
////////////////三维转换////////////////////
function transxyz(x,y,z,_x,_y,_z); //旋转数据
begin
r := array((x,y,z)):*frote_mt;
_x := r[0,0];
_y := r[0,1];
_z := r[0,2];
end
function untransxyz(x,y,z,_x,_y,_z);
begin
r := array((x,y,z)):/frote_mt;
_x := r[0,0];
_y := r[0,1];
_z := r[0,2];
end
function get_new_w_h(w1,h1,w,h,z);//获取变换的大小
begin
//z1 := (w1+h1)/2;
z1 := min(w1,h1);
z := z1;
w := w1;
h := h1;
while true do
begin
ps := init_vecs(h,w,z);
bd := zeros(2,2);
for i,v in ps do
begin
transxyz(v[0],v[1],v[2],_x,_y,_z);
bd[0,0] := min(_x,bd[0,0]);
bd[0,1] := max(_x,bd[0,1]);
bd[1,0] := min(_y,bd[1,0]);
bd[1,1] := max(_y,bd[1,1]);
end
bw := bd[0,1]-bd[0,0];
bh := bd[1,1]-bd[1,0];
if bw<w1 and bh<h1 then break;
w*=0.99;
h*=0.99;
z*=0.99;
end
mj1 := w*h;
bk := array(w,h,z);
z := z1;
w := h1;
h := w1;
while true do
begin
ps := init_vecs(h,w,z);
bd := zeros(2,2);
for i,v in ps do
begin
transxyz(v[0],v[1],v[2],_x,_y,_z);
bd[0,0] := min(_x,bd[0,0]);
bd[0,1] := max(_x,bd[0,1]);
bd[1,0] := min(_y,bd[1,0]);
bd[1,1] := max(_y,bd[1,1]);
end
bw := bd[0,1]-bd[0,0];
bh := bd[1,1]-bd[1,0];
if bw<w1 and bh<h1 then break;
w*=0.99;
h*=0.99;
z*=0.99;
end
mj2 := w*h;
if mj2<mj1 then
begin
[w,h,z] := bk;
end
end
function recalc_size(); //重算大小
begin
w1 := fcvs_bounds[2]-fcvs_bounds[0];
h1 := fcvs_bounds[3]-fcvs_bounds[1];
fbounds_center := array(fcvs_bounds[0]+w1/2,fcvs_bounds[1]+h1/2,0);
get_new_w_h(w1,h1,w,h,z);
fcoordinate_sizes[0] := h;
fcoordinate_sizes[1] := w;
fcoordinate_sizes[2] := z;
fzoom_coordinate_rates[0] := (fzoom_bounds[0,1]-fzoom_bounds[0,0])/h;
fzoom_coordinate_rates[1] := (fzoom_bounds[1,1]-fzoom_bounds[1,0])/w;
fzoom_coordinate_rates[2] := (fzoom_bounds[2,1]-fzoom_bounds[2,0])/z;
fbox_vertexs := array();
for i,v in init_vecs(h,w,z) do
begin
transxyz(v[0],v[1],v[2],x,y,z);
fbox_vertexs[i] := array(x,y,z);
end
end
function init_vecs(x,y,z); //初始化顶点
begin
r := array();
r[0]:=array(-x/2, -y/2, -z/2); //0
r[1]:=array(-x/2, y/2, -z/2); //1
r[2]:=array(x/2, y/2, -z/2); //2
r[3]:=array(x/2, -y/2, -z/2); //3
r[4]:=array(-x/2, -y/2, z/2); //4
r[5]:=array(-x/2, y/2, z/2); //5
r[6]:=array(x/2, y/2, z/2); //6
r[7]:=array(x/2, -y/2, z/2); //7
return r;
end
function get_top_face(); //获取最上面的三个面,便于计算隐藏的线
begin
r := array();
for i , v in fface_v_indexs do
begin
zi := 0;
for j,vj in v do
begin
zi += fbox_vertexs[vj][2];
end
r[i] := zi;
end
r := sselect thisrowindex from r order by thisrow desc end;
return fface_v_indexs[r[0:2]];
end
end
type tg_canvas = class(TcustomCanvas)
uses utslvclgdi;
function create(h);
begin
inherited create();
FCvsHandle := h;
Handle := h;
faxesrgn := new TRGNPOLY();//new TRGNRECT();
faxesrgntemp := new TRGNPOLY();//new TRGNRECT();
end
function axesclip();
begin
if faxesrgn then
begin
_wapi.SelectClipRgn(FCvsHandle,faxesrgn.Handle); //裁剪区域
end
end
function clip_rgn(pts);
begin
faxesrgntemp.points := pts;
h := faxesrgntemp.Handle;
if h then _wapi.SelectClipRgn(FCvsHandle,faxesrgntemp.Handle);
end
function axesunclip();
begin
_wapi.SelectClipRgn(FCvsHandle,0);
end
function destroy();
begin
Handle := 0;
faxesrgn := nil;
end
property axesrec read FaxesRec write set_clip_rect;
private
FaxesRec;
FCvsHandle;
faxesrgn;
faxesrgntemp;
private
function set_clip_rect(rec);
begin
FaxesRec := rec;
//faxesrgn.rect := rec;
pts := rec_to_points(rec);
faxesrgn.points := pts;
end
end
type tg_axis_main = class(tg_axis) //主轴
public
function create(pms);
begin
inherited;
end
protected
function prop_changed(n,v);override;
begin
case n of
"tics_direction","xtics_coord","ytics_coord":
begin
return ;
end else
begin
//echo "\r\n",n;
end
end
inherited;
end
function SetParent(V);override;
begin
end
function get_axes();override;
begin
return faxes;
end
function set_axes(axs);override;
begin
if axs is class(tg_axes) then faxes := axs;
end
private
[weakref] faxes;
end
type tg_label_axis = class(tg_label)
public
function create(pms);
begin
inherited;
ftext := "";
ffont_angle := 0;
end
published
property font_angle read ffont_angle write set_font_angle;//90
property text read ftext write set_text;
protected
function SetParent(V);override;
begin
end
private
ffont_angle;
ftext;
private
function set_font_angle(ag);
begin
if v<>ffont_angle and ifnumber(v) then
begin
ffont_angle := v;
prop_changed("font_angle",v);
end
end
function set_text(v);
begin
if v<>ftext and ifstring(v) then
begin
ftext := v;
prop_changed("text",v);
end
end
end
type tg_label_axes = class(tg_label) //坐标系标签
public
function create(pms);
begin
inherited;
clip_state := tgc_off;
auto_position := tgc_on;
end
protected
function SetParent(V);override;
begin
end
function get_axes();override;
begin
return faxes;
end
function set_axes(axs);override;
begin
if axs is class(tg_axes) then faxes := axs;
end
private
[weakref] faxes;
end
type tg_axis = class(tg_base) //轴对象
function create(pms);
begin
inherited;
clip_state := tgc_off;
fticksize := 12;
fsubticksize := 6;
ftics_direction := tgc_direct_asc; //
fxtics_coord := array(0,1,2,3);
ftcmin := 0;
ftcmax := 3;
ftccount := 3;
fxtics_coord_v := array(0,1,2,3);
fytics_coord := array("tics",0,0);
ftics_labels := array("0","1","2","3");
ftics_segment := tgc_on;
ftics_style := tgc_tics_v;//"v";
fsub_tics := 2;
ftics_color := nil;
//"v". It's the default value, In this case, tics positions are given by the row factor xtics_coord for horizontal axis (ytics_coord for the vertical one).
//"r". In this case, tics positions are given by the vector [min,max,n] where n is the number of intervals.
//"i". In this case the vector given tics positions is of size 4, [k1,k2,a,n] then values are increasing between k1*10^a and k2*10^a, n is the number of intervals.
end
function executecommand(cmd,pm);override;
begin
case cmd of
"tics_recs" : return (visible=tgc_on)?ftics_recs:nil;
"label_rgn": return (flabel.visible=tgc_on)?flabel_rgn:nil;
"get_tics_value":return fxtics_coord_v;
"set_bounds": return set_zoom_bounds(pm);
"get_angleofhoriz" :
begin
get_angleofhoriz(xarg,ifh,sz);
return array(xarg,ifh,sz);
end
end;
end
function paint(cvs);override;
begin
if visible<>tgc_on then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
subtks := array();
idx := 0;
if fsub_tics>1 then
begin
for i:= 0 to length(fxtics_coord_v)-2 do
begin
dx := (fxtics_coord_v[i+1]-fxtics_coord_v[i])/fsub_tics;
for j := 1 to (fsub_tics-1) do
begin
vi := fxtics_coord_v[i]+dx*j;
if fzoom_bounds and (vi<fzoom_bounds[0] or vi>fzoom_bounds[1]) then continue;
subtks[idx++] := vi;
end
end
end
return draw_axis(cvs,subtks);
end
protected
function draw_tics(cvs,info);virtual;
begin
for i,v in info do
begin
cvs.drawtext(v[0],v[1]);
end
end
function check_parent(p);override;
begin
return (not(p)) or (p is class(tg_compound)) or (p is class(tg_axes));
end
published
/////////////////////////////////////
property tics_direction read ftics_direction write set_tics_direction;//= "top"
property tics_coord read fxtics_coord write set_xtics_coord ;//= [2,3,4,5,6,7]
property ytics_coord read fytics_coord write set_ytics_coord ;//= 4
property tics_segment read ftics_segment write set_tics_segment; // true,false
property tics_color read ftics_color write set_tics_color; // -1
property tics_style read ftics_style write set_tics_style; // = "v"
property sub_tics read fsub_tics write set_sub_tics; // = 2
property tics_labels read ftics_labels write set_tics_labels; // = ["2","3","4","5","6","7"]
property axis_label read flabel write flabel;
private
flabel_rgn;
ftics_recs;
fzoom_bounds;
fticksize;
fsubticksize;
fxtics_coord_v;
ftcmin;
ftcmax;
ftccount;
///////////////////////////////
ftics_direction;
fxtics_coord;
fytics_coord;
fsub_tics;
ftics_color;
ftics_segment;
ftics_style;
ftics_labels;
flabel;
//format_n ;//= ""
//fractional_font ;//= "off"
//clip_state ;//= "off"
//clip_box ;//= []
//user_data ;//= []
//tag ;//= ""
private
function v_to_cvs(tpax,v,x,y);
begin
case tpax of
"x":zoom_to_xyz(v,fytics_coord[1],fytics_coord[2],x,y);
"y":zoom_to_xyz(fytics_coord[0],v,fytics_coord[2],x,y);
"z":zoom_to_xyz(fytics_coord[0],fytics_coord[1],v,x,y);
end;
end
function get_tic_to(direc,size,arg,_x,_y);
begin
pi2 := pi()/2;
if direc=tgc_direct_desc then
begin
p_trans(size,0,-arg-pi2,_x,_y);
end
else
begin
p_trans(size,0,-arg+pi2,_x,_y);
end
return 1;
end
function get_angleofhoriz(xarg,ifh,sz); //获取角度以及位置
begin
xarg := 0;ifh := false;sz:=0;
tkxys := array();
get_axis_type(tpax);
if fzoom_bounds then
begin
v_to_cvs(tpax,fzoom_bounds[0],x,y);
tkxys[0] := array(x,y);
v_to_cvs(tpax,fzoom_bounds[1],x2,y2);
tkxys[1] := array(x2,y2);
sz := (x2-x)^2+(y2-y)^2;
if sz>0 then sz := sqrt(sz);
end else
begin
minv := minvalue(fxtics_coord_v);
manv := maxvalue(fxtics_coord_v);
if not(minv<manv) then return false;
v_to_cvs(tpax,minv,x,y);
tkxys[0] := array(x,y);
v_to_cvs(tpax,manv,x,y);
tkxys[1] := array(x,y);
end
if length(tkxys)<2 then return false;
dxy := (tkxys[1]-tkxys[0]);
if (like_0(dxy[0])) and like_0(dxy[1]) then return false;
a_180 := pi();
a_90 := a_180/2;
a_30 := a_180/6;
a_60 := a_180/3;
a_45 := a_180/4;
a_150 := a_180/6*5;
xarg := d2angle(array(5,0),dxy); //和x夹角
yarg := d2angle(array(0,5),dxy); //和y夹角
if isnan(xarg) then
begin
if dxy[0]>0 then xarg := 0;
else xarg := a_180;
end
if isnan(yarg) then
begin
if dxy[1]>0 then yarg := 0;
else yarg := a_180;
end
if xarg<a_30 or xarg>a_150 then
begin
ifh := true;
end
if like_0( xarg) then
begin
ifh := true;
end else
if a_like_b(xarg,a_180) then
begin
xarg := -xarg;
ifh := true;
end else
if a_like_b(yarg,a_90) then
begin
xarg := 0;
ifh := true;
end else
if yarg = 0 then
begin
xarg := a_90;
end else
if yarg=a_180 then
begin
xarg:=-a_90;
end else
if xarg<a_90 and yarg>a_90 then //第1
begin
xarg := -xarg;
end else
if xarg>a_90 and yarg>a_90 then //第2
begin
xarg :=-xarg;
end else
if yarg<a_90 and xarg>a_90 then //第3
begin
end else
if yarg<a_90 and xarg<a_90 then //第4
begin
end
end
function get_axis_type(tpax);
begin
tpax := "x";
if ifnumber(fytics_coord[1]) and ifnumber(fytics_coord[2]) then tpax := "x";
else if ifnumber(fytics_coord[2]) and ifnumber(fytics_coord[0]) then tpax := "y";
else if ifnumber(fytics_coord[0]) and ifnumber(fytics_coord[1]) then tpax := "z";
return tpax;
end
function draw_axis(cvs,subtks);
begin
pw := lineinfo.width;
tksize := pw+fticksize;
tic_space := 3;
tksizesub := fsubticksize+pw;
get_axis_type(tpax);
set_lineinfo_to_canvas(cvs);
tkxys := array();
xarg := 0;
ifvert := false;
get_angleofhoriz(xarg,ifvert,sz);
if like_0(sz) then return ;
for i,v in fxtics_coord_v do
begin
v_to_cvs(tpax,v,x,y);
tkxys[i] := array(x,y);
end
///////////////////轴线////////////////////////////////
if ftics_segment=tgc_on then
begin
if fzoom_bounds then
begin
v_to_cvs(tpax,fzoom_bounds[0],x1,y1);
v_to_cvs(tpax,fzoom_bounds[1],x2,y2);
cvs.moveto(array(x1,y1));
cvs.lineto(array(x2,y2));
x3 := (x1+x2)/2;
y3 := (y1+y2)/2;
ax_pos := array(x1,y1,x2,y2,x3,y3);
end else
begin
for i,v in tkxys do
begin
if i=0 then
cvs.moveto(v);
else
cvs.lineto(v);
end
end
end
/////////////////////////////////////////////////////
//////////////////刻度线以及刻度值///////////////////////////////////////
ts_size := array(fontinfo.size+4,fontinfo.size*2+4);
tcsinfo := array();
get_tic_to(ftics_direction,tksize,xarg,_xticlen,_yticklen);
if ifnumber(ftics_color) then cvs.pen.color := ftics_color;
ftics_recs := array();
for i,vi in fxtics_coord_v do
begin
if fzoom_bounds and (vi<fzoom_bounds[0] or vi>fzoom_bounds[1]) then continue;
v := tkxys[i];
lbi := ftics_labels[i];
x := v[0];
y := v[1];
cvs.moveto(array(x,y));
x1 :=x+_xticlen;
y1 := y+_yticklen;
cvs.lineto(array(x1,y1));
//continue;
sz := nil;
if lbi then
begin
sz := array((length(lbi))*fontinfo.size+4,fontinfo.size*2+4) ;//cvs.GetTextExtent(lbi);
end
if sz then
begin
if ifvert then //x
begin
rec := array(x1-sz[0]/2,0,x1+sz[0]/2,0);
if _yticklen>0 then
begin
rec[1] := y1+tic_space;
rec[3] := y1+sz[1]+tic_space;
end else
begin
rec[1] := y1-sz[1]-tic_space;
rec[3] := y1-tic_space;
end
end else //y
begin
ts_size[1] := max(ts_size[1],sz[0]);
rec := array(0,y1-sz[1]/2,0,y1+sz[1]/2);
if _xticlen>0 then
begin
rec[0] := x1+tic_space;
rec[2] := x1+sz[0]+tic_space;
end else
begin
rec[0] := x1-sz[0]-tic_space;
rec[2] := x1-tic_space;
end
end
tcsinfo[length(tcsinfo)] := array(lbi,rec,"h");
ftics_recs[i] := rec;
end
end
if tcsinfo then
begin
set_fontinfo_to_canvas(cvs);
draw_tics(cvs,tcsinfo);
end
/////////////////////////////////////////////////////////////////////////
////////////////////子刻度线////////////////////////////////////////////////
get_tic_to(ftics_direction,tksizesub,xarg,_xstic,_ystic);
for i,v in subtks do
begin
v_to_cvs(tpax,v,x,y);
cvs.moveto(array(x,y));
//get_tic_to(ftics_direction,tksizesub,xarg,_x,_y);
cvs.lineto(array(_xstic+x,y+_ystic));
end
//if not ax_pos then return ;
flabel_rgn := array();
if flabel is class(tg_label_axis) then //绘制标签
begin
//tx := ax_pos[2]-ax_pos[1]
if flabel.visible<>tgc_on then return ;
t := flabel.text;
if not t then return ;
if not fzoom_bounds then return ;
lbft := flabel.fontinfo;
sz := lbft.size;
set_fontinfo_to_canvas(cvs,lbft);
_x := _xticlen;
_y := _yticklen;
bs :=2;//xarg<0?1:2;//(xarg<0?2.2:0.2);
slen := sz*length(t);
zlen := max(abs(ax_pos[2]-ax_pos[0]),abs(ax_pos[3]-ax_pos[1]));
rt := (1-slen/zlen);
tx := fzoom_bounds[0] + (rt>0? (rt*(fzoom_bounds[1]-fzoom_bounds[0])/2):0);
v_to_cvs(tpax,tx,x1,y1);
nxarg := (r_2_a(xarg) mod 180);//abs()*pi());
//echo "\r\narg:",r_2_a(xarg),"===",nxarg;
nxarg := nxarg*pi()/180;
if _y<0 then _y-=ts_size[0]+tic_space+sz*bs;
else _y+=ts_size[0]+tic_space+sz*bs;
if _x<0 then _x -= sz*bs+ts_size[1]+tic_space;
else _x+=sz*bs+ts_size[1]+tic_space;
nx := x1+_x;//ax_pos[4]+_x;
ny := y1+_y;//ax_pos[5]+_y;
t_rec := array(nx,ny,nx+slen,ny+lbft.size);
flabel_rgn := rec_to_points(t_rec);
if like_0(nxarg) then
begin
cvs.textout(t,array(nx,ny));
end else
begin
rgn_points_trans(flabel_rgn,-nxarg);
cvs.SaveDC();
cvs.trans(-nxarg,nx,ny);
cvs.textout(t,array(0,0));
cvs.RestoreDC();
end
end
end
function set_zoom_bounds(v);
begin
if ifarray(v) and v[0]<v[1] then
begin
fzoom_bounds := array(v[0],v[1]);
end else
begin
fzoom_bounds := nil;
end
end
function set_tics_direction(v);
begin
if v<>ftics_direction and ( v in array(tgc_direct_asc,tgc_direct_desc)) then
begin
ftics_direction := v;
prop_changed("tics_direction",v);
end
end
function tc_to_label(v);
begin
return format("%f",v);//tostn(v);
end
function set_xtics_coord(v);
begin
if v<> fxtics_coord and ifarray(v) then
begin
case ftics_style of
tgc_tics_v:
begin
lbs := array();
for i,vi in v do
begin
if not ifnumber(vi) then return ;
lbs[i] := tc_to_label(vi);
end
ftcmin := minvalue(v);
ftcmax := maxvalue(v);
if ftcmin=ftcmax then return ;
ftccount := length(v)-1;
fxtics_coord := v;
fxtics_coord_v := v;
ftics_labels := lbs;
end
tgc_tics_r:
begin
if not(v[0]<v[1] and v[2]>=1) then return ;
fxtics_coord := v;
ftcmin := v[0];
ftcmax :=v[1];
ftccount := v[2];
type_c_to_r();
end
end;
fxtics_coord := v;
prop_changed("xtics_coord",v);
end
end
function ytics_ok(v);
begin
if ifarray(v) and length(v)>=3 then
begin
nmc := 0;
for i := 0 to 2 do
begin
if ifnumber(v[i]) then nmc++;
end
return nmc=2;
end
end
function set_ytics_coord(v);
begin
if v<> fytics_coord and ytics_ok(v) then
begin
fytics_coord := v;
prop_changed("ytics_coord",v);
end
end
function set_tics_segment(v);
begin
if not tg_boolen_value(n,nv) then return ;
if ftics_segment<>nv then
begin
ftics_segment := nv;
prop_changed("tics_segment",nv);
end
end
function set_tics_color(v);
begin
if ftics_color<>v then
begin
ftics_color := v;
prop_changed("tics_color",v);
end
end
function set_tics_style(v);
begin
if v<>ftics_style and( v in array(tgc_tics_v,tgc_tics_r)) then
begin
ftics_style := v;
case v of
tgc_tics_v:
begin
fxtics_coord := array();
for i,v in fxtics_coord_v do
begin
fxtics_coord[i] := v;
end
end
tgc_tics_r:
begin
fxtics_coord := array();
fxtics_coord[0] := ftcmin;
fxtics_coord[1] := ftcmax;
fxtics_coord[2] := ftccount;
type_c_to_r();
end
end ;
prop_changed("tics_style",v);
end
end
function type_c_to_r();
begin
fxtics_coord_v := array();
ftics_labels := array();
vidx := 0;
for x := ftcmin to ftcmax step (ftcmax-ftcmin)/ftccount do
begin
fxtics_coord_v[vidx] := x;
ftics_labels[vidx] := tc_to_label(x);
vidx++;
end
if x>=ftcmax then
begin
fxtics_coord_v[vidx-1] := ftcmax ;
ftics_labels[vidx-1] := tc_to_label(ftcmax) ;
end else
begin
fxtics_coord_v[vidx] := ftcmax ;
ftics_labels[vidx] := tc_to_label(ftcmax) ;
end
end
function set_sub_tics(v);
begin
if v>=0 and v<>fsub_tics then
begin
fsub_tics := v;
prop_changed("sub_tics",v);
end
end
function set_tics_labels(v);
begin
if ifarray(v) and v<>ftics_labels then
begin
ftics_labels:=v;
prop_changed("tics_labels",v);
end
end
end
type tg_text = class(tg_base)
public
function create(pms);
begin
inherited;
clip_state := tgc_off;
ftext := array();
fdata := array();
ffont_angle := 0;
end
function paint(cvs);override;
begin
if (visible<>tgc_on) then return ;
if not fdata then return ;
if not zoom_to_xyz(fdata[0],fdata[1],fdata[2],x,y) then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
get_text_size(w,h,hi);
set_lineinfo_to_canvas(cvs);
FPaintrect := array(x,y,x+w,y+h);
Frgnpoints := rec_to_points(FPaintrect)[0:3];
if ffont_angle<>0 then
begin
cvs.SaveDC();
cvs.trans(-ffont_angle,x,y);
rgn_points_trans(Frgnpoints,-ffont_angle);
x := 0;
y := 0;
end
if line_mode then
begin
rc := array(x,y,x+w,y+h);
cvs.draw_rect().rect(rc).draw();
end
set_fontinfo_to_canvas(cvs);
for i,v in ftext do
begin
cvs.textout(v,array(x,y+i*hi));
end
if ffont_angle<>0 then
cvs.RestoreDC();
end
function executecommand(cmd,p);override;
begin
case cmd of
"text_rec": return (visible=tgc_on)? FPaintrect:nil;
"text_rgn": return (visible=tgc_on)? Frgnpoints:nil;
end ;
return inherited;
end
published
property text read ftext write set_text;
property data read fdata write set_data;
property font_angle read ffont_angle write set_font_angle;
private
FPaintrect;
Frgnpoints;
ftext;
fdata;
ffont_angle;
private
function get_text_size(w,h,hi);
begin
fw := fontinfo.size;
fh := fw*2;
hi:=fh+2;
w := 0;
h := 0;
for i,v in ftext do
begin
si := v;
w := max(w,length(si)*fw);
h+=fh;
end
h+=2;
end
function set_text(v);
begin
tx := array();
for i,vi in v do
begin
if ifstring(vi) then tx[length(tx)] := vi;
end
if ftext<>tx then
begin
ftext :=tx;
prop_changed("text",tx);
end
end
function set_data(d);
begin
if fdata<>d and ifarray(d) and ifnumber(d[0]) and ifnumber(d[1]) then
begin
fdata := d;
prop_changed("data",d);
end
end
function set_font_angle(arg);
begin
if arg<>ffont_angle then
begin
ffont_angle := arg;
prop_changed("font_angle",arg);
end
end
end
type tg_label =class(tg_base) //标签对象
function create(pms);
begin
inherited;
clip_state := tgc_off;
ftext := false;
flocation := tgc_by_coordinates;
fposition := array(0,0);
ffill_mode := false;
ffont_angle := 0;
fauto_rotation := false;
end
function paint(cvs);override;
begin
if tgc_on<>visible then return ;
if not ftext then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
set_fontinfo_to_canvas(cvs);
p := fposition;
if fauto_position=tgc_on then
begin
p := fauto_position_value;
end else
begin
p := fposition;
end
case flocation of
tgc_by_axes:
begin
if not axes_mapping(p[0],p[1],0,x_,y_) then return ;
end else //tgc_by_coordinates:
begin
if not zoom_to_xyz(p[0],p[1],0,x_,y_) then return ;
end
end
txtw := length(ftext)*fontinfo.size;
rec := array(x_,y_,x_+txtw,y_+fontinfo.size);
flabel_rgn := rec_to_points(rec)[0:3];
if ffont_angle<>0 then
begin
rgn_points_trans(flabel_rgn,-ffont_angle);
cvs.SaveDC();
cvs.trans(-ffont_angle,x_,y_);
cvs.textout(ftext,array(0,0));
cvs.RestoreDC();
end else
cvs.textout(ftext,array(x_,y_));
end
function executecommand(cmd,p);override;
begin
case cmd of
"auto_position_value":
begin
fauto_position_value := p;
return ;
end
"label_rgn":
begin
return (visible=tgc_on)?flabel_rgn:nil;
end
end;
return inherited;
end
protected
function check_parent(p);override;
begin
return (not p) or (p is class(tg_axis));
end
published
property text read ftext write set_text;//= ""
property position read fposition write set_positon;//[-27.697388,-1.7130177]
property location read flocation write Set_location;
property auto_position read fauto_position write set_auto_position;//"on"
//property auto_position_value read fauto_position_value write fauto_position_value;//"on"
property auto_rotation read fauto_rotation write set_auto_rotation;//"on"
property font_angle read ffont_angle write set_font_angle;//90
//font_foreground ;//= 6
//foreground ;//= 9
//background ;//= 23
//fill_mode ;//= "off"
//font_style ;//= 6
//font_size ;//= 4
//fractional_font ;//= "off"
//font_angle ;//= 90
private
flabel_rgn;
flocation;
ftext;
fposition;
fauto_position_value;
ffont_angle;
fauto_position;
fauto_rotation;
private
function Set_location(v);
begin
if flocation<>v and (v in array(tgc_by_axes,tgc_by_coordinates)) then
begin
flocation := v;
end
end
function set_auto_position(v);
begin
if not tg_boolen_value(v,nv) then return ;
if nv<>fauto_position then
begin
fauto_position := nv;
prop_changed("auto_postion",nil);
end
end
function set_font_angle(v);
begin
if v<>ffont_angle and ifnumber(v) then
begin
ffont_angle := v;
prop_changed("font_angle",v);
end
end
function set_text(v);
begin
if ifstring(v) and v<>ftext then
begin
ftext := v;
prop_changed("text",nil);
end
end
function set_positon(v);
begin
if ifarray(v) and ifnumber(v[0]) and ifnumber(v[1]) and v[0]<>fposition[0] and v[1]<>fposition[1] then
begin
fposition[0] :=v[0];
fposition[1] :=v[1];
fauto_position := tgc_off;
prop_changed("postion",v);
end
end
function set_auto_rotation(v);
begin
if not tg_boolen_value(v,nv) then return ;
if fauto_rotation<>nv then
begin
fauto_rotation := nv;
prop_changed("auto_rotation",nv);
end
end
end
type tg_compound = class(tg_graph) //组合对象
function create(pms);
begin
inherited;
end
protected
function check_parent(p);override;
begin
return (not(p)) or (p is class(tg_compound)) or (p is class(tg_axes));
end
end
type tg_tips = class(tg_base) //提示
function create(pms);
begin
inherited;
flocation := tgc_by_coordinates;
fdisplay_components := "xy";
fbox_mode := tgc_on;
mark_mode := tgc_on;
markinfo.Style := tgc_mks_square;
markinfo.size := 5;
fline_style := 0;
fforeground := -1;
fbackground := -2;
fmark_style := 11;
fdata_idx := -1;
frow_mode := false;
end
function executecommand(cmd,pm);override;
begin
case cmd of
"fresh":
begin
FData := nil;
ftext :="";
f_ps := nil;
prop_changed("fdata_idx",pm);
end
"tips_rec": return (visible=tgc_on)?FPaintrect:nil;
end
end
function paint(cvs);override;
begin
FPaintrect := array();
if tgc_on<>visible then return ;
p := parent;
if not p then return ;
d := get_data();
if ifnil(d) then return ;
ss := get_text();
if not ss then return ;
if not(f_ps and ifnumber(f_ps[0]) and ifnumber(f_ps[1])) then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
ws := 0;
hs := array();
w := fontinfo.size;
h := w*2;
for i,v in ss do
begin
ws := max(ws,length(v)*w+w);
hs[i] := h+4;
end
zoom_to_xyz(d[0],d[1],z,x_,y_);
sz := array(ws,sum(hs));
if mark_mode = tgc_on then
begin
mk := markinfo;
msz := max(ceil(mk.size/2),2);
paint_marks(mk,cvs,array((x_,y_)));
end
case flocation of
tgc_in_upper_left: lc := 0;
tgc_in_upper_right: lc := 1;
tgc_in_lower_right: lc := 2;
tgc_in_lower_left: lc := 3;
else
lc := (fdata_idx+1) mod 3;//randomfrom(array(0,1,2,3));
end ;
rec := get_rect_at_corner(x_,y_,sz[0],sz[1],msz,lc);
FPaintrect := rec;
if fbox_mode=tgc_on then
begin
set_lineinfo_to_canvas(cvs);
cvs.draw_rect.rect(rec).draw();
end
b_x := rec[0];
b_y := rec[1];
set_fontinfo_to_canvas(cvs);
for i,v in ss do
begin
rci := array(b_x,b_y,b_x+ws,b_y+hs[i]);
cvs.drawtext(v,rci);
b_y+=hs[i];
end
end
published
//property interp_mode read finterp_mode write finterp_mode; //"on"
property location read flocation write set_location;
property box_mode read fbox_mode write set_box_mode; //"on"
property display_components read fdisplay_components write set_display_components; //"xy"
property data_idx read fdata_idx write set_data_idx;
property display_function read fdisplay_function write fdisplay_function;
property text read get_text write set_text;
property data read get_data;
private
[weakref]fdisplay_function;
flocation;
fbox_mode;
//finterp_mode;
fdisplay_components;
fdata_idx;
ftext;
fdata;
FPaintrect;
//auto_orientation ;//= "on"
//orientation ;//= 3
//label_mode ;//= "on"
//data ;//= [66.064054,-1.3511706,0]
//display_components ;//= "xy"
//display_function ;//= ""
//text ;//= ["X:66.064";"Y:-1.351"]
//detached_position ;//= []
protected
function check_parent(p);override;
begin
return ifnil(p) or (p is class(tg_graph));
end
private
f_ps;
function init_display(tip,ps,txts);
begin
d := get_data();
if ifarray(d) and ifnumber(d[0]) and ifnumber(d[1]) then
begin
px := d[0];
py := d[1];
ps := array(px,py);
txts := array();
for i := 1 to length(fdisplay_components) do
begin
vi := fdisplay_components[i];
case vi of
"x","X":
begin
txts[length(txts)] := vi+format(":%f",px);
end
"y","Y":
begin
txts[length(txts)] := vi+format(":%f",py);
end
end ;
end
end
end
function set_text(txt);
begin
if get_text()<>txt and ifarray(txt) then
begin
ftext := array();
for i,v in txt do
begin
if ifstring(v) then
begin
ftext[idx++] := v;
end
end
end
end
function get_text();
begin
if ftext then return ftext;
if iffuncptr(display_function) then
begin
call(display_function,self(true),ps,txt);
f_ps := ps;
end else
begin
init_display(self(true),ps,txt);
f_ps := ps;
end
ftext := txt;
return ftext;
end
function get_data();
begin
if fdata then return FData;
if not(fdata_idx>=0) then return nil;
p := parent;
if p then
begin
FData := p.get_graph_data_by_idx(fdata_idx);
return fdata;
end
return nil;
end
function set_data_idx(idx);
begin
if ifnumber(idx) and idx<>fdata_idx then
begin
fdata_idx := idx ;
executecommand("fresh",pm);
end
end
function set_location(v);
begin
if v<>flocation then
begin
flocation := v;
prop_changed("location",nv);
end
end
function set_display_components(v);
begin
if not( v and ifstring(v)) then return ;
if d_comp_ok(v) and fdisplay_components<>v then
begin
fdisplay_components := v;
executecommand("fresh",pm);
end
end
function set_box_mode(v);
begin
if not tg_boolen_value(v,nv) then return ;
if nv<>fbox_mode then
begin
fbox_mode := nv;
prop_changed("box_mode",nv);
end
end
function d_comp_ok(dcp);
begin
t := array("x":1,"y":1,"z":1);
for i := 1 to length(dcp) do
begin
vi := dcp[i];
if t[vi]<>1 then return false;
t[vi] := 2;
end
return true;
end
end
type tg_legend = class(tg_base) //图例
function create(pms);
begin
inherited;
clip_state := tgc_off;
flocation := tgc_in_upper_right;
flinks := array();
FText := array();
fposition := nil;
end
function paint(cvs);override;
begin
if tgc_on<>visible then return ;
if clip_state=tgc_on then cvs.axesclip();
else cvs.axesunclip();
get_lenged_sizes(lw,lh,ws,hs,objs,ss);
arec := cvs.axesrec;
rc := arec;
dis := 30;
cvs.axesunclip();
set_lineinfo_to_canvas(cvs);
case flocation of
tgc_upper_caption:
begin
x := arec[0];
y := arec[1];
mx := ceil((arec[2]-arec[0]-lw)/2)-dis;
rc := get_rect_at_corner(x,y,lw,lh,dis,2,mx);
cvs.draw_rect().rect(rc).draw();
end
tgc_lower_caption:
begin
x := arec[0];
y := arec[3];
mx := ceil((arec[2]-arec[0]-lw)/2)-dis;
rc := get_rect_at_corner(x,y,lw,lh,dis,1,mx);
cvs.draw_rect().rect(rc).draw();
end
tgc_in_upper_right:
begin
x := arec[2];
y := arec[1];
rc := get_rect_at_corner(x,y,lw,lh,dis,3);
cvs.draw_rect().rect(rc).draw();
end
tgc_in_upper_left:
begin
x := arec[0];
y := arec[1];
rc := get_rect_at_corner(x,y,lw,lh,dis,2);
cvs.draw_rect().rect(rc).draw();
end
tgc_in_lower_left:
begin
x := arec[0];
y := arec[3];
rc := get_rect_at_corner(x,y,lw,lh,dis,1);
cvs.draw_rect().rect(rc).draw();
end
tgc_in_lower_right:
begin
x := arec[2];
y := arec[3];
rc := get_rect_at_corner(x,y,lw,lh,dis,0);
cvs.draw_rect().rect(rc).draw();
end
tgc_by_coordinates: //根据位置信息设置处理
begin
if ifnil(fposition) then
begin
x := arec[2];
y := arec[1];
rc := get_rect_at_corner(x,y,lw,lh,0,3);
xyz_to_zoom(rc[0],rc[1],0,_x,_y,_z);
fposition := array(_x,_y);
end else
begin
zoom_to_xyz(fposition[0],fposition[1],0,_x,_y);
rc:= array(_x,_y,_x+lw,_y+lh);
end
cvs.draw_rect().rect(rc).draw();
end
tgc_by_axes:
begin
if ifnil(fposition) then
begin
x := arec[2];
y := arec[1];
rc := get_rect_at_corner(x,y,lw,lh,0,3);
axes_unmapping(rc[0],rc[1],_x,_y,_z);
fposition := array(_x,_y);
end else
begin
axes_mapping(fposition[0],fposition[1],0,_x,_y);
rc:= array(_x,_y,_x+lw,_y+lh);
end
cvs.draw_rect().rect(rc).draw();
end
end;
b_x := rc[0];
b_y := rc[1];
flegend_rec := rc;
set_fontinfo_to_canvas(cvs);
flegend_sub_recs := array();
for i,v in objs do
begin
hi := hs[i];
if v then
begin
rci := array(b_x,b_y,b_x+ws[0],b_y+hi);
v.paint_legend(cvs,rci);
end
flegend_sub_recs[i] := rci;
si := ss[i];
if si then
begin
rci := array(b_x+ws[0],b_y,b_x+ws[0]+ws[1],b_y+hi);
cvs.drawtext(si,rci);
end
b_y+=hi;
end
cvs.axesclip();
end
function executecommand(cmd,p);override;
begin
case cmd of
"legend_rec":return (visible=tgc_on)? flegend_rec:nil;
"legend_sub_recs":return (visible=tgc_on)? flegend_sub_recs:nil;
end
return inherited;
end
published
property location read flocation write set_location;
property postion read fposition write set_postion;
property links read flinks write set_links;
property text read FText write set_text;
protected
function check_parent(p);override;
begin
return ifnil(p) or (p is class(tg_axes));
end
private
[weakref] flinks;
flocation;
FText;
fposition;
flegend_rec;
flegend_sub_recs;
//text ;//= "y1"
//font_style ;//= 6
//font_size ;//= 1
//font_color ;//= -1
//fractional_font ;//= "off"
//links ;//= "Polyline" [] 数组
//legend_location ;//= "in_upper_right"
//position ;//= [0.7379099,0.1325]
//line_width ;//= 0.1
//line_mode ;//= "on"
//thickness ;//= 1
//foreground ;//= -1
//fill_mode ;//= "on"
//background ;//= -2
//marks_count ;//= 3
//clip_state ;//= "off"
//clip_box ;//= []
private
function get_lenged_sizes(lw,lh,ws,hs,objs,ss);
begin
ws := array(0,0);
hs := array();
w := fontinfo.size;
h := w*2;
objs := array();
ss := array();
for i:= 0 to max(length(flinks),length(ftext))-1 do
begin
vi := flinks[i];
si := ftext[i];
if vi is class(tg_graph) then
begin
objs[i] := vi;
vi.get_legend_size(w1,h1);
ws[0] := max(ws[0],w1);
end else
begin
h1 := 0;
objs[i] := 0;
end
if ifstring(si) then
begin
ws[1] := max(w*length(si)+2,ws[1]);
ss[i] := si;
end else
begin
ss[i] := nil;
end
hs[i] := max(h+4,h1);
end
lw := ws[0]+ws[1];
lh := sum(hs);
end
function set_postion(v);
begin
if fposition<>v and ifarray(v) and ifnumber(v[0]) and ifnumber(v[1]) then
begin
fposition := array(v[0],v[1]);
prop_changed("postion",v);
end
end
function set_text(s);
begin
idx := 0;
flg := false;
for i,v in s do
begin
if not ifstring(v) then continue;
if v<>ftext[idx] then
begin
ftext[idx] := v;
flg++;
end
idx++;
end
if flg then prop_changed("text",s);
end
function set_links(vs);
begin
if ifarray(vs) and vs<>flinks then
begin
flinks := vs;
prop_changed("links_changed",vs);
end
end
function set_location(v);
begin
vs := static array(tgc_in_upper_right:true,tgc_in_upper_left:true,tgc_in_lower_right:true,tgc_in_lower_left:true,
//tgc_out_upper_right,tgc_out_upper_left,tgc_out_lower_right,tgc_out_lower_left,
tgc_upper_caption:true,tgc_lower_caption:true,
tgc_by_coordinates:true,tgc_by_axes:true);
if v<>flocation and (vs[v]) then
begin
flocation := v;
end
end
end
type tg_graph_base = class(tg_base) //兼容绘图和goup两个类型
function create(pm);
begin
inherited;
end
function get_data_bounds();virtual; //获取数据边界
begin
return get_node_data_bounds(self(true));
end
end
type tg_graph = class(tg_graph_base) //绘图对象,包括数据,提示等内容
function create(pms);
begin
inherited;
fgraph_data := array();
end
function get_data_tips(); //获得数据提示对象
begin
r := array();
for i:= 0 to NodeCount-1 do
begin
vi := GetNodeByIndex(i);
if vi is class(tg_tips) then
begin
r[ridx++] := vi;
end
end
return r;
end
function get_legend_size(w,h);virtual;
begin
h := fontinfo.size+4;
w := 100;
end
function paint_legend(cvs,rec);virtual; //绘制图例
begin
end
function get_graph_data_by_idx(idx); //获取数据点
begin
return fgraph_data[idx];
end
property graph_data read fgraph_data write set_graph_data;
protected
fgraph_data;//数据
protected
function prop_changed(n,v);override;
begin
case n of
"data":
begin
for i,v in get_data_tips() do
begin
v.executecommand("fresh",nil);
end
ax := axes;
if ax then
ax.executecommand(cmd_data_changed);
end else
begin
inherited;
end
end ;
end
function set_graph_data(v);virtual;
begin
if v<>fgraph_data then
begin
fgraph_data := v;
prop_changed("data",v);
end
end
end
type tg_Polyline = class(tg_graph) //线图对象
function create(pms);
begin
inherited;
clip_state := tgc_on;
fclosed := tgc_off;
line_mode := tgc_on;
mark_mode := tgc_off;
fpolyline_style := tgc_LS_interpolated;// interpolated,staircase,barplot,arrowed,filled,bar
fbar_width := 0;
fdata_bounds := array((0,1),(0,1),(0,1));
end
function get_data_bounds();override;
begin
return fdata_bounds;
end
function paint(cvs);override;
begin
if tgc_on<> visible then return ;
if clip_state=tgc_on then
begin
//cvs.axesclip();
bx := axes.zoom_box;
pts := array();
for i,v in rec_to_points( array(bx[0,0],bx[1,0],bx[0,1],bx[1,1])) do
begin
zoom_to_xyz(v[0],v[1],bx[2,0],x,y);
pts[i] := array(x,y);
end
cvs.clip_rgn(pts);
end else
begin
cvs.axesunclip();
end
//echo tostn(bx);
xys := array();
set_lineinfo_to_canvas(cvs);
ys := array();
for i,v in fgraph_data do
begin
if not zoom_to_xyz(v[0],v[1],bx[2,0],x,y) then return ;
xys[i] := array(integer(x),integer(y));
case fpolyline_style of
tgc_LS_bar,tgc_LS_barplot,tgc_LS_filled:
begin
zoom_to_xyz(v[0],0,0,x,y) ;
ys[i] := array(x,y);
end
end;
end
fline_points_in_canvas := xys;
//zoom_to_xyz(0,0,0,x,y);
paint_lines(cvs,fpolyline_style,xys,fclosed,array("line_mode":line_mode,"bar_width":fbar_width,"color":lineinfo.color,"bkcolor":lineinfo.bkcolor,"xy0":ys));
mk := markinfo.clone();
if mark_mode=tgc_on and mk.size>2 then
begin
paint_marks(mk,cvs,xys);
end
inherited;
end
function executecommand(cmd,p);override;
begin
case cmd of
"points_in_canvas":return (visible=tgc_on)? fline_points_in_canvas:nil;
end;
return inherited;
end
function get_legend_size(w,h);virtual;
begin
mk := markinfo;
h := fontinfo.size+4;
w := 100;
if mark_mode=tgc_on then
begin
h := max(10,mk.size+4);
w := 5*h;
end
end
function paint_legend(cvs,rec);override; //绘制图例
begin
y0 := ceil(rec[1]+(rec[3]-rec[1])/2);
dis := ceil((rec[2]-rec[0])/5);
xys := array((rec[0]+dis,y0),(rec[0]+4*dis,y0));
set_lineinfo_to_canvas(cvs);
paint_lines(cvs,tgc_LS_interpolated,xys,0,array("line_mode":line_mode,"bar_width":fbar_width,"color":lineinfo.color,"bkcolor":lineinfo.bkcolor));
mk := markinfo.clone();
if mark_mode=tgc_on and mk.size>2 then
begin
xys := array((rec[0]+dis*2,y0),(rec[0]+3*dis,y0));
paint_marks(mk,cvs,xys);
end
end
property closed read fclosed write set_line_closed;//= "off"
property polyline_style read fpolyline_style write set_polyline_style;//= "0"
property bar_width read fbar_width write fbar_width;//= "0"
private
fline_points_in_canvas;
fdata_bounds;
fclosed;
fforeground;
fbackground;
fpolyline_style;
fbar_width;
//datatips;//: ["Datatip";"Datatip"]
//datatip_display_mode;//: "always"
//display_function ;//= ""
//display_function_data ;//= []
//fill_mode ;//= "off"
//thickness ;//= 4
//arrow_size_factor ;//= 1
//interp_color_vector ;//= []
//interp_color_mode ;//= "off"
//colors ;//= []
//mark_offset ;//= 0
//mark_stride ;//= 1
//x_shift ;//= []
//y_shift ;//= []
//z_shift ;//= []
//bar_width ;//= 0
//clip_state ;//= "clipgrf"
//clip_box ;//= []
protected
function set_graph_data(d);override; //设置数据
begin
if d<>fgraph_data then
begin
fx := d[:,0];
fy := d[:,1];
fdata_bounds[0,0] := minvalue(fx);
fdata_bounds[1,0] := minvalue(fy);
fdata_bounds[0,1] := maxvalue(fx);
fdata_bounds[1,1] := maxvalue(fy);
inherited;
end
end
private
function set_line_closed(v);
begin
if not tg_boolen_value(v,nv) then return ;
if nv<>fclosed then
begin
fclosed := nv;
prop_changed("closed",nv);
end
end
function set_polyline_style(v);
begin
if v<>fpolyline_style then
begin
fpolyline_style := v;
end
end
end
type tg_line_info = class(tg_const)
function create();
begin
fcolor := 0;
FWidth := 1;
FStyle := tgc_PS_SOLID;
fbkcolor := nil;
end
function clone();
begin
r := new tg_line_info();
r.style := fstyle;
r.width := FWidth;
r.size := FWidth;
r.color := fcolor;
r.bkcolor := fbkcolor;
return r;
end
property Style read FStyle write FStyle;
property width read FWidth write fwidth;
property size read FWidth write fwidth;
property color read fcolor write fcolor;
property bkcolor read fbkcolor write fbkcolor;
private
fwidth;
fcolor;
FStyle;
fbkcolor;
end
type tg_font_info = class(tg_const) //字体信息
function create();
begin
fstyle := nil;
fsize := 7;
fforeground := 0;
fbackground := nil;
end
function clone();
begin
r := new tg_font_info();
r.style := fstyle;
r.size := fsize;
r.color := fforeground;
r.bkcolor := fbackground;
return r;
end
property style read fstyle write fstyle;
property size read fsize write fsize;
property color read fforeground write fforeground;
property bkcolor read fbackground write fbackground;
private
fstyle;
fsize;
fsize_unit;
fforeground;
fbackground;
end
type tg_mark_info = class(tg_const) //标记信息
function create();
begin
fstyle := tgc_mks_dot;
fsize := 0;
fsize_unit := tgc_mk_point;
fforeground := 0;
fbackground := 0xffffff;
end
function clone();
begin
r := new tg_mark_info();
r.Style := fstyle;
r.size := fsize;
r.size_unit := fsize_unit;
r.color := fforeground;
r.bkcolor := fbackground;
return r;
end
property style read fstyle write fstyle;
property size read fsize write fsize;
property size_unit read fsize_unit write fsize_unit;
property color read fforeground write fforeground;
property bkcolor read fbackground write fbackground;
private
fstyle;
fsize;
fsize_unit;
fforeground;
fbackground;
end
type tg_evet_conainter = class(tg_const)
function create();
begin
fCapturelist := new tevent_list();
fbubblelist := new tevent_list();
end
function addEventListener(evtype,fn,ifCapture);virtual;
begin
if ifCapture then return fCapturelist.add(evtype,fn);
return fbubblelist.add(evtype,fn);
end
function removeEventListener(evtype,fn,ifCapture);
begin
if ifCapture then return fCapturelist.remove(evtype,fn);
return fbubblelist.remove(evtype,fn);
end
function dealevent(evt,ifCapture);
begin
if ifCapture then return fCapturelist.dispatch(evt);
return fbubblelist.dispatch(evt);
end
private
fCapturelist;
fbubblelist;
end
type tg_base = class(TNode,tg_evet_conainter) //基类,提供层次关系结构
public
function create(pms);
begin
class(TNode).create();
class(tg_evet_conainter).create();
fchange_locked := false;
fclip_state := tgc_on;
fvisibe := tgc_on;
fline_mode := tgc_off;
fmark_mode := tgc_off;
flineinfo := new tg_line_info();
fmarkinfo := new tg_mark_info();
ffontinfo := new tg_font_info();
end
function axes_mapping(x,y,z,_x,_y);virtual;
begin
p := get_axes();
if p then return p.axes_mapping(x,y,z,_x,_y);
return false;
end
function axes_unmapping(x,y,z,_x,_y);virtual;
begin
p := get_axes();
if p then return p.axes_unmapping(x,y,z,_x,_y);
return false;
end
function zoom_to_xyz(x,y,z,_x,_y,_z);virtual;
begin
p := get_axes();
if p then return p.zoom_to_xyz(x,y,z,_x,_y,_z);
return false;
end
function xyz_to_zoom(x,y,z,x_,y_,z_);virtual;
begin
p := get_axes();
if p then return p.xyz_to_zoom(x,y,z,x_,y_,z_);
return false;
end
function executecommand(cmd,pm);virtual;
begin
end
function paint(cvs);virtual; //绘制
begin
if tgc_on<> visible then return ;
for i := 0 to NodeCount-1 do
begin
vi := GetNodeByIndex(i);
vi.paint(cvs);
end
end
function hit_at(info):bool;
begin
if fonhit_at then return call(fonhit_at,self(true),info) ;
return false;
end
function set_lineinfo_to_canvas(cvs,info);
begin
if info is class(tg_line_info) then li := info;
else
li := lineinfo;
cl := li.color;
cvs.pen.style := li.style;
if ifnumber(cl) then
begin
cvs.pen.color := cl;
end else
begin
cvs.pen.Style := tgc_BS_NULL;
end
cvs.pen.width := li.width;
bcl := li.bkcolor;
if ifnumber(bcl) then
begin
cvs.brush.color := li.bkcolor;
cvs.brush.Style := tgc_BS_SOLID;
end
else
begin
cvs.brush.Style := tgc_BS_NULL;
end
end
function set_fontinfo_to_canvas(cvs,info);
begin
if info is class(tg_font_info) then fi := info;
else
fi := fontinfo;
cvs.font.color := fi.color;
cvs.font.bkcolor := fi.bkcolor;
cvs.font.width := fi.size;
cvs.font.height := fi.size*2;
end
function dispatchEvent(evt); //分发
begin
if not(evt is class(tg_evt)) then return 1;
tg := self(true);
p := tg;
while p do
begin
if p is class(tg_axes) then
begin
p := p.figure;
break;
end
p := p.parent;
end
if not p then return 0;
return p.dispatchEvent(evt,tg);
end
published
property line_mode read fline_mode write set_line_mode;
property mark_mode read fmark_mode write set_mark_mode;
property clip_state read fclip_state write set_clip_state;
property axes read get_axes write set_axes;
property visible read fvisibe write setvisible;
property lineinfo read flineinfo;
property markinfo read fmarkinfo;
property fontinfo read ffontinfo;
property change_locked read fchange_locked write fchange_locked;
property onhit_at read fonhit_at write fonhit_at;
public
user_data;
tag;
protected
function get_axes();virtual;
begin
p := parent;
if p then return p.axes;
end
function set_axes(axs);virtual;
begin
end
function check_parent(p);virtual; //父节点检查
begin
return true;
end
function prop_changed(n,v);virtual; //改变通知
begin
if fchange_locked then return ;
axs := get_axes();
if axs then
begin
if axs.change_locked then return ;
fg := axs.figure;
end
if fg then
begin
fg.executecommand("figure_need_fresh",p);
end
end
function SetParent(V);virtual;
begin
if not check_parent(v) then return ;
if v then ct := v.NodeCount;
r := inherited;
if v then ct2 := v.NodeCount;
if ct2>ct then
begin
ax := axes;
if ax then ax.executecommand(cmd_node_add_in,self(true));
end
return r;
end
private
[weakref]fonhit_at;
fclip_state;
fline_mode;
fmark_mode;
fvisibe;
flineinfo;
fmarkinfo;
ffontinfo;
fchange_locked;
function set_clip_state(v);
begin
if tg_boolen_value(v,nv) and (nv<>fclip_state) then
begin
fclip_state := nv;
prop_changed("clip_state",nv);
end
end
function set_line_mode(v);
begin
if tg_boolen_value(v,nv) and (nv<>fline_mode) then
begin
fline_mode := nv;
prop_changed("line_mode",nv);
end
end
function set_mark_mode(v);
begin
if tg_boolen_value(v,nv) and nv<>fmark_mode then
begin
fmark_mode := nv;
prop_changed("mark_mode",nv);
end
end
function setvisible(v);//设置可见
begin
if tg_boolen_value(v,nv) and (nv<>fvisibe) then
begin
fvisibe := nv;
prop_changed("visible",fvisibe);
end
end
end
type tg_const = class()
////////////基础///////////////////
static const tgc_off = "off";
static const tgc_on = "on";
static const tgc_box_off = "off";
static const tgc_box_on = "on";
static const tgc_box_half = "half";
/////////////坐标轴///////////////////
static const tgc_direct_asc = "asc";
static const tgc_direct_desc = "desc";
static const tgc_top = "top";
static const tgc_bottom = "bottom";
static const tgc_left = "left";
static const tgc_right = "right";
static const tgc_middle = "middle";
static const tgc_origin = "origin";
static const tgc_box_hidden_axes = "hidden_axes";
static const tgc_tics_v = "v";
static const tgc_tics_r = "r";
static const tgc_tics_i = "i";
//////标记类型//////////////////////
static const tgc_mks_dot = "dot"; //原点
static const tgc_mks_plus = "plus"; //加号
static const tgc_mks_star = "star"; //圈叉
static const tgc_mks_diamond = "diamond"; //正方形
static const tgc_mks_diamond_plus = "diamond_plus"; //正方形
static const tgc_mks_square = "square"; //正方形
static const tgc_mks_circle = "circle";//圆圈
static const tgc_mks_pentagram = "pentagram";//五角
static const tgc_mks_asterisk = "asterisk";//米字
static const tgc_mks_cross = "cross";//叉
static const tgc_mks_triangle_up = "triangle_up";
static const tgc_mks_triangle_down = "triangle_down";
static const tgc_mks_triangle_left = "triangle_left";
static const tgc_mks_triangle_right = "triangle_right";
static const tgc_mk_tabulated = "tabulated";
static const tgc_mk_point = "point";
/////////////////数据提示类型////////////////////////////////////
static const tgc_DT_always = "always";
static const tgc_DT_mouseclick = "mouseclick";
static const tgc_DT_mouseover = "mouseover";
////////////画笔画刷类型/////////////////////////////////
static const tgc_PS_SOLID=0x0;
static const tgc_PS_DASH=0x1;
static const tgc_PS_DOT=0x2;
static const tgc_PS_DASHDOT=0x3;
static const tgc_PS_DASHDOTDOT=0x4;
static const tgc_PS_NULL=0x5 ;
static const tgc_BS_NULL=1;
static const tgc_BS_SOLID=0;
///////////////////线型///////////////////////////////
static const tgc_LS_interpolated="interpolated";
static const tgc_LS_staircase="staircase";
static const tgc_LS_arrowed="arrowed";
static const tgc_LS_barplot="barplot";
static const tgc_LS_filled="filled";
static const tgc_LS_bar="bar";
/////////////////相对位置////////////////////////////
static const tgc_in_upper_right = "in_upper_right";
static const tgc_in_upper_left = "in_upper_left";
static const tgc_in_lower_right = "in_lower_right";
static const tgc_in_lower_left = "in_lower_left";
static const tgc_upper_caption = "upper_caption";
static const tgc_lower_caption = "lower_caption";
static const tgc_by_coordinates = "by_coordinates";
static const tgc_by_axes = "by_axes";
//static const tgc_out_upper_right = "out_upper_right";
//static const tgc_out_upper_left = "out_upper_left";
//static const tgc_out_lower_right = "out_lower_right";
//static const tgc_out_lower_left = "out_lower_left";
//////////////
static evt_mouse_down = "mouse_down";
static evt_mouse_move = "mouse_move";
static evt_mouse_in = "mouse_in";
static evt_mouse_out = "mouse_out";
static evt_mouse_up = "mouse_up";
static const CAPTURING_PHASE = 1;
static const AT_TARGET = 2;
static const BUBBLING_PHASE = 3;
///////////////////////////
static const cmd_zoom_inc = "zoom_inc";
static const cmd_figure_changed = "figure_changed";
static const cmd_data_changed = "data_changed";
static const cmd_node_add_in = "node_add_in";
end
type tg_evt =class() //消息
function create(etype,pms);
begin
feventtype := etype;
ftimeStamp := mtic;
fisTrusted := false;
feventPhase := 0;
freturnValue := true;
fdefaultPrevented := false;
fbubbles := true;
FstopImmediatePropagationed := false;
if not ifarray(pms) then return ;
fiparams := pms;
fisTrusted := pms["istrusted"]?true:false;
ftarget := pms["target"];
fcurrentTarget := pms["currenttarget"];
fbubbles := pms["bubbles"]?true:false;
feventPhase := (pms["eventphase"]>0)?pms["eventphase"]:0;
end
function clone(d); //克隆对象
begin
if ifarray(d) then d2 := fiparams union d;
else d2 := d;
co := self(true).Classinfo(1);
return createobject(co,feventtype,d2);
end
function preventdefault(); //阻止默认行为
begin
fdefaultPrevented := true;
end
function stoppropagation(); //停止传播
begin
fstoppropagationed := true;
end
function stopImmediatePropagation(); //阻止当前类型的消息
begin
FstopImmediatePropagationed := true;
end
published
property bubbles read fbubbles; //是否冒泡,只读
property currentTarget read fcurrentTarget;//当前绑定的对象,只读
property target read ftarget;//目标对象,只读
property stoppropagationed read fstoppropagationed;//是否已经调用 stoppropagation,只读
property stopImmediatePropagationed read FstopImmediatePropagationed;//是否已经调用 stopImmediatePropagation,只读
property defaultPrevented read fdefaultPrevented;//是否已经调用 preventdefault,只读
property returnValue read freturnValue write freturnValue;//true表示正常执行,false表示阻止默认行为
property eventPhase read feventPhase;//只读,0,1,捕获,2到达目标,3,冒泡
property timeStamp read ftimeStamp;//只读,加载完成到现在的时间
property eventtype read feventtype;//只读类型
property isTrusted read fisTrusted;//true表示用户触发,false表示代码触发
property init_params read fiparams; //初始化参数
private
feventtype;
ftimeStamp;
fisTrusted;
feventPhase;
freturnValue;
fdefaultPrevented;
fstoppropagationed;
ftarget;
fbubbles;
fcurrentTarget;
FstopImmediatePropagationed;
fiparams;
end
type tg_evt_custom = class(tg_evt) //自定义消息
function create(etyp,pms);
begin
inherited;
fdetail := array();
if ifarray(pms) then fdetail := pms["detail"];
end
property detail read fdetail;
private
fdetail;
end
type tg_evt_mouse = class(tg_evt_custom) //鼠标消息
function create(etyp,pms);
begin
inherited;
if ifarray(pms) then
begin
fcvsx := pms["cvsx"];
fcvsy := pms["cvsy"];
fdouble := pms["double"];
fshift := pms["shift"];
fctl := pms["ctrl"];
end
end
property cvsx read fcvsx;
property cvsy read fcvsy;
property shift read fshift;
property double read fdouble;
property ctrl read fctrl;
private
fcvsx;
fcvsy;
fshift;
fdouble;
fctrl;
end
implementation
///////////事件存储对象///////////////////////
type tevent_item = class()
function create(n,f);
begin
ename := n;
efunc := f;
end
ename;
[weakref]efunc;
end
type tevent_list = class()
function create();
begin
FItems := array();
end
function add(n,f);
begin
if not(ifstring(n) and n) then return 0;
if not ifobj(f) then return 0;
for i,v in FItems do
begin
if (v.ename=n and v.efunc=f) then return ;
end
FItems[length(FItems)] := new tevent_item(n,f);
return true;
end
function remove(n,f);
begin
idx := -1;
for i,v in FItems do
begin
if (ifnil(f) and v.ename = n) or (ifnil(n) and v.efunc=f) or (v.efunc=f and v.ename = n) then
begin
idx := i;
break;
end
end
if idx>0 then
begin
deleteindex(FItems,idx);
remove(n,f);
end
end
function dispatch(e);
begin
for i,it in FItems do
begin
if it then
begin
if e.stoppropagationed or e.stopImmediatePropagationed then return ;
f := it.efunc;
n := it.ename;
if f and n=e.eventtype then call(f,e);
end
end
end
FItems;
end
function node_hit_list(nd,info); //节点命中
begin
nnd := node_hit_at(nd,info);
r := array();
if nnd then
begin
r[0] := nnd ;
idx := 1;
while nnd do
begin
nnd := nnd.parent;
if nnd then r[idx] := nnd;
idx++;
end
end
return r;
end
function node_hit_at(nd,info); //命中处理
begin
if (nd.visible=nd.tgc_off) then return 0;
nct := nd.NodeCount;
if nct>0 then
begin
for i := nd.NodeCount-1 downto 0 do
begin
hnod := node_hit_at(nd.GetNodeByIndex(i),info) ;
if hnod then return hnod;
end
end
if nd.hit_at(info) then return nd;
return 0;
end
function mg_bds(bds,d); //合并数据上下界
begin
d[0,0] := min(bds[0,0],d[0,0]);
d[0,1] := max(bds[0,1],d[0,1]);
d[1,0] := min(bds[1,0],d[1,0]);
d[1,1] := max(bds[1,1],d[1,1]);
d[2,0] := min(bds[2,0],d[2,0]);
d[2,1] := max(bds[2,1],d[2,1]);
end
function p_trans(x,y,ag,_x,_y);//旋转
begin
_x := x*cos(ag)+y*sin(ag);
_y := -x*sin(ag)+y*cos(ag);
end
function paint_lines(cvs,pls,xys,cls,ifo);//划线
begin
o := static new tg_const();
case pls of
o.tgc_LS_staircase:
begin
if ifo["line_mode"]<>o.tgc_on then return ;
last := array();
for i,v in xys do
begin
if i=0 then
begin
last := v;
cvs.moveto(v);
end else
begin
cvs.lineto(array(v[0],last[1]));
cvs.lineto(v);
last := v;
end
end
end
o.tgc_LS_barplot:
begin
for i,v in xys do
begin
cvs.moveto(array(v[0],v[1]));
cvs.lineto(array(ifo["xy0",i,0],ifo["xy0",i,1]));
end
paint_lines(cvs,o.tgc_LS_interpolated,xys,cls,ifo);
end
o.tgc_LS_bar:
begin
b_w := integer(ifo["bar_width"]/2);
cvs.brush.color := ifo["bkcolor"];
for i,v in xys do
begin
if b_w>=1 then
begin
v1 := array(v[0]-b_w,v[1]);
v2 := array(v[0]+b_w,v[1]);
v3 := array(ifo["xy0",i,0]+b_w,ifo["xy0",i,1]);
v4 := array(ifo["xy0",i,0]-b_w,ifo["xy0",i,1]);
cvs.draw_polygon().points(array(v1,v2,v3,v4)).draw();
end else
begin
cvs.moveto(array(v[0],v[1]));
cvs.lineto(array(ifo["xy0",i,0],ifo["xy0",i,1]));
end
end
paint_lines(cvs,o.tgc_LS_interpolated,xys,cls,ifo);
end
o.tgc_LS_arrowed:
begin
if ifo["line_mode"]<>o.tgc_on then return ;
paint_lines(cvs,o.tgc_LS_interpolated,xys,cls,ifo);
vlast := xys[0];
for i,v in xys do
begin
if i<1 then continue;
x := v[0];
y := v[1];
dx := x-vlast[0];
dy := y-vlast[1];
arg := arctan(dy/dx)+pi();
sz := 15;
p_trans(sz,0,-(arg-pi()/6),x1,y1);
cvs.moveto(v);
cvs.lineto(array(v[0]+x1,v[1]+y1));
p_trans(sz,0,-(arg+pi()/6),x1,y1);
cvs.moveto(v);
cvs.lineto(array(v[0]+x1,v[1]+y1));
vlast := v;
end
end
o.tgc_LS_filled:
begin
if cls=o.tgc_on then
begin
cvs.brush.color := ifo["bkcolor"];
cvs.draw_polygon().points(xys).draw();
end else
begin
cvs.brush.color := ifo["color"];
for i,v in xys do
begin
if i=0 then continue;
v1 := v;
v4 := xys[i-1];
v2 := array(ifo["xy0",i,0],ifo["xy0",i,1]);
v3 := array(ifo["xy0",i-1,0],ifo["xy0",i-1,1]);
cvs.draw_polygon().points(array(v1,v2,v3,v4)).draw();
end
end
paint_lines(cvs,o.tgc_LS_interpolated,xys,cls,ifo);
end
else
begin
if ifo["line_mode"]<>o.tgc_on then return ;
cvs.draw_polyline().points(xys union ((cls=o.tgc_on and length(xys)>2)?array(xys[0]):array())).draw();
end
end
end
function paint_marks(mk,dc,xys); //绘制点
begin
o := static new tg_const();
tp := mk.Style;
sz := mk.size;
a := integer(sz/2);
b := max(a,(sz-a));
a := b;
dc.pen.Style := 0;
dc.pen.color := mk.color;
dc.brush.style := 0;
dc.brush.color := mk.bkcolor;
case tp of
o.tgc_mks_pentagram:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
vv := array();
for ii := 0 to 11 do
begin
if (ii mod 2)=1 then
begin
p_trans(0,-a/2,(ii*36)/180*pi(),_x,_y);
end else
p_trans(0,-a,(ii*36)/180*pi(),_x,_y);
vv[ii] := array(v[0]+_x,v[1]+_y);
end
sp.points(vv).draw();
end
end
o.tgc_mks_triangle_up:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
v1 := array(v[0],v[1]-a);
p_trans(0,-a,120/180*pi(),_x,_y);
v2 := array(v[0]+_x,v[1]+_y);
p_trans(0,-a,-120/180*pi(),_x,_y);
v3 := array(v[0]+_x,v[1]+_y);
sp.points(array(v1,v3,v2)).draw();
end
end
o.tgc_mks_triangle_down:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
v1 := array(v[0],v[1]+a);
p_trans(0,a,120/180*pi(),_x,_y);
v2 := array(v[0]+_x,v[1]+_y);
p_trans(0,a,-120/180*pi(),_x,_y);
v3 := array(v[0]+_x,v[1]+_y);
sp.points(array(v1,v3,v2)).draw();
end
end
o.tgc_mks_triangle_left:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
v1 := array(v[0]-a,v[1]);
p_trans(-a,0,120/180*pi(),_x,_y);
v2 := array(v[0]+_x,v[1]+_y);
p_trans(-a,0,-120/180*pi(),_x,_y);
v3 := array(v[0]+_x,v[1]+_y);
sp.points(array(v1,v3,v2)).draw();
end
end
o.tgc_mks_triangle_right:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
v1 := array(v[0]+a,v[1]);
p_trans(a,0,120/180*pi(),_x,_y);
v2 := array(v[0]+_x,v[1]+_y);
p_trans(a,0,-120/180*pi(),_x,_y);
v3 := array(v[0]+_x,v[1]+_y);
sp.points(array(v1,v3,v2)).draw();
end
end
o.tgc_mks_diamond_plus:
begin
mk.Style := o.tgc_mks_diamond ;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_plus;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_diamond_plus;
end
o.tgc_mks_diamond:
begin
sp := dc.draw_polygon();
for i,v in xys do
begin
x := v[0];
y := v[1];
v1 := array(x-a,y);
v2 := array(x+b,y);
v3 := array(x,y-a);
v4 := array(x,y+b);
sp.points(array(v1,v3,v2,v4)).draw();
end
end
o.tgc_mks_dot,o.tgc_mks_circle,o.tgc_mks_square:
begin
if tp=o.tgc_mks_dot then
dc.brush.color := mk.color;
if tp=o.tgc_mks_square then pse := dc.draw_rect();
else
pse := dc.draw_ellipse();
for i,v in xys do
begin
rec := array(v[0]-a,v[1]-a,v[0]+b,v[1]+b);
pse.rect(rec).draw();
end
end
o.tgc_mks_plus:
begin
for i,v in xys do
begin
x := v[0];
y := v[1];
v1 := array(x-a,y);
v2 := array(x+b,y);
v3 := array(x,y-a);
v4 := array(x,y+b);
dc.moveto(v1);
dc.lineto(v2);
dc.moveto(v3);
dc.lineto(v4);
end
end
o.tgc_mks_star:
begin
mk.Style := o.tgc_mks_circle;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_plus;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_star;
end
o.tgc_mks_cross:
begin
for i,v in xys do
begin
x := v[0];
y := v[1];
v1 := array(x-a,y-a);
v2 := array(x+b,y+b);
v3 := array(x+b,y-a);
v4 := array(x-a,y+b);
dc.moveto(v1);
dc.lineto(v2);
dc.moveto(v3);
dc.lineto(v4);
end
end
o.tgc_mks_asterisk:
begin
mk.Style := o.tgc_mks_cross;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_plus;
paint_marks(mk,dc,xys);
mk.Style := o.tgc_mks_asterisk;
end
end ;
end
function tg_boolen_value(v,nv); //规则化boolean
begin
if v=true or v="on" then
begin
nv := "on";
return true;
end else
if v=false or v="off" then
begin
nv := "off";
return true;
end
end
////////////////边界取整////////////////////////////
function new_bound_factor(a,n);
begin
if a>1 and a<=10 then
begin
return int(a)*10^n;
end else
if a>10 then
begin
n++;
return new_bound_factor(a/10,n);
end else
if a<=1 then
begin
n--;
return new_bound_factor(a*10,n);
end
end
function new_bounds(a,b,a_,b_,par);
begin
a_ := a;
b_ := b;
if not(par>=1) then par:=20;//20;
r := new_bound_factor((b-a)/par,n);
if r<>0 then
begin
a_:=floor(a/r)*r;
b_:= ceil(b/r)*r;
end
return r;
end
function get_node_data_bounds(nd); //获取节点的范围
begin
d := zeros(3,2);
for i := 0 to nd.NodeCount-1 do
begin
vi := nd.GetNodeByIndex(i);
if vi is class(tg_graph_base) then
begin
bds := vi.get_data_bounds();
mg_bds(bds,d);
end
end
return d;
end
function get_rect_at_corner(x,y,w,h,itv,flg,mvx,mvy); //计算围绕点的区域位置
begin
//0左上 1右上 2 右下 3 左下
r := zeros(4);
case flg of
0:
begin
r[0] :=x-w-itv;
r[1] :=y-h-itv;
r[2] :=x-itv;
r[3] :=y-itv;
end
1:
begin
r[0] :=x+itv;
r[1] :=y-h-itv;
r[2] :=x+w+itv;
r[3] :=y-itv;
end
2:
begin
r[0] :=x+itv;
r[1] :=y+itv;
r[2] :=x+w+itv;
r[3] :=y+h+itv;
end
3:
begin
r[0] :=x-w-itv;
r[1] :=y+itv;
r[2] :=x-itv;
r[3] :=y+h+itv;
end
4: //中
begin
w2 := ceil(w/2);
h2 := ceil(h/2);
r[0] :=x-w2;
r[1] :=y-h2;
r[2] :=x+w2;
r[3] :=y+h2;
end
end;
if mvx>0 or mvx<0 then
begin
r[0]+=mvx;
r[2]+=mvx;
end
if mvy>0 or mvy<0 then
begin
r[1]+=mvy;
r[3]+=mvy;
end
return r;
end
/////////////辅助//////////////////////////////////////
function like_0(x,jd);
begin
if jd>10 then return (x+jd=jd);
return (x+1000)=1000;
end
function a_like_b(a,b,jd);
begin
return like_0(a-b);
end
function r_2_a(arg);
begin
return arg*180/pi();
end
function a_2_r(arg);
begin
return arg*pi()/180;
end
function d2angle(v1,v2); //角度计算
begin
return arccos(sum(v1*v2)/vectorsize(v1)/vectorsize(v2));
end
function vectorsize(v); //向量长度
begin
return (v[0]^2+v[1]^2)^0.5;
end
function rec_to_points(rec);
begin
return array(rec[array(0,1)],rec[array(2,1)],rec[array(2,3)],rec[array(0,3)],rec[array(0,1)]);
end
function point_in_rgn(p,rgn_); //判断点是否在区域中
begin
arg := 0;
rgn := rgn_ union array(rgn_[0]);
for i := 1 to length(rgn)-1 do
begin
p1 := rgn[i-1];
p2 := rgn[i];
v1 := array(p1[0]-p[0],p1[1]-p[1]);
v2 := array(p2[0]-p[0],p2[1]-p[1]);
argi := d2angle(v1,v2);
arg+=argi;
end
return (abs(arg/2-pi())<0.01);
end
function rgn_points_trans(pts,ag);
begin
for i := 1 to length(pts)-1 do
begin
p_trans(pts[i,0]-pts[0,0],pts[i,1]-pts[0,1],ag,px,py);
pts[i] := array(pts[0,0]+px,pts[0,1]+py);
end
end
function tg_get_true_idx(idx);
begin
nidx := idx;
case idx of
"x","X": nidx := 0;
"y","Y": nidx := 1;
"z","Z": nidx := 2;
end ;
return nidx;
end
////////////////////////////////////////
initialization
finalization
end.