unit utvclgraphics; interface uses utslvclauxiliary; //tsl绘图库 //20240126 //20240204 添加说明 { 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 是否裁剪区域 Coordinate_Mapping(x,y,z,var _x,var _y) 通过坐标点计算画布点位置 Coordinate_unMapping(x,y,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对象 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_left tgc_right tgc_bottom tgc_top tics_style 刻度类型 tgc_tics_v (设置值) tgc_tics_r ([x0,x1,inteval]) xtics_coord 刻度,根据tics_style 确定 [2,3,4,5,6,7] 计算 [start,end,interval] ytics_coord 位置,设置在另一个方向的位置,相对坐标系的数据位置 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函数实现图形的绘制 其仅仅作为一个案例,用户可以按照其原理构造自己的画布对象,驱动绘制,得到图形 } { //////////////////绘图范例////////////////////////// uses tslvcl,utvclgraphics; app := initializeapplication(); app.createform(class(tfm),fm); fm.show(); app.run(); type tfm = class(tvcform) function create(aowner); begin inherited; 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 } 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 DoMouseWheel(o,e);override; begin p := ScreenToClient(e.xpos,e.ypos); ffigure.executecommand("zoom_inc",array("delta":e.delta,"x":p[0],"y":p[1])); end function DoWMSIZE(o,e);override; begin inherited; ffigure.executecommand("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(); //echo "\r\ninvalidate time:",datetimetostr(now()); InvalidateRect(nil,false); Fneed_invaliate := false; end private ffigure; fg_timer; Fneed_invaliate; ffigureprepared; end type tg_figure = class() ///////// 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 "zoom_inc": begin for i,v in faxeses.data do begin v.executecommand("zoom_inc",p); end end "figure_changed": begin for i,v in faxeses.data do begin v.executecommand("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; //刷新回调 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 private [weakref] frect_getter; [weakref] ffresh_caller; fwilladdaxs; fwilldelaxs; faxeses; end type tg_axes = class(tg_base) //坐标系 private [weakref]fFigure; ///////////////坐标辅助计算///////////////////////// p_left; p_top; p_width; p_height; dx_min; dx_max; dx_len; dy_min; dy_max; dy_len; rt_x; rt_y; f_changed; static const c_g_paint_rect=2; static const c_g_data_changed=1; static const c_g_data_zoombox=4; /////////////////////////////////////////// public function executecommand(cmd,pm);override; begin ochanged := f_changed; case cmd of "zoom_inc": begin if not ifarray(pm) then return ; p0 := pm["x"]; p1 := pm["y"]; for i := 0 to 1 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 Coordinate_unMapping(p0,p1,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)[i],a,b) then continue ; rt := 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 "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 "figure_changed": begin f_changed .|= c_g_paint_rect; f_changed .|= c_g_data_zoombox; end "data_changed": begin f_changed .|= c_g_data_changed; f_changed .|= c_g_data_zoombox; end end ; if ochanged<>f_changed then prop_changed("data_changed",f_changed); end function Coordinate_unMapping(x,y,_x,_y,_z);override; //画布到坐标 begin if not(fFigure) then return 0; if faxes_reverse[0]=tgc_on then //x轴 begin _x := fzoom_box[0,0]-(x-p_left-p_width)/rt_x; end else begin _x := (x-p_left)/rt_x+fzoom_box[0,0]; end if faxes_reverse[1]=tgc_on then //y轴 begin _y := (y-p_top)/rt_y +fzoom_box[1,0]; end else begin _y := fzoom_box[1,0]-(y-p_top-p_height)/rt_y; end return true; 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 Coordinate_Mapping(x,y,z,_x,_y);override; //坐标到画布 begin if not(fFigure) then return 0; if faxes_reverse[0]=tgc_on then //x轴 begin _x := p_left+p_width-(x-fzoom_box[0,0])*rt_x; end else begin _x := (x-fzoom_box[0,0])*rt_x+p_left; end if faxes_reverse[1]=tgc_on then //y轴 begin _y := (y-fzoom_box[1,0])*rt_y+p_top; end else begin _y := p_top+p_height-(y-fzoom_box[1,0])*rt_y; end return true; end function paint_pre(cvs); begin if not visible then return ; axes_changed(); modify_coordinate_postion(); 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(); for i,v in array(ftitle,fx_label,fy_label) do //标签 begin v.paint(cvs); end if fbox = tgc_on then begin set_lineinfo_to_canvas(cvs); cvs.moveto(array(p_left,p_top)); cvs.lineto(array(p_left+p_width,p_top)); cvs.lineto(array(p_left+p_width,p_top+p_height)); cvs.lineto(array(p_left,p_top+p_height)); cvs.lineto(array(p_left,p_top)); end end function axes_changed();//改变 begin if not fFigure then return ; if f_changed then begin 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]; 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; end if (f_changed .& c_g_data_zoombox)=c_g_data_zoombox then begin auto_set_axis(); end dx_min := fzoom_box[0,0]; dx_max := fzoom_box[0,1]; dx_len := dx_max-dx_min; dy_min := fzoom_box[1,0]; dy_max := fzoom_box[1,1]; dy_len := dy_max-dy_min; rt_x := p_width/ dx_len; rt_y := p_height/dy_len; end f_changed := 0; end function create(pms); begin inherited; fdata_bounds_locked := array(0,0,0); f_changed := 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); fview := "2d"; fbox := tgc_off; ffilled := tgc_off; fx_location := tgc_bottom; 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; case i of 0: axi.tics_direction := tgc_bottom; 1:axi.tics_direction := tgc_left; 2:axi.visible := false; end ; faxes_objects[i] := axi; axi.axes := self(true); end ftitle := new tg_label_axes(); ftitle.axes := self(true); fx_label := new tg_label_axes(); fx_label.axes := self(true); fy_label := new tg_label_axes(); fy_label.axes := self(true); fy_label.font_angle := pi()/2; 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 view read fview write set_view; //立体 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 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 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; fview; 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 Coordinate_Mapping(v,0,0,_x,_y) then begin cvs.moveto(array(_x,y1)); cvs.lineto(array(_x,y2)); end end end xg := fgrid[1]; if xg.width>0 and ifnumber(xg.color) then begin set_lineinfo_to_canvas(cvs,xg); x1 := p_left; x2 := p_left+p_width; for i,v in faxes_objects[1].executecommand("get_tics_value") do begin if vfzoom_box[1,1] then continue; if Coordinate_Mapping(0,v,0,_x,_y) then begin cvs.moveto(array(x1,_y)); cvs.lineto(array(x2,_y)); end end end end function auto_set_axis();//自动计算坐标 begin sz := array(p_width,p_height); for i:=0 to 1 do begin axi :=faxes_objects[i]; axi.executecommand("set_bounds",fzoom_box[i]); fsz := axi.fontinfo.size; if fauto_ticks[i] = tgc_on then begin if i=0 then begin n := integer(sz[0]/(fsz*15)); end else if i=1 then begin n := integer(sz[1]/(fsz*6)); 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 := bs; stp := bs*rt; vi := a_; ii := 0; while vi<=b_ do begin xcd[ii++] := vi; vi+=stp; end end axi.xtics_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 fx_label and (fx_label.visible=tgc_on) and (fx_label.auto_position=tgc_on) then begin s := fx_label.text; if s then begin x := p_left+(p_width-length(s)*10)/2; ax := faxes_objects[0]; y := p_top+p_height+20; if ax.visible=tgc_on and ax.tics_direction = tgc_bottom then begin y +=ax.fontinfo.size*2; end if fx_label.location=tgc_by_coordinates then Coordinate_unMapping(x,y,_x,_y,_z); else axes_unmapping(x,y,_x,_y,_z); p := array(_x,_y); fx_label.executecommand("auto_position_value",p); end end if fy_label and (fy_label.visible=tgc_on) and (fy_label.auto_position=tgc_on) then begin s := fy_label.text; fsz := fy_label.fontinfo.size; if s then begin y := p_top+(p_height-length(s)*fsz)/2; if (fy_location= tgc_left) then begin x := p_left+p_width+5+fsz*2; end else begin x := p_left-5;//-fy_label.fontinfo.size; end if fy_label.location=tgc_by_coordinates then Coordinate_unMapping(x,y,_x,_y,_z); else axes_unmapping(x,y,_x,_y,_z); p := array(_x,_y); fy_label.executecommand("auto_position_value",p); end end 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); 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 Coordinate_unMapping(x,y,_x,_y,_z); else axes_unmapping(x,y,_x,_y,_z); ftitle.executecommand("auto_position_value",array(_x,_y)); end end end function modify_coordinate_postion();//修正坐标轴位置 begin axy := faxes_objects[1]; case fy_location of tgc_left: begin axy.ytics_coord := fzoom_box[0,(faxes_reverse[0] = tgc_on)]; end tgc_right: begin axy.ytics_coord := fzoom_box[0,(faxes_reverse[0]<> tgc_on)]; end tgc_middle: begin axy.ytics_coord := fzoom_box[0,0]+(fzoom_box[0,1]-fzoom_box[0,0])/2; end tgc_origin: begin if fzoom_box[0,0]<0 and fzoom_box[0,1]>0 then axy.ytics_coord := 0; else begin axy.ytics_coord := fzoom_box[0,(faxes_reverse[0] = tgc_on)]; end end end ; axx := faxes_objects[0]; case fx_location of tgc_bottom: begin axx.ytics_coord := fzoom_box[1,(faxes_reverse[1]= tgc_on)]; end tgc_top: begin axx.ytics_coord := fzoom_box[1,(faxes_reverse[1]<> tgc_on)]; end tgc_middle: begin axx.ytics_coord := fzoom_box[1,0]+(fzoom_box[1,1]-fzoom_box[1,0])/2; end tgc_origin: begin if fzoom_box[1,0]<0 and fzoom_box[1,1]>0 then axx.ytics_coord := 0; else begin axx.ytics_coord := fzoom_box[1,(faxes_reverse[1]= tgc_on)]; end end end ; 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 (v in array(tgc_box_on,tgc_box_off,tgc_box_half,tgc_box_hidden_axes)) and v<>fbox then begin fbox := v; 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; if v=tgc_bottom or v=tgc_top then faxes_objects[0].tics_direction := 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; if v=tgc_left or v=tgc_right then faxes_objects[1].tics_direction := v; prop_changed("y_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(idx,v);//自动更新坐标标签 begin tg_boolen_value(v,nv); 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(idx); begin if idx in array(0,1) 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(idx,v); begin 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(idx,v); begin 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(idx,v); //反向 begin if v=tgc_off or v=tgc_on then begin if idx in array(0,1,2) then begin faxes_reverse[idx] := v; prop_changed("axes_reverse",idx); end end else //get begin if idx in array(0,1,2) 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(idx,v); //小刻度线 begin 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 end type tg_canvas = class(TcustomCanvas) uses utslvclgdi; function create(h); begin inherited create(); FCvsHandle := h; Handle := h; faxesrgn := new TRGNRECT(); end function axesclip(); begin if faxesrgn then begin _wapi.SelectClipRgn(FCvsHandle,faxesrgn.Handle); //裁剪区域 end end function axesunclip(); begin _wapi.SelectClipRgn(FCvsHandle,0); end function destroy(); begin Handle := 0; faxesrgn := nil; end property axesrec read FaxesRec write set_clip_rect; private FaxesRec; FCvsHandle; faxesrgn; private function set_clip_rect(rec); begin FaxesRec := rec; faxesrgn.rect := rec; end end type tg_axis_main = class(tg_axis) //主轴 public function create(pms); begin inherited; 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_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_bottom; // fxtics_coord := array(0,1,2,3); ftcmin := 0; ftcmax := 3; ftccount := 3; fxtics_coord_v := array(0,1,2,3); fytics_coord := 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 "get_tics_value":return fxtics_coord_v; "set_bounds": return set_zoom_bounds(pm); 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 case ftics_direction of tgc_top: begin draw_axis(cvs,subtks,1); end tgc_bottom: begin draw_axis(cvs,subtks,1+2); end tgc_left: begin draw_axis(cvs,subtks,0); end tgc_right: begin draw_axis(cvs,subtks,0+2); end end 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 xtics_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"] private 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; //format_n ;//= "" //fractional_font ;//= "off" //clip_state ;//= "off" //clip_box ;//= [] //user_data ;//= [] //tag ;//= "" private function draw_axis(cvs,subtks,flg); begin pw := lineinfo.width; tklen := fticksize+(pw>0?pw:0); tklensub := fsubticksize+(pw>0?pw:0); vtic := flg .& 1 ; vtic2 := (flg .&2)?1:-1; set_lineinfo_to_canvas(cvs); set_fontinfo_to_canvas(cvs); ///////////////////轴线//////////////////////////////// if ftics_segment=tgc_on then begin if fzoom_bounds then begin if vtic then begin Coordinate_Mapping(fzoom_bounds[0],fytics_coord,0,x,y); cvs.moveto(array(x,y)); Coordinate_Mapping(fzoom_bounds[1],fytics_coord,0,x,y); cvs.lineto(array(x,y)); end else begin Coordinate_Mapping(fytics_coord,fzoom_bounds[0],0,x,y); cvs.moveto(array(x,y)); Coordinate_Mapping(fytics_coord,fzoom_bounds[1],0,x,y); cvs.lineto(array(x,y)); end end else begin for i,v in fxtics_coord_v do begin if vtic then Coordinate_Mapping(v,fytics_coord,0,x,y); else Coordinate_Mapping(fytics_coord,v,0,x,y); if i=0 then cvs.moveto(array(x,y)); else cvs.lineto(array(x,y)); end end end ///////////////////////////////////////////////////// //////////////////刻度线以及刻度值/////////////////////////////////////// tcsinfo := array(); if ifnumber(ftics_color) then cvs.pen.color := ftics_color; for i,v in fxtics_coord_v do begin if fzoom_bounds and (vfzoom_bounds[1]) then continue; if vtic then Coordinate_Mapping(v,fytics_coord,0,x,y); else Coordinate_Mapping(fytics_coord,v,0,x,y); lbi := ftics_labels[i]; cvs.moveto(array(x,y)); sz := nil; if lbi then begin sz := array((length(lbi))*fontinfo.size+4,fontinfo.size*2+4) ;//cvs.GetTextExtent(lbi); end if vtic then begin ny := y+(vtic2*tklen); cvs.lineto(array(x,ny)); if sz then begin rec := array(x-sz[0]/2,0,x+sz[0]/2,0); if ny>y then begin rec[1] := ny+5; rec[3] := ny+sz[1]+5; end else begin rec[1] := ny-sz[1]-5; rec[3] := ny-5; end end tcsinfo[length(tcsinfo)] := array(lbi,rec,"h"); //draw_tics(cvs,lbi,rec); //cvs.drawtext(lbi,rec); end else begin nx := x+(vtic2*tklen); cvs.lineto(array(nx,y)); if sz then begin rec := array(0,y-sz[1]/2,0,y+sz[1]/2); if nx>x then begin rec[0] := nx+5; rec[2] := nx+sz[0]+5; end else begin rec[0] := nx-sz[0]-5; rec[2] := nx-5; end //draw_tics(cvs,lbi,rec); tcsinfo[length(tcsinfo)] := array(lbi,rec,"v"); //cvs.drawtext(lbi,rec); end end //cvs.textout(lbi,array(x,y)); end if tcsinfo then draw_tics(cvs,tcsinfo); ///////////////////////////////////////////////////////////////////////// ////////////////////子刻度线//////////////////////////////////////////////// for i,v in subtks do begin if vtic then Coordinate_Mapping(v,fytics_coord,0,x,y); else Coordinate_Mapping(fytics_coord,v,0,x,y); cvs.moveto(array(x,y)); if vtic then cvs.lineto(array(x,y+(vtic2*tklensub))); else cvs.lineto(array(x+(vtic2*tklensub),y)); end end function set_zoom_bounds(v); begin if ifarray(v) and v[0]ftics_direction and ( v in array(tgc_top,tgc_left,tgc_right,tgc_bottom)) 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 set_ytics_coord(v); begin if v<> fytics_coord then begin fytics_coord := v; prop_changed("ytics_coord",v); end end function set_tics_segment(v); begin nv := v?true:false; if ftics_segment<>v then begin ftics_segment := v; prop_changed("tics_segment",v); 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 Coordinate_Mapping(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); if ffont_angle<>0 then begin cvs.SaveDC(); cvs.trans(-ffont_angle,x,y); 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 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 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 Coordinate_Mapping(p[0],p[1],0,x_,y_) then return ; end end if ffont_angle<>0 then begin 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 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 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; end end end function paint(cvs);override; begin 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 Coordinate_Mapping(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); 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; //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); Coordinate_unMapping(rc[0],rc[1],_x,_y,_z); fposition := array(_x,_y); end else begin Coordinate_Mapping(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]; set_fontinfo_to_canvas(cvs); 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 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 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; //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,tgc_in_upper_left,tgc_in_lower_right,tgc_in_lower_left, //tgc_out_upper_right,tgc_out_upper_left,tgc_out_lower_right,tgc_out_lower_left, tgc_upper_caption,tgc_lower_caption, tgc_by_coordinates,tgc_by_axes); if v<>flocation and (v in vs) 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("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 cvs.axesclip(); else cvs.axesunclip(); xys := array(); set_lineinfo_to_canvas(cvs); for i,v in fgraph_data do begin if not Coordinate_Mapping(v[0],v[1],z,x,y) then return ; xys[i] := array(integer(x),integer(y)); end Coordinate_Mapping(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,"x":x,"y":y)); mk := markinfo; if mark_mode=tgc_on and mk.size>2 then begin paint_marks(mk,cvs,xys); end 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; 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 fclosed;//= "off" property polyline_style read fpolyline_style write set_polyline_style;//= "0" property bar_width read fbar_width write fbar_width;//= "0" private 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_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 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 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 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_base = class(TNode,tg_const) //基类,提供层次关系结构 public function create(pms); begin class(TNode).create(); 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 Coordinate_Mapping(x,y,z,_x,_y);virtual; begin p := get_axes(); if p then return p.Coordinate_Mapping(x,y,z,_x,_y); return false; end function Coordinate_unMapping(x,y,x_,y_,z_);virtual; begin p := get_axes; if p then return p.Coordinate_unMapping(x,y,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 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 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; 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 axs := get_axes(); if axs then fg := axs.figure; 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("node_add_in",self(true)); end return r; end private fclip_state; fline_mode; fmark_mode; fvisibe; flineinfo; fmarkinfo; ffontinfo; 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_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"; ////////////// end implementation type tg_3d_box = class() function create(); begin ftheta := 0; falpha := 0; f_changed := 0; flinesindex := 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) ); fvectorsindex := 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), ); fbounds := array(0,0,200,200); fsizes := array(200,200,200); frotemt := eye(3); fvcenter := array(100,100,100); fzoombounds := array((0,200),(0,200),(0,200)); //fvectors :=init_vecs(200,200,200) ; faces := array(); FRates := array(1,1,1); frevers := array(1,1,0); end function set_trans(t,a); //设置转换角度 begin if (t=ftheta) and (falpha=a) then return ; ftheta := t; falpha := a; c := cos(a); s := sin(a); c1 := cos(t); s1 := sin(t); frotemt := 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)); //frotemt := array((1,0,0),(0,c1,s1),(0,-s1,c1)):*array((c,s,0),(-s,c,0),(0,0,1)):*array((0,1,0),(1,0,0),(0,0,1)); f_changed := true; end function refresh_box();//重算坐标框架 begin if f_changed then begin f_changed := 0; recalc_size(); end end function transxyz(x,y,z,_x,_y,_z); //旋转数据 begin r := array((x,y,z)):*frotemt; _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,0)):/frotemt; _x := r[0,0]; _y := r[0,1]; _z := r[0,2]; end function zoom_to_xy(x,y,z,_x,_y,_z); //---------- begin if frevers[0] then x0 := fsizes[0]/2-(x-fzoombounds[0,0])/FRates[0]; else x0 := (x-fzoombounds[0,0])/FRates[0] -fsizes[0]/2; if frevers[1] then y0 := fsizes[1]/2-(y-fzoombounds[1,0])/FRates[1]; else y0 := (y-fzoombounds[1,0])/FRates[1] -fsizes[1]/2; if frevers[2] then z0 := fsizes[2]/2-(z-fzoombounds[2,0])/FRates[2]; else z0 := (z-fzoombounds[2,0])/FRates[2] -fsizes[2]/2; transxyz(x0,y0,z0,x1,y1,_z); x1 +=fvcenter[0]; y1 +=fvcenter[1]; _x := x1; _y := y1; end property theta read ftheta; property alpha read falpha; property bounds read fbounds write set_bounds; property zoombounds read gs_zoombounds write gs_zoombounds; property size read get_size; function paint_box(cvs); begin r := array(); cvs.pen.color := 0xff0000; lines := array(); ps2 := array(); inpoints := array(); echo "\r\n>>>",(abs(ftheta/pi()) mod 2); if (abs(ftheta/pi()) mod 2)=0 then begin for i:= 0 to 3 do begin if point_in_rgn(fvectors[4:7],fvectors[i]) then begin inpoints[length(inpoints)] := i; end end end else begin for i:= 4 to 7 do begin if point_in_rgn(fvectors[0:3],fvectors[i]) then begin inpoints[length(inpoints)] := i; end end end hd := array(); for i,v in flinesindex do begin ps := fvectors[v]; if (inpoints intersect v) then hd[i] := true; for j,vj in ps do lines[i,j] := vj[0:1]+fvcenter; //cvs.draw_polyline().points(ps1).draw(); end for i,v in lines do begin ps1 := v; if hd[i] then cvs.pen.style := 1; else cvs.pen.style := 0; cvs.draw_polyline().points(ps1).draw(); end return ; for i,v in fvectorsindex do begin ps := fvectors[v,0:1]; ps1 := array(); for j,vj in ps do ps1[j] := vj+fvcenter; ps1[j+1] := ps1[0]; cvs.draw_polyline().points(ps1).draw(); //break; end end private //////////长宽高//////////////////// fvcenter; //中心 ////////////////////// fvectorsindex; //定点次序 flinesindex;// ftheta; falpha; frotemt; fbounds; f_changed; fzoombounds; fvectors; FRates; fsizes; frevers; private function gs_zoombounds(idx,v); //小刻度线 begin if ifarray(idx) then begin if ifarray(v) then begin for i,vi in idx do begin gs_zoombounds(vi,v[vi]); end end else begin r := array(); for i,vi in idx do begin return gs_zoombounds(vi); end end end if ifarray(v) and ifnumber(v[0]) and (v[0]v then begin fbounds := v; f_changed := true; end end function get_size(); begin return fsizes; end function get_new_w_h(w1,h1,w,h,z); begin z1 := (w1+h1)/2; 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 bwo.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(v[0],ifo["y"])); 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(v[0]+b_w,ifo["y"]); v4 := array(v[0]-b_w,ifo["y"]); cvs.draw_polygon().points(array(v1,v2,v3,v4)).draw(); end else begin cvs.moveto(array(v[0],v[1])); cvs.lineto(array(v[0],ifo["y"])); 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 cvs.brush.color := ifo["color"]; for i,v in xys do begin if i=0 then continue; v1 := v; v2 := array(v[0],ifo["y"]); v4 := xys[i-1]; v3 := array(v4[0],ifo["y"]); cvs.draw_polygon().points(array(v1,v2,v3,v4)).draw(); end paint_lines(cvs,o.tgc_LS_interpolated,xys,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 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 //////////////////////////////////////// initialization finalization end.