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 分别获取对应的x,y轴 ,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,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 afdata_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 vfzoom_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 vfzoom_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+p_width) then return false; if y(p_top+p_height) then return false; return true; end function zoom_bound_op(a,b,dx,x,a1,b1);//缩放 begin if xb 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 bwffont_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 (vifzoom_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(minv0 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 xarga_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 xarga_90 then //第1 begin xarg := -xarg; end else if xarg>a_90 and yarg>a_90 then //第2 begin xarg :=-xarg; end else if yarga_90 then //第3 begin end else if yargfzoom_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]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]=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.