C#: 星座星盘计算算法

前一篇提到计算八卦五行的算法,这里要跟大家分享一个星座星盘的算法。你们可能觉得笔者怎么开始研究这些玄幻的东西了,确实笔者觉得有一些真的是很扯,不过笔者的目的是为了研究大数据。好了,说到星盘笔者发现新浪星座有个很不错的星盘解说的http://astro.sina.com.cn/pc/zodiac.html大家可以试一下,笔者就觉得分析出来的星盘那个图很不错看起来很专业,图里面的也是数据格式的而不是底下文字描述的。后来想想,星座这种东西应该国外比国内更多研究,于是就搜了一些英文资料。(这里也鼓励大家多学一门外语总是好的)。居然无意中发现新浪星盘用的就是国外的Astrolog,还是开源的,从版本上看是5.416,而这个Astrolog是一直有更新的,目前已经是6.10版本了。新浪还有不少收费占卜的,笔者没试过,因为这并不是笔者看重的。


不敢独享,跟大家分享一下,官网是http://www.astrolog.org/可以下载到源代码,是C++的,很明显大家猜笔者会把这个改成C#版的,更重要的是,改成中文版的。哈哈,笔者也这么认为的,不过代码量太大,就不重写了,另外由于里面有不少C的写法比如sprintf要支持中文比较麻烦,而且已经有人做过中文版软件,这不是我目的,所以打包成dll让C#调用,中文部分根据输出在C#代码处理会比较可行。

在代码之前,笔者先分享一些基本知识,首先是12星座。



其次是星和行星



上面的太阳(Sun)和月亮(Moon)就不必解释了,其他的行星都给出了英文名、符号和解释。网络的图没有冥王星英文是(Pluto)。


好了开始代码部分,首先我们要添加用于C#访问的函数,

#define API_EXPORT __declspec(dllexport)

先这里做个预定义,后面每个函数都要用到。使用功能之前要先给astrolog程序来做个初始化

EXTERN_C API_EXPORT void __stdcall init()
{
is.S = stdout;
FProcessSwitchFile(DEFAULT_INFOFILE, NULL);
is.fSzPersist = fTrue;
}


初始化好了就可以调用实质的函数来生成星图,保存星图到文件夹,并把右侧数据信息保存到字符串来返回

EXTERN_C API_EXPORT wchar_t* __stdcall ProcessAstrolog(wchar_t* filepath, int year, int month,int day,double time)
{
AllInfo = (char*)malloc(5000 * sizeof(char));


if (AllInfo == NULL) return NULL;


char* result;

int i=0,j=0;
ciCore = { month, day, year, time, 0.0, 8.0, 122.19984, 47.36584, "", "" };
char *v0 = "astrolog";
char *v1 = "-Xo";
char *v2 = w2c(filepath);
if (v2 == NULL) return NULL;
char * vs[] = { v0, v1,v2 };
i= FProcessSwitches(3, vs);

Action();


sprintf(result, "%s", AllInfo);
free(v2);
v2 = NULL;
free(AllInfo);
AllInfo = NULL;


return c2w( result);
}

EXTERN_C API_EXPORT int __stdcall freeSMem(wchar_t* intptr)
{
free(intptr);
intptr = NULL;
return 1;
}

这里面还涉及到C#的char是用2个字节来存储的而在C++里面char是用1个字节来存储的,从这里大家也可以理解为什么笔者放弃在C++里面直接汉化输出了。既然有这么个gap,我们就需要做转换工作,C#里面的char对应着C++里面的wchar_t,传进来之后要把高位的扔掉,生成一个长度相等,每位是C++的char大小的空间来存放新字符串,反之从C++的字符串传到C#的也要做一次这样的反操作。大家可以不理解,直接拷贝下面的代码用就是了。上面的freeSMem函数是因为返回的字符串内容要在C#里面用完了才能销毁,所以有这个函数供C#来调用并销毁。


wchar_t* c2w(char* CStr)
{
size_t len = strlen(CStr) + 1;
size_t converted = 0;
wchar_t *WStr;
WStr = (wchar_t*)malloc(len * sizeof(wchar_t));
if (WStr == NULL) return NULL;
mbstowcs_s(&converted, WStr, len, CStr, _TRUNCATE);
return WStr;
}


char* w2c(wchar_t* WStr)
{
size_t len = wcslen(WStr) + 1;
size_t converted = 0;
char *CStr;
CStr = (char*)malloc(len * sizeof(char));
if (CStr == NULL) return NULL;
wcstombs_s(&converted, CStr, len, WStr, _TRUNCATE);
return CStr;
}

上面的c2w和w2c里面的c和w分别代表C++的char和wchar_t。

好了可以介绍上面这个ProcessAstrolog()函数了,首先给AllInfo 分配了一段内存来保存右侧数据信息用来返回到C#,然后更新用户数据包括年月日时间等的信息,即更新ciCore变量,接着模拟执行一条保存星图的命令,这个其实大家可以使用cmd尝试执行Astrolog.exe -Xo d:\abc.bmp这样的语句,就知道本函数的方法了。传进去后保存图片并不是立刻执行的,所以需要加入Action()这一句来保存图片,最后释放指针并返回字符串结果。

然后就到C#代码了,见下面

[DllImport(@"Astrolog.dll")]
        extern unsafe static void init();

[DllImport(@"Astrolog.dll")]
        extern unsafe static IntPtr ProcessAstrolog(char* filepath, int year, int month, int day, double time);

先定义DllImport,这个不难。


 void processastrolog()
        {
            try
            {
                DateTime t = this.dateTimePicker1.Value;
                string filepath = "d:\\lyx\\xyz.bmp";
                int freeresult=0;
                unsafe
                {
                    
                    //在传递字符串时,将字符所在的内存固化,并取出字符数组的指针
                    fixed (char* p = &(filepath.ToCharArray()[0]))
                    {
                        //调用方法
                        IntPtr abc = ProcessAstrolog(p, t.Year, t.Month, t.Day, Convert.ToDouble( (t.Hour+t.Minute/100.0).ToString("0.00")));


                        if (abc == null) {
                            MessageBox.Show("Astrolog处理出错!");
                            return;
                        }


                        this.richTextBox1.Text += Marshal.PtrToStringAuto(abc);


                        freeresult= freeSMem(abc);
                    }
                }
                if (File.Exists(filepath))
                {
                    this.pictureBox1.ImageLocation = filepath;
                }
                MessageBox.Show(freeresult.ToString());
            }
            catch
            { }
           
        }

然后要先建1个图片链接字符串,固化到内存并把内存首地址传进dll,如果用过C#做图像处理的应该对锁内存很熟悉吧。然后把图片地址,年月日时间等传进dll,获取返回的字符串连接,并输出到文本框,因为这个字符串所在的内存是C++里面动态开辟的,所以需要释放,最后加载图片就可以了。

C++修改项目属性为输出dll而不是exe,修改C#的项目属性,将目标平台设置为x86,并且允许非安全代码。

一切都很不错,成功执行,成功保存图片并返回字符串结果。可惜的是,运行不了多久就会内存报错,这真的是百思不得其解的郁闷事,笔者怎么说写代码15年了也是混过C和C++的,包括单片机的汇编,内存管理大家都知道是个头疼事不过笔者还是挺自信的,仔细检查一下,所有的malloc之后都free了,并设置指针指向NULL了,C#里面也把代码都放进try catch里面了,还是报错,而且内存错误是致命的不可能继续执行。

万般无奈之下,笔者开始了另一种方式,在C#里面开辟内存地址存放返回的字符串传给C++,而C++里面的只要有malloc那么在返回到C#之前就free掉,并且做了工作状态的限制,新建1个布尔类型的全局变量叫DllProcessing,在程序开始的时候才赋值为真程序末尾赋值为假,在为真的状态下AllInfo才能够被操作,即if(DllProcessing) strcat(AllInfo, sz);。并且让C#的unsafe里面的代码尽量少,最后代码如下

DllProcessing = true;
AllInfo = resultString;


/* Month, Day, Year, Time in hours, Daylight offset, Time zone, Longitude, Latitude, Name for chart, Name of location */
ciCore = { month, day, year, time, DaylightOffset, Timezone, lgt, lat, "", "" };
char *v0 = "astrolog";
char *v1 = "-Xo";
char *v2 = w2c(filepath);
if (v2 == NULL) return NULL;
char * vs[] = { v0, v1,v2 };


FProcessSwitches(3, vs);
Action();


DllProcessing = false;


free(v2);
v2 = NULL;


return AllInfo;


C#代码如下

                Byte[] bPara = new Byte[2000];    //新建字节数组  
                IntPtr pRet;
                unsafe
                {


                    //在传递字符串时,将字符所在的内存固化,并取出字符数组的指针
                    fixed (char* p = &(filepath.ToCharArray()[0]))
                    {
                        //调用方法
                        pRet = DoAstrolog(ref bPara[0], p, t.Year, t.Month, t.Day, Convert.ToDouble((t.Hour + t.Minute / 100.0).ToString("0.00")),0.0,-8.0, 122.19984, 47.36584);
                    }
                }
                
                if (pRet == null)
                {
                    MessageBox.Show("Astrolog处理出错!");
                    return;
                }


                string strGet = System.Text.Encoding.Default.GetString(bPara, 0, bPara.Length);    //将字节数组转换为字符串  
                string strRet = Marshal.PtrToStringAnsi(pRet);


                this.richTextBox1.Text += strRet;


这次就好了,没有深究前面代码内存出错的原因,估计是在C++ malloc的字符串指针在返回到C#之后没有立即销毁,而这段时间C++里面的函数在看不见的地方有没有调用过不知道,毕竟C++的代码并没有深入去研究,那么在C#去释放这段地址的时候可能它已经改变了,就出错了。所以建议是,自己在C++额外植入的代码,用了malloc在自己可预见的范围内就要销毁,否则C++原有部分就是个黑匣子,你都不知道会发生什么。

可以获得所有需要的数据了,这里输出的数据经过笔者筛选,没用的不输出,然后可以根据这些数据来做自己想做的事情了。最后要给大家介绍另一位大师的文章也是研究astrolog的,和代码没关系,不过可以获得不少星盘研究的知识,http://blog.sina.com.cn/s/blog_80b9fc470101hmpy.html。



附下载链接:

http://download.csdn.net/detail/lyx_zhl/9808555

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/23532.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

星盘php,占星树星盘教程:如果通过星盘推算盘主适合哪个领域的工作?

塔罗 星盘占卜,请找阳阳老师 ~ XYZ:无论你遇到任何疑问,都请随时留言给阳阳老师,我会在看到信息后的第一时间回复的 Orz... 关注我,每天一个关于命理学的一个小知识(笑) ————其它热点内容请在文章底部查看 今天&a…

【Prompting】ChatGPT Prompt Engineering开发指南(6)

ChatGPT Prompt Engineering开发指南:Expanding/The Chat Format Expanding自定义对客户电子邮件的自动回复提醒模型使用客户电子邮件中的详细信息 The Chat Format总结内容来源 在本教程中,第一部分学习生成客户服务电子邮件,这些电子邮件是…

做外贸如何能提高开发信的回复率?

Snow给我分享了一封他们的开发信,我觉着写得很好,分享给大家。 各位可以仔细看下这封开发信。 一封好的开发信,要包含下面一些个要点: 1. 尽可能的简单,不要太长,一般3-8句话就可以了,太长客户…

ChatGPT背后的指令学习是什么?PSU最新首篇《指令学习》技术全面综述,详述指令学习关键问题

来源: 专知 任务语义可以用一组输入到输出的例子或一条文本指令来表示。传统的自然语言处理(NLP)机器学习方法主要依赖于大规模特定任务样本集的可用性。出现了两个问题: 首先,收集特定于任务的标记示例,不适用于任务可能太复杂或太昂贵而无法注释&#…

使用Python机器学习预测足球比赛结果:第一篇 数据采集 (下)

利物浦7比0狂胜曼联,这个锅不能再让C罗背了吧。预测足球比分有什么好方法吗? 微信搜索关注《Python学研大本营》,加入读者群,分享更多精彩 探索足球结果和赔率的 Python 项目。 那么,让我们按照我所遵循的步骤进行&a…

cas latex模板参考文献APA等引用格式(Elsevier期刊)

目录 一、在模板中引入需要的 .bst 文件,每个文件都是一种参考文献的格式 二、模板中引入.bst 文件的格式 三、在 \documentclass 之后,\begin{document} 之前,引入 natbib 包 四、在文章正文中引用参考文献 例如:期待的参考文献格…

作为测试人员,我们该如何看待AI

前几天看到一篇文章讨论从测试人员的角度去理解AI的,稍微翻译了一下。原文地址https://stevethedoc.wordpress.com/2023/06/18/how-should-we-view-ai-as-testers 上周三和周四,我有幸与我的两位同事Sushmitha Sivan和Bhavana Akula一起参加了伦敦的AI峰…

【Ai工具合集,一定有你需要的!】

花费了一天的时间测试了市面上各大Ai工具,然后帮大家整理总结出来了这些工具,一定记得点赞收藏保存,后面肯定会用到! 使用说明 1.部分Ai工具需要魔法上网,请自行解决;部分工具需要收费,可以尝…

把 ChatGPT 加入 Flutter 开发,会有怎样的体验?

前言 ChatGPT 最近一直都处于技术圈的讨论焦点。它除了可作为普通用户的日常 AI 助手,还可以帮助开发者加速开发进度。声网社区的一位开发者"小猿"就基于 ChatGPT 做了一场实验。仅 40 分钟就实现了一个互动直播 Demo。他是怎么做的呢?他将整个…

加入Beezy GPT-4体验官俱乐部,成为高级AI功能“领航员”

目前,Beezy已率先接入GPT-4 API ,无需科学上网,为您带来简单好用的智能体验。 GPT-4 VS GPT-3.5 一、优点 GPT-4和 GPT-3.5语言模型在前沿技术的推动下,都具备了相当出色的自然语言生成能力。相较于GPT-3.5, GPT-4 实现…

迎来新兴市场数字化转型红利,雅乐科技潇洒画出“向上曲线”

3月14日,“中东小腾讯”雅乐科技公布了最新一季财报。财报显示,雅乐科技2022年第四季度,营收7510万美元,同比增长11.2%;净利润为1660万美元,净利润率22.1%;2022年全年营收3.036亿美元&#xff0…

梦幻西游手游排队显示服务器已满,梦幻西游手游排队进不去 一直排队解决方法...

今天小编为大家带来了梦幻西游手游排队进不去 一直排队解决方法,感兴趣的朋友们可以跟着小编去下文了解一下哦! 梦幻西游手游排队进不去,一直排队怎么办?游戏新开服,总是会有一堆服务器排队问题,那么梦幻西…

梦幻西游单机架设教程-端游篇

准备工具: GGE 服务端 客户端 服务器 源码 废话不多说教程开始 我们打开GEE双击打开ggemain.exe这个程序 程序打开之后点击右上角文件设置 关联lua文件和关联项目文件后保存 打开服务端找到服务端. sublime-projectl打开把127.0.0.1改成我们服务器的ip 5、把默认端口…

好玩的免费GM游戏整理汇总

前言 我所有架设的游戏发布和更新都会实时整理到本文 https://echeverra.cn/h5game ,建议收藏。 游戏全部免费带GM后台(可以免费充值发送游戏道具),且长期维护,其中大天使之剑和梦幻西游我会一直一直维护下去。 有人…

【手游服务端】梦幻西游十五门派端+教程+GM物品后台

下载链接:https://pan.baidu.com/s/1ds_xFq1Rd1_xC4515BRGXw 提取码:soho 【手游服务端】梦幻西游十五门派端教程GM物品后台

最新亲测转转交易猫闲鱼后台源码

教程:修改数据库账号密码直接使用。 下载程序:https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

微信聊天记录导出工具WeChatExporter开源啦!

【2019年08月21日更新】 距离第一次发布软件已经有了许多新功能和稳定性上的提升,本文的一些内容已经过时,欢迎直接到GitHub上看ReadMe:https://github.com/tsycnh/WeChatExporter 之前曾经写过一个导出微信聊天记录的工具,偶尔自…

闲鱼跳转app源码+后台管理

教程:修改数据库账号密码直接使用。 源码带有教程! 下载程序:https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3

2021最新版闲鱼过模拟器

找了市面上的所有模拟器,有的不能登陆,有的黑屏,有的不能聊天等等,但功夫不负有心人,终于找到一款可以可以过闲鱼的模拟器,只需要简单的配置就可以,这个模拟器不改连打开都成问题,哈…

转转交易猫闲鱼后台源码 功能强大免授权

不用设置什么伪静态,也不用安装什么扩展,正常搭建即可。 搭建教程:添加网站→上传源码→解压源码→导入数据库→修改数据库路径config/Conn.php 下载源码:https://pan.baidu.com/s/16lN3gvRIZm7pqhvVMYYecQ?pwd6zw3