橡皮筋算法的原理和实现

橡皮筋算法

 

      程序员,可以选择研究技术,也可以选择赚钱。但是以赚钱的心态去做程序员,会品尝不到技术的很多快乐。

 

1.橡皮筋算法原理

      橡皮筋算法,指的是什么,我们都应该很清楚了。以直线为例,就是直线的一端固定,拉着直线的另一个端点,不断调整直线的位置,直到找到合适的位置后,直线才真正的画出来,前面的线不保留。

      按照我们一般的逻辑思维,就是不断的擦除刚画过的线,只保留最后的一根直线。但在计算机绘图中,没有擦除的方法,而是用反色覆盖掉原来的图像。也就是不断的用反色重画前面画出的线。

2. 橡皮筋算法实现

unitFrmElastic;

 

interface

 

uses

  Winapi.Windows, Winapi.Messages,System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,

  Vcl.Controls, Vcl.Forms, Vcl.Dialogs,Vcl.StdCtrls;

 

type

  TFormElastic = class(TForm)

    procedure FormMouseDown(Sender: TObject;Button: TMouseButton;

      Shift: TShiftState; X, Y: Integer);

    procedure FormMouseMove(Sender: TObject;Shift: TShiftState; X, Y: Integer);

    procedure FormMouseUp(Sender: TObject;Button: TMouseButton;

      Shift: TShiftState; X, Y: Integer);

  private

    { Private declarations }

    ptOrigin: TPoint;  //原始点,用于记录鼠标按下时的点坐标

    ptTarget: TPoint;  //目标点,用于记录鼠标移动或弹起时的点坐标

  public

    { Public declarations }

  end;

 

var

  FormElastic: TFormElastic;

 

implementation

 

{$R*.dfm}

 

//画线(橡皮筋算法)

procedureDrawElasticLine(Canvas: TCanvas; ptBegin, ptOldEnd, ptNewEnd: TPoint);

begin

  //画笔模式,适用pmNotXor来画橡皮筋,因为两次取反可以还原背景色。

  Canvas.Pen.Mode := pmNotXor;

  Canvas.pen.Style := psSolid; //直线画笔

  Canvas.Pen.Color := clBlack; //黑色画笔

 

  //画刷模式

  Canvas.Brush.style := bsClear; //画刷不填充

 

  //画旧线(相当于擦除),此时旧线所在位置的背景色被线的颜色覆盖

  Canvas.MoveTo(ptBegin.X, ptBegin.Y);

  Canvas.LineTo(ptOldEnd.X, ptOldEnd.Y);

 

  //画新线,此时新线所在位置的背景色还是原来的背景色

  Canvas.MoveTo(ptBegin.X, ptBegin.Y);

  Canvas.LineTo(ptNewEnd.X, ptNewEnd.Y);

end;

 

procedureTFormElastic.FormMouseDown(Sender: TObject; Button: TMouseButton;

  Shift: TShiftState; X, Y: Integer);

begin

    inherited;

 

    //记录鼠标按下时的原始点坐标

    ptOrigin.x := X;

    ptOrigin.y := Y;

 

    //初始化目标点坐标

    ptTarget := ptOrigin;

end;

 

procedureTFormElastic.FormMouseMove(Sender: TObject; Shift: TShiftState; X,

  Y: Integer);

var

  ptNewEnd: TPoint;

begin

  inherited;

 

  //如果是在鼠标左键按下的同时,进行鼠标移动操作,则进行画线操作

  if ssLeft in Shift then

  begin

    //记录新的目标点坐标

    ptNewEnd.X := X;

    ptNewEnd.Y := Y;

 

    //画线(橡皮筋算法)

    DrawElasticLine(Canvas, ptOrigin, ptTarget,ptNewEnd);

 

    //记录新的目标点坐标

    ptTarget := ptNewEnd;

  end;

end;

 

procedureTFormElastic.FormMouseUp(Sender: TObject; Button: TMouseButton;

  Shift: TShiftState; X, Y: Integer);

var

  ptNewEnd: TPoint;

begin

  inherited;

 

  //记录新的目标点坐标

  ptNewEnd.X := X;

  ptNewEnd.Y := Y;

 

  //画线(橡皮筋算法)

  DrawElasticLine(Canvas, ptOrigin, ptTarget,ptNewEnd);

end;

 

end.

3.研究一下画笔对象(TPen)

      知其然,还要知其所以然,编程不只是为了实现,更应该是一种兴趣,一种爱好。

 

      Windows中定义的绘图方式也影响显示器上所画线的外观。设想画这样一条直线,它的色彩由画笔色彩和画线区域原来的色彩共同决定。设想用同一种画笔在白色表面上画出黑线而在黑色表面上画出白线,而且不用知道表面是什么色彩。这样的功能对您有用吗?通过绘图方式的设定,这些都可以实作。当Windows使用画笔来画线时,它实际上执行画笔图素与目标位置处原来图素之间的某种位元布尔运算。

        

      使用 TPen 类可以描述Windows 的笔(Pen)属性,应用程序常用TPen对象在画布Canvas上绘制各种图形。所有和线条有关的绘图函数都会受TPen影响,如LineTo、Ellipse、Polygon、PolyLine、Rectangle等函数。可以利用Canvas.Pen来读写Pen,借此修改Pen的属性,画笔的颜色在Color 属性中定义,线段宽度在Width 属性中定义,类型和模式则分别在Style和Mode 属性中定义。

      Color 属性控制线的颜色,如clBlack(黑色)、clBlue(蓝色)和clGreen(绿色)等。

      Style 属性确定线的式样,如psSolid(实线)和psDash(短线)等,详见下表。

 

取值

含义

pSolid

画实线段

pSDash

画由下划线组成的线段

pSDot

画由点组成的线段

psDashDot

画点划线

psDashDotDot

画双点划线

psClear

画看不见的线段

psInsideFrame

画边界的矩形线框

 

       Mode用来确定画笔与屏幕上原有点的颜色混合方式。可结合当前的颜色、屏幕的颜色或它们的反转值,对线段的颜色重新定义。但不改变Color属性属性,详见下表。

 

取值

含义

pmBlack

像素始终为黑色

pmWhite

像素始终为白色

pmNop

像素保持不变

pmNot

像素为屏幕颜色的反色(这样可以覆盖掉上次的绘图,自动擦除上次绘制的图形)

pmCopy

像素为笔的颜色(即Color  属性中的颜色)

pmNotCopy

像素为笔颜色的反色

下面是当前画笔的颜色和屏幕色的组合运算得到的绘图模式

pmMergePenNot

pmCopy和pmNot的并集(即像素为笔颜色或屏幕颜色反色)

pmMaskPenNot

pmCopy和pmNot的交集(即像素为笔颜色与屏幕颜色反色)

pmMergeNotPen

pmNotCopy和屏幕像素值的并集(即像素为笔颜色反色或屏幕颜色)

pmMaskNotPen

pmNotCopy和屏幕像素值的并集(即像素为笔颜色反色与屏幕颜色)

pmMerge

pmCopy和屏幕像素值的并集(即像素为笔颜色或屏幕颜色)

pmNotMerge

pmMerge的反色

pmMask

pmCopy和屏幕像素值的交集(即像素为笔颜色与屏幕颜色)

pmNotMask

pmMask的反色

pmXor

pmCopy和屏幕像素值的异或(像素为笔颜色异或屏幕颜色,连续异或两次会变为原来颜色)

pmNotXor

pmXor的反色

 

4.再研究一下画线的橡皮筋算法

已知条件:

假定画布的颜色为a,画笔的颜色为b,画出来的直线颜色为c

如果a=b,则相当于用a色的画笔在a色的画布上画东西,是什么结果也看不出来的。

 

1).在画布上画出一条c=黑色的直线,而不管画布是什么颜色a。

分析:

如果画布的颜色a=黑色,那么画出来的c=黑色的直线是看不见的。

如果画布的颜色a<>黑色,那么可以有两种选择:

1.1.设置Mode= pmBlack,此时不管画笔b是什么颜色,画出来的线都是c=黑色的;

1.2.设置Mode=pmCopy,并设置画笔的颜色为b=黑色,此时,不管画布的颜色是什么,画出来的直线也都是c=黑色的。

总结:

此时最适合使用Mode= pmBlack颜色混合模式,不去管画布颜色和画笔颜色,画出来的直线都是c=黑色。效率也是最高的。

 

2).擦掉第一个问题中画出来的c=黑色的直线

分析:

想擦掉这条直线,我们可以使用画布的颜色,再重新画一遍这条直线。即让画笔的颜色b=a,此时如果已知了画布的颜色a,就很简单了。但我们不知道画布的颜色。但是我们知道以下关系

2.1.c=a^b(用b色画笔在a色的画布上画出了c的一条直线,此时直线位置的画布颜色变成了a=c)

2.2.c^b=(a^b)^b=a^(b^b)=a^1=a(用b色的画笔在c色的画布上画出了c=a色的直线)

总结:

不管画笔的颜色b是什么,经过和画布颜色a的两次亦或运算后,就得到了原始的画布颜色a,所以此时适合于使用Mode= pmXor颜色混合模式。

但存在一个问题,如果a^b以后的结果c1,凑巧c1=a,那么将永远不能画出直线来。如果c1颜色和背景色相反,我们知道一定能画出直线来。所以我们为了既能画出直线来,又能擦除直线,最适合使用Mode= pmNotXor颜色混合模式。最常用的场景是在白色的背景上画各种颜色的图。此时,我们再实现这个算法

 

//画线擦除线

procedureDrawEraseLine(Canvas: TCanvas; ptBegin, ptEnd: TPoint);

begin

  //画笔模式,适用pmNotXor,因为两次取反可以还原背景色。

  Canvas.Pen.Mode := pmNotXor;

  Canvas.pen.Style := psSolid; //直线画笔

  Canvas.Pen.Color := clBlack; //黑色画笔

 

  //画刷模式

  Canvas.Brush.style := bsClear; //画刷不填充

 

  //画线

  Canvas.MoveTo(ptBegin.X, ptBegin.Y);

  Canvas.LineTo(ptEnd.X, ptEnd.Y);

 

  //擦线(此时旧线所在位置的背景色被线的颜色覆盖,用该颜色亦或画笔的颜色)

  Canvas.MoveTo(ptBegin.X, ptBegin.Y);

  Canvas.LineTo(ptEnd.X, ptEnd.Y);

end;

 

 

时间: 2024-11-05 12:14:43

橡皮筋算法的原理和实现的相关文章

线程-Mina框架死锁检测算法的原理?

问题描述 Mina框架死锁检测算法的原理? 30C private void checkDeadLock() { if (!(this instanceof CloseFuture || this instanceof WriteFuture || this instanceof ReadFuture || this instanceof ConnectFuture)) { return; } StackTraceElement[] stackTrace = Thread.currentThre

IDA* 算法的原理和步骤

问题描述 IDA* 算法的原理和步骤 我想了解下IDA*算法的相关原理,我只需要知道它的运行原理和步骤,按顺序怎么执行下去的,麻烦大牛们给个解答,不需要代码,我弄懂了自然会写,谢谢

机器学习系列------1. GBDT算法的原理

GBDT算法是一种监督学习算法.监督学习算法需要解决如下两个问题: 1.损失函数尽可能的小,这样使得目标函数能够尽可能的符合样本 2.正则化函数对训练结果进行惩罚,避免过拟合,这样在预测的时候才能够准确. GBDT算法需要最终学习到损失函数尽可能小并且有效的防止过拟合. 以样本随时间变化对某件事情发生的变化为例,如下几副图形象的说明了机器学习的作用. 假设随着时间的变化对K话题存在如下样本: 如果没有有效的正则化,则学习结果会如下图所示: 这种情况下,学习结果跟样本非常符合,损失函数也非常小,但

搜索引擎算法原理 百度算法的原理 [

随着网络的平民化,更多人在网络上想找到自己的信息,都喜欢在搜索引擎框中打入自己想搜索的关键词,而不是像在网络的早期,去黄页等网站寻找,有效节省大量的时间.那么在我们每天通过搜索引擎来寻找我们的信息同时,你是否知道搜索引擎的简单原理,什么是搜索引擎呢?那么搜索引擎有什么算法.机密的玄机呢?    随着搜索经济的崛起,人们开始越加关注全球各大搜索引擎的性能.技术和日流量.作为企业,会根据搜索引擎的知名度以及日流量来选择是否要投放广告等:作为普通网民,会根据搜索引擎的性能和技术来选择自己喜欢的引擎查找

缺失的白皮书:DPOS共识算法工作原理及鲁棒性根源分析

雷锋网(公众号:雷锋网)按:本文发表于Steem,作者是dantheman.译者是万云首席技术官奚海峰,首发公众号万云BaaS.奚海峰曾任IBM研究院工程师和高级咨询顾问,Sempra Commodities 主管架构师及 Tudor Investment 软件开发主管.在美国12年间,获得了包括"IBM 研究成就奖"在内的多次嘉奖,在一流国际会议和杂志上发表过多篇学术论文,并且持有美国发明专利.雷锋网已获授权转载. 这篇"缺失的白皮书"是对委托权益证明(DPOS)

全排列算法的原理和实现代码_C 语言

全排列是将一组数按一定顺序进行排列,如果这组数有n个,那么全排列数为n!个.现以{1, 2, 3, 4, 5}为例说明如何编写全排列的递归算法. 1.首先看最后两个数4, 5. 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列. 由于一个数的全排列就是其本身,从而得到以上结果. 2.再看后三个数3, 4, 5.它们的全排列为3 4 5.3 5 4. 4 3 5. 4 5 3. 5 3 4. 5 4 3 六组数. 即以3开头的和4,5的全排列的组合.以4开头的和3,5的

布点算法的原理和实现

在数据可视化的过程中,绘制网络拓扑图是很重要的,它能清晰呈现一个复杂网络的结构,节点的重要性和关系.比如下面几张图: 下面这张图是我的软件绘制的: 这些都有一个共同的问题,就是如何让图绘制的更加美观? 复杂的图结构,已经没法人工布局了.所以计算机自动布局,就成了一个有趣而重要的话题.我们将其称为布点算法. 基本原理 一个好的布点算法应该能尽量满足以下四个特点: 对称性:绘制网络对应将具有相同结构的子图围绕绘图中心平衡布局 连接角最大化原则,使同一节点任意两条边形成的角度尽量大边交叉数量最小原则(

朴素贝叶斯分类算法的原理与实践

今天介绍一下朴素贝叶斯分类算法,讲一下基本原理,再以文本分类实践. 一个简单的例子 朴素贝叶斯算法是一个典型的统计学习方法,主要理论基础就是一个贝叶斯公式,贝叶斯公式的基本定义如下: 这个公式虽然看上去简单,但它却能总结历史,预知未来.公式的右边是总结历史,公式的左边是预知未来,如果把Y看出类别,X看出特征,P(Yk|X)就是在已知特征X的情况下求Yk类别的概率,而对P(Yk|X)的计算又全部转化到类别Yk的特征分布上来. 举个例子,大学的时候,某男生经常去图书室晚自习,发现他喜欢的那个女生也常

MySQL中Join算法实现原理分析

在MySQL 中,只有一种 Join 算法,就是大名鼎鼎的 Nested Loop Join,他没有其他很多数据库所提供的 Hash Join,也没有 Sort Merge Join.顾名思义,Nested Loop Join 实际上就是通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果.如果还有第三个参与 Join,则再通过前两个表的 Join 结果集作为循环基础数据,再一次通过循环查询条件到第三个表中查询数据,如此往复. 还是