C#简单晶圆wafermapping显示示范demo

 点击,双击可改变颜色

预设5行8列数据:

 using (fratte.at.WafermapDisplay.Form1 form_show = new fratte.at.WafermapDisplay.Form1()){int[,] data_demo = new int[,]{{ 0,0,0,1,0 },{ 0,5,1,0,0 },{ 1,7,6,2,3 },{ 1,0,1,2,3 },{ 0,2,0,2,3 }, { 1,5,6,2,3 },{ 1,0,6,2,3 }, { 1,0,50,0,1 } };form_show.SetDataSet(data_demo);form_show.SetInteractive(true);form_show.ShowDialog();}

预设颜色对应表:

 private void setupDefaultColors(){// Just some sample colors to get startedcolors = new Color[255];colors[0] = Color.Green;colors[1] = Color.Red;colors[2] = Color.Yellow;colors[3] = Color.Blue;colors[4] = Color.Orange;colors[5] = Color.Magenta;colors[6] = Color.DarkBlue;colors[7] = Color.Pink;colors[50] = Color.Black;}

Wafermap.cs动态库

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;namespace fratte.at.WafermapDisplay
{public partial class Wafermap : UserControl{private String tooSmallString = "TOO SMALL";public String TooSmallString{get { return tooSmallString; }set { tooSmallString = value; }}private String noDataString = "NO DATA";public String NoDataString{get { return noDataString; }set { noDataString = value; }}private int translation_x=0;public int TranslationX{get { return translation_x; }set { translation_x = value; }}private int translation_y=0;public int TranslationY{get { return translation_y; }set { translation_y = value; }}private int rotation;public int Rotation{get { return rotation; }set { if (value % 90 == 0 && value >= 0 && value < 360)rotation = value;elsethrow new ArgumentException("Rotation has to be 0, 90, 180 or 270 degrees (Is "+value+")");}}private float zoom;public float Zoom{get { return zoom; }set { zoom = value; }}private int notchLocation = 0;public int Notchlocation{get { return notchLocation; }set {if (value % 90 == 0 && value >= 0 && value <= 270)notchLocation = value;elsethrow new ArgumentException("NotchLocation has to be 0, 90, 180 or 270 degrees (Is "+value+")");}}private int[,] dataset;public int[,] Dataset{get { return dataset; }set { dataset = value; }}private Color[] colors;public Color[] Colors{get { return colors; }set { colors = value; }}public Wafermap(){zoom=1f;InitializeComponent();SetStyle(ControlStyles.ResizeRedraw, true);DoubleBuffered = true;setupDefaultColors();registerEvents();}private void setupDefaultColors(){// Just some sample colors to get startedcolors = new Color[255];colors[0] = Color.Green;colors[1] = Color.Red;colors[2] = Color.Yellow;colors[3] = Color.Blue;colors[4] = Color.Orange;colors[5] = Color.Magenta;colors[6] = Color.DarkBlue;colors[7] = Color.Pink;colors[50] = Color.Black;}private void Wafermap_Load(object sender, EventArgs e){this.Dock = DockStyle.Fill;}private bool isScaled;public bool IsScaled{get { return isScaled; }}private int scaleFactor;public int ScaleFactor{get { return scaleFactor; }}// We need some globals to be available for calculationsRectangleF boundingBox_;SizeF dieSize_;protected override void OnPaint(PaintEventArgs e){// set rotatione.Graphics.RotateTransform((float)rotation);if(rotation!=0){// When we rotate, we also have to translateswitch (rotation){case 90:e.Graphics.TranslateTransform(0, -boundingBox_.Width);break;case 180:e.Graphics.TranslateTransform(-boundingBox_.Width,-boundingBox_.Height);break;case 270:e.Graphics.TranslateTransform(-boundingBox_.Height, 0);break;}}// set additional translatione.Graphics.TranslateTransform(translation_x, translation_y); // Use antialiase.Graphics.SmoothingMode = SmoothingMode.AntiAlias;// Here comes everything that has to be calculated on each resize/redraw// Just do this calculations once// Let's find the best Size for the outlinefloat w = this.Width*zoom;float h = this.Height*zoom;float size = w < h ? w : h;// Wafersize is size-2 because we're not drawing the first and the last pixelsSizeF wafersize = new SizeF(size - 2, size - 2);PointF starting = new PointF((w - size) / 2f, (h - size) / 2f);RectangleF boundingBox = new RectangleF(starting, wafersize);boundingBox_ = boundingBox;// Create graphics path.GraphicsPath clipPath = new GraphicsPath();clipPath.AddEllipse(boundingBox);// Set clipping region to path.e.Graphics.SetClip(clipPath, CombineMode.Replace);drawCircle(e.Graphics,boundingBox);drawNotch(e.Graphics, boundingBox, notchLocation);// Let's calculate everything needed for drawing the diesif (dataset != null && dataset.Length > 0){int maxX = dataset.GetLength(0);int maxY = dataset.GetLength(1);float sizeX = boundingBox.Width / (float)maxX;float sizeY = boundingBox.Height / (float)maxY;int every = 1;// If dieSizeX or dieSizeY is less then 2 pixels// take only every nth diewhile (sizeX <= 2 || sizeY <= 2){every = every * 2;sizeX = boundingBox.Width / (float)(maxX/every);sizeY = boundingBox.Height / (float)(maxY/every);}SizeF dieSize = new SizeF(sizeX, sizeY);dieSize_ = dieSize;// If every != 1 we recalculate the input data// Otherwise we pass the original dataset// Caveat: We must not overwrite the original dataset ;)if (every > 1){// Create a new dataset// Get the highest bin code in x/y to x/y + every as result for x/y// First set the propertyisScaled = true;scaleFactor = every;drawDies(e.Graphics, boundingBox, fratte.at.WafermapDisplay.WafermapTools.scaleArray(dataset,every), dieSize);// Print "Too small" messageFontFamily myFontFamily = new FontFamily("Arial");Font myFont = new Font(myFontFamily,10,FontStyle.Bold,GraphicsUnit.Pixel);e.Graphics.DrawString(tooSmallString, myFont, new SolidBrush(Color.Red), boundingBox.Location);}else{// PropertiesisScaled = false;scaleFactor = 1;// Simply draw the diedrawDies(e.Graphics, boundingBox, dataset, dieSize);}}else{// Display "No Data" messageFontFamily myFontFamily = new FontFamily("Arial");Font myFont = new Font(myFontFamily,10,FontStyle.Bold,GraphicsUnit.Pixel);e.Graphics.DrawString(noDataString, myFont,new SolidBrush( Color.Red), boundingBox.Location);}}// Try to reuse - only instantiated onceSolidBrush waferFillbrush = new SolidBrush(Color.Silver);Pen blackPen = new Pen(Color.Black);SolidBrush notchFillBrush = new SolidBrush(Color.Black);private void drawCircle(Graphics g, RectangleF boundingBox){ g.FillEllipse(waferFillbrush, boundingBox);g.DrawEllipse(blackPen, boundingBox);}private void drawNotch(Graphics g, RectangleF boundingBox, int location){// Draw the notch (Phyical property on the wafer for alignment. Can be at 0, 90, 180, 270 degrees// starting from 0° at the bottom CCW)// The Shape is  fixed to a cut circlefloat size=boundingBox.Width<boundingBox.Height?boundingBox.Width:boundingBox.Height;size = size * 0.05f;// Calculate the location of the notch// 180°float x=boundingBox.X+(boundingBox.Width/2f)-(size/2f);float y=boundingBox.Y-(size/2f);int start = 0;int end = 180;switch (location){case 0:y = boundingBox.Y +boundingBox.Height-(size / 2f);end = -180;break;case 90:x = boundingBox.X - (size / 2f);y = boundingBox.Y +(boundingBox.Height/2f)- (size / 2f);start = 90;end = -180;break;case 270:x = boundingBox.X +boundingBox.Width- (size / 2f);y = boundingBox.Y + (boundingBox.Height / 2f) - (size / 2f);start = 90;end = 180;break;}g.FillPie(notchFillBrush, x, y, size, size,start,end);}Pen dieOutlinePen = new Pen(Color.Black);private void drawDies(Graphics g, RectangleF boundingBox, int[,] data, SizeF dieSize){for (int x = 0; x < data.GetLength(0); x++){for (int y = 0; y < data.GetLength(1); y++){Color fill = Color.FromArgb(120,colors[data[x, y]]);PointF position = new PointF(boundingBox.X+(float)x * dieSize.Width,boundingBox.Y+(float)y*dieSize.Height);RectangleF die = new RectangleF(position, dieSize);g.FillRectangle(new SolidBrush(fill), die);g.DrawRectangle(dieOutlinePen, die.X,die.Y,die.Width,die.Height);}}}private bool interactive=false;public bool Interactive{get { return interactive; }set { interactive = value;registerEvents();}}private void registerEvents(){// Event to be registeredif (interactive){this.MouseClick += Wafermap_MouseClick;this.MouseMove += Wafermap_MouseMove;this.MouseDoubleClick += Wafermap_MouseDbClick;}}void Wafermap_MouseMove(object sender, MouseEventArgs e){// This one is going to be tricky// We need to calculate the die coordinates from screen coordinates// We have global vars boundingBox_ and dieSize_float x_coord=((float)e.X - boundingBox_.X) / dieSize_.Width;float y_coord = ((float)e.Y - boundingBox_.Y) / dieSize_.Height;int x = (int)Math.Floor(x_coord);int y = (int)Math.Floor(y_coord);try{dieEntered(x, y, dataset[x, y]);}catch (Exception){System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString()+ ":确认在wafer区域移动..");}}public void Wafermap_MouseClick(object sender, MouseEventArgs e){// Basically the same as MouseMove, just a few other infos passedfloat x_coord = ((float)e.X - boundingBox_.X) / dieSize_.Width;float y_coord = ((float)e.Y - boundingBox_.Y) / dieSize_.Height;int x = (int)Math.Floor(x_coord);int y = (int)Math.Floor(y_coord);try{//dieClicked(x, y, dataset[x, y], e.Button);dieClicked(x, y, 0, e.Button);}catch (Exception ex){System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString() + ":确认单击区域..");throw ex;}}public void Wafermap_MouseDbClick(object sender, MouseEventArgs e){// Basically the same as MouseMove, just a few other infos passedfloat x_coord = ((float)e.X - boundingBox_.X) / dieSize_.Width;float y_coord = ((float)e.Y - boundingBox_.Y) / dieSize_.Height;int x = (int)Math.Floor(x_coord);int y = (int)Math.Floor(y_coord);try{dieClicked(x, y, 2, e.Button);}catch (Exception ex){System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString() + ":确认双击区域.");throw ex;}}// This method will get called if the mousepointer enters a diepublic virtual void dieEntered(int x, int y, int bincode){// updateDie(x, y, bincode);}// This method should get overridden if you want to reakt on clicks on a diepublic virtual void dieClicked(int x, int y, int bincode,MouseButtons btn){updateDie(x,y, bincode);}// This method should be used to change die coloring of a bin directly// This is needed to avoid redraws when not neccessary// The updated bins are filled with higher alpha to highlight thempublic void updateDie(int x, int y, int bincode){//  Color fill = Color.FromArgb(255, colors[bincode]);Color fill = colors[bincode];PointF position = new PointF(boundingBox_.X + (float)x * dieSize_.Width, boundingBox_.Y + (float)y * dieSize_.Height);RectangleF die = new RectangleF(position, dieSize_);Graphics g = this.CreateGraphics();// update clipping// Create graphics path.GraphicsPath clipPath = new GraphicsPath();clipPath.AddEllipse(boundingBox_);// Set clipping region to path.g.SetClip(clipPath, CombineMode.Replace);// Drawg.FillRectangle(new SolidBrush(fill), die);g.DrawRectangle(dieOutlinePen, die.X, die.Y, die.Width, die.Height);}}
}

构造函数注册点击事件:

 public Wafermap(){zoom=1f;InitializeComponent();SetStyle(ControlStyles.ResizeRedraw, true);DoubleBuffered = true;setupDefaultColors();registerEvents();}

点击双击事件绑定:

 private void registerEvents(){// Event to be registeredif (interactive){this.MouseClick += Wafermap_MouseClick;this.MouseMove += Wafermap_MouseMove;this.MouseDoubleClick += Wafermap_MouseDbClick;}}

SetInteractive(true);

激活事件注册功能

功能代码源码:

待更新。。。

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

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

相关文章

“1688商品评论接口:打造完美电商口碑的秘密武器!“

1688商品评论接口是一种供卖家使用的接口&#xff0c;可以让卖家通过该接口维护商品的评论信息&#xff0c;包括评论内容、评分、评论时间等等。 通过使用该接口&#xff0c;卖家可以方便地管理商品的评论信息&#xff0c;包括查看、修改、删除评论等操作。同时&#xff0c;该…

2023秋招华为技术岗线上面试经历

2023/10/16 个人情况&#xff1a;博士&#xff0c;预计2024年毕业&#xff0c;参加了2023秋招&#xff0c;华为应聘到3面主管面。 下面按招聘流程顺序&#xff0c;记录我的面试经历。因为想写详细一点的独立文章&#xff0c;所以想来想去还是放到CSDN上。 1. 宣讲会 宣讲会…

Radius OTP完成堡垒机登录认证 安当加密

Radius OTP&#xff08;One-Time Password&#xff09;是一种用于身份验证的协议&#xff0c;它通过向用户发送一个一次性密码来验证用户的身份。使用Radius OTP可以实现堡垒机登录&#xff0c;以下是一些实现步骤&#xff1a; 1、安装Radius服务器 首先需要安装Radius服务器…

QTday02(常用类、UI界面下的开发、信号与槽)

今日任务 1. 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#x…

基于YOLOv8模型的水下目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的水下目标检测系统可用于日常生活中检测与定位鱼、水母、企鹅、海鹦、鲨鱼、海星、黄貂鱼&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统…

基因组的Phasing原理

1.Phasing的概念 Phasing&#xff0c;或者说Genotype Phasing&#xff0c;它的中文名有很多&#xff1a;基因定相、基因分型、单倍体分型、单倍体构建等在不同的语境下都有人说过。但不管如何&#xff0c;所谓Phasing就是要把一个二倍体&#xff08;甚至是多倍体&#xff09;基…

license授权方案

文章目录 概要license文件内容架构流程图实现 概要 当我们的商业软件售卖给客户后&#xff0c;往往需要对分发出去的软件进行限制&#xff0c;比如指定使用者&#xff0c;限制软件使用有效时间&#xff0c;声明版权信息、限制软件使用磁盘大小等。很多场景又是离线使用&#x…

使用 Elasticsearch 作为向量数据库:深入研究 dense_vector 和 script_score

Elasticsearch 是一个非常强大且灵活的搜索和分析引擎。 虽然其主要用例围绕全文搜索&#xff0c;但它的用途广泛&#xff0c;足以用于各种其他功能。 其中一项引起许多开发人员和数据科学家关注的功能是使用 Elasticsearch 作为向量数据库。 随着 dense_vector 数据类型的出现…

一文带你GO语言入门

什么是go语言? Go语言(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。Go语言的主要特点包括:- 简洁和简单 - 语法简单明快,易于学习和使用 特点 高效 编译速度快,执行效率高 并发支持 原生支持并发,利用goroutine实现高效的并发…

金山终端安全系统V9.0 SQL注入漏洞复现

0x01 产品简介 金山终端安全系统是一款为企业提供终端防护的安全产品&#xff0c;针对恶意软件、病毒和外部攻击提供防范措施&#xff0c;帮助维护企业数据和网络。 0x02 漏洞概述 金山终端安全系统V9.0 /inter/update_software_info_v2.php页面存在sql注入漏洞&#xff0c;该…

ORACLE内存结构

内存体系结构 ​​​​​​​ 目录 内存体系结构 2.1自动内存管理 2.2自动SGA内存管理 2.3手动SGA内存管理 2.3.1数据库缓冲区 2.3.1.1保留池 2.3.1.2回收池 2.3.2共享池 2.3.2.1SQL查询结果和函数查询结果 2.3.2.2库缓存 2.3.2.3数据字典缓存 2.3.3大池 2.3.4 …

【Linux学习笔记】代码编辑工具vim

1. vim工具基本模式的转换2. vim命令模式下的各种编辑命令2.1. 光标行定位2.2. 光标自由定位2.3. 复制粘贴2.4. 删除2.5. 文本的大小写替换2.6. 文本的替换2.7. 文本的前删后删2.8. 撤销操作 3. vim底行模式下的命令3.1. 设置行号与取消设置行号3.2. 分屏操作3.3. 在不退出vim的…