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("≠"); 01042 break; 01043 01044 case mcMMT_INEQUALITY_GE: 01045 opname = wxT("≥"); 01046 break; 01047 01048 case mcMMT_INEQUALITY_LE: 01049 opname = wxT("≤"); 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
[ Top ] |