Posts tagged ‘开源’

Degrafa的Bezier源码浅析(一)

先解释下Bezier曲线:

http://en.wikipedia.org/wiki/Bézier_curve

Degrafa是一套很强大的图形算法类库,并且开源,对Bezier曲线的绘制提供了很好的支持。说起Bezier曲线,其实就是Photoshop和flash里常用的钢笔工具啦,主要就是用来绘画路径或者绘画不规则图形。前者的应用领域非常广泛,比如使图形沿着路径运动,或者按路径不规则排列图形(具体一例就是扭曲的美术字布局)。这些都会用到Bezier曲线。

Degrafa提供的tutorial不是很完备,很多时候为了扩展应用不得不看源码。我这里只就Bezier相关的处理过程分析一下。

Degrafa下面的类非常之多,跟Bezier相关的主要有:

  • com.degrafa.geometry.splines.BezierSpline
  • com.degrafa.geometry.CubicBezier

两者都继承自com.degrafa.geometry.Geometry。很多图形库都有着类似的继承体系,Geometry作为一个基础的图形类,下面还有很多经过定义的不同种类的图形。

CubicBezier看字面意思,是一个三次贝塞尔曲线,事实上确实如此,它有四个点(start,end,2 control points)控制,其实也就是wiki上的那个图形

而BezierSpline跟真正的钢笔工具非常像,它由一系列点和control points来控制一整条曲线。这里最好看它的注释:

The BezierSpline can be used for drawing of a smooth curve through
multiple points, with some shape control over the curve via a tension
parameter. It may also be used for general path animation with tension
control, optional closed-path control, and velocity control
(arc-length parameterization).

乍看一下,它好像就是若干个CubicBezier的组合,其实关系不是很近。BezierSpline内部确实用到了CubicBezier对象(源码的第一行private var _bezier:Array),它是用来管理三次bezier曲线段的(BezierSpline包括很多的段)。

在使用BezierSpline曲线之前,需要提供一系列的点(钢笔工具的点类似)。使用到的property包括:

  • points
  • data

两者实质相同形式不同而已。

绘画曲线都使用draw方法,这个方法是由Geometry定义,并由它的子类重写的(典型的继承体系)。BezierSpline和CubicBezier都有类似的draw定义方式:

/**
* Begins the draw phase for geometry objects. All geometry objects
* override this to do their specific rendering.
*
* @param graphics The current context to draw to.
* @param rc A Rectangle object used for fill bounds.
**/
override public function draw(graphics:Graphics,rc:Rectangle):void{	

	//re init if required
 	if (invalidated) preDraw(); 

	//init the layout in this case done after predraw.
	if (_layoutConstraint) calculateLayout();

	super.draw(graphics, (rc)? rc:bounds);

}

preDraw在这个体系里非常重要,是用来在绘画之前计算各个点的位置,就像我们使用graphic那样定义好MoveTo和lineTo,所不同的这里会用到很多算法。与draw一样,preDraw在Geometry里定义在子类里重写,每个子类都有不同的方法。比如BezierSpline:

/**
* @inheritDoc
**/
   override public function preDraw():void{
   	if( invalidated ){

        	if(!points.length){return;}

        	_assignControlPoints();

        	//add a move to for the first item.
        	commandStack.length=0;

	//add a MoveTo at the start of the commandStack rendering chain
	commandStack.addMoveTo(points[0].x,points[0].y);

	var cubic:CubicBezier;

        //todo not sure were this extra one is coming from yet.
        //re:: - 1 on the count
        for( var i:uint=0; i<_bezier.length-1; ++i ){

        	cubic = _bezier[i];

        	commandStack.addCubicBezierTo(cubic.x0,cubic.y0,cubic.cx,
       	cubic.cy,cubic.cx1,cubic.cy1,cubic.x1,cubic.y1,1);

  	}

     		invalidated = false;
}
	    }

挖到这里,基本上快看到bezier算法在Degrafa里怎么实现的了,关键就是这个commandStack,字面意思:命令退栈,命令集合。

分布式版本控制Git

首先恭喜一下Git越来越有名了,很多有名的开源项目开始使用git做版本控制,如ROR等。我已经在项目中用了git一段时间,感觉快速且操作简单,况且由于某些原因源码不便放到svn服务器。Git成了这种情况下良好的选择。

记得之前讲过Git的基本用法,但是对Git这个分布式的版本控制没有做过多概念上的说明,这里就来比较下几类版本控制技术的区别:

本地版本控制(Local Version Control System):简单的说,就是仓库(repository,众多文档版本的集合)存放在本地,工作文档也是在本地。这类方式不用服务器,缺点也很明显,不便于多人配合开发。

中心化的版本控制(Centralized Version Control System):相比于上一种,这类方式注重协同开发,因此将仓库放到中心服务器上,便于数据管理和访问控制。经典的SVN就是这类。

分布式的版本控制(Distributed Version Control System):应该说,上面一种已经够完美了(至少我一直是这么认为了)。可惜数据太集中也有隐患,比如服务器down掉,就不能工作了,另外断网的情况下也不行。分布式就用来解决这种问题,Git属于这类。它的特点是本地完全的copy服务器的数据(包括所有的版本),即使在服务器不能使用的情况下,本地依然可以commit和checkout,甚至回复或者重建服务器上的仓库。

Flex源码学习之mx.utils.*

我承认这个标题有点标题党的味道。其实我的意思是想说,flex framework里有些code并不是依赖于framework的,怎么说呢,它们是纯算法,是数据处理,而并没有用到其它的flex framework class已经一些,比如metadata特性(有也可以改掉)。比如下面要提到的mx.utils.ColorUtil,还有StringUtil。于是我们就可以把它们提炼出来,用在普通AS3/Flash project当中,而不需要依赖,导入flex framework。

flex sdk已经开源了,进入sdk folder查找ColorUtil。来看看它处理brightness的算法

/**
 *  Performs a scaled brightness adjustment of an RGB color.
 *
 *  @param rgb Original RGB color.
 *
 *  @param brite The percentage to brighten or darken the original color.
 *  If positive, the original color is brightened toward white
 *  by this percentage. If negative, it is darkened toward black
 *  by this percentage.
 *  The range for this parameter is -100 to 100;
 *  -100 produces black while 100 produces white.
 *  If this parameter is 0, the RGB color returned
 *  is the same as the original color.
 *
 *  @return New RGB color.
 */
public static function adjustBrightness(rgb:uint, brite:Number):uint
{
	var r:Number;
	var g:Number;
	var b:Number;
 
	if (brite == 0)
		return rgb;
 
	if (brite < 0)
	{
		brite = (100 + brite) / 100;
		r = ((rgb >> 16) & 0xFF) * brite;
		g = ((rgb >> 8) & 0xFF) * brite;
		b = (rgb & 0xFF) * brite;
	}
	else // bright > 0
	{
		brite /= 100;
		r = ((rgb >> 16) & 0xFF);
		g = ((rgb >> 8) & 0xFF);
		b = (rgb & 0xFF);
 
		r += ((0xFF - r) * brite);
		g += ((0xFF - g) * brite);
		b += ((0xFF - b) * brite);
 
		r = Math.min(r, 255);
		g = Math.min(g, 255);
		b = Math.min(b, 255);
	}
 
	return (r << 16) | (g << 8) | b;
}

是不是很优雅。Adobe的精英工程师创造出来的,效率及简介性肯定可以保证,况且开源了,为啥不好好利用呢。flex code里有很多好货可以发掘。

另一款别致的AutoCompleteComboBox

原文见这里,名字叫FilterComboBox。继承自ComboBase,可以根据输入的文字来自动匹配dataprovider,并显示在下拉列表,相当实用的Flex组件

sample点击这里。右键可以查看源码

AIR开源项目教程系列(二)细化结构设计

假设之前已经有一张列表,描述操作流程(也就是初定下的需求)。下面就可以开始设计程序结构了。我觉得,拉起来就写code并不是多好的习惯,至少脑子里也该有个结构概念吧。

还是MVC

MVC是个永恒经典的结构模型,不光可以脱离UI的束缚,而且可以让人形成一种习惯,就是,没了UI也叫程序,让逻辑决定程序的走向。试想下,如果AIR项目没有UI那算啥。设计就要先从没有UI开始。这一点,flex和flash做得不是太好,因为程序的开头总是sprite或mxml。

所以说,细化程序结构的第一步就是拆分逻辑层和视图层。拿JonFTP为例,现在抛弃UI的概念,试想下一个FTP流程该什么样子。登录,上传,关闭。一个主要的流程就是如此。

workflow1

workflow1

若干流程的集合就是逻辑层,不需要想的太复杂,比如用户该怎么选怎么点,这是视图层该干的事情。

怎么把若干流程揉合在一起

我以前总是到最后才考虑怎么把各个功能综合起来,其实它应该在考虑细节之前考虑。比如上面讲的,登录,上传,关闭是一条路,登录,上传,下载,关闭也是条路,中间的操作可以任意组合而不应该含有冲突。也就是说,无论怎么变化,有几点是肯定的:

  • 登录,关闭一定是一条流程的首尾
  • 中间的操作可以任意变化,且不能相互冲突
  • 流程之前不能有联系(新的session需要用户身份)

于是,我就设计了这么个结构:

  • 准备一个“工厂”,产生,托管和消灭一条流程(Session)
  • 流程以登录操作为开始,以关闭操作为结束
  • 任何操作方式(包括登录和关闭)设计为独立的过程(process),过程之间可能要有联系。不要忘了,过程组合也是过程的一种。

初期我是这么考虑的,到了后来还是出现了一些变化,这是后话。

转换到计算机语言

有了上面的“大白话”结构,就可以用计算机语言(AS3)来描述了。相应的就是:

  • 准备一个全局的FTPClient类,代表一个session,实例由工厂方法或者工厂类产生。
  • 准备一个树状的继承结构,顶层为CProcess,代表一个过程(向FTP服务器请求并获得数据,解析),子类包括一个CGroup,可以add若干个CProcess,它代表一个过程组合(比如批量删除)。
  • FTPClient接受CProcess作为输入,执行并处理数据,CProcess以事件方式通知UI执行成功与否。

初期的设计就是如此,不过随着开发的进展,肯定会有修改甚至是推翻。不过都是正常的。这里总结下我的设计步骤

  1. 拆分逻辑层和视图层
  2. 先设计逻辑层
  3. 逻辑层以流程(session)为主导,不可依赖用户操作
  4. 以书面化形式描述各种流程,并寻找相同点和不同点
  5. 转换用计算机语言描述,并形成一个大致的架构
  6. 开发过程中不断修改

AIR开源项目教程系列(一)准备你的项目

今天开始系列教程的第一篇了,准备把我自己的AIR项目JonFTP的开发经验分享下。

调整你的精神状态

今天看了部片子叫《校花我爱你》(《I Love You, Beth Cooper》),我觉得用它来强调我们做事的动力再合适不过了。这部片子强调的一个主题就是“只留青春,不留遗憾”。当你要做一件事的时候,能避开人的惰性,避开世俗的眼光,才能不留遗憾。想做就做吧。

坚定你的想法

当你开始准备一个自己的项目的时候,初期的准备往往是很重要的。兵马未动粮草先行,用在项目开发上同样适用。拿JonFTP(一个FTP客户端)来说,首先需要考虑,这个项目是用来干嘛的,最好不要让你的概念模糊,不然以后会乱套,直接打击你并使你失去兴趣。所以第一桩事情就是反复对自己讲:这个东西是干嘛使的。目的就是给自己一个继续的理由,给项目一个目标。最好给自己准备一张白纸,写下你对这个项目的理解以及产品描述,贴在你的桌子上。

查看同类产品

你不会牛到发明吧(这样的话不必看下去了),呵呵,不管你的目的是不是抄袭,先看看同类产品。我这里说的看,不是去找源码,要明白的是,编码是后面的事情,初期先把自己当成一个不懂编码的普通用户,查看同类产品的目的。就是来坚定你的想法并核实产品描述的正确性,或者给自己一个直观体验,让描述更加具体。还是拿JonFTP来说,我需要做的就是找找比较有名的几个FTP客户端产品,比如FileZilla,这类成熟的产品往往在用户体验(操作体验)上也是成熟的。要借鉴的就是它的操作体验。你可以拿张纸随便涂鸦,先从简单的开始。还是拿FTP客户端为例,用FTP的操作大体上是:

  1. 准备host,用户名,密码连接远端的ftp服务器
  2. 连接失败后返回上一步,连接成功后到下一步
  3. 显示远端服务器的文件系统
  4. 做各种操作
  5. 关闭连接
  6. 退出程序

当然我的blog上只能用1234的标号,如果自己写的话可以随意的用树的方式组织(因为操作的流程总不可能是流线型的吧,分支合并非常常见),但一定要让自己看懂。不详细不要紧,因为借鉴总是反反复复的。

除了程序还需要什么

这个容易被忽视因为我们是写程序的。为啥要提到这个,我们的用户总不是写程序的吧,那么就需要照顾他们的感受。我觉得开源项目需要:

  • 官网 — 放你的blog里吧,包括系统介绍,和截图。
  • 用户手册 — 一定要的,不然没人会用,即使你的程序傻瓜到极点,要知道,没有最懒只有更懒的人。
  • 更新Log — 展示每次升级带来的好处。
  • 升级系统 — 最好不要每次都让用户去下载,尽量在程序中集成自动升级(不是强制升级)
  • 留言板 — 给反馈一个通道

Sun被甲骨文收购

这条新闻可算重磅啊。Sun作为java语言的领路人,是当年可以与Microsoft一较高下的明星企业,而到如今盛极而衰,落到被人收购的下场,不能不让人感叹。当然并不是说java算玩完了。我不是资深业内认识,来看看一些专家的评论吧:

http://news.csdn.net/n/20090320/124301.html

我挺赞同他关于开源的论述。 开源这个玩意儿现在被炒得太热了,是时候该冷静下来看看IT的本质,IT该怎么发展该怎么走,并不是一个“开源”能解决的事。事实上,说它是趋势还太早,只能说它是一种手段,只是众多赚钱手段的一种。

Linux下的.Net

早上晃了下csdn,看着这么一篇文章:Mono 2.0 发布 Linux 上的 .NET 框架成熟了吗?。很有意思哦,开源社区打算把.net framework重新实现在linux上,做出C#的linux版编译器,linux版CLR。仇人也能结亲家,IT真是很有意思,能人辈出。