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

news2025/7/14 19:28:55

 点击,双击可改变颜色

预设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 started
            colors = 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;
                else
                    throw 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;
                else
                    throw 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 started
            colors = 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 calculations
        RectangleF boundingBox_;
        SizeF dieSize_;
        
        protected override void OnPaint(PaintEventArgs e)
        {
             
  
            // set rotation
            e.Graphics.RotateTransform((float)rotation);
            if(rotation!=0)
            {
                // When we rotate, we also have to translate
                switch (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 translation
            e.Graphics.TranslateTransform(translation_x, translation_y); 

            // Use antialias
            e.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 outline
            float 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 pixels
            SizeF 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 dies
            if (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 die
                while (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 property
                    isScaled = true;
                    scaleFactor = every;
                    drawDies(e.Graphics, boundingBox, fratte.at.WafermapDisplay.WafermapTools.scaleArray(dataset,every), dieSize);
                    // Print "Too small" message
                    FontFamily 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
                {
                    // Properties
                    isScaled = false;
                    scaleFactor = 1;

                    // Simply draw the die
                    drawDies(e.Graphics, boundingBox, dataset, dieSize);
                }
            }
            else
            {
                // Display "No Data" message
                FontFamily 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 once
        SolidBrush 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 circle
            float 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 registered
            if (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 passed
            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
            {
                //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 passed
            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
            {
                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 die
        public 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 die
        public 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 them
        public 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);
            // Draw
            g.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 registered
            if (interactive)
            {
                this.MouseClick += Wafermap_MouseClick;
                this.MouseMove += Wafermap_MouseMove;
                this.MouseDoubleClick += Wafermap_MouseDbClick;
                
            }
        }

SetInteractive(true);

激活事件注册功能

功能代码源码:

待更新。。。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud: feign整合sentinel实现降级

一、加依赖&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache…

软件测试用例设计方法-因果图法

边界值法是等价类划分法的补充&#xff0c;所以&#xff0c;它们是一对搭档。 那么&#xff0c;判定表法有没有它的搭档呢&#xff1f; 答案是&#xff0c;有的。那就是本篇文章分享的用例设计方法—— 因果图法 。 定义 因果图法&#xff1a; 用来处理等价类划分和边界值考…

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

摘要&#xff1a;基于YOLOv8模型的老虎目标检测系统可用于日常生活中检测与定位老虎目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算法训练数据集…

postgresql中uuid的使用

1.安装扩展插件 create extension "pgcrypto"; 2.查询uuid #36位uuid select gen_random_uuid();#去除斜杠 select REPLACE(gen_random_uuid()::text, -, ) 3.uuid在字段默认值上的使用 注:在函数前,需要加上模式名称

6.SNMP报错-Error opening specified endpoint “udp6:[::1]:161“处理

启动SNMP服务 /etc/init.d/snmpd start 出现以下报错信息 [....] Starting snmpd (via systemctl): snmpd.serviceJob for snmpd.service failed because the control process exited with error code. See "systemctl status snmpd.service" and "journalctl…

树控件的使用

目录 1、修改树控件的基础属性&#xff1a; 2、准备图标 &#xff1a; &#xff08;1&#xff09;、ico后缀的图片放入当前文件路径的rc中 &#xff08;2&#xff09;、在Icon中添加资源&#xff0c;导入图片 &#xff08;3&#xff09;、准备HICON图标 &#xff08;4&am…

牛客:FZ113 牛群的配对

FZ113 牛群的配对 文章目录 FZ113 牛群的配对题目描述题解思路题解代码 题目描述 题解思路 倒序遍历字符串&#xff0c;若当前字符是d且前一个字符是c&#xff0c;或者当前字符是b且前一个字符是a则在字符串中消除这两个字符&#xff0c;直到字符串便遍历完毕&#xff0c;若字…

prometheus获取kubelet接口监控数据

一、前言 k8s集群的kubelet服务内部有自带的cadvisor服务用于收集k8s集群的监控数据&#xff0c;所以可以通过调用kubelet的接口就能获取pod的资源监控数据&#xff0c;在新版本的k8s中&#xff0c;kubelet的监控数据获取端口为10250端口&#xff0c;老版本的是10255端口 二、…

web前端基础训练-----创建用户反馈表单

1&#xff0c;实验代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>用户反馈表单</title></head><body><form><fieldset><h1>用户反馈</h1><hr/><h4>亲爱的用…

tortoise 快捷操作分支合并

请大佬来看看有没有问题&#xff1f;&#xff0c;补充一下 1.创建新分支&#xff1a;bbb 2.在分支中修改我需要的功能 3.提交&#xff0c;本地代码&#xff0c;分支可推送&#xff0c;也可不推送到远端 4. 切换到需要合并的目标分支master&#xff0c;然后点击分支合并&#x…

Java并发面试题:(四)synchronized和lock区别

synchronized 关键字 synchronized关键字解决的是多个线程之间访问资源的同步性&#xff0c;synchronized关键字可以保证被它 修饰的方法或者代码块在任意时刻只能有一个线程执行。 另外&#xff0c;在 Java 早期版本中&#xff0c; synchronized属于重量级锁&#xff0c;效率…

“Web 3.0引领未来:下一代互联网技术将来袭!“

"下一代互联网技术&#xff0c;称为Web 3.0或Web3&#xff0c;主要利用机器学习、人工智能&#xff08;AI&#xff09;和区块链技术。" 与 Web2 相比&#xff0c;Web3 为消费者提供了对其在线数据的更多自主权&#xff0c;而Web2 专注于托管在”集中式“网站上的用户…

rv1126-rv1109-yaffs2-mkyaffs2image610

今天使用了一下yaffs2功能 就是生成一个yaffs的包 从移植的角度先生成ro_1109.yaffs包 烧录进去 操作步骤&#xff1a; 创建和生成ro文件夹和 mkyaffs2image610可执行程序 然后用 fakeroot ./mkyaffs2image610 ro ro_1109.yaffs 1 2生成了ro_1109.yaffs 例&#xff1a; …

无人机航拍图像拼接与目标识别

一、简介 无人机用来做图像侦察是常见功能&#xff0c;现有技术基本是无人机对某片区域进行飞行&#xff0c;人工实时监控飞行图像&#xff0c;将图像录制成视频供事后回放。此方法对人员业务要求比较高、反应速度足够快、不利于信息收集、录制视频丢失空间信息、对于后期开展区…

Ubuntu20网络总是连接失败,查看ip只有ipv6,没有ipv4

对于连接失败。 将网络适配器改成桥接模式。 原先使用的 NAT模式导致连接失败。 对于只有ipv6没有ipv4 是因为没有勾选桥接模式的物理状态。 当然可能还有其他原因&#xff0c;其他的就只能百度了。 继续点击网络适配器。 勾选复制物理网络连接状态。

【分享】一个基于 Python 开发的12306 抢票项目,快来学习!

哈喽&#xff0c;大家好&#xff0c;我是木易巷~ 12306抢票软件 "黄金周" 十一黄金周如约而至&#xff0c;这意味着某些开源项目又将迎来一次繁荣的热潮。这次&#xff0c;上榜的是一个与 12306 抢票相关的脚本&#xff0c;它基于 Python 编写&#xff0c;具备自动…

超全整理,性能测试——数据库索引问题定位+分析(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、数据库服务器添…

堆排序代码模板

#include<iostream> using namespace std; const int N 1e5 9; int h[N], n, m, Size;//小根堆//u表示三个点中的根节点 void down(int u) {int t u;//设t为三个点中最小的那个点//如果左儿子存在并且小于根节点就将左儿子赋值给tif (u * 2 < Size && h[u …

SourceTree 这是一个无效的源路径/URL

原因&#xff1a;权限检测出现问题 解决&#xff1a; ssh-add /Users/haijunyan/.ssh/id_rsa ssh-add -K /Users/haijunyan/.ssh/id_rsa 稍后&#xff0c;重新测试&#xff1a; 备注&#xff1a; https://www.ngui.cc/el/1727107.html?actiononClick

哪些企业适合做私域?

什么是私域&#xff1f; 简单直白来说&#xff0c;就是不用花钱就可以触达客户的渠道。私域流量就是私人的流量&#xff08;不用花钱&#xff09;。 哪些企业适合做私域&#xff1f; 》复购率高 比如美妆护肤产品行业、餐饮等快消品行业。 可通过群发推广消息、朋友圈营销和在…