七巧板 Chi7ren V0.1

2023-12-02 10:58
文章标签 v0.1 七巧板 chi7ren

本文主要是介绍七巧板 Chi7ren V0.1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Chi7ren
Version 0.1


    著名哲学家伯利克里:”一个有思想,但是不能表达的人,如同自己没有思想。“

前言
    前阵子看《COM技术内幕》,知道提供的最后一个程序是“七巧板”程序,当时看前几章的时候也很期待,那个Tangram程序会是怎么样的?看了介绍好像还有GDI版和OpenGL版,可以选择。甚是期待,但也是一直没去编译提供的源代码,只是按每一章的代码,去一章一章的去实现,想按“顺序”很自然的到最后一章,可以揭开它的“神秘面纱”。
     有一天,我觉得我应该看看到底是个怎么样的“七巧板”了,以为很酷很帅的。就开始去编译源代码,结果遇到了点小麻烦,还好网上搜了下,还是把一个个错误给解决了。直到编译通过,生成EXE了。打开一看,啊,太失望了。不管是GDI,还是OpenGL都是那么“难看”。但是想想,《COM技术内幕》当然是讲COM为主啦,至于最后的Tnagram也只是对所有COM知识的一次汇总,但是具体代码没去研究,觉得还是很神奇。毕竟看了《COM技术内幕》还是有很大的收获,不过忘了做点笔记,想想看书还是得做点笔记好,以后可以翻阅,有据可查。
     一直也想写个小游戏,可一直不知道该写什么,又想把看《Windows程序设计》的过程中能写点东西,加深对Windows SDK编程的理解,特别是消息机制的理解。还有就是家里可爱的小外甥,小外甥女,如果做的好的话,能给他们玩“舅舅做的游戏”,也是很酷的一件事。又觉得自己一直在看书,想问题,却很少动手写点东西,实践动手编程的能力实在有待提高。基于以上几点,“Chi7ren”(“七小孩”自己取的代号)就开始了...


    有的时候,想是一回事,做又是一回事,写代码又是另一回事!

开发:

 图形结构:

    先把“七小孩”给画出来吧。我把坐标都定死了,我的设想应该是按客户区的大小是可以伸缩的,这也是一个验证的过程,不管怎么样先把图呈现出来先。画图是比较容易的,建立颜色画刷(CreateSolidBrush),选进设备描述表(SelectObject),画多边形(Polygon),一切都那么容易...   

     既然是“七巧板”,当然要七种颜色,我想到了彩虹的七颜色,所以在网上搜了他们的“资料”:
       赤色 【RGB】255, 0, 0     【CMYK】 0, 100, 100, 0
     橙色 【RGB】255, 165, 0 【CMYK】0, 35, 100, 0
     黄色 【RGB】255, 255, 0 【CMYK】0, 0, 100, 0
     绿色 【RGB】0, 255, 0     【CMYK】100, 0, 100, 0
     青色 【RGB】0, 127, 255 【CMYK】100, 50, 0, 0
     蓝色 【RGB】0, 0, 255     【CMYK】100, 100, 0, 0
     紫色 【RGB】139, 0, 255 【CMYK】45, 100, 0, 0

    (说明:这里的显示颜色和具体的RGB并不配对,只是为了好看!!)
     "小孩"的结构:
     struct TangPolygon
    {
        POINT polyPoint[4];    //多边形点,因为最多四边形,为简单就设为“四个点”
        COLORREF rgb;        //图形颜色
        size_t polyType;        //图形类型,即 3:三角形;4:四边形
        float angle;        //保存“世界坐标”角度,绘图时用
    };


 图形移动:
    要实现图形的移动,首先得判断此时该移动哪个图形?通过鼠标左键单击,选择“激活”一个图形,然后鼠标拖动这个图形。然而问题是如何判断哪个图形被激活呢?难道还用判断鼠标坐标在哪个图形的“包围盒”内??这就麻烦了...后来想想,诶,我不是有每个图形的颜色吗?为什么不通过GetPixel得到当前鼠标位置的颜色,再和“七小孩”逐个比较不就知道哪个被激活了吗?这就大大简化了编码难度,也相当实用。

 图形旋转:
    这一点是我一开始就知道的可能难点所在!开始的时候,在想能有OpenGL里的坐标变换就好了,想当然的以为Win32 API应该没有这提供类似函数吧。然后试着通过改变顶点的坐标来实现图形的旋转,发现这实在有难度,大量的计算还不一定准确,难道没办法了吗??后来就去网上搜Win32 API有没有坐标变换的现成函数,啊哈、、还是被我找到了,说《Windows图形编程》里有提到这方面的内容,正好有电子书,也就去翻了下,还是找到了解决方法,以为之前学过OpengGL三维编程,理解这种坐标变换还是不难。关键还是这个函数ModifyWorldTransform,实现了左边转换。具体过程类似图1所示:

图1:坐标变换

SHOW:

当你有个锤子的时候,什么东西看起来都像是钉子。   
                                                                                          
-摘自《世界因你不同》

P.S.:
    程序就像版本号一样(Version0.1),只是个简单的雏形,对于程序的改进可能会继续,我想后续版本的改进可能会出于以下几个方向:
  1. 将Win32 API封装,这样有利于后续开发,也有利于对“面向对象思想”的加深理解;
  2. 将《Windows程序设计》中每章的内容都融入在程序中,这样有利于对Win32编程的进一步掌握和理解;
  3. 使用3D图形库如OpenGL进行开发,用户可选择;
  4. 结合招聘各种能力,锻炼各种能力;
  5. ...   
希望:多指点,多提意见,感激不尽!

致谢:
  • 感谢我的室友,Zhu,感谢他一直的鼓励,也感谢他提的一些宝贵意见。
  • 还有最近看的几本书对我的影响《把时间当做朋友-运用心智获得解放》,特别是其中提到《奇特的一生》中的事件-时间日记;以及李开复自传《世界因你不同》,让我不停的寻找发自内心的声音,里面的很多方法如“新闻头条”,“墓志铭”,“从心选择”,也让我受益匪浅。  

成功并没有绝对的意义,成功,就是做最好的自己,并把最好的你呈现出来。 

源代码:
/ //
//Author:    shenzi
//Date:       2009.12.15
//Version:    0.1
///

#include
#include
#include
#include "resource.h"

//右键点击“七巧板”,旋转的角度,5度
const float acc = static_cast(5.0/180.0*3.1415926);

//“七巧板”图形的多边形结构
struct TangPolygon
{
    POINT polyPoint[4];    //多边形点,因为最多四边形,为简单就设为“四个点”
    COLORREF rgb;          //图形颜色
    size_t polyType;       //图形类型,即 3:三角形;4:四边形
    float angle;           //保存“世界坐标”角度,绘图时用
};

//预设的“七巧板”
TangPolygon g_Tangram[7] = {
    {{0, 0, 0, 320, 160, 160, 0, 0},RGB(255, 0, 0)/*赤色*/ ,3, 0},    
    {{0, 0, 160, 160, 320, 0, 0, 0},RGB(255, 165, 0)/*橙色*/ ,3, 0},
    {{0, 320, 160, 320, 80, 240, 0, 0},RGB(255, 255, 0)/*黄色*/ ,3, 0},
    {{160, 160, 240, 240, 240, 80, 0, 0},RGB(0, 255, 0)/*绿色*/ ,3, 0},
    {{160, 320, 320, 320, 320, 160, 0, 0},RGB(0, 127, 255)/*青色*/ ,3, 0},    
    {{80, 240, 160, 320, 240, 240, 160, 160},RGB(0, 0, 255)/*蓝色*/ ,4, 0},
    {{240, 80, 240, 240, 320, 160, 320, 0},RGB(139, 0, 255)/*紫色*/ ,4, 0}
                         };

/ //
//Author:    shenzi
//Date:        2009.12.15
//Version:    0.1
///

#include "Tangram.h"

//窗口过程函数
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

//辅助函数,得到图形的中心坐标
POINT  GetCenter(POINT *pPoint, size_t size);

//主函数
int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PTSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("Tangram");
    HWND hwnd;
    MSG msg;
    WNDCLASS wndclass;

    wndclass.cbClsExtra        = 0;
    wndclass.cbWndExtra        = 0;
    wndclass.hbrBackground    = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
    //画了个“七巧板”ICON
    wndclass.hIcon            = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TANGRAM));
    wndclass.hInstance        = hInstance;
    wndclass.lpfnWndProc    = WndProc;
    wndclass.lpszClassName    = szAppName;
    wndclass.lpszMenuName    = NULL;
    wndclass.style            = CS_HREDRAW | CS_VREDRAW ;

    if (!::RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("Erroe:..."), TEXT("Error"), MB_ICONERROR);
        return 0;
    }
    
    hwnd = ::CreateWindow(szAppName,
                        //取了个名字“七小孩”,版本就是0.1了,以后可能慢慢完善。
                        TEXT("Chi7ren! Version 0.1"),
                        WS_OVERLAPPEDWINDOW | WS_VSCROLL,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        NULL,
                        NULL,
                        hInstance,
                        NULL);

    ::ShowWindow(hwnd, iCmdShow);
    ::UpdateWindow(hwnd);

    while(::GetMessage(&msg, NULL, 0, 0))
    {
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }

    return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    //客户区大小
    static int cxClient, cyClient; 
 

    HDC hdc, hdcMem ;    
    HBITMAP  hBmp;
    HBRUSH hbrush;
   
    static int priX, priY;
    int moveLenthX, moveLenthY;

    //指定当前可移动的“小孩”。
    static int movePolygon;        
    PAINTSTRUCT ps;

    COLORREF color;
    POINT center;
    unsigned int i;

    //“世界坐标”旋转用到的两个XFORM结构
    static XFORM Tansform = {1, 0, 0, 1, 0, 0};
    static XFORM Tanslate = {1, 0, 0, 1, 0, 0};

    switch (message)
    {
        //窗口大小改变时,得到新的客户区大小;
    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);    
        return 0;
        //鼠标左键,确定当前可移动的图形
    case WM_LBUTTONDOWN:    
        priX = LOWORD(lParam);
        priY = HIWORD(lParam);

        hdc = ::GetDC(hwnd);
        color = ::GetPixel(hdc, priX, priY);
        for (i = 0; i < 7; i++)
        {
            if (color == g_Tangram[i].rgb)
            {
                movePolygon = i;            
                break;
            }
        }
        ::ReleaseDC(hwnd, hdc);
        return 0;
        //鼠标右键,实现图形的旋转功能,"SHIFT"改变旋转方向;
    case WM_RBUTTONDOWN:        
        priX = LOWORD(lParam);
        priY = HIWORD(lParam);
        
        hdc = ::GetDC(hwnd);
        color = ::GetPixel(hdc, priX, priY);
        for (i = 0; i < 7; i++)
        {
            if (color == g_Tangram[i].rgb)
            {
                movePolygon = i;
                if (wParam & MK_SHIFT)
                {
                    g_Tangram[i].angle += acc;
                }
                else
                {
                    g_Tangram[i].angle -= acc;
                }
                break;
            }
        }
        ::ReleaseDC(hwnd, hdc);
        ::InvalidateRect(hwnd, NULL, FALSE);
        return 0;
        //鼠标移动并且左键按下,得到移动距离,并重绘
    case WM_MOUSEMOVE:
        if (wParam & MK_LBUTTON)
        {
            moveLenthX = LOWORD(lParam) - priX;
            moveLenthY = HIWORD(lParam) - priY;
            priX = LOWORD(lParam);
            priY = HIWORD(lParam);

            for (i = 0; i < g_Tangram[movePolygon].polyType; i++)
            {
                g_Tangram[movePolygon].polyPoint[i].x += moveLenthX;
                g_Tangram[movePolygon].polyPoint[i].y += moveLenthY;
            }        
        }
        ::InvalidateRect(hwnd, NULL, FALSE);
        return 0;
        //状态改变时,绘图
    case WM_PAINT:
        hdc = ::BeginPaint(hwnd, &ps);
 
        //兼容DC,并选进相应的位图,解决“屏幕闪烁”问题;在兼容DC上画图,
        //画完后再BitBlt到客户区,实现双缓存。

        hdcMem = ::CreateCompatibleDC(hdc);
        hBmp = ::CreateCompatibleBitmap(hdc, cxClient, cyClient);
        ::SelectObject(hdcMem, hBmp);

        //为选进位图设定背景:白色
        ::PatBlt(hdcMem, 0, 0, cxClient, cyClient, WHITENESS);

        //设定设备描述表高级图形模式,允许全局转换,即实现图形世界坐标转换;
        ::SetGraphicsMode(hdcMem, GM_ADVANCED);

        //绘制“七巧板”
        for (i = 0; i < 7; i++)
        {
            //得到当前处理图形的中心点
            center = GetCenter(g_Tangram[i].polyPoint, g_Tangram[i].polyType);

            //全局转换:
            //1.重置当前全局转换

            ::ModifyWorldTransform(hdcMem, NULL, MWT_IDENTITY);
            
            //2.先把世界坐标移到“中心”点
            Tansform.eDx = static_cast(-center.x);
            Tansform.eDy = static_cast(-center.y);
            ::ModifyWorldTransform(hdcMem, &Tansform, MWT_RIGHTMULTIPLY);

            //3.再做旋转
            Tanslate.eM11 = cos(g_Tangram[i].angle);
            Tanslate.eM12 = -sin(g_Tangram[i].angle);
            Tanslate.eM21 = sin(g_Tangram[i].angle);
            Tanslate.eM22 = cos(g_Tangram[i].angle);
            ::ModifyWorldTransform(hdcMem, &Tanslate, MWT_RIGHTMULTIPLY);

            //4.最后移回原处
            Tansform.eDx = static_cast(center.x);
            Tansform.eDy = static_cast(center.y);
            ::ModifyWorldTransform(hdcMem, &Tansform, MWT_RIGHTMULTIPLY);

            //选定图形颜色,绘制该图形
            hbrush = ::CreateSolidBrush(g_Tangram[i].rgb);
            ::SelectObject(hdcMem, hbrush);         
            ::Polygon(hdcMem, g_Tangram[i].polyPoint, g_Tangram[i].polyType);
            ::DeleteObject(hbrush);        
        }

        //****重置全局转换,不知道为什么需要加这条语句,不加这条语句最后个图形的
        //旋转就会处问题。

        ::ModifyWorldTransform(hdcMem, NULL, MWT_IDENTITY);

        //把结果“贴到”客户区
        ::BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY);

        //删除创建的对象
        ::DeleteObject(hBmp);
        ::DeleteDC(hdcMem);

        ::EndPaint(hwnd, &ps);
        return 0;
    case WM_DESTROY:
        ::PostQuitMessage(0);
        return 0;
    }
    return ::DefWindowProc(hwnd, message, wParam, lParam);
}

POINT  GetCenter(POINT *pPoint, size_t size)
{
    unsigned int i = 0;
    POINT center = {0, 0};
    for (i = 0; i < size; i++)
    {
        center.x += pPoint[i].x;
        center.y += pPoint[i].y;
    }
    center.x /= size;
    center.y /= size;
    return center;
}









 

这篇关于七巧板 Chi7ren V0.1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/445081

相关文章

面向对象设计的五大原则:SOLID原则(聚合和耦合)_v0.1.0

文章目录 聚合、组合与耦合1. **聚合(Aggregation)**2. **组合(Composition)**3. **耦合(Coupling)**比较总结总结 面向对象设计五大原则:SOLID原则1. 单一职责原则(Single Responsibility Principle,SRP)原则解释举例说明初始设计(不符合单一职责原则)改进后 2. 开闭原则(Open/Closed Pr

【Rust日报】2020-10-23 - rust-gpu v0.1发布,尝试让Rust成为GPU编程的一等语言

rust-gpu v0.1发布,尝试让Rust成为GPU编程的一等语言 纵观游戏开发的历史,离不开GPU编程,其中最为重要的一个概念是Sharder language,即着色器语言。如今主流的着色器语言主要有三种: 基于 OpenGL 的 OpenGL Shading Language,简称 GLSL;基于 微软DirectX 的 High Level Shading Language,简称 H

Codestral-22B-v0.1-4bit部署

Codestral-22B-v0.1-4bit                        模型文件地址         mistral-inference                                    仓库文件地址 一、Codestral-22B-v0.1环境安装 1、硬件配置 2、配置环境 建议最好自己新建一个con

Ollama本地运行 Codestral-22B-v0.1

Ollama本地运行 Codestral-22B-v0.1 0. 引言1. 运行 codestral:22b-v0.1-q8_02. 简单测试下它的代码能力 0. 引言 Mixtral 5月30日发布了 Codestral-22B-v0.1。 Codestrall-22B-v0.1 在 80 多种编程语言的多样化数据集上进行训练,包括最流行的语言,例如 Python、Java、

行军图生成器V0.1版

行军图生成器V0.1版 问题的引出思路实现界面和效果展示 问题的引出 六月份几乎一行代码都没写,因为去了一趟西藏。回来之后,忙着做视频,做了半个月,总算完成了日记部分。视频当中要用到地图,想着学别人的样子做个地图的小动画,没想到找了半天也没找到好的方法。网上可以用的是利用PPT 动画生成办法,可以用,但是效果不好。如果线路不是单调的,PPT生成的动画会出现,不是沿着道路前进的现象

最强开源模型 Mixtral-8x7B-Instruct-v0.1 详细介绍:稀疏 Mixtral of experts

LLM votes 评测排行榜: https://huggingface.co/spaces/lmsys/chatbot-arena-leaderboard 模型链接: ​​​​​​https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1

EOJ-大学生程序设计邀请赛(华东师范大学)-I-七巧板

ACM模版 描述 题解 计算几何问题……不难,就是麻烦,精度问题也需要着重注意,注意人家输入精确到 10−12 10^{-12},而不是拼接时精确到 10−12 10^{-12}! 我是通过判断面积是否可以构成正方形(与最大边符合),三角形是否有五个,四边形是否有两个,七个多边形一共23条边排序后是否符合七巧板的规格等等,当然,我这个也不是最简单的,完全可以通过判断多边形之间各

java重构工具_Piranha (过时代码自动重构工具)免费版v0.1.2

Piranha是一款代码重构工具,软件中使用了和陈旧标志相关的代码,还会对标志进行自动重构,用户可以在软件中输入一定的命令,去对标志的名称和预期进行行为的干预,软件将会使用这些输入的内容来根据预期的行为对代码进行重构。 软件介绍 Piranha是一个自动重构与陈旧标志相关代码的工具。在更高的层次上,该工具的输入是标志的名称和预期的行为,在属性文件中指定了与标志相关的API列表。Piranha将

安卓第一阶段实训项目:基于存储卡音乐播放器v0.1(实训报告)

基于存储卡音乐播放器V0.1 (一)功能要求 1.播放存储卡上一首音乐 2.播放|暂停按钮,可切换 3.显示要播放的音乐名 4.要求窗口有背景图片 (二) 知识点 1.按钮(Button) 2.标签(TextView) 3.进度条(ProgressBar) 4.拖拽条(SeekBar) 5.列表控件(ListView) 6.单选按钮(RadioButton) 7.媒体播放器(MediaPl

A Fault-Tolerant、Self-heal、Hot-upgrade、Distributed design methodology v0.1

本文描述了一种容错、自恢复、热升级、分布式系统的设计方法和框架,其在实践中被证实为一种可靠、可行的方法学。 一、Fault-Tolerant 容错最常用的思想之一是冗余redundancy,防止单点故障SPOF;最常用的机制是复制。 容错设计需要有一个清晰的容错模型Fault Model,它包括故障状态Fault State,状态取得,高级些的特性包括故障传播Failure Propa