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

MathMng.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 "MathMng.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 <wx/dcscreen.h>
00046  #include "mc/MathMng.h"
00047  #include "mc/Monomial.h"
00048  #include "mc/Number.h"
00049  #include "mc/Symbol.h"
00050 #endif
00051 
00052 
00053 
00054 // setup customizable variables
00055 int mcMathMngHelpers::sgui_nSpaceLeftRight = 1;
00056 int mcMathMngHelpers::sgui_nSpaceAroundSeparator = 5;
00057 mcStyleArray *mcMathMngHelpers::sgui_pNormalStyles = NULL;
00058 mcStyleArray *mcMathMngHelpers::sgui_pSmallStyles = NULL;
00059 mcStyleArray *mcMathMngHelpers::sgui_pBigStyles = NULL;
00060 
00061 mcMathMngCmd mcMathMngHelpers::sgui_cmd[] = 
00062 { 
00063  mcMathMngCmd(mcMMC_MOVE_SEL, wxT("Move the selection")),
00064  mcMathMngCmd(mcMMC_MULT_SEL, wxT("Multiply everything by this")),
00065  mcMathMngCmd(mcMMC_DIV_SEL, wxT("Divide everything by this")),
00066  mcMathMngCmd(mcMMC_ADDSUB_SEL, wxT("Add this")),
00067 
00068  mcMathMngCmd(mcMMC_SIMPLIFY, wxT("Simplify selection")),
00069  mcMathMngCmd(mcMMC_EXPAND, wxT("Expand selection"))
00070 };
00071 
00072 
00073 
00074 
00075 // ----------------------------------------
00076 // mcMATHMNG - general functions
00077 // ----------------------------------------
00078 
00079 #ifdef __MCDEBUG__
00080 
00081 void mcMathMngHelpers::data_Check() const
00082 {
00083  bool leftempty = data_GetLeftMem().data_isArrayEmpty();
00084 
00085  // if we are a mcMMT_EXPRESSION then the right member should not be empty
00086  // (unless also the left member is empty: in this case, we are just
00087  //  uninitialized but we are still valid)
00088  mcASSERT(mdata_nDataType != mcMMT_EXPRESSION ||
00089   !data_GetRightMem().data_isArrayEmpty() ||
00090   leftempty, 
00091   wxT("The second member is empty while it should not be"));
00092  mcUNUSED(leftempty);
00093 
00094  // recurse in the children
00095  mcElementHelpers::data_Check();
00096 }
00097 
00098 wxString mcMathMngHelpers::data_Debug(long flags) const
00099 {
00100  int n = mcMathCore::Get()->m_nIndentationStep;
00101  wxString str = wxT("mcMathMng [\n") + wxString(wxT(' '), n) + wxT("LEFT MEMBER - ") + 
00102      data_GetLeftMem().data_GetDebug(n, flags) + 
00103      wxT("\n\n") + wxString(wxT(' '), n) + wxT("RIGHT MEMBER - ") +
00104      data_GetRightMem().data_GetDebug(n, flags) + 
00105      wxT("mcMathMng ]\n");
00106  return str;
00107 }
00108 
00109 #endif  // __MCDEBUG__
00110 
00111 void mcMathMngHelpers::data_DeepCopy(const mcElementHelpers *p)
00112 {
00113  const mcMathMngHelpers *mm = (const mcMathMngHelpers *)p;
00114 
00115  // use standard copy for simple variables
00116  mdata_nDataType = mm->mdata_nDataType;
00117  mgui_nCursorPos = mm->mgui_nCursorPos;
00118  
00119  // this will copy just the pointer and this is what we want...
00120  mgui_pStyleArray = mm->mgui_pStyleArray;
00121  
00122  // use deep copy for mcPolynomials
00123  if (mm->mdata_eLMember != mcEmptyElement)
00124   mdata_eLMember.data_DeepCopy(mm->mdata_eLMember);
00125 
00126  if (mm->mdata_eRMember != mcEmptyElement)
00127   mdata_eRMember.data_DeepCopy(mm->mdata_eRMember);
00128 }
00129 
00130 void mcMathMngHelpers::data_SetFilter(const mcFilter *p)
00131 {
00132  mdata_eLMember.data_SetFilter(p);
00133  mdata_eRMember.data_SetFilter(p);
00134 }
00135 /*
00136 mcElement mcMathMngHelpers::data_GetElemFromID(int id)
00137 {
00138  mcElement p = data_GetLeftMem().data_GetElemFromID(id);  // BAD
00139  if (p == mcEmptyElement)
00140   return data_GetRightMem().data_GetElemFromID(id);
00141  return p;
00142 }*/
00143 
00144 void mcMathMngHelpers::data_GetConstSourceDest(const mcPolynomialHelpers **s, 
00145          const mcPolynomialHelpers **d, bool toleft) const
00146 {
00147  if (!toleft) {
00148 
00149   // the elements to modify are placed in the first member
00150   if (s) *s = mdata_eLMember.hlp();
00151   if (d) *d = mdata_eRMember.hlp();
00152 
00153  } else {
00154 
00155   // the elements to modify are placed in the second member
00156   if (d) *d = mdata_eLMember.hlp();
00157   if (s) *s = mdata_eRMember.hlp();
00158  }
00159 }
00160 
00161 void mcMathMngHelpers::data_SetMember(bool left, const mcPolynomial &p, mcMathMngType newtype)
00162 {
00163  if (p == mcEmptyPolynomial)
00164   return;
00165 
00166  // copy the given pointer
00167  if (left)
00168   data_GetLeftMem().data_DeepCopy(p.hlp());
00169  else
00170   data_GetRightMem().data_DeepCopy(p.hlp());
00171 
00172  // change our type ID
00173  mdata_nDataType = newtype;
00174 }
00175 
00176 
00177 
00178 
00179 
00180 // ----------------------------------------
00181 // mcMATHMNG - GUI position functions
00182 // ----------------------------------------
00183 
00184 int mcMathMngHelpers::gui_GetXOfLeftMem() const
00185 {
00186  // easy enough...
00187  return sgui_nSpaceLeftRight;
00188 }
00189 
00190 int mcMathMngHelpers::gui_GetXOfSeparator(int yoff) const
00191 {
00192  mcUNUSED(yoff);
00193  return gui_GetXOfLeftMem()+data_GetLeftMem().gui_GetWidth()+sgui_nSpaceAroundSeparator;
00194 }
00195 
00196 int mcMathMngHelpers::gui_GetXOfRightMem() const
00197 {
00198  return gui_GetXOfLeftMem()+data_GetLeftMem().gui_GetWidth()+sgui_nSpaceAroundSeparator+
00199    gui_GetSeparatorSize().GetWidth()+sgui_nSpaceAroundSeparator;
00200 }
00201 
00202 
00203 int mcMathMngHelpers::gui_GetYOfLeftMem() const
00204 {
00205  // mcMathMng does not add any space above & below
00206  return 0;
00207 }
00208 
00209 int mcMathMngHelpers::gui_GetYOfSeparator(int yoff) const
00210 {
00211  if (yoff < 0) yoff = gui_GetYAnchor();
00212  return yoff-(gui_GetSeparatorSize().GetHeight()/2);
00213 }
00214 
00215 int mcMathMngHelpers::gui_GetYOfRightMem() const
00216 {
00217  return 0;
00218 }
00219 
00220 wxRect mcMathMngHelpers::gui_GetRectOfLeftMem() const
00221 {
00222  return wxRect(gui_GetXOfLeftMem(), gui_GetYOfLeftMem(), 
00223    data_GetLeftMem().gui_GetWidth(), data_GetLeftMem().gui_GetHeight());
00224 }
00225 
00226 wxRect mcMathMngHelpers::gui_GetRectOfRightMem() const
00227 {
00228  return wxRect(gui_GetXOfRightMem(), gui_GetYOfRightMem(), 
00229    data_GetRightMem().gui_GetWidth(), data_GetRightMem().gui_GetHeight());
00230 }
00231 
00232 
00233 
00234 
00235 // ----------------------------------------
00236 // mcMATHMNG - GUI functions
00237 // ----------------------------------------
00238 
00239 // mcMATHMNG rendering:
00240 //
00241 //   x LEFTMEM y SEPARATOR y RIGHTMEM x
00242 //
00243 // where
00244 //   x is sgui_nSpaceLeftRight
00245 //   y is sgui_nSpaceAroundSeparator
00246 //
00247 
00248 void mcMathMngHelpers::gui_InitStyles()
00249 {
00250  gui_DeleteStyles();
00251  
00252  // create the small & big styles copying the normal one...
00253  sgui_pNormalStyles = new mcStyleArray(mcElementHelpers::sgui_pDefaultStyles);
00254  sgui_pSmallStyles = new mcStyleArray(sgui_pNormalStyles);
00255  sgui_pBigStyles = new mcStyleArray(sgui_pNormalStyles);
00256  
00257  // they are all identic now: change the sizes
00258  sgui_pSmallStyles->ScaleSize(0.7f);
00259  sgui_pBigStyles->ScaleSize(2.0f);
00260 }
00261 
00262 void mcMathMngHelpers::gui_DeleteStyles()
00263 {
00264  mcSAFE_DELETE(sgui_pSmallStyles);
00265  mcSAFE_DELETE(sgui_pNormalStyles);
00266  mcSAFE_DELETE(sgui_pBigStyles);
00267 }
00268 
00269 int mcMathMngHelpers::gui_GetYAnchor() const
00270 {
00271  return mcMAX(data_GetLeftMem().gui_GetCenterLine(),
00272   data_GetRightMem().gui_GetCenterLine());
00273 }
00274 
00275 void mcMathMngHelpers::gui_DoRecalcSize()
00276 {
00277  // first of all, recalc our separator's size
00278  gui_RecalcSeparatorSize();
00279 
00280  // set the height of this object
00281  mgui_sz.SetHeight(mcMAX(gui_GetYOfLeftMem(), gui_GetYOfRightMem())+
00282    mcMAX(data_GetLeftMem().gui_GetHeight(), data_GetRightMem().gui_GetHeight()));
00283 
00284  if (mdata_nDataType == mcMMT_EXPRESSION) {
00285  
00286   mgui_sz.SetWidth(gui_GetXOfLeftMem()+data_GetLeftMem().gui_GetWidth()+
00287       sgui_nSpaceLeftRight);
00288 
00289  } else {
00290 
00291   mgui_sz.SetWidth(gui_GetXOfRightMem()+data_GetRightMem().gui_GetWidth()+
00292       sgui_nSpaceLeftRight);
00293  }
00294 }
00295 
00296 void mcMathMngHelpers::gui_SelectSeparatorStyle(wxDC &dc) const
00297 {
00298  // use the special text-settings
00299  gui_GetStyle(0)->GetSpecialTextSettings()->gui_Select(dc);
00300 }
00301 
00302 void mcMathMngHelpers::gui_RecalcSeparatorSize()
00303 {
00304  // cannot calculate separator size if separator doesn't exist
00305  if (mdata_nDataType == mcMMT_EXPRESSION)
00306   return;
00307 
00308  // always use first member's style
00309  wxScreenDC dc;
00310  gui_SelectSeparatorStyle(dc);
00311  mgui_szSeparator = mcElementHelpers::gui_GetSizeOf(&dc, io_GetSeparatorSymbol());
00312 }
00313 
00314 void mcMathMngHelpers::gui_GetConstSelectionSourceDest(const mcPolynomialHelpers **s, 
00315            const mcPolynomialHelpers **d) const
00316 {
00317  // use selected element count to decide
00318  if (data_GetLeftMem().gui_GetSelElemCount() > 0) {
00319 
00320   // the elements to modify are placed in the first member
00321   if (s) *s = mdata_eLMember.hlp();
00322   if (d) *d = mdata_eRMember.hlp();
00323 
00324  } else {
00325 
00326   // the elements to modify are placed in the second member
00327   if (d) *d = mdata_eLMember.hlp();
00328   if (s) *s = mdata_eRMember.hlp();
00329  }
00330 }
00331 
00332 int mcMathMngHelpers::gui_Draw(wxDC &hDC, int x, int y, long flags, const wxPoint &pt) const
00333 {
00334  mcGUILOG(wxT("mcMathMngHelpers::gui_Draw [%s]"), mcTXTTHIS);
00335  
00336  long f1=mcDRW_ALLOW_TOTAL_SELECTION, f2=mcDRW_ALLOW_TOTAL_SELECTION;
00337  int n=-1, m, yoff;
00338 
00339  flags |= mcDRW_ALLOW_TOTAL_SELECTION;
00340 
00341 /* // if a special array has been selected, reselect it here
00342  if (mgui_pStyleArray) {
00343 
00344   // use the mcElement::gui_SetStyleArray instead of the
00345   // mcElementHelpers::sgui_SetStyleArray: in this way the style
00346   // update will be recursive
00347   data_GetLeftMem().gui_SetStyleArray(mgui_pStyleArray);
00348   data_GetRightMem().gui_SetStyleArray(mgui_pStyleArray);
00349  }*/
00350 
00351  switch (mdata_nDataType) {
00352  case mcMMT_EXPRESSION:
00353 
00354   // draw only the left member
00355   n = data_GetLeftMem().gui_Draw(hDC, x+gui_GetXOfLeftMem(), 
00356          y+gui_GetYOfLeftMem(), flags, pt);
00357   break;
00358 
00359  case mcMMT_EQUATION:
00360  case mcMMT_INEQUALITY_NE:
00361  case mcMMT_INEQUALITY_G:
00362  case mcMMT_INEQUALITY_GE:
00363  case mcMMT_INEQUALITY_L:
00364  case mcMMT_INEQUALITY_LE:
00365 
00366   // is the mouse cursor over the left member ?
00367   if (flags & mcDRW_USEPOINT) {
00368    wxRect rc(gui_GetRectOfLeftMem());
00369    rc.Offset(x, y);
00370 
00371    if (rc.Inside(pt)) {
00372     f1 |= mcDRW_USEPOINT;
00373     f2 |= mcDRW_NONACTIVE;
00374    } else {
00375     f1 |= mcDRW_NONACTIVE;
00376     f2 |= mcDRW_USEPOINT;
00377    }
00378   }
00379 
00380   // this function is slow; call only once
00381   yoff = gui_GetYAnchor();
00382 
00383   // draw the first member aligned with tallest member
00384   n = data_GetLeftMem().gui_ExDraw(hDC, x+gui_GetXOfLeftMem(),
00385         y+gui_GetYOfLeftMem(), f1, pt, yoff);
00386 
00387   // draw the separator symbol vertically centered
00388   // using the style of the first member
00389   gui_SelectSeparatorStyle(hDC);
00390   hDC.DrawText(io_GetSeparatorSymbol(),
00391    x+gui_GetXOfSeparator(yoff),
00392    y+gui_GetYOfSeparator(yoff));
00393 
00394   // also draw the second member vertically centered
00395   m = data_GetRightMem().gui_ExDraw(hDC, x+gui_GetXOfRightMem(), 
00396         y+gui_GetYOfRightMem(), f2, pt, yoff);
00397 
00398   // set to the correct value the return value
00399   if (n == -1) n = m;
00400   break;
00401 
00402  default:
00403   mcASSERT(0, wxT("Invalid datatype value"));
00404  }
00405 
00406  return n;
00407 }
00408 
00409 mcElement &mcMathMngHelpers::gui_GetActiveElem(int x, int y, const wxPoint &pt)
00410 {
00411  wxRect rc(gui_GetRectOfLeftMem());
00412  rc.Offset(x, y);
00413  int yoff = gui_GetYAnchor();
00414 
00415  // is it inside the left member ?
00416  if (rc.Inside(pt))
00417   return data_GetLeftMem().gui_ExGetActiveElem(rc.x, rc.y, pt, yoff);
00418 
00419  // or the right one ?
00420  return data_GetRightMem().gui_ExGetActiveElem(x+gui_GetXOfRightMem(), 
00421           y+gui_GetYOfRightMem(), pt, yoff);
00422 }
00423 
00424 mcMoveCursorRes mcMathMngHelpers::gui_MoveCursor(mcMoveCursorFlag flag, long modifiers)
00425 {
00426  mcMoveCursorRes code;
00427 
00428  // move the cursor using the functions of the mcPolynomials
00429  if (mgui_nCursorPos == mcMATHMNG_LEFT)
00430   code = data_GetLeftMem().gui_MoveCursor(flag, modifiers);
00431  else
00432   code = data_GetRightMem().gui_MoveCursor(flag, modifiers);
00433 
00434  // check return code
00435  if (code == mcMCR_SETFOCUS_PREVIOUS) {
00436 
00437   if (mgui_nCursorPos == mcMATHMNG_LEFT || mdata_nDataType == mcMMT_EXPRESSION) {
00438    return mcMCR_SETFOCUS_PREVIOUS;
00439   } else {
00440 
00441    // cursor si now on the first member
00442    data_GetLeftMem().gui_SetCursorPos(mcCP_END);
00443    mgui_nCursorPos = mcMATHMNG_LEFT;
00444   }
00445  }
00446 
00447  if (code == mcMCR_SETFOCUS_NEXT) {
00448   if (mgui_nCursorPos == mcMATHMNG_RIGHT || mdata_nDataType == mcMMT_EXPRESSION) {
00449    return mcMCR_SETFOCUS_NEXT;
00450   } else {
00451 
00452    // cursor is now on the second member
00453    data_GetRightMem().gui_SetCursorPos(mcCP_BEGIN);
00454    mgui_nCursorPos = mcMATHMNG_RIGHT;
00455   }
00456  }
00457 
00458  if (code == mcMCR_SETFOCUS_ABOVE || code == mcMCR_SETFOCUS_BELOW)
00459   return code;
00460  return mcMCR_OKAY;
00461 }
00462 
00463 int mcMathMngHelpers::gui_MoveCursorUsingPoint(wxDC &dc, const wxPoint &p)
00464 {
00465  mcGUILOG(wxT("mcMathMngHelpers::gui_MoveCursorUsingPoint - moving to [%d;%d]"), p.x, p.y);
00466 
00467  // find in which rect is the mouse cursor located
00468  wxRect rc(gui_GetRectOfLeftMem());
00469  wxPoint pt(p);
00470 
00471  // is it in the first member ?
00472  if (rc.Inside(p)) {
00473   mgui_nCursorPos = mcMATHMNG_LEFT;
00474 
00475   pt.x -= rc.x;
00476   pt.y -= rc.y;
00477   return data_GetLeftMem().gui_MoveCursorUsingPoint(dc, p);
00478  }
00479 
00480  if (mdata_nDataType != mcMMT_EXPRESSION) {
00481  
00482   rc.x = gui_GetXOfSeparator();
00483   rc.y = gui_GetYOfSeparator();
00484   rc.width = gui_GetSeparatorSize().GetWidth();
00485   rc.height = gui_GetSeparatorSize().GetHeight();
00486   
00487   // is it on the separator symbol ?
00488   if (rc.Inside(p)) {
00489    
00490    // then we have to decide for the left or the right member:
00491    // the cursor cannot be in the middle of the symbol !!!
00492    rc.width /= 2;
00493    if (rc.Inside(p)) {
00494        mgui_nCursorPos = mcMATHMNG_LEFT;
00495           data_GetLeftMem().gui_SetCursorPos(mcCP_END);
00496            } else {
00497             mgui_nCursorPos = mcMATHMNG_RIGHT;
00498           data_GetRightMem().gui_SetCursorPos(mcCP_BEGIN);
00499             }
00500     }
00501  
00502   rc = gui_GetRectOfRightMem();
00503 
00504   // is it in the second member ?
00505   if (rc.Inside(p)) {
00506    mgui_nCursorPos = mcMATHMNG_RIGHT;
00507 
00508    pt.x -= rc.x;
00509    pt.y -= rc.y;
00510    return data_GetRightMem().gui_MoveCursorUsingPoint(dc, pt);
00511   }
00512  }
00513 
00514  return mcMCR_CANNOT_SETFOCUS;
00515 }
00516 
00517 int mcMathMngHelpers::gui_GetRelCursorPos(wxDC &hDC, wxPoint *ptCursorPos) const
00518 {
00519  int n, yoff = -1;
00520 
00521  if (mdata_nDataType != mcMMT_EXPRESSION) {
00522 
00523   // get the center line from the tallest member
00524   yoff = gui_GetYAnchor();
00525  }
00526 
00527  if (mgui_nCursorPos == mcMATHMNG_LEFT) {
00528 
00529   n = data_GetLeftMem().gui_ExGetRelCursorPos(hDC, ptCursorPos, yoff);
00530   ptCursorPos->x += gui_GetXOfLeftMem();
00531   ptCursorPos->y += gui_GetYOfLeftMem();
00532  
00533  } else {
00534 
00535   n = data_GetRightMem().gui_ExGetRelCursorPos(hDC, ptCursorPos, yoff);
00536   ptCursorPos->x += gui_GetXOfRightMem();
00537   ptCursorPos->y += gui_GetYOfRightMem();
00538  }
00539 
00540  return n;
00541 }
00542 
00543 void mcMathMngHelpers::gui_OnSelect(wxDC &hDC, wxRect &rc)
00544 {
00545  // check which mcPolynomial we must call
00546  wxRect leftrc(gui_GetRectOfLeftMem());
00547  wxRect rightrc(gui_GetRectOfRightMem());
00548 
00549  // and deselect the other
00550  if (leftrc.Intersects(rc)) {
00551 
00552   // select the left member
00553   rc.Offset(-leftrc.x, -leftrc.y);
00554   data_GetLeftMem().gui_OnSelect(hDC, rc);
00555   data_GetRightMem().gui_DeSelect();
00556 
00557  } else if (mdata_nDataType != mcMMT_EXPRESSION &&
00558     rightrc.Intersects(rc)) {
00559 
00560   // select the right member
00561   rc.Offset(-rightrc.x, -rightrc.y);
00562   data_GetRightMem().gui_OnSelect(hDC, rc);
00563   data_GetLeftMem().gui_DeSelect();
00564 
00565  } else {
00566 
00567   // deselect everything since the given rect does not intersect anything...
00568   gui_DeSelect();
00569   return;
00570  }
00571 
00572  // mark also ourselves as selected if we contain
00573  // something which is selected...
00574  if (data_GetLeftMem().gui_isSelected() ||
00575   data_GetRightMem().gui_isSelected())
00576   gui_Select();
00577 }
00578 
00579 void mcMathMngHelpers::gui_SetCursorPos(const mcCursorPos &cp)
00580 {
00581  if (cp.isBegin()) {
00582 
00583   data_GetLeftMem().gui_SetCursorPos(mcCP_BEGIN);
00584   mgui_nCursorPos = mcMATHMNG_LEFT;
00585 
00586  } else if (cp.isEnd()) {
00587 
00588   // if the data inserted is an expression, the mcMATHMNG_RIGHT member is hidden:
00589   // we must move the cursor at the end of the mcMATHMNG_LEFT member...
00590   if (mdata_nDataType != mcMMT_EXPRESSION) {
00591    data_GetRightMem().gui_SetCursorPos(mcCP_END);
00592    mgui_nCursorPos = mcMATHMNG_RIGHT;
00593   } else {
00594    data_GetLeftMem().gui_SetCursorPos(mcCP_END);
00595    mgui_nCursorPos = mcMATHMNG_LEFT;
00596   }
00597 
00598  } else {
00599 
00600   mcASSERT(0, wxT("invalid flag"));
00601  }
00602 }
00603 
00604 void mcMathMngHelpers::gui_GetCursorPos(mcCursorPos &cp) const
00605 {
00606  if (mgui_nCursorPos == mcMATHMNG_LEFT && 
00607   data_GetLeftMem().gui_GetCursorPos().isBegin()) {
00608   cp.gui_Push(mcCP_BEGIN);
00609   return;
00610  }
00611 
00612  if (mgui_nCursorPos == mcMATHMNG_RIGHT && 
00613   data_GetRightMem().gui_GetCursorPos().isEnd()) {
00614   cp.gui_Push(mcCP_END);
00615   return;
00616  }
00617 
00618  cp.gui_Push(mgui_nCursorPos);
00619  if (mgui_nCursorPos == mcMATHMNG_LEFT)
00620   data_GetLeftMem().gui_GetCursorPos(cp);
00621  else
00622   data_GetRightMem().gui_GetCursorPos(cp);
00623 }
00624 
00625 mcInputRes mcMathMngHelpers::gui_Input(const mcKey &key, mcElement *)
00626 {
00627  mcMathMngType t = mcMMT_NOT_SET;
00628  mcElement p;
00629  int r;
00630 
00631  // intercept here the keypressed used to create the relational operators....
00632  if (gui_isRelationalOp(key)) {
00633 
00634   // convert keypress to relational operator...
00635   t = math_GetMathTypeFrom(key);
00636   
00637   // change current data type....
00638   mcMathMngType old = mdata_nDataType;
00639   bool b = (t == mdata_nDataType);
00640   if (t != mcMMT_NOT_SET) mdata_nDataType = t;
00641 
00642   // did the user already typed such relation operator ?
00643   if (b && t != mcMMT_NOT_SET) {
00644    
00645    // ...yes...
00646    mcMathCore::Get()->SyntaxError(wxT("This data already contains this symbol"));
00647    return mcIR_OKAY;
00648   }
00649   
00650   // special case: there was no previous relational operator...
00651   if (old == mcMMT_EXPRESSION) {
00652    
00653    // start to put data in second member;
00654    mgui_nCursorPos = mcMATHMNG_RIGHT;   // switch to the second member
00655    data_GetRightMem().gui_SetCursorPos(mcCP_BEGIN);
00656    
00657    // reset the mcMATHMNG_RIGHT member
00658    data_GetRightMem().data_DeleteAll();
00659    data_GetRightMem().gui_AddNewEmptyMonomial();
00660    gui_RecalcSize();
00661   }
00662   
00663   return mcIR_OKAY;
00664  }
00665 
00666  // let our mcPolynomial do everything
00667  mcGUILOG(wxT("mcMathMngHelpers::gui_Input - the character to process is [%c]"), key.GetKeyCode());
00668  mcPolynomial &pmem = (mgui_nCursorPos == mcMATHMNG_LEFT) ? data_GetLeftMem() : data_GetRightMem();
00669  r = pmem.gui_Input(key, &p); 
00670 
00671  switch (r) {
00672  case mcIR_OKAY:
00673   break;
00674 
00675  case mcIR_DELETE_PREVIOUS:
00676  case mcIR_DELETE_NEXT:
00677   if ((r == mcIR_DELETE_PREVIOUS && mgui_nCursorPos == mcMATHMNG_LEFT) ||
00678    (r == mcIR_DELETE_NEXT && mgui_nCursorPos == mcMATHMNG_RIGHT)) {
00679 
00680    // there is nothing before...
00681    mcMathCore::Get()->SyntaxError(wxT("Cannot delete !!"));
00682   } else {
00683 
00684    // delete the separator symbol
00685    mdata_nDataType = mcMMT_EXPRESSION;
00686    gui_SetCursorPos(mcCP_END);
00687   }
00688   break;
00689 
00690  case mcIR_DELETE_THIS:
00691   if (mgui_nCursorPos == mcMATHMNG_LEFT) {
00692 
00693    // user is trying to delete the only empty box remained
00694    // in the expression... stop him
00695    mcMathCore::Get()->SyntaxError(wxT("Cannot delete this empty box"));
00696 
00697    // reset the mcMATHMNG_LEFT member
00698    data_GetLeftMem().gui_AddNewEmptyMonomial();
00699 
00700   } else {
00701 
00702    // delete the separator symbol and modify data type
00703    mdata_nDataType = mcMMT_EXPRESSION;
00704    mgui_nCursorPos = mcMATHMNG_LEFT;
00705    data_GetLeftMem().gui_SetCursorPos(mcCP_END);
00706   }
00707   break;
00708 
00709  default:
00710   mcASSERT(0, wxT("Unhandled return flag..."));
00711  }
00712 
00713 
00714  mcGUILOG(wxT("mcMathMngHelpers::gui_Input - after processing: [%s]"), io_GetInlinedExpr().c_str());
00715  gui_RecalcSize();
00716 
00717  return mcIR_OKAY;
00718 }
00719 
00720 mcInsertRes mcMathMngHelpers::gui_Insert(const mcElement &toinsert, mcElement *newelem)
00721 {
00722  switch (mgui_nCursorPos) {
00723  case mcMATHMNG_LEFT:
00724   data_GetLeftMem().gui_Insert(toinsert, NULL);
00725   break;
00726 
00727  case mcMATHMNG_RIGHT:
00728   data_GetRightMem().gui_Insert(toinsert, NULL);
00729   break;
00730  }
00731 
00732  return mcINSR_OKAY;
00733 }
00734 
00735 mcElement mcMathMngHelpers::gui_GetSelection() const
00736 {
00737  // just create a new mcMathMng containing the selected
00738  // portions of the two members.
00739  // Since only one of the two members can contain selections,
00740  // one of the two members of the returned mcMathMng will be empty...
00741  mcMathMng res;
00742 
00743  if (data_GetLeftMem().gui_isSelected()) {
00744   res.data_GetLeftMem() = data_GetLeftMem().gui_GetSelection();
00745  } else {
00746   res.data_GetRightMem() = data_GetRightMem().gui_GetSelection();
00747  }
00748 
00749  return res;
00750 }
00751 
00752 void mcMathMngHelpers::gui_DeleteSelection()
00753 {
00754  data_GetLeftMem().gui_DeleteSelection();
00755  data_GetRightMem().gui_DeleteSelection();
00756 
00757  if (data_GetLeftMem().data_isArrayEmpty())
00758   data_GetLeftMem().gui_AddNewEmptyMonomial();
00759  if (data_GetRightMem().data_isArrayEmpty())
00760   data_GetRightMem().gui_AddNewEmptyMonomial();
00761 
00762  gui_SetCursorPos(mcCP_BEGIN);
00763  gui_RecalcSize();
00764 }
00765 
00766 bool mcMathMngHelpers::gui_isRelationalOp(const mcKey &key)
00767 {
00768  wxChar c = key.GetKeyCode();
00769 
00770  if ((c == mcMMRO_LESS ||
00771   c == mcMMRO_GREATER ||
00772   c == mcMMRO_EQUAL) &&
00773   key.isSpecialKey())
00774   return TRUE;
00775 
00776  if ((c == mcMMRO_LESS_OR_EQUAL ||
00777   c == mcMMRO_GREATER_OR_EQUAL ||
00778   c == mcMMRO_NOT_EQUAL) &&
00779   key.isSpecialKey())
00780   return TRUE;
00781 
00782  return FALSE;
00783 }
00784 
00785 void mcMathMngHelpers::gui_UpdateExpDepth()
00786 {
00787  data_GetLeftMem().gui_SetAtSameLevelOf(this);
00788  data_GetRightMem().gui_SetAtSameLevelOf(this);
00789 
00790  // always call base version
00791  mcElementHelpers::gui_UpdateExpDepth();
00792 }
00793 
00794 
00795 
00796 
00797 // ----------------------------------------
00798 // mcMATHMNG - GUI+MATH functions
00799 // ----------------------------------------
00800 
00801 void mcMathMngHelpers::gui_MoveSel()
00802 {
00803  mcPolynomialHelpers *psource, *pdest;
00804 
00805  // init the psource and pdest variables
00806  gui_GetSelectionSourceDest(&psource, &pdest);
00807 
00808  // be sure that the selection is extended at least to an entire monomial
00809  if (psource->math_GetSelCount() == 1)
00810   psource->math_GetSel(0).gui_SelectAll();
00811 
00812  // first of all, move the selection in a temporary polynomial
00813  mcPolynomial sel(psource->gui_GetSelection());
00814  psource->gui_DeleteSelection();
00815 
00816  // change all the signs of the temporary polynomial
00817  sel.math_ChangeAllSigns();
00818 
00819  // add the temporary polynomial to the destination
00820  pdest->math_Add(sel, NULL, TRUE);
00821 
00822  // clean up and reset
00823  //ResetGUI();
00824 }
00825 
00826 void mcMathMngHelpers::gui_AddSubSel()
00827 {
00828  mcPolynomialHelpers *psource;
00829 
00830  // init the psource and pdest variables
00831  gui_GetSelectionSourceDest(&psource, NULL);
00832 
00833  // be sure that the selection is extended at least to an entire monomial
00834  if (psource->math_GetSelCount() == 1)
00835   psource->math_GetSel(0).gui_SelectAll();
00836 
00837  // just create two copies of the selection
00838  mcPolynomial sel(psource->gui_GetSelection());
00839  mcPolynomial sel2(sel);
00840 
00841  // and add/sub both of them in the source pointer
00842  psource->math_SimpleAdd(sel);
00843  psource->math_SimpleSubtract(sel2);
00844 
00845  // clean up and reset
00846  //ResetGUI();
00847 }
00848 
00849 void mcMathMngHelpers::gui_MultiplyBySel(bool bDivide)
00850 {
00851  mcElement tmp;
00852 
00853  // a little check
00854  mcASSERT(mdata_nDataType != mcMMT_EXPRESSION, wxT("Invalid data type"));
00855 
00856  // find which is the member which contains selected elements
00857  int n1 = data_GetLeftMem().gui_GetSelElemCount();
00858  int n2 = data_GetRightMem().gui_GetSelElemCount();
00859 
00860  // gets the selection (the gui_GetSelection() function returns a copy
00861  // of the selection, so we need to delete the tmp pointer at the
00862  // end of the function...)
00863  if (n1)
00864   tmp = data_GetLeftMem().gui_GetSelection();
00865  else if (n2)
00866   tmp = data_GetRightMem().gui_GetSelection();
00867  else
00868   return;   // no selection
00869 
00870  // the gui_GetSelection() function may return something different from
00871  // a mcPolynomial... check it
00872  /*if (tmp.data_GetType() != mcET_ELEMENTARRAY) {
00873 
00874  }*/
00875 
00876  // now, multiply both expressions by tmp
00877  if (bDivide) {
00878   data_GetLeftMem().math_SimpleDivideBy(tmp);
00879   data_GetRightMem().math_SimpleDivideBy(tmp);
00880  } else {
00881   data_GetLeftMem().math_SimpleMultiplyBy(tmp);
00882   data_GetRightMem().math_SimpleMultiplyBy(tmp);
00883  }
00884 
00885  //ResetGUI();
00886 }
00887 
00888 void mcMathMngHelpers::gui_GetPossibleOperations(mcMathMngCmdID *pCmdID) const
00889 {
00890  mcASSERT(pCmdID != NULL, wxT("invalid pointer"));
00891  switch (mdata_nDataType) {
00892 
00893  case mcMMT_NOT_SET:
00894  case mcMMT_EXPRESSION:
00895 
00896   // don't break here
00897 
00898   // for equations and all type of inequalities...
00899  case mcMMT_EQUATION:
00900  case mcMMT_INEQUALITY_NE:
00901  case mcMMT_INEQUALITY_G:
00902  case mcMMT_INEQUALITY_GE:
00903  case mcMMT_INEQUALITY_L:
00904  case mcMMT_INEQUALITY_LE:
00905 
00906   pCmdID[0] = mcMMC_SIMPLIFY;
00907   pCmdID[1] = mcMMC_EXPAND;
00908 
00909   break;
00910  }
00911 }
00912 
00913 wxArrayString mcMathMngHelpers::gui_GetPossibleOpOnSel(mcMathMngCmd *pCmdID) const
00914 {
00915  wxArrayString arr;
00916  wxString str;
00917 
00918  // WARNING: PREREQUISITE FOR THIS FUNCTION IS THAT
00919  //      AT LEAST ONE MONOMIAL IS SELECTED SOMEWHERE
00920  //      IN THE OBJECT
00921 
00922  mcASSERT(pCmdID != NULL, wxT("invalid pointer"));
00923 
00924 /* switch (mdata_nDataType) {
00925 
00926  case mcMMT_NOT_SET:
00927  case mcMMT_EXPRESSION:
00928 
00929   // don't break here
00930 
00931   // for equations and all type of inequalities...
00932  case mcMMT_EQUATION:
00933  case mcMMT_INEQUALITY_NE:
00934  case mcMMT_INEQUALITY_G:
00935  case mcMMT_INEQUALITY_GE:
00936  case mcMMT_INEQUALITY_L:
00937  case mcMMT_INEQUALITY_LE:
00938 
00939   // add the "move" commands
00940   if (data_GetLeftMem().gui_GetSelElemCount() > 0) {
00941 
00942    // this element is placed on the first member
00943    arr.Add(wxT("Move to second member"));
00944   } else if (data_GetRightMem().gui_GetSelElemCount() > 0) {
00945 
00946    // this element is placed on the second member
00947    arr.Add(wxT("Move to first member"));
00948   }
00949 
00950   pCmdID[0] = mcMMC_MOVE_SEL;
00951 
00952   // add the "multiply by" command
00953   str.Printf(wxT("Multiply everything by this"));
00954   arr.Add(str);
00955   pCmdID[1] = mcMMC_MULT_SEL;
00956 
00957   // add the "divide by" command
00958   str.Printf(wxT("Divide everything by this"));
00959   arr.Add(str);
00960   pCmdID[2] = mcMMC_DIV_SEL;
00961 
00962   // add the "add and subtract by" command
00963   str.Printf(wxT("math_Add and subtract this"));
00964   arr.Add(str);
00965   pCmdID[3] = mcMMC_ADDSUB_SEL;
00966 
00967   break;
00968  }*/
00969 
00970  return arr;
00971 }
00972 
00973 void mcMathMngHelpers::gui_ExecCmdOnSel(mcMathMngCmdID cmdid)
00974 {
00975  long flags = mcEXPSIM_NOFLAGS;
00976 
00977  switch (cmdid) {
00978 
00979   // operations available on selection
00980  case mcMMC_MOVE_SEL:
00981   gui_MoveSel();
00982   break;
00983  case mcMMC_MULT_SEL:
00984   gui_MultiplyBySel(FALSE);
00985   break;
00986  case mcMMC_DIV_SEL:
00987   gui_MultiplyBySel(TRUE);
00988   break;
00989  case mcMMC_ADDSUB_SEL:
00990   gui_AddSubSel();
00991   break;
00992 
00993   // global operations
00994  case mcMMC_SIMPLIFY:
00995   math_Simplify(flags, (mcElement *)NULL);
00996   break;
00997  case mcMMC_EXPAND:
00998   math_Expand(flags, (mcElement *)NULL);
00999 
01000   // here I usually put debug routines just to test some
01001   // functions....
01002   //bool b = data_GetLeftMem().math_hasSameContentOf(&m_eRMember);
01003   //bool b = data_GetLeftMem().math_ContainsUnknowns(NULL);
01004 
01005   //mcNumber *mynum = new mcNumber(NULL);
01006   //mynum.math_Set(2.0);
01007   //mcElement p = data_GetLeftMem().math_Find(1, mynum);
01008 
01009   break;
01010  }
01011 }
01012 
01013 
01014 
01015 
01016 
01017 
01018 // ----------------------------------------
01019 // mcMATHMNG - IO functions
01020 // ----------------------------------------
01021 
01022 wxXml2Node mcMathMngHelpers::io_GetMathML(bool bGetPresentation) const
01023 {
01024  wxString opname;
01025 
01026  // export MathML
01027  switch (mdata_nDataType) {
01028  case mcMMT_NOT_SET:
01029   break;
01030 
01031  case mcMMT_EXPRESSION:
01032   return data_GetLeftMem().io_GetMathML(bGetPresentation);
01033 
01034  case mcMMT_EQUATION:
01035  case mcMMT_INEQUALITY_G:
01036  case mcMMT_INEQUALITY_L:
01037   opname = io_GetSeparatorSymbol();
01038   break;
01039 
01040  case mcMMT_INEQUALITY_NE:
01041   opname = wxT("&#x02260;");
01042   break;
01043 
01044  case mcMMT_INEQUALITY_GE:
01045   opname = wxT("&#x02265;");
01046   break;
01047 
01048  case mcMMT_INEQUALITY_LE:
01049   opname = wxT("&#x02264;");
01050   break;
01051  }
01052 
01053  wxXml2Node global, op;
01054  wxXml2Node left(data_GetLeftMem().io_GetMathML(bGetPresentation));
01055  wxXml2Node right(data_GetRightMem().io_GetMathML(bGetPresentation));
01056  
01057  if (bGetPresentation) {
01058 
01059   // create an MROW using the <MO>opname</MO> to divide the two members
01060    global.CreateTemp(wxXML_ELEMENT_NODE, wxXml2EmptyDoc, wxT("mrow"));
01061   op.CreateTemp(wxXML_TEXT_NODE, wxXml2EmptyDoc, wxT("mo"), opname);
01062   
01063  } else {
01064  
01065   // THIS HAS NOT BEEN CHECKED !!!
01066   global.CreateTemp(wxXML_ELEMENT_NODE, wxXml2EmptyDoc, wxT("apply"));
01067   op.CreateTemp(wxXML_TEXT_NODE, wxXml2EmptyDoc, wxT("EQ"));
01068   }
01069 
01070  // set the MathML of the left & right member
01071  global.AddChild(left);
01072  global.AddChild(op);
01073  global.AddChild(right);
01074 
01075  return global;
01076 }
01077 
01078 wxString mcMathMngHelpers::io_GetSeparatorSymbol(bool bUseSpecialChars) const
01079 {
01080  if (!bUseSpecialChars) {
01081   switch (mdata_nDataType) {
01082   case mcMMT_INEQUALITY_NE:
01083    return wxT("!=");
01084   case mcMMT_INEQUALITY_GE:
01085    return wxT(">=");
01086   case mcMMT_INEQUALITY_LE:
01087    return wxT("<=");
01088 
01089   default: // all other cases are handled below...
01090    break;
01091   }
01092  }
01093  
01094  if (mdata_nDataType == mcMMT_EXPRESSION)
01095   return wxEmptyString;
01096  
01097  // see math_GetMathTypeFrom() for more info...
01098  wxChar sym = (wxChar)math_GetRelationalOpFor(mdata_nDataType);
01099  
01100  return wxString(sym);
01101 }
01102  /*dest = wxString(wxT(' '), indent) + wxT("<SEMANTICS>\n") + io_GetMathML(indent+mcMathCore::Get()->m_nIndentationStep) +
01103   wxString(wxT(' '), indent+mcMathCore::Get()->m_nIndentationStep) + wxT("<ANNOTATION-XML ENCODING=\")MathML-Content\wxT(">\n") +
01104   GetContentMathML(indent+2*mcMathCore::Get()->m_nIndentationStep) + wxString(wxT(' '), indent+mcMathCore::Get()->m_nIndentationStep) +
01105   wxT("</ANNOTATION-XML>\n") + wxString(wxT(' '), indent) + wxT("</SEMANTICS>\n");*/
01106 
01107 wxString mcMathMngHelpers::io_GetInlinedExpr() const
01108 {
01109  // just merge the two inlined expressions...
01110  wxString res = data_GetLeftMem().io_GetInlinedExpr();
01111  
01112  if (mdata_nDataType != mcMMT_EXPRESSION)
01113   res += io_GetSeparatorSymbol(FALSE) + data_GetRightMem().io_GetInlinedExpr();
01114 
01115  return res;
01116 }
01117 
01118 bool mcMathMngHelpers::io_ImportPresentationMathML(wxXml2Node maintag, wxString &pErr)
01119 {
01120  // import only presentation math ml... ignore semantics\annotation TAGS
01121  if (maintag.GetName() == wxT("semantics"))
01122   maintag = maintag.GetChildren();
01123 
01124  // presentation markup should begin with an MROW tag
01125  if (maintag.GetName() != wxT("mrow")) {
01126   if (pErr) pErr = wxT("Presentation markup should be enclosed in MROW tag");
01127   return FALSE;
01128  }
01129 
01130  // search a separator symbol
01131  //if (XmlSearchTagInChildren(main, "mo")
01132 
01133  // all import functions requires the tags (not their content)
01134  // to be lowercase...
01135  maintag.MakeLower();
01136 
01137  data_GetLeftMem().io_ImportPresentationMathML(maintag, pErr);
01138 
01139  return TRUE;
01140 }
01141 
01142 bool mcMathMngHelpers::io_ImportInlinedExpr(const wxString &toimport, int *, wxString &perr)
01143 {
01144  wxString lmem, rmem;
01145  wxString err;
01146 
01147  // reset left & right members
01148  data_GetLeftMem().data_DeleteAll();
01149  data_GetRightMem().data_DeleteAll();
01150 
01151  // VERY IMPORTANT: remove all the spaces from the input string
01152  wxString str(toimport);
01153  str.Replace(wxT(" "), wxT(""));
01154  if (str.IsEmpty()) 
01155   return TRUE;  // nothing to import ?
01156 
01157  // check which type of math data we must decode...
01158  if (str.Contains(wxT(">=")))
01159   mdata_nDataType = mcMMT_INEQUALITY_GE;
01160  else if (str.Contains(wxT("<=")))
01161   mdata_nDataType = mcMMT_INEQUALITY_LE;
01162  else if (str.Contains(wxT(">")))
01163   mdata_nDataType = mcMMT_INEQUALITY_G;
01164  else if (str.Contains(wxT("<")))
01165   mdata_nDataType = mcMMT_INEQUALITY_L;
01166  else if (str.Contains(wxT("!=")))
01167   mdata_nDataType = mcMMT_INEQUALITY_NE;
01168  else if (str.Contains(wxT("=")) || str.Contains(wxT("==")))
01169   mdata_nDataType = mcMMT_EQUATION;
01170  else
01171   mdata_nDataType = mcMMT_EXPRESSION;
01172 
01173  // now, split the given string in two main tokens;
01174  // one for the left and one for the right member
01175  int n = str.Len();
01176  if (mdata_nDataType != mcMMT_EXPRESSION) {
01177   int s = str.Find(io_GetSeparatorSymbol(FALSE));
01178 
01179   mcASSERT(n != -1, wxT("A separator has been previously detected..."));
01180   lmem = str.Left(s);
01181 
01182   // in right member string to import, do not include
01183   // the separator symbol....
01184   rmem = str.Right(n-s-1);
01185 
01186  } else {
01187 
01188   // the entire string should be parsed by left member...
01189   lmem = str;
01190  }
01191 
01192  // import LEFT member string
01193  bool b = data_GetLeftMem().io_ImportInlinedExpr(lmem, &n, err);  
01194 
01195  // eventually import RIGHT member string
01196  if (mdata_nDataType != mcMMT_EXPRESSION) {
01197 
01198   if (rmem.IsEmpty())
01199    data_GetRightMem().math_WrapNumber(0);
01200   else
01201    b &= data_GetRightMem().io_ImportInlinedExpr(rmem, &n, err);
01202  }
01203 
01204  // if we have to report an error, copy the string into the given pointer
01205  if (perr) perr = err;
01206 
01207  return b;
01208 }
01209 
01210 
01211 
01212 
01213 
01214 
01215 
01216 // ----------------------------------------
01217 // mcMATHMNG - math functions
01218 // ----------------------------------------
01219 
01220 /*void mcMathMngHelpers::ResetGUI()
01221 {
01222  if (!mcMathCore::Get()->isGUIEnabled())
01223   return;
01224  
01225  // update gui
01226  gui_DeepRecalcSize();
01227  gui_DeSelect();
01228 
01229  // old cursor position maybe wrong now....
01230  gui_SetCursorPos(mcCP_BEGIN);
01231 }*/
01232 bool mcMathMngHelpers::math_Compare(const mcElement &p, long flags) const
01233 {
01234  if (!math_CompareThisOnly(p, flags))
01235   return FALSE;
01236 
01237  const mcMathMng &m = (const mcMathMng &)p;
01238  if (!data_GetLeftMem().math_Compare(m.data_GetLeftMem(), flags))
01239   return FALSE;
01240  if (!data_GetRightMem().math_Compare(m.data_GetRightMem(), flags))
01241   return FALSE;
01242  return TRUE;
01243 }
01244 
01245 mcMathMngRelationalOp mcMathMngHelpers::math_GetRelationalOpFor(mcMathMngType type)
01246 {
01247  switch (type) {
01248  case mcMMT_INEQUALITY_L:
01249   return mcMMRO_LESS;
01250  case mcMMT_INEQUALITY_G:
01251   return mcMMRO_GREATER;
01252  case mcMMT_EQUATION:
01253   return mcMMRO_EQUAL;
01254  case mcMMT_INEQUALITY_GE:
01255   return mcMMRO_GREATER_OR_EQUAL;
01256  case mcMMT_INEQUALITY_NE:
01257   return mcMMRO_NOT_EQUAL;
01258  case mcMMT_INEQUALITY_LE:
01259   return mcMMRO_LESS_OR_EQUAL;
01260 
01261  case mcMMT_NOT_SET:  // invalid values of type
01262  case mcMMT_EXPRESSION:
01263   return (mcMathMngRelationalOp)-1;
01264  }
01265  
01266  return mcMMRO_EQUAL;
01267 }
01268 
01269 mcMathMngType mcMathMngHelpers::math_GetMathTypeFor(mcMathMngRelationalOp type)
01270 {
01271  switch (type) {
01272  case mcMMRO_LESS:
01273   return mcMMT_INEQUALITY_L;
01274  case mcMMRO_GREATER:
01275   return mcMMT_INEQUALITY_G;
01276  case mcMMRO_EQUAL:
01277   return mcMMT_EQUATION;
01278  case mcMMRO_GREATER_OR_EQUAL:
01279   return mcMMT_INEQUALITY_GE;
01280  case mcMMRO_NOT_EQUAL:
01281   return mcMMT_INEQUALITY_NE;
01282  case mcMMRO_LESS_OR_EQUAL:
01283   return mcMMT_INEQUALITY_LE;
01284  }
01285  
01286  return mcMMT_NOT_SET;
01287 }
01288 
01289 mcMathMngType mcMathMngHelpers::math_GetMathTypeFrom(const mcKey &key)
01290 {
01291  // the mcMathMngRelationalOp enumeration values coincide with the
01292  // ASCII values of the keys used to produce them...
01293  mcMathMngRelationalOp r = (mcMathMngRelationalOp)key.GetKeyCode();
01294 
01295  // but to produce a relational op, we must also check that
01296  // the key used was a special key...
01297  if (!key.isSpecialKey())
01298   return mcMMT_NOT_SET;
01299 
01300  return math_GetMathTypeFor(r);
01301 }
01302 
01303 bool mcMathMngHelpers::math_CompareThisOnly(const mcElement &e, long flags) const
01304 {
01305  const mcMathMng &p = (const mcMathMng &)e;
01306  bool res = TRUE;
01307 
01308  if (!mcElementHelpers::math_CompareThisOnly(p, flags))
01309   return FALSE;
01310  
01311  // compare members
01312  res &= data_GetLeftMem().math_Compare(p.data_GetLeftMem(), flags);
01313  res &= data_GetRightMem().math_Compare(p.data_GetRightMem(), flags);
01314 
01315  return res;
01316 }
01317 
01318 bool mcMathMngHelpers::math_ContainsInvalidSymbols() const
01319 {
01320  // check if we have some unregistered symbols in the left/right member...
01321  if (data_GetLeftMem().math_ContainsInvalidSymbols() ||
01322   data_GetRightMem().math_ContainsInvalidSymbols())
01323   return TRUE;
01324  return FALSE;
01325 }
01326 
01327 mcExpSimRes mcMathMngHelpers::math_Simplify(long lflags, long rflags)
01328 {
01329  // simplify the left member
01330  mcLOG(wxT("mcMathMngHelpers::math_Simplify [%s] - simplifying the left member"), mcTXT(mdata_eLMember));
01331  mcExpSimRes n1 = data_GetLeftMem().math_Simplify(lflags);
01332 
01333  if (mdata_nDataType == mcMMT_EXPRESSION)
01334   return n1;  // we have finished...
01335 
01336  // simplify the right member
01337  mcLOG(wxT("mcMathMngHelpers::math_Simplify [%s] - simplifying the right member"), mcTXT(mdata_eRMember));
01338  mcExpSimRes n2 = data_GetRightMem().math_Simplify(rflags);
01339 
01340  // if we have finished to simplify the two polynomials
01341  if (n1 == n2 && n1 == mcESR_DONE) {
01342 
01343   // now the hard work: our aim is to make the data shorter.
01344   // thus, we must move the unknowns to the left...
01345   //for (int i=0; i < 
01346  }
01347 
01348  // if both left & right member has completed their simplification...
01349  if (n1 == n2 && n1 == mcESR_DONE)
01350   return mcESR_DONE;
01351  return mcESR_NOTFINISHED;
01352 }
01353 
01354 mcExpSimRes mcMathMngHelpers::math_Expand(long lflags, long rflags)
01355 {
01356  mcExpSimRes n1 = data_GetLeftMem().math_Expand(lflags);
01357 
01358  if (mdata_nDataType != mcMMT_EXPRESSION)
01359   data_GetRightMem().math_Expand(rflags);
01360 
01361  //ResetGUI();
01362  return n1;
01363 }
01364 /*
01365 bool mcMathMngHelpers::isComplete() const
01366 {
01367  // mcEmptyBox and mcParenthesis (which are different from mcBracket)
01368  // are not accepted in math operations...
01369  if (data_GetLeftMem().data_GetNumOfElemType(mcET_EMPTYBOX) > 0)
01370   return FALSE;
01371  if (data_GetLeftMem().data_GetNumOfElemType(mcET_PARENTHESIS) > 0)
01372   return FALSE;
01373 
01374  if (mdata_nDataType != mcMMT_EXPRESSION) {
01375   if (data_GetRightMem().data_GetNumOfElemType(mcET_EMPTYBOX) > 0)
01376    return FALSE;
01377   if (data_GetRightMem().data_GetNumOfElemType(mcET_PARENTHESIS) > 0)
01378    return FALSE;
01379  }
01380 
01381  return TRUE;
01382 }*/
01383 
01384 bool mcMathMngHelpers::math_isMaxSimplified() const
01385 {
01386  // both left & right members must be simplified to
01387  // consider this entire object as simplified...
01388  return data_GetLeftMem().math_isMaxSimplified(mcEXPSIM_NOFLAGS) &&
01389   data_GetRightMem().math_isMaxSimplified(mcEXPSIM_NOFLAGS);
01390 }
01391 
01392 bool mcMathMngHelpers::math_isConstant() const
01393 {
01394  return data_GetLeftMem().math_isConstant() &&
01395   data_GetRightMem().math_isConstant();
01396 }
01397 
01398 mcMathType mcMathMngHelpers::math_GetMathType() const
01399 {
01400  // get polynomial classifications
01401  mcMathType mt = data_GetLeftMem().math_GetMathType();
01402  switch (mdata_nDataType) {
01403 
01404  case mcMMT_NOT_SET:
01405  case mcMMT_EXPRESSION:
01406   return mt;
01407 
01408   // for equations and all type of inequalities...
01409  case mcMMT_EQUATION:
01410  case mcMMT_INEQUALITY_NE:
01411  case mcMMT_INEQUALITY_G:
01412  case mcMMT_INEQUALITY_GE:
01413  case mcMMT_INEQUALITY_L:
01414  case mcMMT_INEQUALITY_LE:
01415   mt.math_Add(data_GetRightMem().math_GetMathType());
01416   return mt;
01417  }
01418 
01419  // this should never be returned !
01420  mcMathType invalid(mcMTL1_NOT_RECOGNIZED, 
01421   mcMTL2_NOT_RECOGNIZED, mcMTL3_NOT_RECOGNIZED);
01422  return invalid;
01423 }
01424 
01425 void mcMathMngHelpers::math_Move(int mathidx, bool toleft)
01426 {
01427  mcPolynomialHelpers *s = NULL, *d = NULL;
01428  data_GetSourceDest(&s, &d, toleft);
01429  
01430  mcASSERT(mathidx < s->math_GetCount(), wxT("invalid index"));
01431  
01432  // do not move a monomial containing a zero mcNumber
01433  if (s->math_Get(mathidx).math_isWrappingOnly(0.0))
01434   return;
01435 
01436  // before removing the monomial, get its sign
01437  int sign = s->math_GetSign(mathidx);
01438 
01439  // clone & remove from the source member the mathidx-th monomial 
01440  mcMonomial p = s->math_Get(mathidx);
01441  s->math_Remove(mathidx);
01442  
01443  // put it in the left member adding/subtracting if the sign
01444  // is respectively negative/positive...
01445  d->math_SimpleAdd(p, (sign == -1 ? TRUE : FALSE));
01446 }
01447 
01448 void mcMathMngHelpers::math_MoveSymbol(const mcSymbolProperties *sym, bool toleft)
01449 {
01450  int offset = 0;
01451  mcPolynomialHelpers *s = NULL, *d = NULL;
01452  data_GetSourceDest(&s, &d, toleft);
01453 
01454  // we need to do s.math_GetCount() cycles and to start
01455  // with the elements placed on the left of the source polynomial
01456  // (offset is initially zero) so that we can be sure that the
01457  // first offset-th elements must not be moved and "offset" is a
01458  // valid index; if we would have started from the right, then
01459  // the index could become invalid in some cases...
01460  for (int i=s->math_GetCount(); i > 0; i--) {
01461 
01462   // move only monomials containing a symbol contained in the given mcSymbolArray...
01463   if (s->math_Get(offset).math_ContainsSymbol(sym))
01464    math_Move(offset, toleft); // still try with the offset-th
01465   else
01466    offset++; // try with next
01467  }
01468 }
01469 
01470 void mcMathMngHelpers::math_MoveFreeFrom(const mcSymbolProperties *sym, bool toleft)
01471 {
01472  int offset = 0;
01473  mcPolynomialHelpers *s = NULL, *d = NULL;
01474  data_GetSourceDest(&s, &d, toleft);
01475 
01476  for (int i=s->math_GetCount(); i > 0; i--) {
01477 
01478   // move only monomials that do not contain symbols...
01479   if (!s->math_Get(offset).math_ContainsSymbol(sym))
01480    math_Move(offset, toleft); // still try with the offset-th
01481   else
01482    offset++; // try with next
01483  }
01484 }
01485 
01486 void mcMathMngHelpers::math_MoveSymbols(const mcSymbolArray *arr, bool toleft)
01487 {
01488  int offset = 0;
01489  mcPolynomialHelpers *s = NULL, *d = NULL;
01490  data_GetSourceDest(&s, &d, toleft);
01491 
01492  for (int i=s->math_GetCount(); i > 0; i--) {
01493 
01494   // move only monomials containing a symbol contained in the given mcSymbolArray...
01495   if (s->math_Get(offset).math_ContainsOneOf(arr))
01496    math_Move(offset, toleft); // still try with the offset-th
01497   else
01498    offset++; // try with next
01499  }
01500 }
01501 
01502 void mcMathMngHelpers::math_MoveNonSymbol(bool toleft)
01503 {
01504  int offset = 0;
01505  mcPolynomialHelpers *s = NULL, *d = NULL;
01506  data_GetSourceDest(&s, &d, toleft);
01507 
01508  for (int i=s->math_GetCount(); i > 0; i--) {
01509 
01510   // move only monomials that do not contain symbols...
01511   if (!s->math_Get(offset).math_ContainsSymbols())
01512    math_Move(offset, toleft); // still try with the offset-th
01513   else
01514    offset++; // try with next
01515  }
01516 }
01517 
01518 void mcMathMngHelpers::math_MoveUnknowns(bool toLeft)
01519 { math_MoveSymbols(&mcSymbol::arrUnknowns, toLeft); }
01520 
01521 void mcMathMngHelpers::math_MoveConstants(bool toLeft)
01522 { math_MoveSymbols(&mcSymbol::arrConstants, toLeft); }
01523 
01524 void mcMathMngHelpers::math_MoveParameters(bool toLeft)
01525 { math_MoveSymbols(&mcSymbol::arrParameters, toLeft); }
01526 
01527 void mcMathMngHelpers::math_MoveAll(bool toleft)
01528 {
01529  mcPolynomialHelpers *s = NULL, *d = NULL;
01530  data_GetSourceDest(&s, &d, toleft);
01531 
01532  // move all...
01533  for (int i=s->math_GetCount(); i > 0; i--)
01534   math_Move(0, toleft);
01535 }
01536 
01537 
01538 
01539 
01540 // -------------------------------------------------
01541 // mcMATHMNG - functions working with polynomials 
01542 // -------------------------------------------------
01543 
01544 mcBasicOpRes mcMathMngHelpers::math_MultiplyBy(const mcElement &pol, mcElement *pp)
01545 {
01546  mcBasicOpRes r = data_GetLeftMem().math_MultiplyBy(pol, pp);
01547 
01548  if (mdata_nDataType != mcMMT_EXPRESSION)
01549   data_GetRightMem().math_SimpleMultiplyBy(pol);
01550 
01551  return r;
01552 }
01553 
01554 mcBasicOpRes mcMathMngHelpers::math_DivideBy(const mcElement &p, mcElement *pp)//mcPolynomial &pol)
01555 {
01556  /*data_GetLeftMem().math_SimpleDivideBy(pol);
01557  
01558  if (mdata_nDataType != mcMMT_EXPRESSION)
01559   data_GetRightMem().math_SimpleDivideBy(pol);*/
01560 
01561  mcBasicOpRes r2 = data_GetLeftMem().math_DivideBy(p, pp);
01562  r2 = data_GetRightMem().math_DivideBy(p, pp);
01563 
01564  return r2;
01565 }
01566 
01567 mcBasicOpRes mcMathMngHelpers::math_Add(const mcElement &p, mcElement *pp, bool add)
01568 {
01569  mcBasicOpRes r = data_GetLeftMem().math_Add(p, pp, add);
01570 
01571  if (mdata_nDataType != mcMMT_EXPRESSION)
01572   data_GetRightMem().math_SimpleAdd(p, add);
01573 
01574  return r;
01575 }
01576 
01577 mcBasicOpRes mcMathMngHelpers::math_Subtract(const mcElement &p, mcElement *pp)
01578 {
01579  mcBasicOpRes r = data_GetLeftMem().math_Subtract(p, pp);
01580  
01581  if (mdata_nDataType != mcMMT_EXPRESSION)
01582   data_GetRightMem().math_SimpleSubtract(p);
01583 
01584  return r;
01585 }
01586 
01587 
01588 
01589 
01590 // -------------------------------------------------
01591 // mcMATHMNG - functions working with monomials 
01592 // -------------------------------------------------
01593 
01594 #define WRAP_MONOMIAL(fncname)        \
01595  mcPolynomial pol;          \
01596  pol.data_AddNewMonomial(mon, -1, TRUE);     \
01597  fncname(pol); 
01598 
01599 void mcMathMngHelpers::math_MultiplyBy(const mcMonomial &mon)
01600 { WRAP_MONOMIAL(math_MultiplyBy); }
01601 
01602 void mcMathMngHelpers::math_DivideBy(const mcMonomial &mon)
01603 { WRAP_MONOMIAL(math_DivideBy); }
01604 
01605 
01606 
01607 
01608 // -------------------------------
01609 // mcMATHMNG - general functions
01610 // -------------------------------
01611 
01612 mcRealValue mcMathMngHelpers::math_Evaluate() const
01613 {
01614  mcRealValue val1 = data_GetLeftMem().math_Evaluate();
01615  if (mdata_nDataType == mcMMT_EXPRESSION) return val1;
01616  
01617  // calc also right member's value
01618  mcRealValue val2 = data_GetRightMem().math_Evaluate();
01619  if (val1 == *mcRealValue::pNAN || val2 == *mcRealValue::pNAN)
01620   return *mcRealValue::pNAN;
01621 
01622  return val1-val2;  // transport right member's result to left member...
01623 }
01624 
01625 mcRealValue mcMathMngHelpers::math_GetLenght() const
01626 {
01627  if (mdata_nDataType == mcMMT_EXPRESSION)
01628   return 0.5;  // the simplest
01629  if (mdata_nDataType == mcMMT_EQUATION)
01630   return 1.0;
01631 
01632  // inequalities are the most difficult...
01633  return 1.5;
01634 }
01635 
01636 mcRealValue mcMathMngHelpers::math_GetTotalLenght() const
01637 {
01638  if (mdata_nDataType == mcMMT_EXPRESSION)
01639   return data_GetLeftMem().math_GetTotalLenght()+math_GetLenght();
01640   
01641  // just sum the lenght of the two members + a little value for the separator
01642  return data_GetLeftMem().math_GetTotalLenght()+
01643     data_GetRightMem().math_GetTotalLenght()+math_GetLenght();
01644 }
01645 
01646 mcElement mcMathMngHelpers::math_Find(int n, const mcElement &tofind, long flags, int *pos) const
01647 {
01648  int left = data_GetLeftMem().math_GetCountOf(tofind, flags);
01649  if (left <= n) {
01650   // the left member does not have enough occurrences of 'tofind'
01651   n-=left;
01652  } else {
01653  
01654   // the required occurrence is in the left member
01655   if (pos) *pos = 0;
01656    return data_GetLeftMem().math_Find(n, tofind, flags);  
01657  }
01658 
01659  if (pos) *pos = 1;
01660  return data_GetRightMem().math_Find(n, tofind, flags);
01661 }
01662 
01663 int mcMathMngHelpers::math_GetCountOf(const mcElement &tocount, long flags) const
01664 {
01665  return data_GetLeftMem().math_GetCountOf(tocount, flags) +
01666    data_GetRightMem().math_GetCountOf(tocount, flags);
01667 }
01668 
01669 int mcMathMngHelpers::math_Replace(const mcElement &tofind, int occ, long flags,
01670         const mcElement &replacement, bool addchildren)
01671 {
01672  int total = 0;
01673  total += data_GetLeftMem().math_Replace(tofind, occ, flags, replacement, addchildren);
01674  total += data_GetRightMem().math_Replace(tofind, occ, flags, replacement, addchildren);
01675 
01676  return total;
01677 }
01678 
01679 int mcMathMngHelpers::math_GetSymbolList(mcSymbol **arr, int size, const mcSymbol &tofind, 
01680         bool left) const
01681 {
01682  if (left)
01683   return data_GetLeftMem().math_GetSymbolList(arr, size, tofind);
01684  return data_GetRightMem().math_GetSymbolList(arr, size, tofind);
01685 }
01686 
01687 mcBasicOpRes mcMathMngHelpers::math_RaiseTo(const mcPolynomial &pol)
01688 {
01689  data_GetLeftMem().math_SimpleRaiseTo(pol);
01690  data_GetRightMem().math_SimpleRaiseTo(pol);
01691  return mcBOR_REMOVE_OPERAND;
01692 }
01693 /*
01694 void mcMathMngHelpers::math_SimpleRaiseTo(const mcPolynomial &pol)
01695 {
01696  mcMATHLOG(wxT("mcMathMngHelpers::math_SimpleRaiseTo [%s] - raising to [%s]"), mcTXTTHIS, mcTXT(pol));
01697 
01698  if (pol.math_isFactorized()) {
01699 
01700   const mcMonomial &elem = pol.math_Get(0);
01701   if (elem.math_GetCount() == 1) {
01702 
01703    const mcElement &num = elem.math_Get(0);
01704    if (num.data_GetType() == mcET_NUMBER) {
01705 
01706     mcRealValue n = pol.math_GetSign(0)*
01707         mcNumber(num).data_Get();
01708 
01709     math_RaiseTo(n);
01710     return;
01711    }
01712   }
01713  }
01714 
01715  math_RaiseTo(pol);
01716 }*/
01717 
01718 bool mcMathMngHelpers::math_ContainsSymbol(const mcSymbolProperties *sym) const
01719 {
01720  return data_GetLeftMem().math_ContainsSymbol(sym) ||
01721    data_GetRightMem().math_ContainsSymbol(sym);
01722 }
01723 
01724 mcIntegerValue mcMathMngHelpers::math_GetMaxDegreeFor(const mcSymbolProperties *sym) const
01725 {
01726  mcIntegerValue m1, m2;
01727 
01728  // get the max degree
01729  m1 = data_GetLeftMem().math_GetMaxDegreeFor(sym);
01730  m2 = data_GetRightMem().math_GetMaxDegreeFor(sym);
01731 
01732  // the given symbol has a non-numeric exponent somewhere in *this ?
01733  if (!m1.isValid() || !m2.isValid())
01734   return *mcIntegerValue::pNAN;
01735 
01736  return mcMAX(m1, m2);
01737 }
01738 
01739 void mcMathMngHelpers::math_FactoreOut(const mcSymbolProperties *sym,
01740         const mcPolynomial &pol,
01741         bool bForceUseless)
01742 {
01743  mcMATHLOG(wxT("mcMathMngHelpers::math_FactoreOut [%s]"), io_GetInlinedExpr().c_str());
01744  data_GetLeftMem().math_FactoreOut(sym, pol, bForceUseless);
01745  data_GetRightMem().math_FactoreOut(sym, pol, bForceUseless);
01746 }
01747 
01748 void mcMathMngHelpers::math_FactoreOutFreeOf(const mcSymbolProperties *sym,
01749         const mcPolynomial &pol,
01750         bool bForceUseless)
01751 {
01752  data_GetLeftMem().math_FactoreOutFreeOf(sym, pol, bForceUseless);
01753  data_GetRightMem().math_FactoreOutFreeOf(sym, pol, bForceUseless);
01754 }
01755 
01756 void mcMathMngHelpers::math_FactoreOutAll(bool bForceUseless)
01757 {
01758  data_GetLeftMem().math_FactoreOutAll(bForceUseless);
01759  data_GetRightMem().math_FactoreOutAll(bForceUseless);
01760 }
01761 
01762 bool mcMathMngHelpers::math_isFactorized() const
01763 {
01764  return data_GetLeftMem().math_isFactorized() &&
01765   data_GetRightMem().math_isFactorized();
01766 }
01767 


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

[ Top ]