数据类设计_图片类设计之8_自由图形类设计_(前端架构)

前言

学的东西多了,要想办法用出来.C和C++是偏向底层的语言,直接与数据打交道.尝试做一些和数据方面相关的内容

引入

前面的内容都是矩阵图形类,现在讨论自由图形类设计

矩阵图形类和自由图形类的差别

左图为矩阵图形类对象,右图为自由图形类对象.矩阵图形类对象单独占据一个矩形框大小的位置,自由图形类对象是单独图形.在拖动时,左边对象带着矩形框,而右边不用.

自由图形类定义

自由图形类和前面的不规则图形类是差不多的,只不过当时举了一个字符的例子,算一个特例,现在让自由图形回到他最初的样子---像素图

复制代码
//自由图形类(像素图)定义
struct Pixel_pic{
    vector<Pixel_point> pps;    //像素点集合
}

//像素点类型定义
struct Pixel_point{
    short x_cord;
    short y_cord;
    short red;
    short green;
    short blue;
}

说明:这里的像素点定义和前面的字符定义有所区别,加上了颜色.原因是节省空间.试想有10000个字符,每个字符平均有50个屏幕点,那么节省空间有10000x50x6=300万字节,即3MB,看起来不大但无颜色的更简洁.

多张像素图的混合

顾名思义,几张图合成一张图,具有层叠效果,区别于矩阵图形类对象.例如上一张图可以看作是"/"和"\"的组合.

1>形式选择

前面矩阵图形类采用函数的写法,这里用类的写法.如果采用"数据类"定义的话,如下

复制代码
//自由图形类(像素图)定义---不好用
struct Pixel_pic{
    vector<Pixel_point> pps;    //像素点集合
    vector<Pixel_pic>   pcs;    //像素图由其他像素图组成
}

和前面的矩阵类定义比起来,看起来有些别扭,因为矩阵类对象用了散列表,而这里好像也不需要.所以考虑用工具类定义.

工具类用什么名称呢?前面有提到过类名要使用名词.建议采用generator或者builder,表示"生成器",用Pixel_pic_Builder.

复制代码
//像素混合器定义
class Pixel_pic_Builder{
    vector<Pixel_pic> pps;
    ...                    //内容暂定
}

2>混合算法

笔者尝试了两种方案,也可以作为一种思维的锻炼.

方案一

代码思路:

1)生成的最终对象,仍是Pixel_pic对象,即"原材料"和"产品"都是相同的数据类型

  1. 在一个矩形方框内混合,每加一张图,每加一个点,去遍历之前存在的点,如果没有,则添加,如果有,则修改.

===============================内容分割线↓=================================

问题:如何确定矩形方框的大小?有一个办法:修改像素图定义如下

复制代码
//更新并略过---自由图形类(像素图)定义
struct Pixel_pic{
    vector<Pixel_point> pps;    //像素点集合
    short length;               //图的长度
    short height;               //图的高度
}

然而这个是无法确定的,因为考虑到直接叠起来的高度比较高,因此略过这一点.

对于高度的问题,可以固定一个,例如软件里的一个框,让像素图的高度来适应他.

===============================内容分割线↑=================================

复制代码
//像素混合器定义---不成熟方案
class Pixel_pic_Builder{
    public:    
        //materials原材料像素图集合;result结果像素图
        Pixel_pic build(vector<Pixel_pic> & materials,Pixel_pic& result){
            //遍历原材料像素图集合
            for(msd=materials.begin();msd!=materials.end();msd++){
                //遍历原材料像素图中的点
                for(msdd=(*msd).pps.begin();msdd!=(*msd).pps.end();msdd++){  
                    //遍历结果像素图中的点              
                    for(rtd=result.pps.begin();rtd!=result.pps.end();rtd++){
                         //点已存在   
                         if((*msdd).x_cord==(*rtd).x_cord)&& (*msdd).y_cord==(*rtd).y_cord){                             
                            //颜色覆盖 
                             (*rtd).red=(*msdd).red;
                             (*rtd).green=(*msdd).green;
                             (*rtd).blue=(*msdd).blue;
                         }
                          //否则加上这个点
                         else
                            result.pps.add(Pixel_point{(*msdd).x_cord,(*msdd).y_cord,(*msdd).red,(*msdd).green,(*msdd).blue});
                     }       
                }
            }
        return result;
        }           
}

说明:遍历图的每一个点,同时遍历已生成的结果图里的点,查询是否有坐标重叠.如果坐标已存在,则用新点颜色覆盖;如果坐标未存在,则在结果中加上这个点.

这个写法非常复杂,而且时间复杂度达到n的3次方了---有一层是像素图动态数组,不算在内的话,复杂度是n的2次方.如果不是没有其他选择方案,不会被用于工程中.

方案二

代码思路:用一个辅助的矩阵类对象.

1>将像素图混合到矩阵类对象中,并记录图中所有点经过的位置.

2>重新遍历矩阵类对象,取出其中经过位置的点组成像素图.

1.定义一个辅助矩阵类

复制代码
//辅助矩阵点定义
struct Assistant_point{
    bool is_choosed;
    short red;
    short green;
    short blue;
}

//辅助矩阵类定义
struct Assistant_matrix{
    short length;
    short height;
    vector<vector<Assistant_point>> aps;
}

为了让程序清晰,不把所有像素图放一起,而是采用每一张都和矩阵类对象混合.引用上面的工具类来做这件事:

2.将像素图写入辅助矩阵类对象

复制代码
//像素混合器定义
class Pixel_pic_Builder{
    public:
        Assistant_matrix & build_in(short x_ref,short y_ref,Assistant_matrix & ax,Pixel_pic & source){    
            //辅助矩阵类对象的初始行指针,定位到被放入像素图的基点位置
            auto axd=ax.aps.begin()+x_ref;
            //遍历像素图
            for(pcd=source.pps.begin();pcd!=source.pps.end();pcd++){
                axd=axd+(*pcd).x_cord;                    //行指针偏移
                //*axd表示得到该行,行仍然是一个vector对象,所以调用begin()基点位置,并计算坐标
                auto axdd=(*axd).begin()+y_ref+(*pcd).y_cord; 
                (*axdd).red=(*pcd).red;
                (*axdd).green=(*pcd).green;        
                (*axdd).blue=(*pcd).blue;   
                (*axdd).is_choosed=true;                   //该点已被选中
            }
        //返回辅助矩阵类对象
        return ax;                                        
        }

}

上面混合了一张图,按照这方法并可以把所有需要混合的图都写入辅助矩阵类对象.

3.将想要得到的Pixel_pic对象从辅助矩阵类对象中抽出来

本来可以用前面的build_in函数写在一起,为了看得清楚一些,分成了两个程序来写.

复制代码
//像素混合器定义---有问题不能用
class Pixel_pic_Builder{
    public:
        Pixel_pic & build_out(Assistant_matrix & ax){ 
            //生成一个空的对象表示结果
            Pixel_pic result();   
            for (short i = 0; i <ax.height; i++)
                for (short j = 0; j <ax.length; j++){
                    //如果显示被标记
                    if(ax[i][j].is_choosed){
                        result.pps.push_back(Pixel_point{i,j,ax[i][j].red,ax[i][j].green,ax[i][j].blue});
                    }    
                }

            }
        return result;
        }
}

这里没有用二维数组的两次vector遍历,用了C语言一样的[][]来表示元素,意思是一样的.如果不成功,可以改成迭代器遍历.

更新

果然上面代码有点问题,修改如下:

复制代码
   Pixel_pic& build_out(Assistant_matrix& ax) {
        //生成一个空的对象表示结果
        Pixel_pic result;
        short i = 0,j=0;
        for ( auto axd=ax.aps.begin() ; axd!=ax.aps.end();axd++,i++)
            for (auto axdd = (*axd).begin(); axdd != (*axd).end(); j++) {
                //如果显示被标记
                if ((*axdd).is_choosed) {
                    result.pps.push_back(Pixel_point{ i,j,(*axdd).red,(*axdd).green,(*axdd).blue });
                }
            }
        return result;
    }

现在可以得到一个以辅助矩阵类对象基点作为基点的像素混合图

问题

代码里有个问题,辅助矩阵类对象的长和高,像素图的长和高,没有表示.怎么解决?

1.不解决

假设辅助矩阵是在ps软件中的画布,给他固定一个尺寸,然后规定像素图的长和高比他小才能用

2.部分解决

给像素图设置两个属性,即修改定义如下:

复制代码
//自由图形类(像素图)定义
struct Pixel_pic{
    short height;
    short length;
    vector<Pixel_point> pps;    //像素点集合
}

再写个算法,像素图超过尺寸后截取图像,规定尺寸小于矩阵对象才能混合.

这样做可能还会有问题.因为限制了图形尺寸功能差许多.

还可以想到的解决方法:把源像素图放到另一个场景中,根据情况从另一个场景写到当前画布来.

重申:毕竟是为了开拓思路而写的帖子,不是真正开发个ps软件,写工程级别代码遇到什么问题再说.

小结

自由图形类的混合算法,从中可以看出解决问题有多种方案,从中选择适当的使用.

每个类型设计中,属性定义很重要;不过也不要太纠结,想到什么都给他写上去也不会错.

相关推荐
sakibcc5 分钟前
Cursor使用指南
前端·程序员·cursor
Monica996 分钟前
BFCache和浏览器缓存
前端
小冯的编程学习之路9 分钟前
【C++项目实战】:基于正倒排索引的Boost搜索引擎(1)
开发语言·c++·搜索引擎
Lecea_L11 分钟前
MockPilot2 Review
前端·next.js
ScilogyHunter12 分钟前
探索Google Test(gtest):C++单元测试的强大工具
c++·单元测试·gtest
了不起的大喜17 分钟前
HarmonyOS-订阅网络状态变化&RCP访问网络
前端
渴望成为python大神的前端小菜鸟17 分钟前
2025前端面试题(vue、react、uniapp、微信小程序、JS、CSS、其他)
前端·javascript·vue.js·面试·微信小程序·uni-app·react
晚风91417 分钟前
Vue 3中的Teleport:超越组件边界的渲染
前端·javascript·vue.js
Cutey91620 分钟前
深拷贝与浅拷贝详解(包含手写深拷贝与浅拷贝实现)
前端·javascript·面试
了不起的大喜22 分钟前
HarmonyOS-ArkUI
前端