Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

MathHelpers.cpp

Go to the documentation of this file.
00001 
00002 // MathCore = a WYSIWYG equation editor + a powerful math engine     //
00003 // Copyright (C) 2003 by Francesco Montorsi                          //
00004 //                                                                   //
00005 // This library is free software; you can redistribute it and/or     //
00006 // modify it under the terms of the GNU Lesser General Public        //
00007 // License as published by the Free Software Foundation; either      //
00008 // version 2.1 of the License, or (at your option) any later         //
00009 // version.                                                          //
00010 //                                                                   //
00011 // This library is distributed in the hope that it will be useful,   //
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of    //
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the      //
00014 // GNU Lesser General Public License for more details.               //
00015 //                                                                   //
00016 // You should have received a copy of the GNU Lesser General Public  //
00017 // License along with this program; if not, write to the Free        //
00018 // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,   //
00019 // MA 02111-1307, USA.                                               //
00020 //                                                                   //
00021 // For any comment, suggestion or feature request, please contact    //
00022 // the administrator of the project at frm@users.sourceforge.net     //
00023 //                                                                   //
00030 
00031 
00032 
00033 // optimization for GCC compiler
00034 #ifdef __GNUG__
00035 #pragma implementation "MathHelpers.h"
00036 #endif
00037 
00038 // includes
00039 #include "mc/mcprec.h"
00040 #ifdef __BORLANDC__
00041     #pragma hdrstop
00042 #endif
00043 
00044 #ifndef mcPRECOMP
00045  #include "mc/MathHelpers.h"
00046  #include "mc/MathCore.h"
00047  #include "mc/Element.h"
00048  #include "mc/Symbol.h"
00049  #include "mc/Range.h"
00050 #endif
00051 
00052 
00053 
00054 
00055 // init statics
00056 mcRange *mcRange::pN = NULL;
00057 mcRange *mcRange::pZ = NULL;
00058 mcRange *mcRange::pR = NULL;
00059 mcRange *mcRange::pC = NULL;
00060 mcRange *mcRange::pEmpty = NULL;
00061 
00062 mcExtRange *mcExtRange::pN = NULL;
00063 mcExtRange *mcExtRange::pZ = NULL;
00064 mcExtRange *mcExtRange::pR = NULL;
00065 mcExtRange *mcExtRange::pC = NULL;
00066 mcExtRange *mcExtRange::pEmpty = NULL;
00067 
00068 
00069 
00070 
00071 
00072 // ----------------------------------------
00073 // mcABSTRACTARRAY
00074 // ----------------------------------------
00075 
00076 void mcAbstractArray::data_Add(mcAbstractItem *pointer)
00077 {
00078  m_arr.Add(pointer);
00079  data_OnArrayChange();
00080 }
00081 
00082 void mcAbstractArray::data_Insert(mcAbstractItem *pointer, int pos)
00083 {
00084  // just ask the wxArrayPtrVoid to make space for a
00085  // new pointer and store it.
00086  m_arr.Insert(pointer, pos);
00087  data_OnArrayChange();
00088 }
00089 
00090 void mcAbstractArray::data_SetItem(mcAbstractItem *pointer, int n)
00091 {
00092  data_Insert(pointer, n); // OnArrayChange is called here
00093  data_RemoveAt(n+1, 1); // OnArrayChange is called here
00094 }
00095 
00096 void mcAbstractArray::data_RemoveAt(int n, int count)
00097 {
00098  // check start & end indexes
00099  if (n < 0 || n >= data_GetCount())
00100   return;
00101  if (n+count > data_GetCount())
00102   count = data_GetCount()-n;
00103 
00104  // delete the object(s)
00105  for (int i=n; i < n+count; i++)
00106   data_Delete(i);
00107 
00108  // and detach it from the array
00109  m_arr.RemoveAt(n, count);
00110  data_OnArrayChange();
00111 }
00112 
00113 void mcAbstractArray::data_Remove(const mcAbstractItem *p)
00114 {
00115  int idx = data_Find(p);
00116  if (idx == -1) return;
00117 
00118  data_RemoveAt(idx);
00119 }
00120 
00121 mcAbstractItem *mcAbstractArray::data_Detach(int idx)
00122 {
00123  mcAbstractItem *toret = data_GetItem(idx);
00124 
00125  // use wxArrayPtrVoid::RemoveAt which just removes the _pointer_
00126  // from the array and does not delete it...
00127  m_arr.RemoveAt(idx, 1);
00128 
00129  return toret;
00130 }
00131 
00132 void mcAbstractArray::data_Clear()
00133 {
00134  data_RemoveAt(0, data_GetCount()); // OnArrayChange is called here
00135 
00136  // the array should already be empty: free its memory
00137  m_arr.Clear();
00138 }
00139  
00140 int mcAbstractArray::data_Find(const mcAbstractItem *pointer) const
00141 {
00142  for (int i=0; i < data_GetCount(); i++)
00143   if (data_GetItem(i) == pointer)
00144    return i;
00145  return -1;
00146 }
00147 
00148 void mcAbstractArray::data_DeepCopy(const mcAbstractArray &arr)
00149 {
00150  data_Clear();
00151  for (int i=0, max=arr.data_GetCount(); i<max; i++)
00152   data_Add(arr.data_GetCopyOf(i));  // OnArrayChange is called here
00153 }
00154 
00155 #ifdef __MCDEBUG__
00156 void mcAbstractArray::data_Check() const
00157 {
00158  mcASSERT(data_GetCount() >= 0, wxT("Invalid count index"));
00159 
00160  // slow but *very* important check
00161  for (int i=0; i < data_GetCount(); i++)
00162   for (int j=0; j < data_GetCount(); j++)
00163    mcASSERT(data_GetItem(i) != data_GetItem(j) || i == j, 
00164      wxT("The i-th pointer is stored twice (as i and as j) !!!"));
00165     
00166 }
00167 #endif
00168 
00169 
00170 
00171 
00172 // ----------------------------------------
00173 // mcTEXTSETTINGS
00174 // ----------------------------------------
00175 
00176 void mcTextSettings::Decode(const wxString &fnt)
00177 {
00178  long style, weight, pointsize, family;
00179  wxString todecode(fnt);  // create a modifiable copy of t
00180  wxString facename;
00181  
00182  // extract the font style
00183  todecode.AfterLast(wxT('-')).ToLong(&style, 0); 
00184  if (style <= 0) style = wxNORMAL;
00185  
00186  // extract the weight of this font
00187  todecode = todecode.BeforeLast(wxT('-'));
00188  todecode.AfterLast(wxT('-')).ToLong(&weight, 0);
00189  if (weight == 0) weight = wxNORMAL;
00190  
00191  // extract point size
00192  todecode = todecode.BeforeLast(wxT('-'));
00193  todecode.AfterLast(wxT('-')).ToLong(&pointsize, 0); 
00194  if (pointsize <= 0) pointsize = 16;
00195  
00196  // extract face name
00197  todecode = todecode.BeforeLast(wxT('-'));
00198  facename = todecode.AfterLast(wxT('-'));
00199  
00200  // extract font family
00201  todecode = todecode.BeforeLast(wxT('-'));
00202  todecode.AfterLast(wxT('-')).ToLong(&family, 0); 
00203  if (family <= 0) family = wxSWISS;
00204  
00205  // build the font
00206  m_hFont.SetPointSize(pointsize);
00207  m_hFont.SetWeight(weight);
00208  m_hFont.SetStyle(style);
00209  m_hFont.SetFamily(family);
00210  if (!facename.IsEmpty()) 
00211   m_hFont.SetFaceName(facename);
00212 }
00213 
00214 
00215 
00216 
00217 // ----------------------------------------
00218 // mcSTYLE
00219 // ----------------------------------------
00220 
00221 bool mcStyle::Ok() 
00222 {
00223  bool res = TRUE;
00224 
00225  // scan the array checking each entry
00226  for (int i=0; i < mcSTYLE_TEXTSETTINGS_NUM; i++)
00227   res &= m_pTextSettings[i].Ok();
00228 
00229  return res;
00230 }
00231 
00232 int mcStyle::GetIndexFor(mcElementType t) const
00233 {
00234  switch (t) {
00235 
00236  // for mcET_OPERATOR, mcET_EMPTYBOX and all the remaining...
00237  default:
00238   return 0;
00239 
00240  case mcET_NUMBER:
00241   return 1;
00242 
00243  case mcET_FUNCTION:
00244   return 2;
00245   
00246  case mcET_TEXT:
00247  case mcET_MATHANDSYSTEM:
00248  case mcET_MATHORSYSTEM:
00249  case mcET_MATHMNG:
00250   return 3;
00251 
00252  case mcET_SYMBOL:
00253   return 4;
00254  }
00255 }
00256 
00257 int mcStyle::GetIndexFor(const mcElement &e) const
00258 {
00259  // a little exception for mcSymbols
00260  if (e.data_GetType() == mcET_SYMBOL) {
00261   mcSymbol p(e);
00262   if (p.hlp()->data_isGreekSymbol())
00263    return mcSTYLE_SPECIAL_SETTINGS;
00264  }
00265 
00266  return GetIndexFor(e.data_GetType());
00267 }
00268 
00269 
00270 
00271 
00272 // ----------------------------------------
00273 // mcSTYLEARRAY
00274 // ----------------------------------------
00275 
00276 mcStyleArray::~mcStyleArray()
00277 {
00278  if (m_pStyles)
00279   delete [] m_pStyles;
00280  m_pStyles = NULL;
00281 }
00282 
00283 void mcStyleArray::CreateArray()
00284 {
00285  if (m_pStyles == NULL)
00286   m_pStyles = new mcStyle[mcELEMENTMATH_MAX_EXPDEPTH];
00287 }
00288 
00289 void mcStyleArray::DeepCopy(const mcStyleArray *p)
00290 {
00291  // copy the array
00292  for (int i=0; i < mcELEMENTMATH_MAX_EXPDEPTH; i++)
00293   m_pStyles[i].DeepCopy(&p->m_pStyles[i]);
00294 }
00295 
00296 void mcStyleArray::Set(const mcStyle *arr)
00297 {
00298  // copy the given styles
00299  for (int i=0; i < mcELEMENTMATH_MAX_EXPDEPTH; i++)
00300   m_pStyles[i].DeepCopy(&arr[i]);
00301 }
00302 
00303 int mcStyleArray::GetCount()
00304 {
00305  // this function cannot be placed as inline function in the declaration
00306  // of mcStyleArray because mcELEMENTMATH_MAX_EXPDEPTH is a #define which
00307  // is placed in wxT("Element.h"), which in turn includes "MathHelpers.h"...
00308  return mcELEMENTMATH_MAX_EXPDEPTH;
00309 }
00310 
00311 int mcStyleArray::gui_GetStyleIndexFor(const mcElement &p) const
00312 {
00313  // style index coincides with exponent depth...
00314  /*if (p.data_GetExpDepth() > 0) {
00315   int u=432;
00316   u=3;
00317  }*/
00318  return p.gui_GetExpDepth();
00319 }
00320 
00321 void mcStyleArray::ScaleSize(float f)
00322 {
00323  for (int i=0; i < mcELEMENTMATH_MAX_EXPDEPTH; i++)
00324   m_pStyles[i].ScaleSize(f);
00325 }
00326 
00327 
00328 
00329 
00330 // ---------------
00331 // mcMATHTYPE
00332 // ---------------
00333 
00334 wxString mcMathType::io_GetDescString() const
00335 {
00336  wxString res;
00337 
00338  switch (m_tMath1) {
00339  case mcMTL1_POLYNOMIAL:
00340   res += wxT("polynomial "); break;
00341  case mcMTL1_RATIONAL:
00342   res += wxT("rational "); break;
00343  case mcMTL1_NOT_RECOGNIZED:
00344   res += wxT("[not-recognized] "); break;
00345  }
00346 
00347  switch (m_tMath2) {
00348  case mcMTL2_ALGEBRAIC:
00349   res += wxT("algebraic "); break;
00350  case mcMTL2_TRANSCENDENT:
00351   res += wxT("transcendental "); break;
00352  case mcMTL2_NOT_RECOGNIZED:
00353   res += wxT("[not-recognized] "); break;
00354  }
00355 
00356  switch (m_tMath3) {
00357  case mcMTL3_CONSTANT:
00358   res += wxT("constant"); break;
00359  case mcMTL3_UNKNOWN:
00360   res += wxT("unknown"); break;
00361  case mcMTL3_PARAMETRIC:
00362   res += wxT("parametric"); break;
00363  case mcMTL3_NOT_RECOGNIZED:
00364   res += wxT("[not-recognized]"); break;
00365  }
00366 
00367  // do not check for the mcMTL4_NOTRECOGNIZED flag
00368  if (m_tMath4 & mcMTL4_LOGARITHMIC)
00369   res += wxT("logarithmic");
00370  if (m_tMath4 & mcMTL4_EXPONENTIAL)
00371   res += wxT("exponential");
00372  if (m_tMath4 & mcMTL4_TRIGONOMETRIC)
00373   res += wxT("trigonometric");
00374 
00375  // last check
00376  if (res.IsEmpty())
00377   res = wxT("[invalid data]");
00378 
00379  return res;
00380 }
00381 
00382 mcMathType mcMathType::math_MultiplyBy(const mcMathType &t)
00383 {
00384  // the result is exactly the same...
00385  return math_Add(t);
00386 }
00387 
00388 mcMathType mcMathType::math_DivideBy(const mcMathType &t)
00389 {
00390  math_MultiplyBy(t);
00391 
00392  // TOTEST
00393  if (t.m_tMath3 != mcMTL3_CONSTANT)
00394   m_tMath1 = mcMTL1_RATIONAL;
00395  
00396  return *this;
00397 }
00398 
00399 mcMathType mcMathType::math_Add(const mcMathType &t)
00400 {
00401  m_tMath1 = mcMIN(m_tMath1, t.m_tMath1);
00402  m_tMath2 = mcMIN(m_tMath2, t.m_tMath2);
00403  m_tMath3 = mcMIN(m_tMath3, t.m_tMath3);
00404 
00405  m_tMath4 = m_tMath4 | t.m_tMath4;
00406 
00407 /* if (m_tMath1 == mcMTL1_POLYNOMIAL && t.m_tMath1 == mcMTL1_POLYNOMIAL)
00408   m_tMath1 = mcMTL1_POLYNOMIAL;
00409  else
00410   m_tMath1 = mcMTL1_RATIONAL;
00411 
00412  if (m_tMath2 == mcMTL2_ALGEBRAIC && t.m_tMath2 == mcMTL2_ALGEBRAIC)
00413   m_tMath2 = mcMTL2_ALGEBRAIC;
00414  else
00415   m_tMath2 = mcMTL2_TRANSCENDENT;
00416 
00417  if (m_tMath3 == mcMTL3_PARAMETRIC || 
00418   t.m_tMath3 == mcMTL3_PARAMETRIC)
00419   m_tMath3 = mcMTL3_PARAMETRIC;
00420  else if (m_tMath3 == mcMTL3_UNKNOWN || 
00421    t.m_tMath3 == mcMTL3_UNKNOWN)
00422   m_tMath3 = mcMTL3_UNKNOWN;
00423  else
00424   m_tMath3 = mcMTL3_CONSTANT;*/
00425   
00426  return *this;
00427 }
00428 
00429 mcMathType mcMathType::math_RaiseTo(const mcMathType &t)
00430 {
00431  math_MultiplyBy(t);
00432 
00433  // TOTEST: it is trascendent only if 't' is not constant
00434  if (t.m_tMath3 != mcMTL3_CONSTANT) {
00435   m_tMath2 = mcMTL2_TRANSCENDENT;
00436   m_tMath4 = mcMTL4_EXPONENTIAL;
00437  }
00438  
00439  return *this;
00440 }
00441 
00442 mcMathType mcMathType::math_ApplyOp(mcElementType optype, const mcMathType &t)
00443 {
00444  if (optype == mcET_ADDOP || optype == mcET_SUBOP)
00445   math_Add(t);
00446  else if (optype == mcET_MULTOP)
00447   math_MultiplyBy(t);
00448  else if (optype == mcET_DIVOP)
00449   math_DivideBy(t);
00450   
00451  return *this;
00452 }
00453 
00454 
00455 
00456 // ----------------------------------------
00457 // mcMATHSYSTEMTYPE
00458 // ----------------------------------------
00459 
00460 wxString mcMathSystemType::io_GetDescString(int nequ) const
00461 {
00462  wxString type;
00463 
00464  switch (m_tMath1) {
00465  case mcMSTL1_NOT_RECOGNIZED:
00466   type = wxT("not recognized"); break;
00467  case mcMSTL1_EQUATIONS:
00468   type = wxString::Format(wxT(" %d-equations system"), nequ); break;
00469  case mcMSTL1_INEQUALITIES:
00470   type = wxString::Format(wxT(" %d-inequalities system"), nequ); break;
00471  case mcMSTL1_EXPRESSION:
00472   type += wxT(" expression"); break;
00473  case mcMSTL1_MIXED:
00474   type = wxT(" mixed system"); break;
00475  }
00476 
00477  return type;
00478 }
00479 
00480 mcMathSystemType mcMathSystemType::math_CombineWith(const mcMathSystemType &t)
00481 {
00482  // if one of the two is unrecognized, then
00483  // also the global system is unrecognized...
00484  if (m_tMath1 == mcMSTL1_NOT_RECOGNIZED ||
00485   t.m_tMath1 == mcMSTL1_NOT_RECOGNIZED) {
00486 
00487   m_tMath1 = mcMSTL1_NOT_RECOGNIZED;
00488   return *this;
00489  }
00490 
00491  if (m_tMath1 != t.m_tMath1)
00492   m_tMath1 = mcMSTL1_MIXED;
00493 
00494  return *this;
00495 }
00496 
00497 
00498 
00499 
00500 // ----------------------------------------
00501 // mcRANGE
00502 // ----------------------------------------
00503 
00504 mcRange::~mcRange()  // cannot be placed in the header
00505 {
00506 }
00507 
00508 void mcRange::math_Set(const mcRealValue &l, const mcRealValue &u)
00509 {
00510  if (!u.isNAN()) { 
00511   //mcSAFE_DELETE(m_pUpper);
00512   //m_pUpper = mcNewPolynomial(); 
00513   //m_pUpper.math_
00514   m_pUpper.math_WrapNumber(u);
00515  }
00516  if (!l.isNAN()) { 
00517   //mcSAFE_DELETE(m_pLower); 
00518   //m_pLower = mcNewPolynomial(); 
00519   m_pLower.math_WrapNumber(l);
00520  }
00521 }
00522 
00523 void mcRange::math_Set(const mcPolynomial &l, const mcPolynomial &u)
00524 {
00525  if (u != mcEmptyElement) m_pUpper = u;
00526  if (l != mcEmptyElement) m_pLower = l;
00527 }
00528 
00529 bool mcRange::math_isFinite() const
00530 { 
00531  return m_pUpper.math_isFinite() & 
00532    m_pLower.math_isFinite(); 
00533 }
00534 
00535 mcRealValue mcRange::math_GetLowerLimitValue() const
00536 { return m_pLower.math_Evaluate(); }
00537 
00538 mcRealValue mcRange::math_GetUpperLimitValue() const
00539 { return m_pUpper.math_Evaluate(); }
00540 
00541 
00542 
00543 #define mcBM_INCLUDE_LCHAR  wxT("[")
00544 #define mcBM_INCLUDE_RCHAR  wxT("]")
00545 
00546 #define mcBM_EXCLUDE_LCHAR  wxT("(")
00547 #define mcBM_EXCLUDE_RCHAR  wxT(")")
00548 
00549 
00550 wxString mcRange::io_GetInlinedExpr() const
00551 {
00552  wxString middle = m_pLower.io_GetInlinedExpr() + wxT(";") +
00553       m_pUpper.io_GetInlinedExpr();
00554 
00555  switch (m_nBounds) {
00556  case mcBM_INCLUDE_BOTH:
00557   return mcBM_INCLUDE_LCHAR + middle + mcBM_INCLUDE_RCHAR;
00558  case mcBM_INCLUDE_LEFT:
00559   return mcBM_INCLUDE_LCHAR + middle + mcBM_EXCLUDE_RCHAR;
00560  case mcBM_INCLUDE_RIGHT:
00561   return mcBM_EXCLUDE_LCHAR + middle + mcBM_INCLUDE_RCHAR;
00562  case mcBM_INCLUDE_NONE:
00563   return mcBM_EXCLUDE_LCHAR + middle + mcBM_EXCLUDE_RCHAR;
00564  }
00565 
00566  // just to avoid warnings
00567  return wxEmptyString;
00568 }
00569 
00570 
00571 
00572 
00573 // ----------------------------------------
00574 // mcEXTRANGE
00575 // ----------------------------------------
00576 
00577 bool mcExtRange::math_isFinite() const
00578 {
00579  bool finite = TRUE;
00580  for (int i=0; i < data_GetCount(); i++)
00581   finite &= data_GetRange(i)->math_isFinite();
00582  return finite;
00583 }
00584 
00585 
00586 
00587 
00588 // ----------------------------------------
00589 // mcSYMBOLPROPERTIES
00590 // ----------------------------------------
00591 
00592 mcSymbolProperties::mcSymbolProperties(int symtype,
00593             const wxString &name,
00594             wxFontEncoding encoding,
00595             const mcRealValue &value,
00596             const wxString &inlinedsym,
00597             const wxString &subscript,
00598             mcExtRange *domain,
00599             bool evaluating)
00600 {
00601  m_nSymbolType = symtype;
00602  m_fEncoding = encoding;
00603  
00604  m_fValue = value;
00605  m_pDomain = NULL;
00606 
00607  // FIXME:
00608  //if (domain) 
00609   //m_pDomain = domain->data_Clone();
00610  
00611  m_strSubscript = subscript;
00612  m_strInlinedSymbol = inlinedsym;
00613  m_strSymbol = name;
00614 
00615  m_bEvaluating = evaluating;
00616 
00617  // create at least a mcSymbol class linked with us.
00618  mcSymbolHelpers *safe = new mcSymbolHelpers;
00619  safe->data_LinkWith(this);
00620 }
00621 
00622 mcSymbolProperties::~mcSymbolProperties()
00623 {
00624  // this symbol is being deleted; if we have instances of
00625  // mcSymbolData which are linked with us, then we must
00626  // unlink them...
00627  for (int i=0,max=(int)m_arrLinkedSymbol.GetCount(); i < max; i++) {
00628   
00629   mcSymbolHelpers *p = (mcSymbolHelpers *)m_arrLinkedSymbol.Item(0);
00630 
00631   // mcSymbol will automatically call our Unlink() function
00632   //if (p) 
00633   mcASSERT(p != NULL, wxT("We are linked with a NULL symbol ??"));
00634   p->data_Unlink();
00635 
00636   if (i == 0) {
00637 
00638    // the first symbol linked with us is a special symbol
00639    // created during mcSymbolProperties construction and
00640    // we are the owner of it, so we must take care of its
00641    // deletion
00642    delete p;
00643   }
00644  }
00645 }
00646 
00647 bool mcSymbolProperties::data_isSameAs(const mcSymbolProperties &s) const
00648 {
00649  // case #1: the two symbols have the same name & encoding & subscript
00650  if (s.m_strSymbol == m_strSymbol && 
00651    s.m_fEncoding == m_fEncoding &&
00652      s.m_strSubscript == m_strSubscript)
00653   return TRUE;
00654   
00655  // case #2: the two symbols have the same inlined expression & subscript
00656  if (s.io_GetInlinedSym() == io_GetInlinedSym() &&
00657   s.m_strSubscript == m_strSubscript)
00658   return TRUE;
00659 
00660  // if the two symbols are different, then these check should be harmless
00661  
00662  return FALSE;
00663 }
00664 
00665 int mcSymbolProperties::math_FindDuplicate(const mcSymbolArray *arr, int occ) const
00666 {
00667  int occurrence = 0;
00668  int n = arr->data_FindSymbol(mcSYMFIND_MATCH_NAME, *this, occurrence);
00669  
00670  while (n != mcSYM_NOTFOUND) {
00671   
00672   const mcSymbolProperties *found = arr->data_GetSymbol(n);
00673   
00674   // ok; we have found a symbol with the same name of *this;
00675   // now check if it satisfies the isSameAs function...
00676   if (this != found && this->data_isSameAs(*found)) {
00677 
00678    // ok, this is the occurrence of the duplicate symbol we were
00679    // searching for the array
00680    if (occ == 0)
00681     return n;
00682    occ--;  // wait for the next one...
00683   }
00684    
00685   // this symbol has our same name but it's not a duplicate...
00686   occurrence++;  // search next
00687   n = arr->data_FindSymbol(mcSYMFIND_MATCH_NAME, *this, occurrence);
00688  }
00689  
00690  return mcSYM_NOTFOUND;
00691 }
00692 
00693 
00694 
00695 
00696 // ----------------------------------------
00697 // mcSYMBOLARRAY
00698 // ----------------------------------------
00699 
00700 int mcSymbolArray::data_FindSymbol(long flags, const wxString &name,
00701          wxFontEncoding enc, const mcRealValue &value,
00702          const wxString &subscript, const wxString &inlined,
00703          int occurrence) const
00704 {
00705  // this should always be synchronized perfectly with mcSymbolProperties
00706  // constructor
00707  mcSymbolProperties tmp(mcSYM_NOTSET, name, enc, value, inlined, subscript);
00708 
00709  return data_FindSymbol(flags, tmp, occurrence);
00710 }
00711 
00712 int mcSymbolArray::data_FindSymbol(long flags, const mcSymbolProperties &sym, int occ) const
00713 {
00714  // search in this array
00715  for (int i=0; i < data_GetCount(); i++) {
00716 
00717   bool match = TRUE;
00718 
00719   // if all required conditions are met...
00720   if (flags & mcSYMFIND_MATCH_NAME) match &= (data_GetSymbolName(i) == sym.m_strSymbol);
00721   if (flags & mcSYMFIND_MATCH_ENCODING) match &= (data_GetEncoding(i) == sym.m_fEncoding);
00722   if (flags & mcSYMFIND_MATCH_VALUE) match &= (math_GetValue(i) == sym.m_fValue);
00723   if (flags & mcSYMFIND_MATCH_INLINED) match &= (io_GetInlinedSymbol(i) == sym.io_GetInlinedSym());
00724   if (flags & mcSYMFIND_MATCH_SUBSCRIPT) match &= (data_GetSubscript(i) == sym.m_strSubscript);
00725 
00726   if (match) {
00727    if (occ == 0)
00728     return i;   // ...then, return what we found
00729 
00730    // this is not the occurrence we're searching...
00731    occ--;
00732   }
00733  }
00734 
00735  // we didn't find it
00736  return mcSYM_NOTFOUND;
00737 }
00738 
00739 mcSymbolProperties *mcSymbolArray::data_AddSymbol(bool bRemovePrevious, 
00740             const wxString &name, 
00741             wxFontEncoding enc, 
00742             const mcRealValue &value, 
00743             const wxString &inlinedsym,
00744             const wxString &sub,
00745             mcExtRange *domain)
00746 {
00747  mcSymbolProperties sym(m_nSymbolArray, name, enc, value, inlinedsym, sub, domain);
00748 
00749  // if we cannot add this symbol return NULL
00750  if (!data_AddSymbol(sym, bRemovePrevious))
00751   return NULL;
00752 
00753  // the new symbol is always appended in the last position...
00754  return data_GetSymbol(data_GetCount()-1);
00755 }
00756 
00757 bool mcSymbolArray::data_AddSymbol(const mcSymbolProperties &newsym, bool bRemovePrevious)
00758 {
00759  bool bpresent = FALSE;
00760  int i, n;
00761 
00762  // FIXME: the newsym.Clone() operation *must* be done before the 
00763  // math_FindDuplicate function is called, because in this case that
00764  // function would miss to intercept itself (since it considers
00765  // a duplicate what is different from itself) as duplicate,
00766  // even if registered in another array (it cannot know it's
00767  // going to be added in *this).
00768  //
00769  // FIXME: data_MoveSymbols is forced to make a clone copy to work...
00770 
00771  // before adding the given object, check if another symbol
00772  // with the same name is already present...
00773  for (i=0; i < mcMAX_SYMBOL_ARRAY_NUM; i++) {
00774   if (m_pArr[i] == NULL) continue;
00775 
00776   n = newsym.math_FindDuplicate(m_pArr[i], 0);
00777   if (n != mcSYM_NOTFOUND) bpresent = TRUE;
00778  }
00779 
00780  if (bpresent && !bRemovePrevious)
00781   return FALSE;  // we cannot proceed
00782 
00783  // add the symbol even if we know there is a duplicate of this one
00784  // somewhere in the linked arrays...
00785  mcSymbolProperties *added = newsym.data_Clone();
00786  added->m_nSymbolType = m_nSymbolArray;
00787  mcAbstractArray::data_Add(added);
00788 
00789  // 'added' is now hold by m_arrSym (who did not make a copy for internal
00790  // storage (and this is very important for the following code): 
00791  //
00792  //               GetSymbol(GetCount()-1) == added
00793 
00794  // if no duplicates are present, we have finished...
00795  if (!bpresent) {
00796 
00797   // don't forget to call the callback
00798   if (m_pAddSymbolCallback)
00799    (*m_pAddSymbolCallback)();
00800   return TRUE;
00801  }
00802 
00803  // ok; we have created a duplicate of the symbol; we must remove
00804  // the old one (redirecting all mcSymbols using that mcSymbolProperties
00805  // on the just added symbol).
00806  for (i=0; i < mcMAX_SYMBOL_ARRAY_NUM; i++) {
00807   if (m_pArr[i] == NULL) continue;
00808 
00809   // search the first duplicate (but we hope only one duplicate is present !)
00810   n = newsym.math_FindDuplicate(m_pArr[i], 0);
00811 
00812   // this is a valid link...
00813   if (n != mcSYM_NOTFOUND) {
00814 
00815    mcSymbolProperties *torem = (mcSymbolProperties *)m_pArr[i]->data_GetSymbol(n);
00816    if (torem == added) {
00817     n = newsym.math_FindDuplicate(m_pArr[i], 1);
00818     if (n == mcSYM_NOTFOUND) continue;
00819    }
00820 
00821    mcASSERT(torem != added, wxT("math_FindDuplicate is broken"));
00822    
00823    // this mcSymbolProperties class must be deleted;
00824    // change the pointers of all mcSymbolHelpers classes
00825    // that are using that symbol...
00826 
00827    // in this FOR loop it's important to get always the
00828    // 1st linked symbol because each Unlink() call will
00829    // remove the symbol wxT('toupdate') from 'torem.m_arrLinkedSymbol'
00830 
00831    // another note: we start from the 1st unlinked symbol
00832    // and not from the 0th unlinked symbol because the first
00833    // mcSymbolHelpers linked with the mcSymbolProperties to remove,
00834    // is its safe symbol class (for more info see mcSymbolProperties)
00835    int j, max;
00836    for (j=1,max=torem->data_GetLinkedSymCount(); j < max; j++) {
00837 
00838     // unlink the symbol from the old mcSymbolProperties
00839     // object (which is going to be removed)
00840     mcSymbolHelpers *toupdate = torem->data_GetLinkedSym(1);
00841     toupdate->data_Unlink();
00842 
00843     // and link it with the new one
00844     // (we cannot use torem.GetLinkedSym() because we
00845     // just unlinked the wxT('toupdate') symbol from 'torem' !!!)
00846     toupdate->data_LinkWith(added);
00847    }
00848 
00849    mcASSERT(max >= 1, wxT("The symbol to remove did not have a safe instance ")
00850         wxT("of a mcSymbolHelpers class ?"));
00851    
00852    // ok; we can now delete the old mcSymbolProperties.
00853    m_pArr[i]->data_RemoveAt(n);
00854   }
00855  }
00856 
00857  // array integrity should have been preserved
00858  if (m_pAddSymbolCallback) (*m_pAddSymbolCallback)();
00859  return TRUE;
00860 }
00861 
00862 mcSymbolProperties *mcSymbolArray::data_MoveSymbols(int i, mcSymbolArray *parr)
00863 {
00864  // VERY IMPORTANT: here we *must* clone the symbol to move: we cannot
00865  //                 use it directly because ?!? FIXME
00866  mcSymbolProperties *p = data_GetSymbol(i)->data_Clone();
00867  bool okay = parr->data_AddSymbol(*p, TRUE);
00868  mcSAFE_DELETE(p); // don't leak memory   
00869  
00870  // using math_AddSymbol, the just moved symbol is the last one of the array
00871  if (!okay) return NULL;
00872  return parr->data_GetSymbol(parr->data_GetCount()-1);
00873 }
00874 
00875 
00876 
00877 
00878 
00879 
00880 
00881 // ----------------------------------------
00882 // mcCURSORPOS
00883 // ----------------------------------------
00884 
00885 void mcCursorPos::gui_Pop()
00886 {
00887  for (int i=0; i<m_nUsed-1; i++)
00888   m_nPos[i] = m_nPos[i+1];
00889  if (!isSpecial(m_nPos[m_nUsed-1])) {
00890   m_nPos[m_nUsed-1] = m_nPos[m_nUsed];
00891   m_nUsed--;
00892  }
00893 }
00894 
00895 void mcCursorPos::gui_Push(const mcCursorPos &c)
00896 {
00897 /*for (int i=m_nUsed; i>0; i--)
00898 m_nPos[i+c.m_nUsed] = m_nPos[i];
00899 for (int j=0; j<c.m_nUsed; j++)
00900 m_nPos[j] = c.m_nPos[j];
00901  m_nUsed+=c.m_nUsed;*/
00902 }


Documentation generated with Doxygen on Sun Feb 6 17:10:47 2005
Visit MathStudio home page for more info

[ Top ]