赞 | 342 |
VIP | 10 |
好人卡 | 8 |
积分 | 262 |
经验 | 235776 |
最后登录 | 2024-9-23 |
在线时间 | 2387 小时 |
Lv5.捕梦者 (版主) 遠航の猫咪
- 梦石
- 3
- 星屑
- 23191
- 在线时间
- 2387 小时
- 注册时间
- 2005-10-15
- 帖子
- 1166
|
加入我们,或者,欢迎回来。
您需要 登录 才可以下载或查看,没有帐号?注册会员
x
不依赖SEP,插入默认工程应该就可以使用
提供20个绘图指令,无论如何应该够用了
Q&A:
Q:这个脚本能用来干什么?
A:绘制异型血槽(如环状)、绘制能力雷达(六边形战士)、绘制渐变转场中的渐变分隔线、异型透视窗格、等等……
Q:绘图指令具体如何调用?
A:参见脚本前面的说明。
Q:能用虚线绘制矩形和直线以外的形状吗?
A:不能。
Q:为什么可填充的形状中不包括矩形?
A:参见Bitmap#fill_rect,如果你使用RGD或者SEP Core那么还有Bitmap#gradient_fill_rect
Q:我想用平行四边形切一个位图传送怎么办?默认只有Bitmap#blt,而你这个插件也只能用正多边形切正方形或者菱形?
A:请找到四边形的四个顶点,然后调用blt_polygon,所有平行四边形都是多边形的一种。
Q:我的位图传送后被切边了,不完整?
A:只有用位图填充,即fill系指令时,你给的位图会被插件自动重复成图案以保证填满。仅单纯的传送不会复制位图,如果你的位图比传送的区域小,尝试使用填充指令而不是传送指令,或者你看看是不是参照点没有写对导致传歪了。
Q:渐变的效率怎么样?
A:肯定是不如GDI+,但是比draw_text快,反正你用足够了。
#============================================================================== # ■ [Bitmap Canvas] 位图画布处理核心 v1.1 by SailCat #------------------------------------------------------------------------------ # 方法:本脚本插入Main之前使用 # 依赖:无 # 版本:v1.1 (Build 221121) # 效果: # 1. 可以用简单指令在位图对象上绘制图形,可以绘制从直线到封闭曲线的15种图形 # 2. 可以用简单指令在位图对象上叠加以不同形状(共5种)剪裁的其他位图 # 配置:画笔线形的配置 # 冲突:无 # 说明: # 1. 绘制直线: # draw_line(起始x, 起始y, 结束x, 结束y, 颜色, 线形) # 2. 绘制矩形(空心): # a) draw_rect(左上x, 左上y, 长, 宽, 颜色, 线形) # b) draw_rect(矩形, 颜色, 线形) # 3. 绘制渐变色直线: # gradient_draw_line(起始x, 起始y, 结束x, 结束y, 颜色1, 颜色2) # 4. 绘制路径(连续直线): # draw_path(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 颜色) # 5. 绘制多边形(连续封闭直线): # draw_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 颜色) # 6. 绘制正多边形: # draw_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 颜色) # 7. 绘制椭圆: # draw_ellipse(圆心x, 圆心y, 半横径,半纵径, 颜色) # 8. 绘制圆: # draw_circle(圆心x, 圆心y, 半径,颜色) # 9. 绘制曲线: # draw_curve(起始x, 起始y, 中继点Ax, 中继点Ay, 中继点Bx, 中继点By[, # 中继点Cx, 中继点Cy[, ...]], 结束x, 结束y, 颜色) # 10. 绘制封闭曲线: # draw_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By, # 点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]], # 颜色) # 11.填涂多边形: # a) fill_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 边框颜色[, # 填充颜色1[, 填充颜色2[, 渐变方向]]]) # b) fill_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 边框颜色, # 填充位图[, 不透明度]) # 12.填涂正多边形: # a) fill_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 边框颜色[, # 填充颜色1[, 填充颜色2[, 渐变方向]]]) # b) fill_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 边框颜色, # 填充位图[, 不透明度]) # 13.填涂椭圆: # a) fill_ellipse(圆心x, 圆心y, 半横径,半纵径, 边框颜色[, 填充颜色1[, # 填充颜色2[, 渐变方向]]]) # b) fill_ellipse(圆心x, 圆心y, 半横径,半纵径, 边框颜色, 填充位图[, # 不透明度]) # 14.填涂圆: # a) fill_circle(圆心x, 圆心y, 半径,边框颜色[, 填充颜色1[, 填充颜色2[, # 渐变方向]]]) # b) fill_circle(圆心x, 圆心y, 半径,边框颜色, 填充位图[, 不透明度]) # 15.填涂封闭曲线: # a) fill_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By, # 点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]], # 边框颜色[, 填充颜色1[, 填充颜色2[, 渐变方向]]]) # b) fill_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By, # 点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]], # 边框颜色, 填充位图[, 不透明度]) # 16.传送多边形: # blt_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 源位图, # 参考点1x, 参考点1y[, 不透明度]) # 17.传送正多边形: # blt_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 源位图, 参考心x, # 参考心y[, 不透明度]) # 18.传送椭圆: # blt_ellipse(圆心x, 圆心y, 半横径,半纵径, 源位图, 参考心x, 参考心y[, # 不透明度]) # 19.传送圆: # blt_circle(圆心x, 圆心y, 半径,源位图, 参考心x, 参考心y[, 不透明度]) # 20.传送封闭曲线: # blt_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By, # 点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]], # 源位图, 参考点1x, 参考点1y[, 不透明度]) #============================================================================== #============================================================================== # ■ SailCat's 插件公用 #============================================================================== module SailCat #-------------------------------------------------------------------------- # ● 脚本配置区 #-------------------------------------------------------------------------- module Canvas_Config CANVAS_LINE_DOTTED = [1, 0] # 点线画笔 CANVAS_LINE_DASHED = [1, 1, 0, 1] # 短虚线画笔 CANVAS_LINE_LONGDASH = [1, 1, 0, 0, 1, 1] # 长虚线画笔 CANVAS_LINE_DASHDOT = [1, 0, 1, 1, 1, 0] # 点划线画笔 CANVAS_LINE_BROKEN = [1, 0, 0] # 散点画笔 end end #============================================================================== # ■ Bitmap #============================================================================== class Bitmap include SailCat::Canvas_Config #-------------------------------------------------------------------------- # ● 常量 #-------------------------------------------------------------------------- CANVAS_LINE_SOLID = [1] # 实心画笔,该常量禁止修改配置 #-------------------------------------------------------------------------- # ● 绘制直线 # x1 : 起始的 X 坐标 # y1 : 起始的 Y 坐标 # x2 : 结束的 X 坐标 # y2 : 结束的 Y 坐标 # color : 直线的颜色 (Color) # style : 直线的线型 #-------------------------------------------------------------------------- def draw_line(x1, y1, x2, y2, color, style = CANVAS_LINE_SOLID) return set_pixel(x1, y1, color) if x1 == x2 and y1 == y2 dx = (x2 - x1).abs dy = (y2 - y1).abs x = x1 y = y1 rx = x2 - x1 <=> 0 ry = y2 - y1 <=> 0 b_index = 0 b_size = style.size if dx == 0 and style == CANVAS_LINE_SOLID fill_rect(x1, [y1, y2].min, 1, dy + 1, color) elsif dy == 0 and style == CANVAS_LINE_SOLID fill_rect([x1, x2].min, y1, dx + 1, 1, color) elsif dx <= dy f = dx.to_f * rx / dy dy.times do set_pixel(x.round, y, color) if style[b_index] == 1 x += f y += ry b_index = (b_index + 1) % b_size end set_pixel(x.round, y, color) else f = dy.to_f * ry / dx dx.times do set_pixel(x, y.round, color) if style[b_index] == 1 x += rx y += f b_index = (b_index + 1) % b_size end set_pixel(x, y.round, color) end end #-------------------------------------------------------------------------- # ● 绘制空心矩形 # 参数形式1 : 左上 X 坐标, 左上 Y 坐标, 宽度, 高度, 颜色, 线型 # 参数形式2 : 目标矩形 (Rect), 颜色, 线型 #-------------------------------------------------------------------------- def draw_rect(*args) case args[0] when Numeric raise ArgumentError if args.size < 4 x, y, w, h, color = args[0..4] style = args[5] || CANVAS_LINE_SOLID when Rect raise ArgumentError if args.size < 2 rect = args[0] x, y, w, h = rect.x, rect.y, rect.width, rect.height color = args[1] style = args[2] || CANVAS_LINE_SOLID else raise ArgumentError end draw_line(x, y, x + w, y, color, style) draw_line(x, y, x, y + h, color, style) draw_line(x + w, y, x + w, y + h, color, style) draw_line(x, y + h, x + w, y + h, color, style) end #-------------------------------------------------------------------------- # ● 绘制渐变直线 # x1 : 起始的 X 坐标 # y1 : 起始的 Y 坐标 # x2 : 结束的 X 坐标 # y2 : 结束的 Y 坐标 # color1 : 直线的起始颜色 (Color) # color2 : 直线的终止颜色 (Color) #-------------------------------------------------------------------------- def gradient_draw_line(x1, y1, x2, y2, color1, color2) return set_pixel(x1, y1, color) if x1 == x2 and y1 == y2 return draw_line(x1, y1, x2, y2, color1) if color1 == color2 dx = (x2 - x1).abs dy = (y2 - y1).abs rx = x2 - x1 <=> 0 ry = y2 - y1 <=> 0 c = color1.clone if dx <= dy f = dx.to_f / dy * rx x = x1.to_f y = y1 dr = (color2.red - color1.red) / dy dg = (color2.green - color1.green) / dy db = (color2.blue - color1.blue) / dy da = (color2.alpha - color1.alpha) / dy (dy + 1).times do set_pixel(x.round, y, c) x += f y += ry c.set(c.red + dr, c.green + dg, c.blue + db, c.alpha + da) end else f = dy.to_f / dx * ry x = x1 y = y1.to_f dr = (color2.red - color1.red) / dx dg = (color2.green - color1.green) / dx db = (color2.blue - color1.blue) / dx da = (color2.alpha - color1.alpha) / dx (dx + 1).times do set_pixel(x, y.round, c) x += rx y += f c.set(c.red + dr, c.green + dg, c.blue + db, c.alpha + da) end end end #-------------------------------------------------------------------------- # ● 绘制路径 # x1 : 第一点的 X 坐标 # y1 : 第一点的 Y 坐标 # x2 : 第二点的 X 坐标 # y2 : 第二点的 Y 坐标 # x3 : 第三点的 X 坐标 # y3 : 第三点的 Y 坐标 # args : 后续的参数(可以加多个点,至少要包括颜色) #-------------------------------------------------------------------------- def draw_path(x1, y1, x2, y2, x3, y3, *args) raise ArgumentError if args.size[0] == 0 or not args[-1].is_a?(Color) color = args[-1] nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-1]) 0.step(nodes.size - 4, 2) {|i| draw_line(*(nodes[i, 4].concat([color])))} end #-------------------------------------------------------------------------- # ● 绘制多边形 # x1 : 第一点的 X 坐标 # y1 : 第一点的 Y 坐标 # x2 : 第二点的 X 坐标 # y2 : 第二点的 Y 坐标 # x3 : 第三点的 X 坐标 # y3 : 第三点的 Y 坐标 # args : 后续的参数(可以加多个点,至少要包括颜色) #-------------------------------------------------------------------------- def draw_polygon(x1, y1, x2, y2, x3, y3, *args) raise ArgumentError if args.size[0] == 0 or not args[-1].is_a?(Color) args.insert(-2, x1, y1) draw_path(x1, y1, x2, y2, x3, y3, *args) end #-------------------------------------------------------------------------- # ● 绘制实心多边形 # x1 : 第一点的 X 坐标 # y1 : 第一点的 Y 坐标 # x2 : 第二点的 X 坐标 # y2 : 第二点的 Y 坐标 # x3 : 第三点的 X 坐标 # y3 : 第三点的 Y 坐标 # args : 后续的参数,包括后续点,并在所有点之后指定填充选项,填充选项有: # 3个颜色 + true/false : 颜色1为边框色,颜色2和颜色3用于填充,最后 # true = 垂直方向渐变 false = 水平方向渐变 # 3个颜色 : 颜色1用于描边,颜色2和颜色3用于填充,固定水平方向渐变 # 2个颜色 : 颜色1用于描边,颜色2用于填充 # 1个颜色 : 以该颜色描边,并实心填充 # 颜色 + 位图 + 数值 : 颜色用于描边,位图用于填充,数值为不透明度 # 颜色 + 位图 : 颜色用于描边,位图用于填充,不透明度固定为255 #-------------------------------------------------------------------------- def fill_polygon(x1, y1, x2, y2, x3, y3, *args) case args[-1] when FalseClass, TrueClass raise ArgumentError unless args[-4..-2].all?{|c| c.is_a?(Color)} fill_mode = args.pop ? 1 : 0 fill2 = args.pop fill1 = args.pop fill_mode = 0 if fill1 == fill2 when Color fill_mode = 0 fill2 = args[-3].is_a?(Color) ? args.pop : args[-1] fill1 = args[-2].is_a?(Color) ? args.pop : args[-1] when Bitmap raise ArgumentError unless args[-2].is_a?(Color) fill_mode = 2 fill_opacity = 255 fill_pattern = args.pop when Numeric raise ArgumentError unless args[-3].is_a?(Color) and args[-2].is_a?(Bitmap) fill_mode = 2 fill_opacity = args.pop fill_pattern = args.pop else raise ArgumentError end draw_polygon(x1, y1, x2, y2, x3, y3, *args) color = args[-1] nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-1]) edges = {} min_y = height max_x = max_y = 0 min_x = width 0.step(nodes.size - 2, 2) do |i| xi, yi = nodes[i, 2] min_y = [min_y, yi].min max_y = [max_y, yi].max min_x = [min_x, xi].min max_x = [max_x, xi].max xj, yj = nodes[(i + 2) % nodes.size, 2] dx = 1.0 * (xi - xj) / (yi - yj) if yi < yj delta = -1 delta -= 2 until (yh = nodes[(i + delta) % nodes.size]) != yi if yh < yi yi += 1 xi += dx end edges[yi] ||= [] edges[yi].push([xi, dx, yj]) elsif yi > yj delta = 5 delta += 2 until (yk = nodes[(i + delta) % nodes.size]) != yj if yj > yk yj += 1 xj += dx end edges[yj] ||= [] edges[yj].push([xj, dx, yi]) end end return unless max_y - min_y > 1 and max_x - min_x > 1 dw = max_x - min_x - 1 dh = max_y - min_y - 1 if fill_mode == 0 if fill1 != fill2 dr = (fill2.red - fill1.red) / dh dg = (fill2.green - fill1.green) / dh db = (fill2.blue - fill1.blue) / dh da = (fill2.alpha - fill1.alpha) / dh gradient = true end f = fill1.clone aet = edges[min_y].each {|edge| edge[0] += edge[1]}.sort! for y in min_y + 1..max_y - 1 aet.concat(edges[y]).sort! if edges[y] 0.step(aet.size - 2, 2) do |i| xi = aet[i][0].round xj = aet[i + 1][0].round xi += 1 until xi == width - 1 or get_pixel(xi, y) != color xj -= 1 until xj == 0 or get_pixel(xj, y) != color fill_rect(xi, y, xj - xi + 1, 1, f) if xj >= xi end aet.reject! {|edge| edge[2] == y} aet.each {|edge| edge[0] += edge[1]}.sort! f.set(f.red + dr, f.green + dg, f.blue + db, f.alpha + da) if gradient end else if fill_mode == 2 src = Bitmap.new(dw, fill_pattern.height) 0.step(dw - 1, fill_pattern.width) do |x| src.blt(x, 0, fill_pattern, fill_pattern.rect, fill_opacity) end else src = Bitmap.new(dw, 1) src.gradient_draw_line(0, 0, dw - 1, 0, fill1, fill2) end ox = -1 - min_x y_index = 0 aet = edges[min_y].each {|edge| edge[0] += edge[1]}.sort! for y in min_y + 1..max_y - 1 aet.concat(edges[y]).sort! if edges[y] 0.step(aet.size - 2, 2) do |i| xi = aet[i][0].round xj = aet[i + 1][0].round xi += 1 until xi == width - 1 or get_pixel(xi, y) != color xj -= 1 until xj == 0 or get_pixel(xj, y) != color blt(xi, y, src, Rect.new(xi + ox, y_index, xj - xi + 1, 1)) end aet.reject! {|edge| edge[2] == y} aet.each {|edge| edge[0] += edge[1]}.sort! y_index = (y_index + 1) % src.height end src.dispose end end #-------------------------------------------------------------------------- # ● 传送位图多边形 # x1 : 第一点的 X 坐标 # y1 : 第一点的 Y 坐标 # x2 : 第二点的 X 坐标 # y2 : 第二点的 Y 坐标 # x3 : 第三点的 X 坐标 # y3 : 第三点的 Y 坐标 # args : 后续的参数(加多个点,最后是位图, 偏移x,偏移y,(可选)不透明度) # 偏移x和偏移y的位置参考第一个点 #-------------------------------------------------------------------------- def blt_polygon(x1, y1, x2, y2, x3, y3, *args) if args[-3].is_a?(Bitmap) src, x0, y0 = args[-3, 3] opacity = 255 nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-3]) elsif args[-4].is_a?(Bitmap) src, x0, y0, opacity = args[-4, 4] nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-4]) else raise ArgumentError end raise ArgumentError unless nodes.size[0] == 0 edges = {} min_y = height max_y = 0 ox = x0 - x1 oy = y0 - y1 0.step(nodes.size - 2, 2) do |i| xi, yi = nodes[i, 2] min_y = [min_y, yi].min max_y = [max_y, yi].max xj, yj = nodes[(i + 2) % nodes.size, 2] dx = 1.0 * (xi - xj) / (yi - yj) if yi < yj delta = -1 delta -= 2 until (yh = nodes[(i + delta) % nodes.size]) != yi if yh < yi yi += 1 xi += dx end edges[yi] ||= [] edges[yi].push([xi, dx, yj]) elsif yi > yj delta = 5 delta += 2 until (yk = nodes[(i + delta) % nodes.size]) != yj if yj > yk yj += 1 xj += dx end edges[yj] ||= [] edges[yj].push([xj, dx, yi]) end end aet = [] for y in min_y..max_y aet.concat(edges[y]).sort! if edges[y] 0.step(aet.size - 1, 2) do |i| xi = aet[i][0].round xj = aet[i + 1][0].round blt(xi, y, src, Rect.new(xi + ox, y + oy, xj - xi + 1, 1), opacity) end aet.reject! {|edge| edge[2] == y} aet.each {|edge| edge[0] += edge[1]}.sort! end end #-------------------------------------------------------------------------- # ● 绘制正多边形 # x : 正多边形外接圆心 X 坐标 # y : 正多边形外接圆心 Y 坐标 # rad : 正多边形外接圆 半径 # edges : 正多边形的边数 # angle : 正多边形旋转角度 # color : 正多边形的颜色 (Color) #-------------------------------------------------------------------------- def draw_isogon(x, y, rad, edges, angle, color) raise ArgumentError if edges < 3 step = Math::PI * 2 / edges args = [] angle_i = Math::PI * (270 + angle) / 180 edges.times do args.push((x + rad * Math.cos(angle_i)).round, (y + rad * Math.sin(angle_i)).round) angle_i += step end draw_polygon(*args.push(color)) end #-------------------------------------------------------------------------- # ● 绘制实心正多边形 # x : 正多边形外接圆心 X 坐标 # y : 正多边形外接圆心 Y 坐标 # rad : 正多边形外接圆 半径 # edges : 正多边形的边数 # angle : 正多边形旋转角度 # color : 边框的颜色 (Color) # fill : 填充选项,具体的填充选项有: # 2个颜色 + true/false : 两个颜色以垂直/水平方式渐变填充 # 2个颜色 : 两个颜色以水平方向渐变填充 # 1个颜色 : 实心填充 # 位图 + 数值 : 以位图图案填充,数值为不透明度 # 位图 : 以位图图案填充,不透明度固定为255 # 省略 : 用边框色实心填充 #-------------------------------------------------------------------------- def fill_isogon(x, y, rad, edges, angle, color, *fill) raise ArgumentError if edges < 3 step = Math::PI * 2 / edges args = [] angle_i = Math::PI * (270 + angle) / 180 edges.times do args.push((x + rad * Math.cos(angle_i)).round, (y + rad * Math.sin(angle_i)).round) angle_i += step end fill_polygon(*args.push(color).concat(fill)) end #-------------------------------------------------------------------------- # ● 传送位图正多边形 # x : 正多边形外接圆心 X 坐标 # y : 正多边形外接圆心 Y 坐标 # rad : 正多边形外接圆 半径 # edges : 正多边形的边数 # angle : 正多边形旋转角度 # src_bitmap : 传送元位图 # x0 : 传送圆心 X 坐标 # y0 : 传送圆心 Y 坐标 # opacity : 不透明度 #-------------------------------------------------------------------------- def blt_isogon(x, y, rad, edges, angle, src_bitmap, x0, y0, opacity = 255) raise ArgumentError if edges < 3 step = Math::PI * 2 / edges args = [] angle_i = Math::PI * (270 + angle) / 180 edges.times do args.push((x + rad * Math.cos(angle_i)).round, (y + rad * Math.sin(angle_i)).round) angle_i += step end args.push(src_bitmap, x0 - x + args[0], y0 - y + args[1], opacity) blt_polygon(*args) end #-------------------------------------------------------------------------- # ● 绘制圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad : 半径 # color : 圆的颜色 (Color) #-------------------------------------------------------------------------- def draw_circle(x, y, rad, color) draw_ellipse(x, y, rad, rad, color) end #-------------------------------------------------------------------------- # ● 绘制椭圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad_x : 水平半径 # rad_y : 垂直半径 # color : 椭圆的颜色 (Color) #-------------------------------------------------------------------------- def draw_ellipse(x, y, rad_x, rad_y, color) fill_ellipse(x, y, rad_x, rad_y, color, nil) end #-------------------------------------------------------------------------- # ● 绘制实心圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad : 半径 # border_color : 圆的边框颜色 (Color) # fill : 填充选项,具体的填充选项有: # nil : 不填充 # 2个颜色 + true/false : 两个颜色以垂直/水平方式渐变填充 # 2个颜色 : 两个颜色以水平方向渐变填充 # 1个颜色 : 实心填充 # 位图 + 数值 : 以位图图案填充,数值为不透明度 # 位图 : 以位图图案填充,不透明度固定为255 # 省略 : 用边框色实心填充 #-------------------------------------------------------------------------- def fill_circle(x, y, rad, border_color, *fill) fill_ellipse(x, y, rad, rad, border_color, *fill) end #-------------------------------------------------------------------------- # ● 绘制实心椭圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad_x : 水平半径 # rad_y : 垂直半径 # border_color : 椭圆的边框颜色 (Color) # fill : 填充选项,具体的填充选项有: # nil : 不填充 # 2个颜色 + true/false : 两个颜色以垂直/水平方式渐变填充 # 2个颜色 : 两个颜色以水平方向渐变填充 # 1个颜色 : 实心填充 # 位图 + 数值 : 以位图图案填充,数值为不透明度 # 位图 : 以位图图案填充,不透明度固定为255 # 省略 : 用边框色实心填充 #-------------------------------------------------------------------------- def fill_ellipse(x, y, rad_x, rad_y, border_color, *fill) raise ArgumentError if rad_x < 0 or rad_y < 0 return set_pixel(x, y, border_color) if rad_x == 0 and rad_y == 0 return fill_rect(x - rad_x, y, rad_x << 1, 1, border_color) if rad_y == 0 return fill_rect(x, y - rad_y, 1, rad_y << 1, border_color) if rad_x == 0 ry2 = rad_y * rad_y rx2 = rad_x * rad_x d = ry2 + rx2 * (0.25 - rad_y) dx = 0 dy = rad_y if fill.size == 0 fill_mode = 0 f1 = f2 = border_color.clone else case fill[0] when Color f1 = fill[0].clone if fill[1] f2 = fill[1].clone fill_mode = f1 == f2 ? 0 : (fill[2] ? 3 : 1) else f2 = f1 fill_mode = 0 end when Bitmap fill_mode = 2 else fill_mode = -1 end end case fill_mode when 1 dist = rad_y - 1 << 1 if dist > 0 dr = (f2.red - f1.red) / dist dg = (f2.green - f1.green) / dist db = (f2.blue - f1.blue) / dist da = (f2.alpha - f1.alpha) / dist end when 2 src = Bitmap.new((rad_x << 1) - 1, fill[0].height) 0.step((rad_x << 1) - 1, fill[0].width) do |x0| src.blt(x0, 0, fill[0], fill[0].rect, fill[1] || 255) end when 3 src = Bitmap.new((rad_x << 1) - 1, 1) src.gradient_draw_line(0, 0, rad_x - 1 << 1 , 0, f1, f2) end begin set_pixel(x + dx, y + dy, border_color) set_pixel(x + dx, y - dy, border_color) set_pixel(x - dx, y - dy, border_color) set_pixel(x - dx, y + dy, border_color) if d <= -1e-6 d += ry2 * ((dx << 1) + 3) else d += ry2 * ((dx << 1) + 3) + rx2 * (1 - dy << 1) dy -= 1 case fill_mode when 0, 1 fill_rect(x - dx, y - dy, (dx << 1) + 1, 1, f1) fill_rect(x - dx, y + dy, (dx << 1) + 1, 1, f2) if fill_mode == 1 f1.set(f1.red + dr, f1.green + dg, f1.blue + db, f1.alpha + da) f2.set(f2.red - dr, f2.green - dg, f2.blue - db, f2.alpha - da) end when 2, 3 blt(x - dx, y - dy, src, Rect.new(rad_x - dx - 1, (rad_y - dy - 1) % src.height,(dx << 1) + 1, 1)) blt(x - dx, y + dy, src, Rect.new(rad_x - dx - 1, (rad_y + dy - 1) % src.height,(dx << 1) + 1, 1)) end end dx += 1 end while ry2 * (dx + 1) < rx2 * (dy - 0.5) d = ry2 * (dx + 0.5) * (dx + 0.5) + rx2 * (dy - 1) * (dy - 1) - rx2 * ry2 sy = dy begin set_pixel(x + dx, y + dy, border_color) set_pixel(x + dx, y - dy, border_color) set_pixel(x - dx, y - dy, border_color) set_pixel(x - dx, y + dy, border_color) if fill_mode >= 0 and dy < sy case fill_mode when 0, 1 fill_rect(x - dx + 1, y - dy, (dx << 1) - 1, 1, f1) fill_rect(x - dx + 1, y + dy, (dx << 1) - 1, 1, f2) unless dy == 0 if fill_mode == 1 f1.set(f1.red + dr, f1.green + dg, f1.blue + db, f1.alpha + da) f2.set(f2.red - dr, f2.green - dg, f2.blue - db, f2.alpha - da) end when 2, 3 blt(x - dx + 1, y - dy, src, Rect.new(rad_x - dx, (rad_y - dy - 1) % src.height,(dx << 1) - 1, 1)) blt(x - dx + 1, y + dy, src, Rect.new(rad_x - dx, (rad_y + dy - 1) % src.height,(dx << 1) - 1, 1)) unless dy == 0 end end if d <= -1e-6 d += ry2 * (dx + 1 << 1) + rx2 * (3 - (dy << 1)) dx += 1 else d += rx2 * (3 - (dy << 1)) end dy -= 1 end while dy >= 0 src.dispose if fill_mode > 1 end #-------------------------------------------------------------------------- # ● 传送位图圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad : 半径 # src_bitmap : 传送元位图 # x0 : 传送圆心 X 坐标 # y0 : 传送圆心 Y 坐标 # opacity : 不透明度 #-------------------------------------------------------------------------- def blt_circle(x, y, rad, src_bitmap, x0, y0, opacity = 255) blt_ellipse(x, y, rad, rad, src_bitmap, x0, y0, opacity) end #-------------------------------------------------------------------------- # ● 传送位图椭圆 # x : 圆心 X 坐标 # y : 圆心 Y 坐标 # rad_x : 水平半径 # rad_y : 垂直半径 # src_bitmap : 传送元位图 # x0 : 传送圆心 X 坐标 # y0 : 传送圆心 Y 坐标 # opacity : 不透明度 #-------------------------------------------------------------------------- def blt_ellipse(x, y, rad_x, rad_y, src_bitmap, x0, y0, opacity = 255) raise ArgumentError if rad_x < 0 or rad_y < 0 return blt(x - rad_x, y, src_bitmap, Rect.new(x0 - rad_x, y0, rad_x << 1, 1), opacity) if rad_y == 0 return blt(x, y - rad_y, src_bitmap, Rect.new(x0, y0 - rad_y, 1, rad_y << 1), opacity) if rad_x == 0 ry2 = rad_y * rad_y rx2 = rad_x * rad_x d = ry2 + rx2 * (0.25 - rad_y) dx = 0 dy = rad_y begin if d <= -1e-6 d += ry2 * ((dx << 1) + 3) else blt(x - dx, y - dy, src_bitmap, Rect.new(x0 - dx, y0 - dy, dx << 1, 1), opacity) blt(x - dx, y + dy, src_bitmap, Rect.new(x0 - dx, y0 + dy, dx << 1, 1), opacity) d += ry2 * ((dx << 1) + 3) + rx2 * (1 - dy << 1) dy -= 1 end dx += 1 end while ry2 * (dx + 1) < rx2 * (dy - 0.5) d = ry2 * (dx + 0.5) * (dx + 0.5) + rx2 * (dy - 1) * (dy - 1) - rx2 * ry2 begin blt(x - dx, y - dy, src_bitmap, Rect.new(x0 - dx, y0 - dy, dx << 1, 1), opacity) blt(x - dx, y + dy, src_bitmap, Rect.new(x0 - dx, y0 + dy, dx << 1, 1), opacity) unless dy == 0 if d <= -1e-6 d += ry2 * (dx + 1 << 1) + rx2 * (3 - (dy << 1)) dx += 1 else d += rx2 * (3 - (dy << 1)) end dy -= 1 end while dy >= 0 end #-------------------------------------------------------------------------- # ● 绘制曲线 # x1 : 起始点 X 坐标 # x2 : 起始点 Y 坐标 # cx1 : 控制点1 X 坐标 # cy1 : 控制点1 Y 坐标 # cx2 : 控制点2 X 坐标 # cx2 : 控制点2 Y 坐标 # x2 : 终止点(或控制点3) X 坐标 # y2 : 终止点(或控制点3) Y 坐标 # args : 后续的参数,可以追加额外的控制点,以最后一个点的坐标为终止点, # 最后还需再指定一个颜色 (Color) #-------------------------------------------------------------------------- def draw_curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, *args) raise ArgumentError if args.size[0] == 0 or not args[-1].is_a?(Color) color = args[-1] points = [x1, y1, cx1, cy1, cx2, cy2, x2, y2].concat(args[0...-1]) draw_path(*get_curve_path(points).push(color)) end #-------------------------------------------------------------------------- # ● 绘制封闭曲线 # x1 : 起始点 X 坐标 # x2 : 起始点 Y 坐标 # cx1 : 控制点1 X 坐标 # cy1 : 控制点1 Y 坐标 # cx2 : 控制点2 X 坐标 # cx2 : 控制点2 Y 坐标 # x2 : 终止点 X 坐标 # y2 : 终止点 Y 坐标 # args : 后续的参数,每多指定一个曲线节点,增加6个参数,分别表示从前一终 # 止点作为起始点曲线的控制点1 X/Y、控制点2 X/Y、及本曲线终点的X/Y # 最后还需再指定一个颜色 (Color) #-------------------------------------------------------------------------- def draw_closed_curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, *args) raise ArgumentError if args.size % 6 != 1 or not args[-1].is_a?(Color) color = args[-1] points = [x1, y1, cx1, cy1, cx2, cy2, x2, y2].concat(args[0...-1]) edges = [] 0.step(points.size - 8, 6) do |i| edges.concat(get_curve_path(points[i, 8])) end draw_polygon(*edges.push(color)) end #-------------------------------------------------------------------------- # ● 绘制填充的封闭曲线 # x1 : 起始点 X 坐标 # x2 : 起始点 Y 坐标 # cx1 : 控制点1 X 坐标 # cy1 : 控制点1 Y 坐标 # cx2 : 控制点2 X 坐标 # cx2 : 控制点2 Y 坐标 # x2 : 终止点 X 坐标 # y2 : 终止点 Y 坐标 # args : 后续的参数,每多指定一个曲线节点,增加6个参数,分别表示从前终止 # 点起始的下一曲线段控制点1 X/Y、控制点2 X/Y、及该曲线终止点的X/Y # 最后要指定填充选项,填充选项有: # 3个颜色 + true/false : 颜色1为边框色,颜色2和颜色3用于填充,最后 # true = 垂直方向渐变 false = 水平方向渐变 # 3个颜色 : 颜色1用于描边,颜色2和颜色3用于填充,水平方向渐变 # 2个颜色 : 颜色1用于描边,颜色2用于填充 # 1个颜色 : 以该颜色描边,并实心填充 # 颜色 + 位图 + 数值 : 颜色用于描边,位图用于填充,数值为不透明度 # 颜色 + 位图 : 颜色用于描边,位图用于填充,不透明度固定为255 #-------------------------------------------------------------------------- def fill_closed_curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, *args) case args[-1] when FalseClass, TrueClass arg_chop = -4 when Color arg_chop = args[-3].is_a?(Color) ? -3 : args[-2].is_a?(Color) ? -2 : -1 when Bitmap arg_chop = -2 when Numeric arg_chop = -3 else raise ArgumentError end raise ArgumentError if (args.size + arg_chop) % 6 != 0 points = [x1, y1, cx1, cy1, cx2, cy2, x2, y2].concat(args[0...arg_chop]) edges = [] 0.step(points.size - 8, 6) do |i| edges.concat(get_curve_path(points[i, 8])[0...-2]) end fill_polygon(*edges.concat(args[arg_chop..-1])) end #-------------------------------------------------------------------------- # ● 传送位图封闭曲线 # x1 : 起始点 X 坐标 # x2 : 起始点 Y 坐标 # cx1 : 控制点1 X 坐标 # cy1 : 控制点1 Y 坐标 # cx2 : 控制点2 X 坐标 # cx2 : 控制点2 Y 坐标 # x2 : 终止点 X 坐标 # y2 : 终止点 Y 坐标 # args : 后续的参数,每多指定一个曲线节点,增加6个参数,分别表示从前终止 # 点起始的下一曲线段控制点1 X/Y、控制点2 X/Y、及该曲线终止点的X/Y # 最后指定传送的位图, 偏移x,偏移y(比照起始点),(可选)不透明度 #-------------------------------------------------------------------------- def blt_closed_curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, *args) if args[-3].is_a?(Bitmap) start = -3 points = [x1, y1, cx1, cy1, cx2, cy2, x2, y2].concat(args[0...-3]) elsif args[-4].is_a?(Bitmap) start = -4 points = [x1, y1, cx1, cy1, cx2, cy2, x2, y2].concat(args[0...-4]) else raise ArgumentError end raise ArgumentError unless points.size % 6 == 2 edges = [] 0.step(points.size - 8, 6) do |i| edges.concat(get_curve_path(points[i, 8])) end blt_polygon(*edges.concat(args[start..-1])) end private #-------------------------------------------------------------------------- # ● 内部函数:计算曲线点位 # points : 接继点表 #-------------------------------------------------------------------------- def get_curve_path(points) max_x = min_x = points[0] max_y = min_y = points[1] 2.step(points.size - 2, 2) do |i| max_x = [max_x, points[i]].max min_x = [min_x, points[i]].min max_y = [max_y, points[i + 1]].max min_y = [min_y, points[i + 1]].min end curve_edge_count = [max_x + max_y - min_x - min_y >> 2, 2].max (0..curve_edge_count).inject([]) do |a, i| pt = points.clone t = i / curve_edge_count.to_f until pt.size == 2 pt = (0...(pt.size >> 1) - 1).to_a.inject([]) do |b, j| x1, y1, x2, y2 = pt[j << 1, 4] b.push((1 - t) * x1 + t * x2, (1 - t) * y1 + t * y2) end end x = pt[0].round y = pt[1].round x == a[-2] && y == a[-1] ? a : a.push(x, y) end end end
#==============================================================================
# ■ [Bitmap Canvas] 位图画布处理核心 v1.1 by SailCat
#------------------------------------------------------------------------------
# 方法:本脚本插入Main之前使用
# 依赖:无
# 版本:v1.1 (Build 221121)
# 效果:
# 1. 可以用简单指令在位图对象上绘制图形,可以绘制从直线到封闭曲线的15种图形
# 2. 可以用简单指令在位图对象上叠加以不同形状(共5种)剪裁的其他位图
# 配置:画笔线形的配置
# 冲突:无
# 说明:
# 1. 绘制直线:
# draw_line(起始x, 起始y, 结束x, 结束y, 颜色, 线形)
# 2. 绘制矩形(空心):
# a) draw_rect(左上x, 左上y, 长, 宽, 颜色, 线形)
# b) draw_rect(矩形, 颜色, 线形)
# 3. 绘制渐变色直线:
# gradient_draw_line(起始x, 起始y, 结束x, 结束y, 颜色1, 颜色2)
# 4. 绘制路径(连续直线):
# draw_path(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 颜色)
# 5. 绘制多边形(连续封闭直线):
# draw_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 颜色)
# 6. 绘制正多边形:
# draw_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 颜色)
# 7. 绘制椭圆:
# draw_ellipse(圆心x, 圆心y, 半横径,半纵径, 颜色)
# 8. 绘制圆:
# draw_circle(圆心x, 圆心y, 半径,颜色)
# 9. 绘制曲线:
# draw_curve(起始x, 起始y, 中继点Ax, 中继点Ay, 中继点Bx, 中继点By[,
# 中继点Cx, 中继点Cy[, ...]], 结束x, 结束y, 颜色)
# 10. 绘制封闭曲线:
# draw_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By,
# 点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]],
# 颜色)
# 11.填涂多边形:
# a) fill_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 边框颜色[,
# 填充颜色1[, 填充颜色2[, 渐变方向]]])
# b) fill_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 边框颜色,
# 填充位图[, 不透明度])
# 12.填涂正多边形:
# a) fill_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 边框颜色[,
# 填充颜色1[, 填充颜色2[, 渐变方向]]])
# b) fill_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 边框颜色,
# 填充位图[, 不透明度])
# 13.填涂椭圆:
# a) fill_ellipse(圆心x, 圆心y, 半横径,半纵径, 边框颜色[, 填充颜色1[,
# 填充颜色2[, 渐变方向]]])
# b) fill_ellipse(圆心x, 圆心y, 半横径,半纵径, 边框颜色, 填充位图[,
# 不透明度])
# 14.填涂圆:
# a) fill_circle(圆心x, 圆心y, 半径,边框颜色[, 填充颜色1[, 填充颜色2[,
# 渐变方向]]])
# b) fill_circle(圆心x, 圆心y, 半径,边框颜色, 填充位图[, 不透明度])
# 15.填涂封闭曲线:
# a) fill_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By,
# 点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]],
# 边框颜色[, 填充颜色1[, 填充颜色2[, 渐变方向]]])
# b) fill_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By,
# 点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]],
# 边框颜色, 填充位图[, 不透明度])
# 16.传送多边形:
# blt_polygon(点1x, 点1y, 点2x, 点2y, 点3x, 点3y[, ...], 源位图,
# 参考点1x, 参考点1y[, 不透明度])
# 17.传送正多边形:
# blt_isogon(外接圆心x, 外接圆心y, 半径, 边数, 旋转角, 源位图, 参考心x,
# 参考心y[, 不透明度])
# 18.传送椭圆:
# blt_ellipse(圆心x, 圆心y, 半横径,半纵径, 源位图, 参考心x, 参考心y[,
# 不透明度])
# 19.传送圆:
# blt_circle(圆心x, 圆心y, 半径,源位图, 参考心x, 参考心y[, 不透明度])
# 20.传送封闭曲线:
# blt_closed_curve(点1x, 点1y, 中继1Ax, 中继1Ay, 中继1Bx, 中继1By,
# 点2x, 点2y[, 中继2Ax, 中继2Ay, 中继2Bx, 中继2By, 点3x, 点3y[, ...]],
# 源位图, 参考点1x, 参考点1y[, 不透明度])
#==============================================================================
#==============================================================================
# ■ SailCat's 插件公用
#==============================================================================
module SailCat
#--------------------------------------------------------------------------
# ● 脚本配置区
#--------------------------------------------------------------------------
module Canvas_Config
CANVAS_LINE_DOTTED = [1, 0] # 点线画笔
CANVAS_LINE_DASHED = [1, 1, 0, 1] # 短虚线画笔
CANVAS_LINE_LONGDASH = [1, 1, 0, 0, 1, 1] # 长虚线画笔
CANVAS_LINE_DASHDOT = [1, 0, 1, 1, 1, 0] # 点划线画笔
CANVAS_LINE_BROKEN = [1, 0, 0] # 散点画笔
end
end
#==============================================================================
# ■ Bitmap
#==============================================================================
class Bitmap
include SailCat::Canvas_Config
#--------------------------------------------------------------------------
# ● 常量
#--------------------------------------------------------------------------
CANVAS_LINE_SOLID = [1] # 实心画笔,该常量禁止修改配置
#--------------------------------------------------------------------------
# ● 绘制直线
# x1 : 起始的 X 坐标
# y1 : 起始的 Y 坐标
# x2 : 结束的 X 坐标
# y2 : 结束的 Y 坐标
# color : 直线的颜色 (Color)
# style : 直线的线型
#--------------------------------------------------------------------------
def draw_line(x1, y1, x2, y2, color, style = CANVAS_LINE_SOLID)
return set_pixel(x1, y1, color) if x1 == x2 and y1 == y2
dx = (x2 - x1).abs
dy = (y2 - y1).abs
x = x1
y = y1
rx = x2 - x1 <=> 0
ry = y2 - y1 <=> 0
b_index = 0
b_size = style.size
if dx == 0 and style == CANVAS_LINE_SOLID
fill_rect(x1, [y1, y2].min, 1, dy + 1, color)
elsif dy == 0 and style == CANVAS_LINE_SOLID
fill_rect([x1, x2].min, y1, dx + 1, 1, color)
elsif dx <= dy
f = dx.to_f * rx / dy
dy.times do
set_pixel(x.round, y, color) if style[b_index] == 1
x += f
y += ry
b_index = (b_index + 1) % b_size
end
set_pixel(x.round, y, color)
else
f = dy.to_f * ry / dx
dx.times do
set_pixel(x, y.round, color) if style[b_index] == 1
x += rx
y += f
b_index = (b_index + 1) % b_size
end
set_pixel(x, y.round, color)
end
end
#--------------------------------------------------------------------------
# ● 绘制空心矩形
# 参数形式1 : 左上 X 坐标, 左上 Y 坐标, 宽度, 高度, 颜色, 线型
# 参数形式2 : 目标矩形 (Rect), 颜色, 线型
#--------------------------------------------------------------------------
def draw_rect(*args)
case args[0]
when Numeric
raise ArgumentError if args.size < 4
x, y, w, h, color = args[0..4]
style = args[5] || CANVAS_LINE_SOLID
when Rect
raise ArgumentError if args.size < 2
rect = args[0]
x, y, w, h = rect.x, rect.y, rect.width, rect.height
color = args[1]
style = args[2] || CANVAS_LINE_SOLID
else
raise ArgumentError
end
draw_line(x, y, x + w, y, color, style)
draw_line(x, y, x, y + h, color, style)
draw_line(x + w, y, x + w, y + h, color, style)
draw_line(x, y + h, x + w, y + h, color, style)
end
#--------------------------------------------------------------------------
# ● 绘制渐变直线
# x1 : 起始的 X 坐标
# y1 : 起始的 Y 坐标
# x2 : 结束的 X 坐标
# y2 : 结束的 Y 坐标
# color1 : 直线的起始颜色 (Color)
# color2 : 直线的终止颜色 (Color)
#--------------------------------------------------------------------------
def gradient_draw_line(x1, y1, x2, y2, color1, color2)
return set_pixel(x1, y1, color) if x1 == x2 and y1 == y2
return draw_line(x1, y1, x2, y2, color1) if color1 == color2
dx = (x2 - x1).abs
dy = (y2 - y1).abs
rx = x2 - x1 <=> 0
ry = y2 - y1 <=> 0
c = color1.clone
if dx <= dy
f = dx.to_f / dy * rx
x = x1.to_f
y = y1
dr = (color2.red - color1.red) / dy
dg = (color2.green - color1.green) / dy
db = (color2.blue - color1.blue) / dy
da = (color2.alpha - color1.alpha) / dy
(dy + 1).times do
set_pixel(x.round, y, c)
x += f
y += ry
c.set(c.red + dr, c.green + dg, c.blue + db, c.alpha + da)
end
else
f = dy.to_f / dx * ry
x = x1
y = y1.to_f
dr = (color2.red - color1.red) / dx
dg = (color2.green - color1.green) / dx
db = (color2.blue - color1.blue) / dx
da = (color2.alpha - color1.alpha) / dx
(dx + 1).times do
set_pixel(x, y.round, c)
x += rx
y += f
c.set(c.red + dr, c.green + dg, c.blue + db, c.alpha + da)
end
end
end
#--------------------------------------------------------------------------
# ● 绘制路径
# x1 : 第一点的 X 坐标
# y1 : 第一点的 Y 坐标
# x2 : 第二点的 X 坐标
# y2 : 第二点的 Y 坐标
# x3 : 第三点的 X 坐标
# y3 : 第三点的 Y 坐标
# args : 后续的参数(可以加多个点,至少要包括颜色)
#--------------------------------------------------------------------------
def draw_path(x1, y1, x2, y2, x3, y3, *args)
raise ArgumentError if args.size[0] == 0 or not args[-1].is_a?(Color)
color = args[-1]
nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-1])
0.step(nodes.size - 4, 2) {|i| draw_line(*(nodes[i, 4].concat([color])))}
end
#--------------------------------------------------------------------------
# ● 绘制多边形
# x1 : 第一点的 X 坐标
# y1 : 第一点的 Y 坐标
# x2 : 第二点的 X 坐标
# y2 : 第二点的 Y 坐标
# x3 : 第三点的 X 坐标
# y3 : 第三点的 Y 坐标
# args : 后续的参数(可以加多个点,至少要包括颜色)
#--------------------------------------------------------------------------
def draw_polygon(x1, y1, x2, y2, x3, y3, *args)
raise ArgumentError if args.size[0] == 0 or not args[-1].is_a?(Color)
args.insert(-2, x1, y1)
draw_path(x1, y1, x2, y2, x3, y3, *args)
end
#--------------------------------------------------------------------------
# ● 绘制实心多边形
# x1 : 第一点的 X 坐标
# y1 : 第一点的 Y 坐标
# x2 : 第二点的 X 坐标
# y2 : 第二点的 Y 坐标
# x3 : 第三点的 X 坐标
# y3 : 第三点的 Y 坐标
# args : 后续的参数,包括后续点,并在所有点之后指定填充选项,填充选项有:
# 3个颜色 + true/false : 颜色1为边框色,颜色2和颜色3用于填充,最后
# true = 垂直方向渐变 false = 水平方向渐变
# 3个颜色 : 颜色1用于描边,颜色2和颜色3用于填充,固定水平方向渐变
# 2个颜色 : 颜色1用于描边,颜色2用于填充
# 1个颜色 : 以该颜色描边,并实心填充
# 颜色 + 位图 + 数值 : 颜色用于描边,位图用于填充,数值为不透明度
# 颜色 + 位图 : 颜色用于描边,位图用于填充,不透明度固定为255
#--------------------------------------------------------------------------
def fill_polygon(x1, y1, x2, y2, x3, y3, *args)
case args[-1]
when FalseClass, TrueClass
raise ArgumentError unless args[-4..-2].all?{|c| c.is_a?(Color)}
fill_mode = args.pop ? 1 : 0
fill2 = args.pop
fill1 = args.pop
fill_mode = 0 if fill1 == fill2
when Color
fill_mode = 0
fill2 = args[-3].is_a?(Color) ? args.pop : args[-1]
fill1 = args[-2].is_a?(Color) ? args.pop : args[-1]
when Bitmap
raise ArgumentError unless args[-2].is_a?(Color)
fill_mode = 2
fill_opacity = 255
fill_pattern = args.pop
when Numeric
raise ArgumentError unless args[-3].is_a?(Color) and
args[-2].is_a?(Bitmap)
fill_mode = 2
fill_opacity = args.pop
fill_pattern = args.pop
else
raise ArgumentError
end
draw_polygon(x1, y1, x2, y2, x3, y3, *args)
color = args[-1]
nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-1])
edges = {}
min_y = height
max_x = max_y = 0
min_x = width
0.step(nodes.size - 2, 2) do |i|
xi, yi = nodes[i, 2]
min_y = [min_y, yi].min
max_y = [max_y, yi].max
min_x = [min_x, xi].min
max_x = [max_x, xi].max
xj, yj = nodes[(i + 2) % nodes.size, 2]
dx = 1.0 * (xi - xj) / (yi - yj)
if yi < yj
delta = -1
delta -= 2 until (yh = nodes[(i + delta) % nodes.size]) != yi
if yh < yi
yi += 1
xi += dx
end
edges[yi] ||= []
edges[yi].push([xi, dx, yj])
elsif yi > yj
delta = 5
delta += 2 until (yk = nodes[(i + delta) % nodes.size]) != yj
if yj > yk
yj += 1
xj += dx
end
edges[yj] ||= []
edges[yj].push([xj, dx, yi])
end
end
return unless max_y - min_y > 1 and max_x - min_x > 1
dw = max_x - min_x - 1
dh = max_y - min_y - 1
if fill_mode == 0
if fill1 != fill2
dr = (fill2.red - fill1.red) / dh
dg = (fill2.green - fill1.green) / dh
db = (fill2.blue - fill1.blue) / dh
da = (fill2.alpha - fill1.alpha) / dh
gradient = true
end
f = fill1.clone
aet = edges[min_y].each {|edge| edge[0] += edge[1]}.sort!
for y in min_y + 1..max_y - 1
aet.concat(edges[y]).sort! if edges[y]
0.step(aet.size - 2, 2) do |i|
xi = aet[i][0].round
xj = aet[i + 1][0].round
xi += 1 until xi == width - 1 or get_pixel(xi, y) != color
xj -= 1 until xj == 0 or get_pixel(xj, y) != color
fill_rect(xi, y, xj - xi + 1, 1, f) if xj >= xi
end
aet.reject! {|edge| edge[2] == y}
aet.each {|edge| edge[0] += edge[1]}.sort!
f.set(f.red + dr, f.green + dg, f.blue + db, f.alpha + da) if gradient
end
else
if fill_mode == 2
src = Bitmap.new(dw, fill_pattern.height)
0.step(dw - 1, fill_pattern.width) do |x|
src.blt(x, 0, fill_pattern, fill_pattern.rect, fill_opacity)
end
else
src = Bitmap.new(dw, 1)
src.gradient_draw_line(0, 0, dw - 1, 0, fill1, fill2)
end
ox = -1 - min_x
y_index = 0
aet = edges[min_y].each {|edge| edge[0] += edge[1]}.sort!
for y in min_y + 1..max_y - 1
aet.concat(edges[y]).sort! if edges[y]
0.step(aet.size - 2, 2) do |i|
xi = aet[i][0].round
xj = aet[i + 1][0].round
xi += 1 until xi == width - 1 or get_pixel(xi, y) != color
xj -= 1 until xj == 0 or get_pixel(xj, y) != color
blt(xi, y, src, Rect.new(xi + ox, y_index, xj - xi + 1, 1))
end
aet.reject! {|edge| edge[2] == y}
aet.each {|edge| edge[0] += edge[1]}.sort!
y_index = (y_index + 1) % src.height
end
src.dispose
end
end
#--------------------------------------------------------------------------
# ● 传送位图多边形
# x1 : 第一点的 X 坐标
# y1 : 第一点的 Y 坐标
# x2 : 第二点的 X 坐标
# y2 : 第二点的 Y 坐标
# x3 : 第三点的 X 坐标
# y3 : 第三点的 Y 坐标
# args : 后续的参数(加多个点,最后是位图, 偏移x,偏移y,(可选)不透明度)
# 偏移x和偏移y的位置参考第一个点
#--------------------------------------------------------------------------
def blt_polygon(x1, y1, x2, y2, x3, y3, *args)
if args[-3].is_a?(Bitmap)
src, x0, y0 = args[-3, 3]
opacity = 255
nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-3])
elsif args[-4].is_a?(Bitmap)
src, x0, y0, opacity = args[-4, 4]
nodes = [x1, y1, x2, y2, x3, y3].concat(args[0...-4])
else
raise ArgumentError
end
raise ArgumentError unless nodes.size[0] == 0
edges = {}
min_y = height
max_y = 0
ox = x0 - x1
oy = y0 - y1
0.step(nodes.size - 2, 2) do |i|
xi, yi = nodes[i, 2]
min_y = [min_y, yi].min
max_y = [max_y, yi].max
xj, yj = nodes[(i + 2) % nodes.size, 2]
dx = 1.0 * (xi - xj) / (yi - yj)
if yi < yj
delta = -1
delta -= 2 until (yh = nodes[(i + delta) % nodes.size]) != yi
if yh < yi
yi += 1
xi += dx
end
edges[yi] ||= []
edges[yi].push([xi, dx, yj])
elsif yi > yj
delta = 5
delta += 2 until (yk = nodes[(i + delta) % nodes.size]) != yj
if yj > yk
yj += 1
xj += dx
end
edges[yj] ||= []
edges[yj].push([xj, dx, yi])
end
end
aet = []
for y in min_y..max_y
aet.concat(edges[y]).sort! if edges[y]
0.step(aet.size - 1, 2) do |i|
xi = aet[i][0].round
xj = aet[i + 1][0].round
blt(xi, y, src, Rect.new(xi + ox, y + oy, xj - xi + 1, 1), opacity)
end
aet.reject! {|edge| edge[2] == y}
aet.each {|edge| edge[0] += edge[1]}.sort!
end
end
#--------------------------------------------------------------------------
# ● 绘制正多边形
# x : 正多边形外接圆心 X 坐标
# y : 正多边形外接圆心 Y 坐标
# rad : 正多边形外接圆 半径
# edges : 正多边形的边数
# angle : 正多边形旋转角度
# color : 正多边形的颜色 (Color)
#--------------------------------------------------------------------------
def draw_isogon(x, y, rad, edges, angle, color)
raise ArgumentError if edges < 3
step = Math::PI * 2 / edges
args = []
angle_i = Math::PI * (270 + angle) / 180
edges.times do
args.push((x + rad * Math.cos(angle_i)).round,
(y + rad * Math.sin(angle_i)).round)
angle_i += step
end
draw_polygon(*args.push(color))
end
#--------------------------------------------------------------------------
# ● 绘制实心正多边形
# x : 正多边形外接圆心 X 坐标
# y : 正多边形外接圆心 Y 坐标
# rad : 正多边形外接圆 半径
# edges : 正多边形的边数
# angle : 正多边形旋转角度
# color : 边框的颜色 (Color)
# fill : 填充选项,具体的填充选项有:
# 2个颜色 + true/false : 两个颜色以垂直/水平方式渐变填充
# 2个颜色 : 两个颜色以水平方向渐变填充
# 1个颜色 : 实心填充
# 位图 + 数值 : 以位图图案填充,数值为不透明度
# 位图 : 以位图图案填充,不透明度固定为255
# 省略 : 用边框色实心填充
#--------------------------------------------------------------------------
def fill_isogon(x, y, rad, edges, angle, color, *fill)
raise ArgumentError if edges < 3
step = Math::PI * 2 / edges
args = []
angle_i = Math::PI * (270 + angle) / 180
edges.times do
args.push((x + rad * Math.cos(angle_i)).round,
(y + rad * Math.sin(angle_i)).round)
angle_i += step
end
fill_polygon(*args.push(color).concat(fill))
end
#--------------------------------------------------------------------------
# ● 传送位图正多边形
# x : 正多边形外接圆心 X 坐标
# y : 正多边形外接圆心 Y 坐标
# rad : 正多边形外接圆 半径
# edges : 正多边形的边数
# angle : 正多边形旋转角度
# src_bitmap : 传送元位图
# x0 : 传送圆心 X 坐标
# y0 : 传送圆心 Y 坐标
# opacity : 不透明度
#--------------------------------------------------------------------------
def blt_isogon(x, y, rad, edges, angle, src_bitmap, x0, y0, opacity = 255)
raise ArgumentError if edges < 3
step = Math::PI * 2 / edges
args = []
angle_i = Math::PI * (270 + angle) / 180
edges.times do
args.push((x + rad * Math.cos(angle_i)).round,
(y + rad * Math.sin(angle_i)).round)
angle_i += step
end
args.push(src_bitmap, x0 - x + args[0], y0 - y + args[1], opacity)
blt_polygon(*args)
end
#--------------------------------------------------------------------------
# ● 绘制圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad : 半径
# color : 圆的颜色 (Color)
#--------------------------------------------------------------------------
def draw_circle(x, y, rad, color)
draw_ellipse(x, y, rad, rad, color)
end
#--------------------------------------------------------------------------
# ● 绘制椭圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad_x : 水平半径
# rad_y : 垂直半径
# color : 椭圆的颜色 (Color)
#--------------------------------------------------------------------------
def draw_ellipse(x, y, rad_x, rad_y, color)
fill_ellipse(x, y, rad_x, rad_y, color, nil)
end
#--------------------------------------------------------------------------
# ● 绘制实心圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad : 半径
# border_color : 圆的边框颜色 (Color)
# fill : 填充选项,具体的填充选项有:
# nil : 不填充
# 2个颜色 + true/false : 两个颜色以垂直/水平方式渐变填充
# 2个颜色 : 两个颜色以水平方向渐变填充
# 1个颜色 : 实心填充
# 位图 + 数值 : 以位图图案填充,数值为不透明度
# 位图 : 以位图图案填充,不透明度固定为255
# 省略 : 用边框色实心填充
#--------------------------------------------------------------------------
def fill_circle(x, y, rad, border_color, *fill)
fill_ellipse(x, y, rad, rad, border_color, *fill)
end
#--------------------------------------------------------------------------
# ● 绘制实心椭圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad_x : 水平半径
# rad_y : 垂直半径
# border_color : 椭圆的边框颜色 (Color)
# fill : 填充选项,具体的填充选项有:
# nil : 不填充
# 2个颜色 + true/false : 两个颜色以垂直/水平方式渐变填充
# 2个颜色 : 两个颜色以水平方向渐变填充
# 1个颜色 : 实心填充
# 位图 + 数值 : 以位图图案填充,数值为不透明度
# 位图 : 以位图图案填充,不透明度固定为255
# 省略 : 用边框色实心填充
#--------------------------------------------------------------------------
def fill_ellipse(x, y, rad_x, rad_y, border_color, *fill)
raise ArgumentError if rad_x < 0 or rad_y < 0
return set_pixel(x, y, border_color) if rad_x == 0 and rad_y == 0
return fill_rect(x - rad_x, y, rad_x << 1, 1, border_color) if rad_y == 0
return fill_rect(x, y - rad_y, 1, rad_y << 1, border_color) if rad_x == 0
ry2 = rad_y * rad_y
rx2 = rad_x * rad_x
d = ry2 + rx2 * (0.25 - rad_y)
dx = 0
dy = rad_y
if fill.size == 0
fill_mode = 0
f1 = f2 = border_color.clone
else
case fill[0]
when Color
f1 = fill[0].clone
if fill[1]
f2 = fill[1].clone
fill_mode = f1 == f2 ? 0 : (fill[2] ? 3 : 1)
else
f2 = f1
fill_mode = 0
end
when Bitmap
fill_mode = 2
else
fill_mode = -1
end
end
case fill_mode
when 1
dist = rad_y - 1 << 1
if dist > 0
dr = (f2.red - f1.red) / dist
dg = (f2.green - f1.green) / dist
db = (f2.blue - f1.blue) / dist
da = (f2.alpha - f1.alpha) / dist
end
when 2
src = Bitmap.new((rad_x << 1) - 1, fill[0].height)
0.step((rad_x << 1) - 1, fill[0].width) do |x0|
src.blt(x0, 0, fill[0], fill[0].rect, fill[1] || 255)
end
when 3
src = Bitmap.new((rad_x << 1) - 1, 1)
src.gradient_draw_line(0, 0, rad_x - 1 << 1 , 0, f1, f2)
end
begin
set_pixel(x + dx, y + dy, border_color)
set_pixel(x + dx, y - dy, border_color)
set_pixel(x - dx, y - dy, border_color)
set_pixel(x - dx, y + dy, border_color)
if d <= -1e-6
d += ry2 * ((dx << 1) + 3)
else
d += ry2 * ((dx << 1) + 3) + rx2 * (1 - dy << 1)
dy -= 1
case fill_mode
when 0, 1
fill_rect(x - dx, y - dy, (dx << 1) + 1, 1, f1)
fill_rect(x - dx, y + dy, (dx << 1) + 1, 1, f2)
if fill_mode == 1
f1.set(f1.red + dr, f1.green + dg, f1.blue + db, f1.alpha + da)
f2.set(f2.red - dr, f2.green - dg, f2.blue - db, f2.alpha - da)
end
when 2, 3
blt(x - dx, y - dy, src, Rect.new(rad_x - dx - 1,
(rad_y - dy - 1) % src.height,(dx << 1) + 1, 1))
blt(x - dx, y + dy, src, Rect.new(rad_x - dx - 1,
(rad_y + dy - 1) % src.height,(dx << 1) + 1, 1))
end
end
dx += 1
end while ry2 * (dx + 1) < rx2 * (dy - 0.5)
d = ry2 * (dx + 0.5) * (dx + 0.5) + rx2 * (dy - 1) * (dy - 1) - rx2 * ry2
sy = dy
begin
set_pixel(x + dx, y + dy, border_color)
set_pixel(x + dx, y - dy, border_color)
set_pixel(x - dx, y - dy, border_color)
set_pixel(x - dx, y + dy, border_color)
if fill_mode >= 0 and dy < sy
case fill_mode
when 0, 1
fill_rect(x - dx + 1, y - dy, (dx << 1) - 1, 1, f1)
fill_rect(x - dx + 1, y + dy, (dx << 1) - 1, 1, f2) unless dy == 0
if fill_mode == 1
f1.set(f1.red + dr, f1.green + dg, f1.blue + db, f1.alpha + da)
f2.set(f2.red - dr, f2.green - dg, f2.blue - db, f2.alpha - da)
end
when 2, 3
blt(x - dx + 1, y - dy, src, Rect.new(rad_x - dx,
(rad_y - dy - 1) % src.height,(dx << 1) - 1, 1))
blt(x - dx + 1, y + dy, src, Rect.new(rad_x - dx,
(rad_y + dy - 1) % src.height,(dx << 1) - 1, 1)) unless dy == 0
end
end
if d <= -1e-6
d += ry2 * (dx + 1 << 1) + rx2 * (3 - (dy << 1))
dx += 1
else
d += rx2 * (3 - (dy << 1))
end
dy -= 1
end while dy >= 0
src.dispose if fill_mode > 1
end
#--------------------------------------------------------------------------
# ● 传送位图圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad : 半径
# src_bitmap : 传送元位图
# x0 : 传送圆心 X 坐标
# y0 : 传送圆心 Y 坐标
# opacity : 不透明度
#--------------------------------------------------------------------------
def blt_circle(x, y, rad, src_bitmap, x0, y0, opacity = 255)
blt_ellipse(x, y, rad, rad, src_bitmap, x0, y0, opacity)
end
#--------------------------------------------------------------------------
# ● 传送位图椭圆
# x : 圆心 X 坐标
# y : 圆心 Y 坐标
# rad_x : 水平半径
# rad_y : 垂直半径
# src_bitmap : 传送元位图
# x0 : 传送圆心 X 坐标
# y0 : 传送圆心 Y 坐标
# opacity : 不透明度
#--------------------------------------------------------------------------
def blt_ellipse(x, y, rad_x, rad_y, src_bitmap, x0, y0, opacity = 255)
raise ArgumentError if rad_x < 0 or rad_y < 0
return blt(x - rad_x, y, src_bitmap, Rect.new(x0 - rad_x, y0,
rad_x << 1, 1), opacity) if rad_y == 0
return blt(x, y - rad_y, src_bitmap, Rect.new(x0, y0 - rad_y,
1, rad_y << 1), opacity) if rad_x == 0
ry2 = rad_y * rad_y
rx2 = rad_x * rad_x
d = ry2 + rx2 * (0.25 - rad_y)
dx = 0
dy = rad_y
begin
if d <= -1e-6
d += ry2 * ((dx << 1) + 3)
else
blt(x - dx, y - dy, src_bitmap, Rect.new(x0 - dx, y0 - dy, dx << 1, 1),
opacity)
blt(x - dx, y + dy, src_bitmap, Rect.new(x0 - dx, y0 + dy, dx << 1, 1),
opacity)
d += ry2 * ((dx << 1) + 3) + rx2 * (1 - dy << 1)
dy -= 1
end
dx += 1
end while ry2 * (dx + 1) < rx2 * (dy - 0.5)
d = ry2 * (dx + 0.5) * (dx + 0.5) + rx2 * (dy - 1) * (dy - 1) - rx2 * ry2
begin
blt(x - dx, y - dy, src_bitmap, Rect.new(x0 - dx, y0 - dy, dx << 1, 1),
opacity)
blt(x - dx, y + dy, src_bitmap, Rect.new(x0 - dx, y0 + dy, dx << 1, 1),
opacity) unless dy == 0
if d <= -1e-6
d += ry2 * (dx + 1 << 1) + rx2 * (3 - (dy << 1))
dx += 1
else
d += rx2 * (3 - (dy << 1))
end
dy -= 1
end while dy >= 0
end
#--------------------------------------------------------------------------
# ● 绘制曲线
# x1 : 起始点 X 坐标
# x2 : 起始点 Y 坐标
# cx1 : 控制点1 X 坐标
# cy1 : 控制点1 Y 坐标
# cx2 : 控制点2 X 坐标
# cx2 : 控制点2 Y 坐标
# x2 : 终止点(或控制点3) X 坐标
# y2 : 终止点(或控制点3) Y 坐标
# args : 后续的参数,可以追加额外的控制点,以最后一个点的坐标为终止点,
# 最后还需再指定一个颜色 (Color)
#--------------------------------------------------------------------------
def draw_curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, *args)
raise ArgumentError if args.size[0] == 0 or not args[-1].is_a?(Color)
color = args[-1]
points = [x1, y1, cx1, cy1, cx2, cy2, x2, y2].concat(args[0...-1])
draw_path(*get_curve_path(points).push(color))
end
#--------------------------------------------------------------------------
# ● 绘制封闭曲线
# x1 : 起始点 X 坐标
# x2 : 起始点 Y 坐标
# cx1 : 控制点1 X 坐标
# cy1 : 控制点1 Y 坐标
# cx2 : 控制点2 X 坐标
# cx2 : 控制点2 Y 坐标
# x2 : 终止点 X 坐标
# y2 : 终止点 Y 坐标
# args : 后续的参数,每多指定一个曲线节点,增加6个参数,分别表示从前一终
# 止点作为起始点曲线的控制点1 X/Y、控制点2 X/Y、及本曲线终点的X/Y
# 最后还需再指定一个颜色 (Color)
#--------------------------------------------------------------------------
def draw_closed_curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, *args)
raise ArgumentError if args.size % 6 != 1 or not args[-1].is_a?(Color)
color = args[-1]
points = [x1, y1, cx1, cy1, cx2, cy2, x2, y2].concat(args[0...-1])
edges = []
0.step(points.size - 8, 6) do |i|
edges.concat(get_curve_path(points[i, 8]))
end
draw_polygon(*edges.push(color))
end
#--------------------------------------------------------------------------
# ● 绘制填充的封闭曲线
# x1 : 起始点 X 坐标
# x2 : 起始点 Y 坐标
# cx1 : 控制点1 X 坐标
# cy1 : 控制点1 Y 坐标
# cx2 : 控制点2 X 坐标
# cx2 : 控制点2 Y 坐标
# x2 : 终止点 X 坐标
# y2 : 终止点 Y 坐标
# args : 后续的参数,每多指定一个曲线节点,增加6个参数,分别表示从前终止
# 点起始的下一曲线段控制点1 X/Y、控制点2 X/Y、及该曲线终止点的X/Y
# 最后要指定填充选项,填充选项有:
# 3个颜色 + true/false : 颜色1为边框色,颜色2和颜色3用于填充,最后
# true = 垂直方向渐变 false = 水平方向渐变
# 3个颜色 : 颜色1用于描边,颜色2和颜色3用于填充,水平方向渐变
# 2个颜色 : 颜色1用于描边,颜色2用于填充
# 1个颜色 : 以该颜色描边,并实心填充
# 颜色 + 位图 + 数值 : 颜色用于描边,位图用于填充,数值为不透明度
# 颜色 + 位图 : 颜色用于描边,位图用于填充,不透明度固定为255
#--------------------------------------------------------------------------
def fill_closed_curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, *args)
case args[-1]
when FalseClass, TrueClass
arg_chop = -4
when Color
arg_chop = args[-3].is_a?(Color) ? -3 :
args[-2].is_a?(Color) ? -2 : -1
when Bitmap
arg_chop = -2
when Numeric
arg_chop = -3
else
raise ArgumentError
end
raise ArgumentError if (args.size + arg_chop) % 6 != 0
points = [x1, y1, cx1, cy1, cx2, cy2, x2, y2].concat(args[0...arg_chop])
edges = []
0.step(points.size - 8, 6) do |i|
edges.concat(get_curve_path(points[i, 8])[0...-2])
end
fill_polygon(*edges.concat(args[arg_chop..-1]))
end
#--------------------------------------------------------------------------
# ● 传送位图封闭曲线
# x1 : 起始点 X 坐标
# x2 : 起始点 Y 坐标
# cx1 : 控制点1 X 坐标
# cy1 : 控制点1 Y 坐标
# cx2 : 控制点2 X 坐标
# cx2 : 控制点2 Y 坐标
# x2 : 终止点 X 坐标
# y2 : 终止点 Y 坐标
# args : 后续的参数,每多指定一个曲线节点,增加6个参数,分别表示从前终止
# 点起始的下一曲线段控制点1 X/Y、控制点2 X/Y、及该曲线终止点的X/Y
# 最后指定传送的位图, 偏移x,偏移y(比照起始点),(可选)不透明度
#--------------------------------------------------------------------------
def blt_closed_curve(x1, y1, cx1, cy1, cx2, cy2, x2, y2, *args)
if args[-3].is_a?(Bitmap)
start = -3
points = [x1, y1, cx1, cy1, cx2, cy2, x2, y2].concat(args[0...-3])
elsif args[-4].is_a?(Bitmap)
start = -4
points = [x1, y1, cx1, cy1, cx2, cy2, x2, y2].concat(args[0...-4])
else
raise ArgumentError
end
raise ArgumentError unless points.size % 6 == 2
edges = []
0.step(points.size - 8, 6) do |i|
edges.concat(get_curve_path(points[i, 8]))
end
blt_polygon(*edges.concat(args[start..-1]))
end
private
#--------------------------------------------------------------------------
# ● 内部函数:计算曲线点位
# points : 接继点表
#--------------------------------------------------------------------------
def get_curve_path(points)
max_x = min_x = points[0]
max_y = min_y = points[1]
2.step(points.size - 2, 2) do |i|
max_x = [max_x, points[i]].max
min_x = [min_x, points[i]].min
max_y = [max_y, points[i + 1]].max
min_y = [min_y, points[i + 1]].min
end
curve_edge_count = [max_x + max_y - min_x - min_y >> 2, 2].max
(0..curve_edge_count).inject([]) do |a, i|
pt = points.clone
t = i / curve_edge_count.to_f
until pt.size == 2
pt = (0...(pt.size >> 1) - 1).to_a.inject([]) do |b, j|
x1, y1, x2, y2 = pt[j << 1, 4]
b.push((1 - t) * x1 + t * x2, (1 - t) * y1 + t * y2)
end
end
x = pt[0].round
y = pt[1].round
x == a[-2] && y == a[-1] ? a : a.push(x, y)
end
end
end
|
评分
-
查看全部评分
|