橡皮筋算法的原理和实现

简介: 橡皮筋算法       程序员,可以选择研究技术,也可以选择赚钱。但是以赚钱的心态去做程序员,会品尝不到技术的很多快乐。 1.橡皮筋算法原理      橡皮筋算法,指的是什么,我们都应该很清楚了。

橡皮筋算法

 

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

 

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;

 

 

相关文章
|
3月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
65 3
|
3月前
|
机器学习/深度学习 算法 机器人
多代理强化学习综述:原理、算法与挑战
多代理强化学习是强化学习的一个子领域,专注于研究在共享环境中共存的多个学习代理的行为。每个代理都受其个体奖励驱动,采取行动以推进自身利益;在某些环境中,这些利益可能与其他代理的利益相冲突,从而产生复杂的群体动态。
311 5
|
5天前
|
机器学习/深度学习 算法 PyTorch
深度强化学习中SAC算法:数学原理、网络架构及其PyTorch实现
软演员-评论家算法(Soft Actor-Critic, SAC)是深度强化学习领域的重要进展,基于最大熵框架优化策略,在探索与利用之间实现动态平衡。SAC通过双Q网络设计和自适应温度参数,提升了训练稳定性和样本效率。本文详细解析了SAC的数学原理、网络架构及PyTorch实现,涵盖演员网络的动作采样与对数概率计算、评论家网络的Q值估计及其损失函数,并介绍了完整的SAC智能体实现流程。SAC在连续动作空间中表现出色,具有高样本效率和稳定的训练过程,适合实际应用场景。
32 7
深度强化学习中SAC算法:数学原理、网络架构及其PyTorch实现
|
14天前
|
算法 Java 数据库
理解CAS算法原理
CAS(Compare and Swap,比较并交换)是一种无锁算法,用于实现多线程环境下的原子操作。它通过比较内存中的值与预期值是否相同来决定是否进行更新。JDK 5引入了基于CAS的乐观锁机制,替代了传统的synchronized独占锁,提升了并发性能。然而,CAS存在ABA问题、循环时间长开销大和只能保证单个共享变量原子性等缺点。为解决这些问题,可以使用版本号机制、合并多个变量或引入pause指令优化CPU执行效率。CAS广泛应用于JDK的原子类中,如AtomicInteger.incrementAndGet(),利用底层Unsafe库实现高效的无锁自增操作。
理解CAS算法原理
|
2月前
|
算法 容器
令牌桶算法原理及实现,图文详解
本文介绍令牌桶算法,一种常用的限流策略,通过恒定速率放入令牌,控制高并发场景下的流量,确保系统稳定运行。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
令牌桶算法原理及实现,图文详解
|
1月前
|
存储 人工智能 缓存
【AI系统】布局转换原理与算法
数据布局转换技术通过优化内存中数据的排布,提升程序执行效率,特别是对于缓存性能的影响显著。本文介绍了数据在内存中的排布方式,包括内存对齐、大小端存储等概念,并详细探讨了张量数据在内存中的排布,如行优先与列优先排布,以及在深度学习中常见的NCHW与NHWC两种数据布局方式。这些布局方式的选择直接影响到程序的性能,尤其是在GPU和CPU上的表现。此外,还讨论了连续与非连续张量的概念及其对性能的影响。
56 3
|
2月前
|
机器学习/深度学习 人工智能 算法
探索人工智能中的强化学习:原理、算法与应用
探索人工智能中的强化学习:原理、算法与应用
|
2月前
|
负载均衡 算法 应用服务中间件
5大负载均衡算法及原理,图解易懂!
本文详细介绍负载均衡的5大核心算法:轮询、加权轮询、随机、最少连接和源地址散列,帮助你深入理解分布式架构中的关键技术。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
5大负载均衡算法及原理,图解易懂!
|
2月前
|
缓存 算法 网络协议
OSPF的路由计算算法:原理与应用
OSPF的路由计算算法:原理与应用
67 4
|
2月前
|
存储 算法 网络协议
OSPF的SPF算法介绍:原理、实现与应用
OSPF的SPF算法介绍:原理、实现与应用
95 3

热门文章

最新文章