Esempio n. 1
0
        public bool findPath(int n1, int depth)
        {
            if (n1 == dest)
            {
                return(true);                   //找到目的元器件端口
            }
            if (depth-- == 0)
            {
                return(false);                  //超过搜索深度
            }
            if (used[n1])
            {
                return(false);                  //已经遍历过此结点
            }
            used[n1] = true;                    //标志位置true
            for (int i = 0; i < elmList.Count; i++)
            {
                CircuitElm ce = getElm(i);      //获取元器件
                if (ce.Equals(firstElm))
                {
                    continue;                   //若是第一个元器件 pass
                }
                if (type == VOLTAGE)            //若既不是导线也不是电源则继续
                {
                    if (!(ce.isWire() || ce.type == TYPES.VoltageElm))
                    {
                        continue;
                    }
                }

                //若当前元器件没有与此结点相连
                int j;
                for (j = 0; j < ce.getPostCount(); j++)
                {
                    if (ce.getNode(j) == n1)
                    {
                        break;
                    }
                }
                if (j == ce.getPostCount())
                {
                    continue;
                }

                for (int k = 0; k < ce.getPostCount(); k++)
                {
                    if (j == k)
                    {
                        continue;
                    }
                    if (ce.getConnection(j, k) && findPath(ce.getNode(k), depth))
                    {
                        used[n1] = false;
                        return(true);
                    }
                }
            }
            used[n1] = false;
            return(false);
        }
Esempio n. 2
0
 public void Stop(string s, CircuitElm ce)
 {
     StopMessage = s;
     Matrix      = null; /* causes an exception */
     StopElm     = ce;
     mSim.SetSimRunning(false);
 }
Esempio n. 3
0
    //设置UI摄像机位置
    private void setUICamera(CircuitElm temp, GameObject UICamera)
    {
        float xx = temp.transform.position.x;
        float yy = temp.transform.position.y;
        float zz = temp.transform.position.z;

        float x = xx;
        float y = yy + 0.5f;
        float z = zz;

        if (temp.type == CirSim.TYPES.AmmeterElm)               //若是电流表,则UI摄像机向上移动
        {
            AmmeterElm elm = temp.GetComponent <AmmeterElm>();  //获取电流表脚本
            x = elm.camPos.position.x;
            y = elm.camPos.position.y + 0.9f;
            z = elm.camPos.position.z;
        }

        UICamera.transform.position = new Vector3(x, y, z);

        Magnifier.SetActive(true);                              //打开放大镜
        Magnifier.GetComponent <Magnifier>().reset();           //初始化
        Magnifier.transform.FindChild("MagnifierChild").gameObject.SetActive(true);
        Magnifier.transform.FindChild("MagnifierChild").gameObject.GetComponent <Magnifier>().reset();
        setMagnifier(Magnifier);
    }
Esempio n. 4
0
        int type;               //类型

        //构造器进行初始化
        public FindPathInfo(int t, CircuitElm e, int d)
        {
            dest     = d;
            type     = t;
            firstElm = e;
            used     = new bool[nodeList.Count];
        }
Esempio n. 5
0
 public void OnTriggerExit(Collider collider)
 {
     //若本元器件正在被触摸,并且碰到了元器件
     if (Utils.holdingName.Equals(transform.name) && collider.tag == "unit" && state != 1)
     {
         unitColliders.Remove(collider.transform.GetComponent <CircuitElm> ());                                      //将本元器件脚本在元器件列表中移除
         Utils.adjustHeight(transform, unitColliders);                                                               //调整高度
     }
     //若本元器件碰到了地板
     else if (Utils.holdingName.Equals(transform.name) && (collider.tag == "plate"))
     {
         floor = 0;                                                                                                                                                  //调整层数
         transform.position = new Vector3(transform.position.x,
                                          0f, transform.position.z);                                                                                                 //调整高度
     }
     //若本元器触碰到其他元器件的纽扣
     else if (collider.tag == "button" && collider.transform.parent.tag == "unit" && (state != 0) && (state != 1))
     {
         CircuitElm temp = collider.transform.parent.GetComponent <CircuitElm> ();                                   //获取正在触摸的元器件引用
         //若不是正常离开纽扣
         if (temp.interfaceList [int.Parse(collider.name)] != null &&
             !temp.interfaceList [int.Parse(collider.name)].Equals(transform.GetComponent <CircuitElm> ()))
         {
             return;
         }
         temp.interfaceList [int.Parse(collider.name)] = null;
         buttonColliders.Remove(collider.gameObject);                                                                                        //删除纽扣
     }
     //若本元器触碰到底板上的纽扣
     else if (collider.tag == "point" && (state == 2 || state == 1))
     {
         buttonColliders.Remove(collider.gameObject);                                                                                        //删除纽扣
     }
 }
Esempio n. 6
0
 public Adjustable(CircuitElm ce, int item)
 {
     MinValue = 1;
     MaxValue = 1000;
     Elm      = ce;
     EditItem = item;
 }
Esempio n. 7
0
 public void OnTriggerEnter(Collider collider)
 {
     //若本元器件正在被触摸,并且碰到了元器件
     if (Utils.holdingName.Equals(transform.name) && (collider.tag == "unit") && state != 1)
     {
         unitColliders.Add(collider.transform.GetComponent <CircuitElm> ());                                                 //将本元器件脚本添加到元器件列表
         Utils.adjustHeight(transform, unitColliders);                                                                       //调整高度
     }
     //若本元器件碰到了地板
     else if (Utils.holdingName.Equals(transform.name) && (collider.tag == "plate"))
     {
         floor = 1;                                                                                                                                          //调整层数
         transform.position = new Vector3(transform.position.x,
                                          0.064f, transform.position.z);                                                                                     //调整高度
     }
     //若本元器触碰到其他元器件的纽扣
     else if (collider.tag == "button" && collider.transform.parent.tag == "unit" && (state != 0) && (state != 1))
     {
         CircuitElm temp = collider.transform.parent.GetComponent <CircuitElm> ();                                   //获取正在触摸的元器件引用
         if (temp.interfaceList [int.Parse(collider.name)] != null &&
             collider.transform.parent.parent != null)                                                               //已经连上的就不能再连了
         {
             return;
         }
         temp.interfaceList [int.Parse(collider.name)] = transform.GetComponent <CircuitElm> ();                     //接口连接
         buttonColliders.Add(collider.gameObject);                                                                   //添加触碰到的纽扣
     }
     //若本元器触碰到底板上的纽扣
     else if (collider.tag == "point" && (state == 2 || state == 1))
     {
         buttonColliders.Add(collider.gameObject);                                                                                                   //添加触碰到的纽扣
     }
 }
Esempio n. 8
0
 /* State object to help find loops in circuit subject to various conditions (depending on type)
  * elm = source and destination element.
  * dest = destination node. */
 public PathInfo(PathType type, CircuitElm elm, int dest, List <CircuitElm> elmList, int nodeCount)
 {
     mDest     = dest;
     mType     = type;
     mFirstElm = elm;
     mElmList  = elmList;
     mVisited  = new bool[nodeCount];
 }
Esempio n. 9
0
 //计算本元器件哪个端口连接下一个元器件
 //root--此元器件 next--下一个元器件
 public static int calNextPort(CircuitElm root, CircuitElm next)
 {
     for (int i = 0; i < root.interfaceList.Count; i++)
     {
         if (root.interfaceList[i] != null && root.interfaceList[i].Equals(next))                    //若该端口连接为此元器件
         {
             return(i);                                                                              //返回连接端口号
         }
     }
     return(-1);                                                                                                                                                              //连接错误
 }
Esempio n. 10
0
        public ScrollValuePopup(int dy, CircuitElm e, CirSim s) : base()
        {
            mMyElm  = e;
            mDeltaY = 0;
            mSim    = s;
            mSim.PushUndo();
            setupValues();

            Text = mName;

            mPnlV = new Panel();
            {
                mPnlV.Left = 4;
                mPnlV.Top  = 4;
                int ofsY = 0;
                /* label */
                mLabels = new Label()
                {
                    Text = "---"
                };
                mLabels.AutoSize = true;
                mLabels.Left     = 4;
                mLabels.Top      = ofsY;
                mPnlV.Controls.Add(mLabels);
                ofsY += mLabels.Height;
                /* trbValue */
                mTrbValue = new TrackBar()
                {
                    Minimum       = 0,
                    Maximum       = mNValues - 1,
                    SmallChange   = 1,
                    LargeChange   = 1,
                    TickFrequency = mNValues / 24,
                    TickStyle     = TickStyle.TopLeft,
                    Width         = 300,
                    Height        = 21,
                    Left          = 4,
                    Top           = ofsY
                };
                ofsY += mTrbValue.Height * 2 / 3;
                mTrbValue.ValueChanged += new EventHandler((sender, ev) => { setElmValue((TrackBar)sender); });
                mPnlV.Width             = mTrbValue.Width + 8;
                mPnlV.Height            = ofsY + 4;
                mPnlV.Controls.Add(mTrbValue);
                /* */
                Controls.Add(mPnlV);
            }

            doDeltaY(dy);
            Width           = mPnlV.Width + 24;
            Height          = mPnlV.Height + 48;
            FormBorderStyle = FormBorderStyle.FixedToolWindow;
        }
Esempio n. 11
0
 public void SetElm(CircuitElm ce)
 {
     mPlots = new List <ScopePlot>();
     if (null != ce && (ce is TransistorElm))
     {
         _setValue(VAL.VCE, ce);
     }
     else
     {
         _setValue(0, ce);
     }
     _initialize();
 }
Esempio n. 12
0
 //设置端口点
 public override void setPosts()
 {
     if (floor == 1)
     {
         points[0] = ((GameObject)buttonColliders[0]).name;
     }
     else
     {
         CircuitElm ce    = ((GameObject)buttonColliders[0]).transform.parent.GetComponent <CircuitElm>(); //获取元器件
         int        index = int.Parse(((GameObject)buttonColliders[0]).name);                              //被碰撞元器件连接纽扣
         points[0] = ce.getPostFromIndex(index);                                                           //获取结点名称
     }
 }
Esempio n. 13
0
        public SliderDialog(CircuitElm ce, CirSim f) : base()
        {
            Text = "Add Sliders";
            sim  = f;
            elm  = ce;

            vp = new Panel();

            einfos = new ElementInfo[10];
            hp     = new Panel();
            {
                hp.AutoSize = true;
                /* Apply */
                applyButton = new Button()
                {
                    Text = "Apply"
                };
                applyButton.Click += new EventHandler((sender, e) => { apply(); });
                ctrlInsert(hp, applyButton);
                /* OK */
                okButton = new Button()
                {
                    Text = "OK"
                };
                okButton.Click += new EventHandler((sender, e) => {
                    apply();
                    closeDialog();
                });
                ctrlInsert(hp, okButton);
                /* Cancel */
                cancelButton = new Button()
                {
                    Text = "Cancel"
                };
                cancelButton.Click += new EventHandler((sender, e) => {
                    closeDialog();
                });
                ctrlInsert(hp, cancelButton);
            }
            /* */
            ctrlInsert(vp, hp);
            /* */
            vp.Left = 4;
            vp.Top  = 4;
            Controls.Add(vp);
            /* */
            buildDialog();
            Width   = vp.Width + 24;
            Height  = vp.Height + 64;
            Visible = false;
        }
Esempio n. 14
0
        public Adjustable(StringTokenizer st, CirSim sim)
        {
            int e = st.nextTokenInt();

            if (e == -1)
            {
                return;
            }
            Elm        = sim.getElm(e);
            EditItem   = st.nextTokenInt();
            MinValue   = st.nextTokenDouble();
            MaxValue   = st.nextTokenDouble();
            SliderText = CustomLogicModel.unescape(st.nextToken());
        }
Esempio n. 15
0
        bool canSplit(CircuitElm ce)
        {
            if (!(ce is WireElm))
            {
                return(false);
            }
            var we = (WireElm)ce;

            if (we.P1.X == we.P2.X || we.P1.Y == we.P2.Y)
            {
                return(true);
            }
            return(false);
        }
Esempio n. 16
0
 void _setValue(VAL val, CircuitElm ce)
 {
     mPlots = new List <ScopePlot>();
     if (val == VAL.INVALID)
     {
         mPlots.Add(new ScopePlot(ce, 0));
     }
     else
     {
         mPlots.Add(new ScopePlot(ce, val));
         ShowV = true;
     }
     _calcVisiblePlots();
     ResetGraph();
 }
Esempio n. 17
0
        public ContextMenuStrip Show(int px, int py, CircuitElm mouseElm)
        {
            mScope.Enabled      = mouseElm.CanViewInScope;
            mFloatScope.Enabled = mouseElm.CanViewInScope;
            mEdit.Enabled       = mouseElm.GetElementInfo(0) != null;
            mFlip.Enabled       = 2 == mouseElm.PostCount;
            mSplit.Enabled      = canSplit(mouseElm);
            mSlider.Enabled     = sliderItemEnabled(mouseElm);

            var popupMenu = new ContextMenuStrip();

            popupMenu.Items.AddRange(mMenuItems.ToArray());
            popupMenu.Show();
            popupMenu.Location = new Point(px, py);
            return(popupMenu);
        }
Esempio n. 18
0
 bool sliderItemEnabled(CircuitElm elm)
 {
     if (elm is PotElm)
     {
         return(false);
     }
     for (int i = 0; ; i++)
     {
         var ei = elm.GetElementInfo(i);
         if (ei == null)
         {
             return(false);
         }
         if (ei.CanCreateAdjustable())
         {
             return(true);
         }
     }
 }
Esempio n. 19
0
    //调整元器件的高度
    public static void adjustHeight(Transform unit, ArrayList unitColliders) //unit-元器件引用 unitColliders-元器件碰撞列表
    {
        CircuitElm temp         = unit.GetComponent <CircuitElm>();          //元器件脚本
        int        currentFloor = temp.floor;                                //元器件当前层数
        int        maxFloor     = 0;                                         //碰撞列表中的最大层数

        //获取最大层数
        for (int i = 0; i < unitColliders.Count; i++)
        {
            CircuitElm tempSon = (CircuitElm)unitColliders[i];//强制转换为原始类型
            if (tempSon.floor > maxFloor)
            {
                maxFloor = tempSon.floor;
            }
        }

        temp.floor = maxFloor + 1;               //提高层数
        adjustHeightAchieve(unit, maxFloor + 1); //调整高度
    }
Esempio n. 20
0
 //设置端口点-有正负极之分
 public override void setPosts()
 {
     if (floor == 1)                                                            //若该元器件直接插在底板上
     {
         Point point = ((GameObject)buttonColliders[0]).GetComponent <Point>(); //获取纽扣上的脚本
         if (point.port == 1)                                                   //该纽扣碰撞的是电池的正极
         {
             points[1] = ((GameObject)buttonColliders[0]).name;                 //获取结点名称
             points[0] = ((GameObject)buttonColliders[1]).name;
         }
         else
         {
             points[0] = ((GameObject)buttonColliders[0]).name;         //获取结点名称
             points[1] = ((GameObject)buttonColliders[1]).name;
         }
     }
     else                                                       //若元器件插在其他元器件上
     {
         int        index;
         CircuitElm thisCE = transform.GetComponent <CircuitElm>();                                         //此元器件
         CircuitElm ce     = ((GameObject)buttonColliders[0]).transform.parent.GetComponent <CircuitElm>(); //获取元器件
         if (thisCE.interfaceList[1].Equals(ce))                                                            //若是电源的正极连接此端口
         {
             ce        = ((GameObject)buttonColliders[0]).transform.parent.GetComponent <CircuitElm>();
             index     = int.Parse(((GameObject)buttonColliders[0]).name);
             points[1] = ce.getPostFromIndex(index);                                            //point2端口点代表电源的正极
             ce        = ((GameObject)buttonColliders[1]).transform.parent.GetComponent <CircuitElm>();
             index     = int.Parse(((GameObject)buttonColliders[1]).name);
             points[0] = ce.getPostFromIndex(index);                                            //point1端口点代表电源的负极
         }
         else                                                                                   //若是电源的正极连接此端口
         {
             ce        = ((GameObject)buttonColliders[0]).transform.parent.GetComponent <CircuitElm>();
             index     = int.Parse(((GameObject)buttonColliders[0]).name);
             points[0] = ce.getPostFromIndex(index);                                            //point1端口点代表电源的负极
             ce        = ((GameObject)buttonColliders[1]).transform.parent.GetComponent <CircuitElm>();
             index     = int.Parse(((GameObject)buttonColliders[1]).name);
             points[1] = ce.getPostFromIndex(index);                                            //point2端口点代表电源的正极
         }
     }
 }
Esempio n. 21
0
 //设置端口点 0、1纽扣代表端口1(point2) 2、3纽扣代表端口0(point1)
 public virtual void setPosts()
 {
     buttonCollidersIndex.Clear();                                                                                                                   //清空纽扣对应端口的列表
     if (floor == 1)                                                                                                                                 //若该元器件直接插在底板上
     {
         if (getPostCount() == 2 || type == CirSim.TYPES.WireElm)                                                                                    //若端口数为两个或者是导线
         {
             if (((GameObject)buttonColliders [0]).GetComponent <Point> ().port == 1)                                                                //若碰到的时1纽扣(端口1)
             {
                 points [0] = ((GameObject)buttonColliders [0]).name;                                                                                //获取结点名称
                 points [1] = ((GameObject)buttonColliders [1]).name;
             }
             else                                                                                                                                            //碰到的是3纽扣(端口0)
             {
                 points [1] = ((GameObject)buttonColliders [0]).name;
                 points [0] = ((GameObject)buttonColliders [1]).name;
             }
         }
         else                                                                                                                                        //端口数大于2并且不是导线
         {
             for (int i = 0; i < downHole; i++)
             {
                 int port = ((GameObject)buttonColliders [i]).GetComponent <Point> ().port;                                                          //获取连接端点数
                 buttonCollidersIndex.Add(port / 2);                                                                                                 //记录纽扣对应的端口
                 points [port / 2] = ((GameObject)buttonColliders [i]).name;                                                                         //设置端点名称
             }
         }
     }
     else if (floor > 1)                                                                                                             //若元器件插在其他元器件上
     {
         for (int i = 0; i < downHole; i++)
         {
             CircuitElm ce    = ((GameObject)buttonColliders [i]).transform.parent.GetComponent <CircuitElm> ();                     //获取元器件
             int        port  = calNextPort(transform.GetComponent <CircuitElm> (), ce);                                             //获取本元器件的连接纽扣
             int        index = int.Parse(((GameObject)buttonColliders [i]).name);                                                   //被碰撞元器件连接纽扣
             buttonCollidersIndex.Add(port / 2);                                                                                     //记录纽扣对应的端口
             points [port / 2] = ce.getPostFromIndex(index);                                                                         //获取结点名称
         }
     }
 }
Esempio n. 22
0
    // 移动平台触屏操作
    void MobileInput()
    {
        if (Utils.isIntroduction)
        {
            return;
        }

        if (Utils.gestureLayer)          //电路连通好后的手势触摸层
        {
            if (Input.touchCount == 1)
            {
                Ray       ray      = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);
                LayerMask unitmask = 1 << LayerMask.NameToLayer("unit");                //规定触摸层数
                if (Physics.Raycast(ray, out hit, 100, unitmask.value) && Input.touches[0].phase == TouchPhase.Began)
                {
                    Utils.audioManager.playAudio(1);                           //播放音效
                    temp = hit.collider.transform.GetComponent <CircuitElm>(); //获取元器件脚本
                    if (temp.type == CirSim.TYPES.SwitchElm)
                    {
                        setUICamera(temp, UICamera);                            //设置UI摄像机位置
                        ((SwitchElm)temp).convert();                            //转换开关状态
                    }
                    else if (temp.type == CirSim.TYPES.SlidingResistanceElm || temp.type == CirSim.TYPES.AmmeterElm)
                    {
                        setUICamera(temp, UICamera);          //设置UI摄像机位置
                    }
                    gameObjGesture = hit.collider.gameObject; //获取触摸物体引用
                    CirSim.analyzeCircuit();                  //分析电路
                }
                else if (Input.touches[0].phase == TouchPhase.Moved)
                {
                    if (gameObjGesture == null)
                    {
                        return;
                    }
                    CircuitElm elm = gameObjGesture.transform.GetComponent <CircuitElm>();         //获取元器件脚本
                    if (elm.type == CirSim.TYPES.SlidingResistanceElm)                             //若为滑动变阻器
                    {
                        ((SlidingResistanceElm)(elm)).slideSwitch(Input.touches[0].deltaPosition); //滑动滑块
                        CirSim.analyzeCircuit();                                                   //分析电路
                    }
                }
                else if (Input.touches[0].phase == TouchPhase.Ended)
                {
                    gameObjGesture = null;               //手持物体引用置null
                }
            }
            return;
        }

        if (gameObj != null)                                                                                    // 如果触控物体不为空
        {
            if (!gameObj.tag.Equals("plate") && Input.touchCount <= 0)                                          // 如果触控物体不为地板并且此时没有手指触控事件
            {
                return;                                                                                         // 直接返回
            }
            else if (gameObj.tag.Equals("plate") && Input.touchCount <= 0)                                      // 如果触控物体为地板并且此时没有手指触控事件
            {
                RotatePlate(gameObj);                                                                           // 校正旋转地板
            }
        }

        // 1个手指触摸屏幕
        if (Input.touchCount == 1)
        {
            Ray       ray          = Camera.main.ScreenPointToRay(Input.GetTouch(0).position); // 定义从摄像机出发的射线
            LayerMask uimask       = 1 << LayerMask.NameToLayer("UI");                         //定义UI层
            LayerMask unitmask     = 1 << LayerMask.NameToLayer("unit");                       // 获取unit层
            LayerMask platemask    = 1 << LayerMask.NameToLayer("plate");                      // 获取plate层
            LayerMask originalmask = 1 << LayerMask.NameToLayer("original");                   // 获取放置初始元器件层

            if (Input.GetMouseButtonDown(0))
            {
                if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))        //触摸在UI上
                //Debug.Log("触摸在UI上");
                {
                    gameObj = null;
                    return;
                }
            }


            if (Input.touches [0].phase == TouchPhase.Began)                                                    // 单指触控

            {
                m_screenpos = Input.touches [0].position;                                // 记录手指触屏的位置

                if (Physics.Raycast(ray, out hit, 100, uimask.value))                    //如果触碰到了UI按钮
                {
                    gameObj = null;
                    return;
                }
                else if (Physics.Raycast(ray, out hit, 100, originalmask.value))        //如果触摸到原始元器件
                {
                    isHoldUnit = true;                                                  //表示持有元件

                    GameObject gb = Instantiate(hit.collider.gameObject);
                    gb.GetComponent <CircuitElm> ().originalPos = new Vector3(hit.collider.transform.position.x, 0.0f, hit.collider.transform.position.z);
                    gb.transform.SetParent(hit.collider.gameObject.transform.parent);                           //初始化一个元器件

                    gameObj       = hit.collider.gameObject;
                    gameObj.tag   = "unit";                                                       //unit层
                    gameObj.layer = 8;                                                            //unit层
                    gameObj.GetComponent <CircuitElm>().convertState(true);                       //转变为透明
                    Utils.holdingName = gameObj.name;                                             //获取手持元器件的名字
                    Vector2 tempPos = Camera.main.WorldToScreenPoint(gameObj.transform.position); // 将元件的世界坐标转换为屏幕坐标
                    offSet = new Vector2(m_screenpos.x - tempPos.x, m_screenpos.y - tempPos.y);   // 触控时考虑偏移
                }
                else if (Physics.Raycast(ray, out hit, 100, unitmask.value))                      // 如果触控到元件
                {
                    isHoldUnit = true;                                                            // 表示持有元件

                    //若元器件被压在底下,则不能动
                    CircuitElm tempCE = hit.collider.transform.GetComponent <CircuitElm>();
                    if (tempCE.interfaceList[0] != null || tempCE.interfaceList[2] != null)
                    {
                        gameObj = null;
                        return;
                    }

                    gameObj = hit.collider.gameObject;                                            // 保存持有元件的对象
                    gameObj.GetComponent <CircuitElm>().convertState(true);                       //变为透明显示元器件
                    CirSim.elmList.Remove(gameObj.GetComponent <CircuitElm>());                   //在元器件列表中删除该元器件
                    Utils.holdingName = gameObj.name;                                             // 获取手持元器件的名字
                    Vector2 tempPos = Camera.main.WorldToScreenPoint(gameObj.transform.position); // 将元件的世界坐标转换为屏幕坐标
                    offSet = new Vector2(m_screenpos.x - tempPos.x, m_screenpos.y - tempPos.y);   // 触控时考虑偏移
                    //gameObj.transform.SetParent(null);									// 设置父物体为空
                }
                else                                                                    // 如果没有触控到元件
                {
                    Utils.holdingName = "null";                                         // 手持物体名称
                    isHoldUnit        = false;                                          // 表示未持有元件
                    gameObj           = Utils.plate;                                    // 保存地板对象
                }
            }
            else if (Input.touches [0].phase == TouchPhase.Moved)                                                       // 手指移动
            {
                if (gameObj == null)
                {
                    return;                                                                // 若手持物体为空,则返回
                }
                Touch touch = Input.touches [0];                                           // 获取touch对象
                switch (gameObj.tag)                                                       // 区别操作对象的便签
                {
                case "unit":                                                               // 元件
                    gameObj.transform.GetComponent <CircuitElm>().state = 2;               //切换元器件的状态
                    Vector3 unitPosition   = gameObj.transform.position;                   // 获取元件世界坐标
                    Vector3 screenPosition = Camera.main.WorldToScreenPoint(unitPosition); // 将元件的世界坐标转为屏幕坐标
                    // 计算时考虑偏移量
                    Vector3 fingerPosition = new Vector3(touch.position.x - offSet.x, touch.position.y - offSet.y, screenPosition.z);
                    Vector3 worldPosition  = Camera.main.ScreenToWorldPoint(fingerPosition);                                                               // 获取触屏点世界坐标
                    gameObj.transform.position = new Vector3(worldPosition.x, gameObj.transform.GetComponent <CircuitElm>().getHeight(), worldPosition.z); // 更新元件世界坐标

                    break;

                case  "plate":                                                                                                  // 底板
                    Vector2 deltaPos = touch.deltaPosition;                                                                     // 获取滑屏当前帧改变值
                    gameObj.transform.Rotate(Vector3.down * deltaPos.x * 0.6f, Space.World);                                    // 根据滑屏距离的水平值旋转底板
                    break;

                default:
                    //Debug.Log ("touch error!");										// 打印错误信息
                    break;
                }
            }
            else if (Input.touches[0].phase == TouchPhase.Ended)
            {
                //Utils.holdingName = null;//手持元起价置空
                if (gameObj != null && gameObj.tag == "unit")
                {
                    //恢复为不透明
                    gameObj.GetComponent <CircuitElm>().convertState(false);
                    gameObj.transform.GetComponent <CircuitElm>().putUnit();//将元器件放到指定位置
                }
            }
        }
        else if (Input.touchCount > 1)                                                                                                  // 如果是多点触控
        // 记录两个手指的位置
        {
            Vector2 finger1 = new Vector2();
            Vector2 finger2 = new Vector2();
            // 记录两个手指的移动
            Vector2 mov1 = new Vector2();
            Vector2 mov2 = new Vector2();

            for (int i = 0; i < 2; i++)                                                                                                 // 遍历触控点
            {
                Touch touch = Input.touches [i];                                                                                        // 获取touch对象
                if (touch.phase == TouchPhase.Ended)                                                                                    // 如果有一只手指松开
                {
                    break;                                                                                                              // 直接跳出循环
                }
                if (touch.phase == TouchPhase.Moved)                                                                                    // 如果行为是移动
                {
                    float mov = 0;                                                                                                      // 定义记录移动距离的变量
                    if (i == 0)                                                                                                         // 如果是第一支手指
                    {
                        finger1 = touch.position;                                                                                       // 记录触屏位置
                        mov1    = touch.deltaPosition;                                                                                  // 记录移动距离
                    }
                    else                                                                                                                // 如果是第二支手指
                    {
                        finger2 = touch.position;                                                                                       // 记录触屏位置
                        mov2    = touch.deltaPosition;                                                                                  // 记录移动距离
                        // Debug.Log (" asd " + Vector2.Angle (mov1, mov2));
                        // 双指运动方向相同
                        if (Vector2.Angle(mov1, mov2) <= 90 && (mov1.magnitude > 0.8f || mov2.magnitude > 0.8f))
                        {
                            if (Vector2.Angle(mov1, new Vector2(1, 0)) < 10)                                                    // 滑动方向向量如果和x正轴向量夹角小于10度
                            // 水平向右旋转
                            {
                                transform.RotateAround(Utils.plate.transform.position, new Vector3(0, -1, 0), RotateHSpeed * Time.deltaTime);
                            }
                            else if (Vector2.Angle(mov1, new Vector2(-1, 0)) < 10)                                      // 滑动方向向量如果和x负轴向量夹角小于10度
                            // 水平向左旋转
                            {
                                transform.RotateAround(Utils.plate.transform.position, new Vector3(0, 1, 0), RotateHSpeed * Time.deltaTime);
                            }
                            else if (Vector2.Angle(mov1, new Vector2(0, 1)) < 10)                                       // 滑动方向向量如果和y负轴向量夹角小于10度
                            //垂直向上旋转
                            {
                                transform.FindChild("Main Camera").Rotate(-RotateVSpeed * Time.deltaTime, 0, 0);
                            }
                            else if (Vector2.Angle(mov1, new Vector2(0, -1)) < 10)                                      // 滑动方向向量如果和y负轴向量夹角小于10度
                            // 垂直向下旋转
                            {
                                transform.FindChild("Main Camera").Rotate(RotateVSpeed * Time.deltaTime, 0, 0);
                            }
                        }
                        else                                                                                                    // 缩放
                        {
                            if (finger1.x > finger2.x)                                                                          // 如果第一根手指的x坐标大于第二根
                            {
                                mov = mov1.x;                                                                                   // 总的移动距离为第一根手指的x方向移动距离
                            }
                            else                                                                                                // 如果第二根手指的x坐标大于第一根
                            {
                                mov = mov2.x;                                                                                   // 总的移动距离为第二根手指的x方向移动距离
                            }
                            if (finger1.y > finger2.y)                                                                          // 如果第一根手指的y坐标大于第二根
                            {
                                mov += mov1.y;                                                                                  // 总的移动距离为第一根手指的y方向移动距离
                            }
                            else                                                                                                // 如果第二根手指的y坐标大于第一根
                            {
                                mov += mov2.y;                                                                                  // 总的移动距离为第二根手指的y方向移动距离
                            }
                            transform.Translate(0, -mov * Time.deltaTime, 0);                                                   // 移动摄像机父物体的y坐标
                            if (transform.position.y <= MaxZoomRatio)                                                           // 如果y坐标小于等于最大放大率
                            {
                                transform.position = new Vector3(transform.position.x, MaxZoomRatio, transform.position.z);
                            }
                            else if (transform.position.y >= MinZoomRatio)                                                      // 如果y坐标大于等于最小放大率
                            {
                                transform.position = new Vector3(transform.position.x, MinZoomRatio, transform.position.z);
                            }
                            //Debug.Log (transform.position + "asd" + transform.FindChild("Main Camera").transform.position);
                        }
                    }
                }
            }
        }
    }
Esempio n. 23
0
 public void setScopeElm(CircuitElm e)
 {
     elmScope.SetElm(e);
     elmScope.ResetGraph();
 }
Esempio n. 24
0
 public ScopePlot(CircuitElm e)
 {
     Elm = e;
 }
Esempio n. 25
0
 public ScopePlot(CircuitElm e, Scope.VAL v)
 {
     Elm   = e;
     Value = v;
 }
Esempio n. 26
0
    //分析电路
    public static void analyzeCircuit()
    {
        if (elmList.Count == 0)                                                         //若元器件列表为空
        {
            return;
        }
        nodeList.Clear();                                       //清空结点列表
        int vscount = 0;                                        //电压源数量(将导线看做电压为0的电压源)

        //步骤一:找到电压源,确定起始元器件
        Debug.Log("步骤一");
        CircuitElm volt = null;                                 //电源源引用

        for (int i = 0; i < elmList.Count; i++)                 //遍历元器件列表
        {
            CircuitElm ce = getElm(i);                          //获取元器件
            if (ce.isDamaged)
            {
                elmList.Remove(ce);                                     //若元器件破损,在元器件列表中删除该元器件
                damageList.Add(ce);                                     //将损坏元器件添加进损坏列表
            }
            if (volt == null && ce.type == TYPES.VoltageElm)            //若找到了一个电源
            {
                volt = ce;                                              //为电压源赋值
            }
        }

        if (volt != null)                                                       //若找到电压源
        {
            CircuitNode cn = new CircuitNode();                                 //创建结点
            cn.name = volt.getPost(0);                                          //获取电压源负极
            nodeList.Add(cn);                                                   //添加进结点列表
        }
        else
        {
            CircuitNode cn = new CircuitNode();                                 //创建结点
            cn.name = null;                                                     //设置结点为空
            nodeList.Add(cn);                                                   //添加进结点列表
            return;
        }

        //步骤二:分配所有的结点和电压源
        Debug.Log("步骤二");
        for (int i = 0; i < elmList.Count; i++)                                 //遍历元器件列表
        {
            CircuitElm ce = getElm(i);                                          //获取元器件
            Debug.Log("元器件" + i + " " + getElm(i).getPost(0));
            int ivs   = ce.getVoltageSourceCount();                             //记录电压源数量
            int posts = ce.getPostCount();                                      //记录端点数量
            for (int j = 0; j < posts; j++)                                     //遍历元器件上的端口
            {
                string port = ce.getPost(j);                                    //获取元器件的端口
                int    k;
                for (k = 0; k < nodeList.Count; k++)                            //遍历结点列表
                {
                    CircuitNode cn = getCircuitNode(k);                         //获取k结点
                    if (cn.name.Equals(port))
                    {
                        break;                                    //从结点列表中找到了该结点
                    }
                }
                if (k == nodeList.Count)                                                //结点列表中无此结点
                {
                    CircuitNode cn = new CircuitNode();                                 //创建结点
                    cn.name = port;                                                     //标记结点名称
                    cn.links.Add(ce, j);                                                //添加进结点序列
                    ce.setNode(j, nodeList.Count);                                      //记录元器件的连接结点
                    nodeList.Add(cn);                                                   //将该结点添加到结点列表
                }
                else                                                                    //结点列表中有此结点
                {
                    getCircuitNode(k).links.Add(ce, j);                                 //添加结点链
                    ce.setNode(j, k);                                                   //记录元器件的连接结点

                    if (k == 0)                                                         //若结点为电源的负极
                    {
                        ce.setNodeVoltage(j, 0);                                        //端口j的电压为0
                    }
                }
            }
            vscount += ivs;                                                     //电压源数量累加
        }
        voltageSources   = new CircuitElm[vscount];                             //创建电压源数组
        vscount          = 0;                                                   //电压源数量置0
        circuitNonLinear = false;                                               //电路是否是非线性的

        Debug.Log("----------结点-----------");
        for (int i = 0; i < nodeList.Count; i++)
        {
            Debug.Log("结点" + i + " : " + getCircuitNode(i).name);
        }

        Debug.Log("---------元器件对应的结点----------");
        //for(int i = 0; i < elmList.Count; i++) {
        //    Debug.Log("元器件"+i+" : "+getElm(i).type+"  "+getElm(i).nodes[0]+"--"+ getElm(i).nodes[1]);
        //}

        //步骤三:初始电路矩阵
        Debug.Log("步骤三");
        for (int i = 0; i < elmList.Count; i++)                                 //遍历元器件
        {
            CircuitElm ce  = getElm(i);                                         //获取元器件
            int        ivs = ce.getVoltageSourceCount();                        //获取电压源数量
            for (int j = 0; j < ivs; j++)                                       //遍历电压源
            {
                voltageSources [vscount] = ce;                                  //为电压源数组赋值
                ce.setVoltageSource(j, vscount++);                              //设置电压源序号
            }
        }

        int matrixSize = nodeList.Count - 1 + vscount;                      //矩阵大小

        circuitMatrix     = new float[matrixSize, matrixSize];              //初始电路矩阵
        circuitRightSide  = new float[matrixSize];                          //初始电路右边矩阵
        origMatrix        = new float[matrixSize, matrixSize];
        origRightSide     = new float[matrixSize];
        circuitMatrixSize = circuitMatrixFullSize = matrixSize;             //初始电路矩阵大小
        circuitRowInfo    = new RowInfo[matrixSize];                        //初始行信息
        circuitPermute    = new int[matrixSize];                            //初始化电路交换数组

        for (int i = 0; i < matrixSize; i++)
        {
            circuitRowInfo [i] = new RowInfo();                                         //创建电路矩阵行信息对象
        }
        circuitNeedsMap = false;
        for (int i = 0; i < elmList.Count; i++)
        {
            CircuitElm ce = getElm(i);                                                  //获取元器件
            ce.stamp();                                                                 //标记元器件,初始化电路矩阵
        }

        for (int i = 0; i < CirSim.circuitMatrixSize; i++)
        {
            string s = i + ": ";
            for (int j = 0; j < CirSim.circuitMatrixSize; j++)
            {
                s += CirSim.circuitMatrix [i, j] + " ";
            }
            s += " " + CirSim.circuitRightSide [i];
            Debug.Log(s);
        }

        //步骤四:处理图中未连接的结点
        Debug.Log("步骤四");
        bool[] closure     = new bool[nodeList.Count];
        bool[] tempclosure = new bool[nodeList.Count];
        bool   changed     = true;                                              //标志位

        closure [0] = true;                                                     //从第0个结点开始
        while (changed)
        {
            changed = false;                                                    //标志位置false
            for (int i = 0; i < elmList.Count; i++)                             //遍历所有元器件
            {
                CircuitElm ce = getElm(i);                                      //获取元器件
                for (int j = 0; j < ce.getPostCount(); j++)                     //遍历元器件的端口
                {
                    if (!closure [ce.getNode(j)])
                    {
                        if (ce.hasGroundConnection(j))                                          //若该端口连接到y阴极
                        {
                            closure [ce.getNode(j)] = changed = true;
                        }
                        continue;
                    }

                    for (int k = 0; k < ce.getPostCount(); k++)                         //再次遍历元器件端口
                    {
                        if (j == k)
                        {
                            continue;                                                           //若两个端口相等则继续
                        }
                        int kn = ce.getNode(k);                                                 //获取端口对应的结点
                        if (ce.getConnection(j, k) && !closure [kn])                            //若两端点相连并没有标记
                        {
                            closure [kn] = true;
                            changed      = true;
                        }
                    }
                }
            }
            if (changed)
            {
                continue;
            }

            //连接未连接的结点
            for (int i = 0; i < nodeList.Count; i++)
            {
                if (!closure [i])
                {
                    stampResistor(0, i, 1e8f);
                    closure [i] = true;
                    changed     = true;
                    break;
                }
            }
        }

        //步骤五:短路等无效连接的判断
        Debug.Log("步骤五");
        for (int i = 0; i < elmList.Count; i++)
        {
            CircuitElm ce = getElm(i);                                                  //获取元器件
            //若为电压源或导线
            if ((ce.type == TYPES.VoltageElm && ce.getPostCount() == 2) ||
                (ce.type == TYPES.WireElm && ce.getPostCount() != 1))
            {
                FindPathInfo fpi = new FindPathInfo(FindPathInfo.VOLTAGE, ce, ce.getNode(1));
                if (fpi.findPath(ce.getNode(0)))                                        //判断是否短路
                //短路
                {
                    Utils.menuListener.PopTipUI("短  路");
                    Debug.Log("短路");
                    return;
                }
            }
        }

        //步骤六:简化矩阵
        Debug.Log("步骤六");
        for (int i = 0; i < matrixSize; i++)                                            //遍历矩阵的每一行
        {
            int     qm = -1, qp = -1;
            float   qv = 0;
            RowInfo re = circuitRowInfo [i];                                                    //获取每一行的信息
            if (re.lsChanges || re.dropRow || re.rsChanges)
            {
                continue;
            }
            float rsadd = 0;

            //寻找可以删除的行
            int j;
            for (j = 0; j < matrixSize; j++)                                                    //遍历矩阵的每一行
            {
                float q = circuitMatrix [i, j];                                                 //获取矩阵值
                if (circuitRowInfo [j].type == RowInfo.ROW_CONST)
                {
                    rsadd -= circuitRowInfo [j].value * q;
                    continue;
                }
                if (q == 0)
                {
                    continue;                                                                   //若矩阵值为0
                }
                if (qp == -1)                                                                   //记录第一个不为0的数值
                {
                    qp = j;                                                                     //记录第一个不为0的列
                    qv = q;                                                                     //记录该矩阵值
                    continue;
                }
                if (qm == -1 && q == -qv)                                                       //记录与qv互为相反数的列
                {
                    qm = j;                                                                     //列数
                    continue;
                }
                break;
            }
            if (j == matrixSize)                                                                //若遍历完了该行
            {
                if (qp == -1)
                {
                    //矩阵错误
                    Debug.Log("矩阵错误");
                    return;
                }
                RowInfo elt = circuitRowInfo [qp];                                              //获取行信息
                if (qm == -1)
                {
                    //一行只有一个常数
                    int k;
                    for (k = 0; elt.type == RowInfo.ROW_EQUAL && k < 100; k++)
                    {
                        qp  = elt.nodeEq;
                        elt = circuitRowInfo [qp];
                    }
                    if (elt.type == RowInfo.ROW_EQUAL)
                    {
                        elt.type = RowInfo.ROW_NORMAL;
                        continue;
                    }
                    if (elt.type != RowInfo.ROW_NORMAL)
                    {
                        continue;
                    }
                    elt.type  = RowInfo.ROW_CONST;                                              //标记为常数
                    elt.value = (circuitRightSide [i] + rsadd) / qv;                            //记录结点电压
                    circuitRowInfo [i].dropRow = true;                                          //删除该行
                    i = -1;
                }
                else if (circuitRightSide [i] + rsadd == 0)
                {
                    //若一行中只有两个非0的数值,并且两个数值互为相反数
                    if (elt.type != RowInfo.ROW_NORMAL)
                    {
                        int qq = qm;
                        qm  = qp;
                        qp  = qq;
                        elt = circuitRowInfo [qp];
                        if (elt.type != RowInfo.ROW_NORMAL)
                        {
                            //交换失败
                            continue;
                        }
                    }
                    elt.type   = RowInfo.ROW_EQUAL;                                             //标记行类型
                    elt.nodeEq = qm;                                                            //记录相等结点
                    circuitRowInfo [i].dropRow = true;                                          //删除标志位置true
                }
            }
        }

        //步骤七:确定新矩阵的大小
        Debug.Log("步骤七");
        int nn = 0;

        for (int i = 0; i != matrixSize; i++)                                   //遍历矩阵的行
        {
            RowInfo elt = circuitRowInfo [i];                                   //获取电路行信息
            if (elt.type == RowInfo.ROW_NORMAL)
            {
                elt.mapCol = nn++;
                continue;
            }
            if (elt.type == RowInfo.ROW_EQUAL)
            {
                RowInfo e2 = null;
                for (int j = 0; j != 100; j++)
                {
                    e2 = circuitRowInfo [elt.nodeEq];
                    if (e2.type != RowInfo.ROW_EQUAL)
                    {
                        break;
                    }
                    if (i == e2.nodeEq)
                    {
                        break;
                    }
                    elt.nodeEq = e2.nodeEq;
                }
            }
            if (elt.type == RowInfo.ROW_CONST)
            {
                elt.mapCol = -1;
            }
        }
        for (int i = 0; i != matrixSize; i++)
        {
            RowInfo elt = circuitRowInfo [i];
            if (elt.type == RowInfo.ROW_EQUAL)
            {
                RowInfo e2 = circuitRowInfo [elt.nodeEq];
                if (e2.type == RowInfo.ROW_CONST)
                {
                    elt.type   = e2.type;
                    elt.value  = e2.value;
                    elt.mapCol = -1;
                }
                else
                {
                    elt.mapCol = e2.mapCol;
                }
            }
        }

        //步骤八:创建新的简化矩阵
        Debug.Log("步骤八");
        Debug.Log("nn-----------------" + nn);
        int newsize = nn;

        float[,] newmatx = new float[newsize, newsize];
        float[] newrs = new float[newsize];
        int     ii    = 0;

        for (int i = 0; i != matrixSize; i++)
        {
            RowInfo rri = circuitRowInfo [i];
            if (rri.dropRow)
            {
                rri.mapRow = -1;
                continue;
            }
            newrs [ii] = circuitRightSide [i];
            rri.mapRow = ii;
            //System.out.println("Row " + i + " maps to " + ii);
            for (int j = 0; j != matrixSize; j++)
            {
                RowInfo ri = circuitRowInfo [j];
                if (ri.type == RowInfo.ROW_CONST)
                {
                    newrs [ii] -= ri.value * circuitMatrix [i, j];
                }
                else
                {
                    newmatx [ii, ri.mapCol] += circuitMatrix [i, j];
                }
            }
            ii++;
        }

        circuitMatrix    = newmatx;
        circuitRightSide = newrs;
        matrixSize       = circuitMatrixSize = newsize;
        for (int i = 0; i != matrixSize; i++)
        {
            origRightSide [i] = circuitRightSide [i];
        }
        for (int i = 0; i != matrixSize; i++)
        {
            for (int j = 0; j != matrixSize; j++)
            {
                origMatrix [i, j] = circuitMatrix [i, j];
            }
        }
        circuitNeedsMap = true;

        Debug.Log("--------新矩阵----------");
        for (int i = 0; i < CirSim.circuitMatrixSize; i++)
        {
            string s = i + ": ";
            for (int j = 0; j < CirSim.circuitMatrixSize; j++)
            {
                s += CirSim.circuitMatrix [i, j] + " ";
            }
            s += " " + CirSim.circuitRightSide [i];
            Debug.Log(s);
        }

        /*for (int i = 0; i != elmList.Count; i++) {
         * CircuitElm ce = getElm(i);
         * ce.doStep();
         * }*/

        if (!lu_factor(circuitMatrix, circuitMatrixSize, circuitPermute))
        {
            Debug.Log("矩阵计算错误");
            for (int i = 0; i < elmList.Count; i++)
            {
                getElm(i).stop();                  //停止所有元器件
            }
            return;
        }

        Debug.Log("--------LU分解后的矩阵----------");
        for (int i = 0; i < CirSim.circuitMatrixSize; i++)
        {
            string s = i + ": ";
            for (int j = 0; j < CirSim.circuitMatrixSize; j++)
            {
                s += CirSim.circuitMatrix [i, j] + " ";
            }
            s += " " + CirSim.circuitRightSide [i];
            Debug.Log(s);
        }

        //矩阵求解
        lu_solve(circuitMatrix, circuitMatrixSize, circuitPermute, circuitRightSide);

        //为每个结点的电压赋值
        for (int i = 0; i < circuitMatrixFullSize; i++)
        {
            RowInfo ri  = circuitRowInfo [i];                                                                           //获取行信息
            float   res = 0;
            if (ri.type == RowInfo.ROW_CONST)
            {
                res = ri.value;
            }
            else
            {
                res = circuitRightSide [ri.mapCol];
            }

            if (double.IsNaN(res))               //若是未知数结束循环
            {
                Debug.Log("res is NaN");
                break;
            }

            if (i < nodeList.Count - 1)
            {
                CircuitNode cn = getCircuitNode(i + 1);                                         //获取结点
                foreach (KeyValuePair <CircuitElm, int> kv in cn.links)                         //遍历结点上的所有端点
                {
                    kv.Key.setNodeVoltage(kv.Value, res);                                       //为结点赋予电压
                    Debug.Log(kv.Key.type + "--" + kv.Value + "         " + res);
                }
            }
            else
            {
                int j = i - (nodeList.Count - 1);
                voltageSources [j].setCurrent(j, res);
            }
        }

        for (int i = 0; i != elmList.Count; i++)
        {
            CircuitElm ce = getElm(i);
            ce.doStep();
        }

        if (!isNext)
        {
            for (int i = 0; i < elmList.Count; i++)
            {
                CircuitElm ce = getElm(i);                                                                      //获取元器件脚本
                if (ce.type == TYPES.MusicChipElm || ce.type == TYPES.RecorderChipElm)                          //包含集成电路
                {
                    isNext = true;
                    analyzeCircuit();                                                                                   //重新分析电路
                    isNext = false;
                    return;
                }
            }
        }

        //运行元器件
        for (int i = 0; i < elmList.Count; i++)
        {
            CircuitElm ce = getElm(i);                                  //获取元器件
            ce.work();                                                  //元器件工作
        }
    }
Esempio n. 27
0
        public void AnalyzeCircuit()
        {
            bool debug   = false;
            var  elmList = mSim.ElmList;

            if (elmList.Count == 0)
            {
                PostDrawList      = new List <Point>();
                BadConnectionList = new List <Point>();
                return;
            }

            StopMessage = null;
            StopElm     = null;

            int vscount = 0;

            NodeList      = new List <CircuitNode>();
            mPostCountMap = new Dictionary <Point, int>();
            bool       gotGround = false;
            bool       gotRail   = false;
            CircuitElm volt      = null;

            calculateWireClosure();

            if (debug)
            {
                Console.WriteLine("ac1");
            }
            /* look for voltage or ground element */
            for (int i = 0; i != elmList.Count; i++)
            {
                var ce = mSim.getElm(i);
                if (ce is GroundElm)
                {
                    gotGround = true;
                    break;
                }

                if (ce is RailElm)
                {
                    gotRail = true;
                }
                if (volt == null && (ce is VoltageElm))
                {
                    volt = ce;
                }
            }

            /* if no ground, and no rails, then the voltage elm's first terminal
             * /* is ground */
            if (!gotGround && volt != null && !gotRail)
            {
                var cn = new CircuitNode();
                var pt = volt.GetPost(0);
                NodeList.Add(cn);
                /* update node map */
                if (mNodeMap.ContainsKey(pt))
                {
                    mNodeMap[pt].Node = 0;
                }
                else
                {
                    mNodeMap.Add(pt, new NodeMapEntry(0));
                }
            }
            else
            {
                /* otherwise allocate extra node for ground */
                var cn = new CircuitNode();
                NodeList.Add(cn);
            }
            if (debug)
            {
                Console.WriteLine("ac2");
            }

            /* allocate nodes and voltage sources */
            LabeledNodeElm.ResetNodeList();
            for (int i = 0; i != elmList.Count; i++)
            {
                var ce     = mSim.getElm(i);
                int inodes = ce.InternalNodeCount;
                int ivs    = ce.VoltageSourceCount;
                int posts  = ce.PostCount;

                /* allocate a node for each post and match posts to nodes */
                for (int j = 0; j != posts; j++)
                {
                    var pt = ce.GetPost(j);
                    if (mPostCountMap.ContainsKey(pt))
                    {
                        int g = mPostCountMap[pt];
                        mPostCountMap[pt] = g + 1;
                    }
                    else
                    {
                        mPostCountMap.Add(pt, 1);
                    }

                    NodeMapEntry cln  = null;
                    var          ccln = mNodeMap.ContainsKey(pt);
                    if (ccln)
                    {
                        cln = mNodeMap[pt];
                    }

                    /* is this node not in map yet?  or is the node number unallocated?
                     * /* (we don't allocate nodes before this because changing the allocation order
                     * /* of nodes changes circuit behavior and breaks backward compatibility;
                     * /* the code below to connect unconnected nodes may connect a different node to ground) */
                    if (!ccln || cln.Node == -1)
                    {
                        var cn  = new CircuitNode();
                        var cnl = new CircuitNodeLink();
                        cnl.Num = j;
                        cnl.Elm = ce;
                        cn.Links.Add(cnl);
                        ce.SetNode(j, NodeList.Count);
                        if (ccln)
                        {
                            cln.Node = NodeList.Count;
                        }
                        else
                        {
                            mNodeMap.Add(pt, new NodeMapEntry(NodeList.Count));
                        }
                        NodeList.Add(cn);
                    }
                    else
                    {
                        int n   = cln.Node;
                        var cnl = new CircuitNodeLink();
                        cnl.Num = j;
                        cnl.Elm = ce;
                        getCircuitNode(n).Links.Add(cnl);
                        ce.SetNode(j, n);

                        /* if it's the ground node, make sure the node voltage is 0,
                         * /* cause it may not get set later */
                        if (n == 0)
                        {
                            ce.SetNodeVoltage(j, 0);
                        }
                    }
                }
                for (int j = 0; j != inodes; j++)
                {
                    var cn = new CircuitNode();
                    cn.Internal = true;
                    var cnl = new CircuitNodeLink();
                    cnl.Num = j + posts;
                    cnl.Elm = ce;
                    cn.Links.Add(cnl);
                    ce.SetNode(cnl.Num, NodeList.Count);
                    NodeList.Add(cn);
                }
                vscount += ivs;
            }

            makePostDrawList();
            if (!calcWireInfo())
            {
                return;
            }
            mNodeMap = null; /* done with this */

            VoltageSources   = new CircuitElm[vscount];
            vscount          = 0;
            CircuitNonLinear = false;
            if (debug)
            {
                Console.WriteLine("ac3");
            }

            /* determine if circuit is nonlinear */
            for (int i = 0; i != elmList.Count; i++)
            {
                var ce = mSim.getElm(i);
                if (ce.NonLinear)
                {
                    CircuitNonLinear = true;
                }
                int ivs = ce.VoltageSourceCount;
                for (int j = 0; j != ivs; j++)
                {
                    VoltageSources[vscount] = ce;
                    ce.SetVoltageSource(j, vscount++);
                }
            }
            VoltageSourceCount = vscount;

            int matrixSize = NodeList.Count - 1 + vscount;

            Matrix         = new double[matrixSize, matrixSize];
            mRightSide     = new double[matrixSize];
            mOrigMatrix    = new double[matrixSize, matrixSize];
            mOrigRightSide = new double[matrixSize];
            mMatrixSize    = mMatrixFullSize = matrixSize;
            mRowInfo       = new RowInfo[matrixSize];
            mPermute       = new int[matrixSize];
            for (int i = 0; i != matrixSize; i++)
            {
                mRowInfo[i] = new RowInfo();
            }
            mCircuitNeedsMap = false;

            /* stamp linear circuit elements */
            for (int i = 0; i != elmList.Count; i++)
            {
                var ce = mSim.getElm(i);
                ce.Stamp();
            }
            if (debug)
            {
                Console.WriteLine("ac4");
            }

            /* determine nodes that are not connected indirectly to ground */
            var  closure = new bool[NodeList.Count];
            bool changed = true;

            closure[0] = true;
            while (changed)
            {
                changed = false;
                for (int i = 0; i != elmList.Count; i++)
                {
                    var ce = mSim.getElm(i);
                    if (ce is WireElm)
                    {
                        continue;
                    }

                    /* loop through all ce's nodes to see if they are connected
                     * /* to other nodes not in closure */
                    for (int j = 0; j < ce.ConnectionNodeCount; j++)
                    {
                        if (!closure[ce.GetConnectionNode(j)])
                        {
                            if (ce.HasGroundConnection(j))
                            {
                                closure[ce.GetConnectionNode(j)] = changed = true;
                            }
                            continue;
                        }
                        int k;
                        for (k = 0; k != ce.ConnectionNodeCount; k++)
                        {
                            if (j == k)
                            {
                                continue;
                            }
                            int kn = ce.GetConnectionNode(k);
                            if (ce.GetConnection(j, k) && !closure[kn])
                            {
                                closure[kn] = true;
                                changed     = true;
                            }
                        }
                    }
                }
                if (changed)
                {
                    continue;
                }

                /* connect one of the unconnected nodes to ground with a big resistor, then try again */
                for (int i = 0; i != NodeList.Count; i++)
                {
                    if (!closure[i] && !getCircuitNode(i).Internal)
                    {
                        /* Console.WriteLine("node " + i + " unconnected"); */
                        StampResistor(0, i, 1e8);
                        closure[i] = true;
                        changed    = true;
                        break;
                    }
                }
            }
            if (debug)
            {
                Console.WriteLine("ac5");
            }

            for (int i = 0; i != elmList.Count; i++)
            {
                var ce = mSim.getElm(i);

                /* look for inductors with no current path */
                if (ce is InductorElm)
                {
                    var fpi = new PathInfo(PathType.INDUCTOR, ce, ce.Nodes[1], elmList, NodeList.Count);
                    if (!fpi.FindPath(ce.Nodes[0]))
                    {
                        if (debug)
                        {
                            Console.WriteLine(ce + " no path");
                        }
                        ce.Reset();
                    }
                }

                /* look for current sources with no current path */
                if (ce is CurrentElm)
                {
                    var cur = (CurrentElm)ce;
                    var fpi = new PathInfo(PathType.INDUCTOR, ce, ce.Nodes[1], elmList, NodeList.Count);
                    if (!fpi.FindPath(ce.Nodes[0]))
                    {
                        cur.stampCurrentSource(true);
                    }
                    else
                    {
                        cur.stampCurrentSource(false);
                    }
                }

                if (ce is VCCSElm)
                {
                    var cur = (VCCSElm)ce;
                    var fpi = new PathInfo(PathType.INDUCTOR, ce, cur.getOutputNode(0), elmList, NodeList.Count);
                    if (cur.hasCurrentOutput() && !fpi.FindPath(cur.getOutputNode(1)))
                    {
                        cur.mBroken = true;
                    }
                    else
                    {
                        cur.mBroken = false;
                    }
                }

                /* look for voltage source or wire loops.  we do this for voltage sources or wire-like elements (not actual wires
                 * /* because those are optimized out, so the findPath won't work) */
                if (2 == ce.PostCount)
                {
                    if ((ce is VoltageElm) || (ce.IsWire && !(ce is WireElm)))
                    {
                        var fpi = new PathInfo(PathType.VOLTAGE, ce, ce.Nodes[1], elmList, NodeList.Count);
                        if (fpi.FindPath(ce.Nodes[0]))
                        {
                            Stop("Voltage source/wire loop with no resistance!", ce);
                            return;
                        }
                    }
                }
                else if (ce is Switch2Elm)
                {
                    /* for Switch2Elms we need to do extra work to look for wire loops */
                    var fpi = new PathInfo(PathType.VOLTAGE, ce, ce.Nodes[0], elmList, NodeList.Count);
                    for (int j = 1; j < ce.PostCount; j++)
                    {
                        if (ce.GetConnection(0, j) && fpi.FindPath(ce.Nodes[j]))
                        {
                            Stop("Voltage source/wire loop with no resistance!", ce);
                            return;
                        }
                    }
                }

                /* look for path from rail to ground */
                if ((ce is RailElm) || (ce is LogicInputElm))
                {
                    var fpi = new PathInfo(PathType.VOLTAGE, ce, ce.Nodes[0], elmList, NodeList.Count);
                    if (fpi.FindPath(0))
                    {
                        Stop("Path to ground with no resistance!", ce);
                        return;
                    }
                }

                /* look for shorted caps, or caps w/ voltage but no R */
                if (ce is CapacitorElm)
                {
                    var fpi = new PathInfo(PathType.SHORT, ce, ce.Nodes[1], elmList, NodeList.Count);
                    if (fpi.FindPath(ce.Nodes[0]))
                    {
                        Console.WriteLine(ce + " shorted");
                        ((CapacitorElm)ce).Shorted();
                    }
                    else
                    {
                        /* a capacitor loop used to cause a matrix error. but we changed the capacitor model
                         * /* so it works fine now. The only issue is if a capacitor is added in parallel with
                         * /* another capacitor with a nonzero voltage; in that case we will get oscillation unless
                         * /* we reset both capacitors to have the same voltage. Rather than check for that, we just
                         * /* give an error. */
                        fpi = new PathInfo(PathType.CAPACITOR_V, ce, ce.Nodes[1], elmList, NodeList.Count);
                        if (fpi.FindPath(ce.Nodes[0]))
                        {
                            Stop("Capacitor loop with no resistance!", ce);
                            return;
                        }
                    }
                }
            }
            if (debug)
            {
                Console.WriteLine("ac6");
            }

            if (!simplifyMatrix(matrixSize))
            {
                return;
            }

            if (debug)
            {
                Console.WriteLine("matrixSize = " + matrixSize + " " + CircuitNonLinear);
                for (int j = 0; j != mMatrixSize; j++)
                {
                    Console.WriteLine("RightSide[{0}]:{1}", j, mRightSide[j]);
                    for (int i = 0; i != mMatrixSize; i++)
                    {
                        Console.WriteLine("  Matrix[{0},{1}]:{2}", j, i, Matrix[j, i]);
                    }
                }
            }

            /* check if we called stop() */
            if (Matrix == null)
            {
                return;
            }

            /* if a matrix is linear, we can do the lu_factor here instead of
             * /* needing to do it every frame */
            if (!CircuitNonLinear)
            {
                if (!luFactor(Matrix, mMatrixSize, mPermute))
                {
                    Stop("Singular matrix!", null);
                    return;
                }
            }

            /* show resistance in voltage sources if there's only one */
            bool gotVoltageSource = false;

            ShowResistanceInVoltageSources = true;
            for (int i = 0; i != elmList.Count; i++)
            {
                var ce = mSim.getElm(i);
                if (ce is VoltageElm)
                {
                    if (gotVoltageSource)
                    {
                        ShowResistanceInVoltageSources = false;
                    }
                    else
                    {
                        gotVoltageSource = true;
                    }
                }
            }
        }