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 "Polynomial.h" 00036 #endif 00037 00038 00039 // includes 00040 #include "mc/mcprec.h" 00041 #ifdef __BORLANDC__ 00042 #pragma hdrstop 00043 #endif 00044 00045 #ifndef mcPRECOMP 00046 #include <wx/tokenzr.h> 00047 #include "mc/Polynomial.h" 00048 #include "mc/Monomial.h" 00049 #include "mc/MathUtils.h" 00050 #endif 00051 00052 00053 00054 // these are required by mcPolynomialMath functions 00055 #include "mc/Bracket.h" 00056 #include "mc/Number.h" 00057 #include "mc/Fraction.h" 00058 #include "mc/Parenthesis.h" 00059 #include "mc/Symbol.h" 00060 00061 00062 mcIMPLEMENT_MAIN_CLASS(mcPolynomial, mcElementArray); 00063 00064 00065 00066 // setup customizable variables 00067 int mcPolynomialHelpers::sgui_nSpaceBetween = 2; 00068 mcPolynomial *mcPolynomialHelpers::smath_pOne = NULL; 00069 mcPolynomial *mcPolynomialHelpers::smath_pEmpty = NULL; 00070 00071 00072 // global objects 00073 mcPolynomial mcEmptyPolynomial((mcPolynomialHelpers*)NULL); 00074 00075 00076 00077 00078 // ---------------------------------------- 00079 // mcPOLENTRY 00080 // ---------------------------------------- 00081 00082 /*int mcPolEntry::math_GetMonIdx(const mcPolynomial &owner) 00083 { return owner.math_DataToMathIdx(mdata_midx); } 00084 00085 int mcPolEntry::math_GetElemIdx(const mcPolynomial &owner) 00086 { return owner.math_DataToMathIdx(mdata_eidx); }*/ 00087 00088 00089 00092 bool isPolynomialOkay(const mcElement &p) 00093 { 00094 static bool lastwasop = FALSE; 00095 00096 if (p.data_GetType() != mcET_MONOMIAL && 00097 p.data_GetType() != mcET_ADDOP && 00098 p.data_GetType() != mcET_SUBOP) { 00099 00100 // only monomials, add & sub operators are supported 00101 return FALSE; 00102 } 00103 00104 if ((p.data_GetType() == mcET_ADDOP || 00105 p.data_GetType() == mcET_SUBOP) && !lastwasop) { 00106 00107 lastwasop = TRUE; 00108 00109 } else if (p.data_GetType() == mcET_MONOMIAL && lastwasop) { 00110 00111 lastwasop = FALSE; 00112 00113 } else { 00114 00115 // this array is containing something which is not a operator 00116 // nor a mcMonomial... or it contains one of these elements 00117 // but in an invalid order... 00118 return FALSE; 00119 } 00120 00121 return TRUE; 00122 } 00123 00124 00125 00126 00127 00128 00129 // ---------------------------------------- 00130 // mcPOLYNOMIALDATA 00131 // ---------------------------------------- 00132 00133 #ifdef __MCDEBUG__ 00134 00135 void mcPolynomialHelpers::data_Check() const 00136 { 00137 // check that a + or - is separing all the monomials in the array 00138 bool b = FALSE; 00139 if (data_GetCount() > 0 && data_isOp(0)) 00140 b = TRUE; 00141 00142 // if we say to ScanArray to check only even elements, the first would 00143 // be skipped !!! check it here.... 00144 if (!b && data_GetCount() > 0) { 00145 00146 mcASSERT(!data_isOp(0), 00147 wxT("If 'b' is FALSE, the first element should be a non-op !!!")); 00148 mcASSERT(data_Get(0).data_GetType() == mcET_MONOMIAL, 00149 wxT("If the first element is not an op, then it should be a mcMonomial !!!")); 00150 } 00151 00152 #ifdef mcENABLE_VERBOSE_CHECK 00153 mcLOG(wxT("mcPolynomialHelpers::data_Check - checking [%s]"), mcTXTTHIS); 00154 #endif 00155 mcASSERT(data_ScanArray(isPolynomialOkay, b), 00156 wxT("Not all the monomials in the array are ") \ 00157 wxT("separed by a mcAddOp or a mcSubOp")); 00158 00159 // this MUST be true... it's an important prerequisite of math functions 00160 //mcASSERT(data_GetCount() == 0 || data_isOp(0), "The expression must always start with a + or -"); 00161 mcElementArrayHelpers::data_Check(); 00162 } 00163 00164 #endif 00165 00166 bool mcPolynomialHelpers::data_isWrappingOnly(mcElementType t) const 00167 { 00168 if (data_GetCount() > 1) // more than an element ? 00169 return FALSE; 00170 00171 // check if we are directly containing the given element type... 00172 // (which can be only a mcOperator or mcMonomial, in this case) 00173 if (data_Get(0).data_GetType() == t) 00174 return TRUE; 00175 00176 // EXTENDED FEATURE mcPOLYNOMIAL-SPECIFIC: 00177 // if we're containing a single monomial, then check if it's 00178 // wrapping only the required element type: data_GetWrapped 00179 // will allow the programmer to extract it... 00180 if (data_Get(0).data_GetType() == mcET_MONOMIAL && 00181 ((const mcMonomial &)data_Get(0)).data_isWrappingOnly(t)) 00182 return TRUE; 00183 return FALSE; 00184 } 00185 00186 const mcElement &mcPolynomialHelpers::data_GetWrapped(mcElementType t) const 00187 { 00188 // we need to call this function to be sure that we 00189 // do not have more than one monomial... 00190 if (!data_isWrappingOnly(t)) 00191 return mcEmptyElement; 00192 00193 // if t is the identifier of a mcMonomial or a mcOperator, we can directly 00194 // return it here 00195 if (data_Get(0).data_GetType() == t) 00196 return data_Get(0); 00197 00198 // otherwise we can extract here from the single monomial we contain... 00199 return ((const mcMonomial &)data_GetElemOfType(0, mcET_MONOMIAL)).data_GetWrapped(t); 00200 } 00201 00202 bool mcPolynomialHelpers::math_isWrappingOnly(mcElementType t) const 00203 { 00204 // see data_isWrappingOnly for details.... 00205 if (math_GetCount() != 1) 00206 return FALSE; 00207 if (math_Get(0).data_GetType() == t) 00208 return TRUE; 00209 if (math_Get(0).math_isWrappingOnly(t)) 00210 return TRUE; 00211 return FALSE; 00212 } 00213 00214 const mcElement &mcPolynomialHelpers::math_GetWrapped(mcElementType t) const 00215 { 00216 // see data_isWrappingOnly for details.... 00217 if (!math_isWrappingOnly(t)) 00218 return mcEmptyElement; 00219 if (math_Get(0).data_GetType() == t) 00220 return math_Get(0); 00221 return math_Get(0).math_GetWrapped(t); 00222 } 00223 00224 bool mcPolynomialHelpers::data_CreateFirstOp() 00225 { 00226 if (!data_isArrayEmpty() && data_isOp(0)) 00227 return FALSE; // one is already present... 00228 00229 // if the first element of the this polynomial is *not* an operator 00230 // we must add one !!! 00231 data_MoveElemRight(0); 00232 data_AddNewOp(mcET_ADDOP, 0); // by default, add a + 00233 return TRUE; 00234 } 00235 00236 void mcPolynomialHelpers::data_DeleteFirstOp() 00237 { 00238 if (data_isArrayEmpty() || !data_isOp(0)) 00239 return; // there is no a first operator to data_Delete 00240 00241 data_DeleteFirst(1); // just remove first element 00242 } 00243 00244 mcElement &mcPolynomialHelpers::data_AddNewWrappedElement(mcElementType t, 00245 bool bOverwrite, int pos) 00246 { 00247 mcASSERT(t != mcET_MONOMIAL, wxT("Cannot nest monomials")); 00248 00249 // create an element of type "t" and create a monomial containing it 00250 mcElement res = mcElementHelpers::data_NewElem(t); 00251 int n = data_AddNewMonomialContaining(&res, pos, bOverwrite); 00252 if (n == -1) return mcEmptyElement; 00253 00254 // then return the index of the new monomial 00255 mcMonomial &m = (mcMonomial &)data_Get(pos); 00256 return m.data_Get(n); 00257 } 00258 00259 void mcPolynomialHelpers::data_DetachAndShiftMonomial(int n) 00260 { 00261 // be sure the n-th element is a monomial 00262 mcASSERT(data_Get(n).data_GetType() == mcET_MONOMIAL, 00263 wxT("This function works on monomials only")); 00264 00265 // data_Detach the n-th monomial and its sign 00266 data_Detach(n); 00267 data_MoveElemLeft(n); 00268 00269 if (n > 0 && data_isOp(n-1)) { 00270 data_Detach(n-1); 00271 data_MoveElemLeft(n-1); 00272 } 00273 } 00274 00275 int mcPolynomialHelpers::data_AddNewMonomialContaining(mcElement *contents, 00276 int n, int pos, bool bOverwrite) 00277 { 00278 // create the new monomial 00279 mcMonomial m; 00280 00281 // add to it the given elements 00282 mcASSERT(n > 0, wxT("Cannot add zero elements")); 00283 int idx = m.data_AddElements(contents, n); 00284 00285 // and then add the monomial to this array 00286 data_AddElements((mcElement *)(&m), 1, pos, bOverwrite); 00287 return idx; 00288 } 00289 00290 bool mcPolynomialHelpers::data_ReplaceParentheses(int leftm, int leftidx, 00291 int rightm, int rightidx, 00292 bool bMoveOnBracketEnd) 00293 { 00294 const mcMonomial &left = (const mcMonomial &)data_Get(leftm); 00295 const mcMonomial &right = (const mcMonomial &)data_Get(rightm); 00296 const mcParenthesis &rightp = (const mcParenthesis &)right.data_Get(rightidx); 00297 mcLOG(wxT("mcPolynomialHelpers::data_ReplaceParentheses - ") 00298 wxT("the monomial containing the left bracket is [%s]"), mcTXT(left)); 00299 mcLOG(wxT("mcPolynomialHelpers::data_ReplaceParentheses - ") 00300 wxT("the monomial containing the right bracket is [%s]"), mcTXT(right)); 00301 00302 // ok, we have found a right bracket and we can thus 00303 // create our new mcBracket... 00304 mcPolynomial contents; 00305 00306 // if the monomial containing the left bracket contains something 00307 // which follows the left parenthesis, then copy it in our 00308 // brand-new polynomial... 00309 if (left.data_GetCount() - leftidx > 0) { 00310 00311 int n = left.data_GetCount() - leftidx - 1; 00312 00313 if (rightm == leftm) { 00314 00315 // if the monomial containing the LEFT and the RIGHT 00316 // parentheses are the same, then we must adjust n 00317 n -= left.data_GetCount()-rightidx; 00318 } 00319 00320 if (n > 0) 00321 contents.data_AddNewMonomialContaining( 00322 left.data_GetArray(leftidx+1), 00323 n, 00324 -1, 00325 TRUE); 00326 } 00327 00328 // now add all the monomials placed between the monomial 00329 // containing the LEFT parenthesis and the one containing 00330 // the RIGHT one... 00331 if (rightm-leftm > 0) { 00332 00333 contents.data_AddElements( 00334 data_GetArray(leftm+1), 00335 rightm-leftm-1); 00336 } 00337 00338 // finally, add the elements ,which are placed in the monomial 00339 // containing the RIGHT bracket, which precede the parenthesis... 00340 if (rightm != leftm && rightidx > 0) { 00341 00342 contents.data_AddNewMonomialContaining( 00343 right.data_GetArray(), 00344 rightidx); 00345 //TRUE); 00346 } 00347 00348 // don't create empty polynomials !!! 00349 if (contents.data_isArrayEmpty()) { 00350 00351 // add a simple empty box; the result will be: 00352 // 00353 // (--) where -- is the empty box !!!! 00354 // 00355 contents.data_AddNewEmptyMonomial(); 00356 } 00357 00358 // don't create empty monomials !!! 00359 /*const mcMonomial &m = contents.data_Get(0);*/ 00360 if (((const mcMonomial &)contents.data_GetElemOfType(0, mcET_MONOMIAL)).data_isArrayEmpty()) { 00361 00362 // in these cases: 00363 // 00364 // ( + ... ) 00365 // ^- empty monomial 00366 // 00367 // we cannot just add an empty box: we must 00368 // instead remove the first monomial; in this 00369 // way, the operator between 1th and 2nd, becomes 00370 // the first operator of the bracket's polynomial... 00371 contents.data_DeleteFirst(1); 00372 } 00373 00374 // complete bracket creation... 00375 mcBracket br; 00376 br.data_SetContent(contents); 00377 00378 // eventually set the bracket's exponent 00379 // (stored in a temporary field of mcParenthesis) 00380 if (rightp.hlp()->mdata_pTmpExp != mcEmptyElement && 00381 !rightp.hlp()->mdata_pTmpExp.data_isArrayEmpty()) { 00382 00383 mcLOG(wxT("mcPolynomialHelpers::data_ReplaceParentheses - ") 00384 wxT("the exponent of the bracket is [%s]"), mcTXT(rightp.hlp()->mdata_pTmpExp)); 00385 br.data_SetExpSub(TRUE, rightp.hlp()->mdata_pTmpExp); 00386 } 00387 00388 mcLOG(wxT("mcPolynomialHelpers::data_ReplaceParentheses - ") 00389 wxT("the new bracket is [%s]"), mcTXT(br)); 00390 br.data_Check(); 00391 00392 // ok, now we have our new bracket; but it must replace 00393 // ALL the elements that we have copied inside the bracket... 00394 mcMonomial &m = (mcMonomial &)left; 00395 00396 // data_Delete the useless elements contained in the first monomial 00397 int cursoridx = -1; 00398 if (rightm != leftm) { 00399 00400 m.data_DeleteLast(m.data_GetCount()-leftidx); 00401 m.data_AddElements((mcElement*)(&br), 1); 00402 cursoridx = m.data_GetCount()-1; 00403 00404 } else { 00405 00406 // both the LEFT and the RIGHT parentheses are contained 00407 // in the same monomial; special code is required in this case... 00408 m.data_AddElements((mcElement*)(&br), 1, leftidx, TRUE); 00409 cursoridx = leftidx; 00410 00411 // remove the elements placed between the bracket we have 00412 // just added and the right parenthesis... 00413 for (int g=leftidx+1; g < rightidx+1; g++) { 00414 00415 m.data_Delete(leftidx+1); 00416 m.data_MoveElemLeft(leftidx+1); 00417 } 00418 } 00419 00420 // place the cursor of the monomial at the end of the 00421 // bracket we have created... 00422 if (mcMathCore::Get()->isGUIEnabled()) { 00423 if (bMoveOnBracketEnd) { 00424 00425 // end of the monomial is the end of the bracket, too: 00426 // ... (...)| ... <-- final pos of cursor 00427 m.gui_SetCursorPos(mcCP_END); 00428 00429 } else { 00430 00431 m.gui_SetCursorOnElemBegin(cursoridx); 00432 00433 // this will set the cursor here: 00434 // ... (|...) ... 00435 // instead of 00436 // ... |(...) ... 00437 // thus simulating the real input of the parenthesis 00438 m.gui_MoveCursor(mcMCF_RIGHT, mcMCF_NOMODIFIERS); 00439 } 00440 } 00441 00442 // finally, add to the first monomial the useful elements 00443 // contained in the right monomial... 00444 if (rightm != leftm) { 00445 00446 m.data_AddElements( 00447 right.data_GetArray(rightidx+1), 00448 right.data_GetCount()-rightidx-1); 00449 00450 // and last, remove the right monomial... 00451 data_Delete(leftm+1); 00452 data_MoveElemLeft(leftm+1); 00453 } 00454 00455 // remove the monomials placed between the two containing 00456 // the LEFT and the RIGHT bracket... 00457 for (int g=leftm+1; g < rightm; g++) { 00458 00459 data_Delete(leftm+1); 00460 data_MoveElemLeft(leftm+1); 00461 } 00462 00463 mcLOG(wxT("mcPolynomialHelpers::data_ReplaceParentheses - ") 00464 wxT("after removing replaced elements, I'm set to [%s]"), mcTXTTHIS); 00465 00466 // move cursor to a valid position 00467 if (mcMathCore::Get()->isGUIEnabled()) 00468 mgui_nCursorPos = leftm; 00469 00470 // stop here 00471 data_Check(); 00472 return TRUE; // a pair of mcParenthesis have been replaced 00473 } 00474 00475 bool mcPolynomialHelpers::data_ReplaceParentheses(bool bMoveOnBracketEnd) 00476 { 00477 bool bFoundFirst = FALSE; // TRUE if the LEFT bracket has already been found 00478 00479 int monomialidx = -1, // the index of the monomial containing the LEFT bracket 00480 bracketidx = -1; // the bracket's index of the LEFT bracket 00481 00482 int bridx = -1, // the current bracket's index in the current monomial 00483 i; // the index of the current monomial 00484 00485 for (i=0; i < data_GetCount(); i++) { 00486 00487 // skip non-monomials... 00488 if (data_Get(i).data_GetType() != mcET_MONOMIAL) 00489 continue; 00490 00491 // ok, process this monomial... 00492 const mcMonomial &m = (const mcMonomial &)data_Get(i); 00493 00494 // ...scanning all its elements... 00495 for (int j=0, max=m.data_GetCount(); j < max; j++) { 00496 00497 const mcElement &curr = m.data_Get(j); 00498 if (curr.data_GetType() != mcET_PARENTHESIS) 00499 continue; 00500 00501 // get a pointer to the just found parenthesis 00502 bridx = j; 00503 const mcParenthesis &p = m.data_Get(bridx); 00504 00505 if (!bFoundFirst) { 00506 00507 // wait for the next... 00508 if (!p.data_isLeftBracket()) 00509 continue; 00510 00511 // ok, we have found the left parenthesis... now, 00512 // we can go on searching its counterpart... 00513 bFoundFirst = TRUE; 00514 monomialidx = i; 00515 bracketidx = bridx; 00516 00517 // copy the elements which are contained in the current 00518 // monomial and which follow the parenthesis in the 00519 // polynomial which will be used as the content array 00520 // for the new bracket element we are trying to create... 00521 00522 } else { 00523 00524 00525 if (p.data_isLeftBracket()) { 00526 00527 // hmmmm, we have find a left bracket instead of 00528 // a right bracket... update our indexes because 00529 // inner brackets must be solved as firsts 00530 monomialidx = i; 00531 bracketidx = bridx; 00532 continue; 00533 } 00534 00535 // proceed with replacement 00536 return data_ReplaceParentheses(monomialidx, bracketidx, i, 00537 bridx, bMoveOnBracketEnd); 00538 } 00539 } 00540 } 00541 00542 // no mcParenthesis have been replaced 00543 return FALSE; 00544 } 00545 00546 void mcPolynomialHelpers::data_ReplaceAllParentheses() 00547 { 00548 bool exit = FALSE; 00549 while (!exit) { 00550 00551 // higly probably, cursor position will be invalid 00552 // after this operations... 00553 exit = !data_ReplaceParentheses(FALSE); 00554 } 00555 } 00556 00557 void mcPolynomialHelpers::gui_ReplaceBracket(const mcBracket &br, bool left) 00558 { 00559 mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - replacing the %s of [%s]"), 00560 (left ? wxT("left") : wxT("right")), mcTXT(br)); 00561 mcPolynomial contents(br.data_GetConstContent()); 00562 mcMonomial &m = mcEmptyMonomial; 00563 00564 int monomialidx = -1, // the index of the monomial containing 'br' 00565 pcursoridx = -1, // a copy of the index of the previous monomial 00566 bridx = -1, // the "br"'s index inside data_Get(monomialidx) 00567 mcursoridx = -1; // the index of the element preceding "br" 00568 00569 // this is a prerequisite... 00570 mcASSERT(contents.data_GetCount() > 0, wxT("Cannot break an empty bracket...")); 00571 00572 // first of all, find the monomial which contains the bracket which 00573 // must be replaced by mcParenthesis + its contents... 00574 for (int i=0; i < data_GetCount(); i++) { 00575 00576 // discard non-monomial elements 00577 if (data_Get(i).data_GetType() != mcET_MONOMIAL) 00578 continue; 00579 const mcMonomial &tocheck = (const mcMonomial &)data_GetConst(i); 00580 00581 // does this monomial contains the bracket to replace ? 00582 if ((bridx = tocheck.data_GetIndexOf(br)) != -1) { 00583 monomialidx = i; // save these info 00584 pcursoridx = monomialidx; 00585 mcursoridx = bridx-1; 00586 m = tocheck; 00587 break; 00588 } 00589 } 00590 00591 mcASSERT(m != mcEmptyElement, wxT("Something wrong")); 00592 mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - the monomial ") 00593 wxT("with the bracket to replace is [%s]"), mcTXT(m)); 00594 m.data_Delete(bridx); 00595 m.data_MoveElemLeft(bridx); 00596 00597 // ok, add the left parenthesis if the parenthesis which had been removed 00598 // is the RIGHT one... 00599 if (!left) { 00600 00601 mcParenthesis left; 00602 left.data_SetAsLeftBracket(); 00603 left.data_AddProperty(mcEP_INITIALIZED); 00604 m.data_AddElements(&left, 1, bridx); 00605 bridx++; 00606 00607 mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - the monomial is [%s]"), mcTXT(m)); 00608 } 00609 00610 // maybe that the first element of the bracket is not a monomial but a 00611 // mcAddOp or a mcSubOp... better check... 00612 mcMonomial &first = (mcMonomial &)contents.data_GetElemOfType(0, mcET_MONOMIAL); 00613 if (contents.data_Get(0).data_GetType() == mcET_MONOMIAL) { 00614 m.data_AddElements(first.data_GetArray(), 00615 first.data_GetCount(), bridx); 00616 //bridx = m.data_GetIndexOf(br); 00617 00618 // delete this monomial since it's already been added 00619 contents.data_Delete(0); 00620 contents.data_MoveElemLeft(0); 00621 } 00622 00623 mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - the monomial is [%s]"), mcTXT(m)); 00624 00625 // add the monomials contained in the just-removed bracket 00626 if (contents.data_GetCount() > 1) { 00627 00628 data_Merge(contents); 00629 monomialidx += contents.data_GetCount(); 00630 } 00631 00632 m = (mcMonomialHelpers *)data_Get(monomialidx).hlp(); 00633 00634 // if the parenthesis which must result as the removed one is the 00635 // LEFT, we must add the RIGHT one... 00636 if (left) { 00637 mcParenthesis right; 00638 right.data_SetAsRightBracket(); 00639 right.data_AddProperty(mcEP_INITIALIZED); 00640 m.data_AddElements(&right, 1, bridx+1); 00641 00642 mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - the monomial is [%s]"), mcTXT(m)); 00643 } 00644 00645 00646 // set the cursor in the right position 00647 if (!left) { 00648 mgui_nCursorPos = monomialidx; 00649 00650 // move the monomial cursor too 00651 if (bridx+1 >= m.data_GetCount()) 00652 m.gui_SetCursorPos(mcCP_END); 00653 else 00654 m.gui_SetCursorOnElemEnd(bridx+1); 00655 } 00656 00657 if (left) { 00658 00659 // move cursor 00660 mgui_nCursorPos = pcursoridx; 00661 m = (mcMonomialHelpers *)data_Get(pcursoridx).hlp(); 00662 00663 if (mcursoridx < 0) { 00664 00665 // there were no elements before the bracket; the cursor 00666 // must be placed at the beginning of the monomial... 00667 m.gui_SetCursorPos(mcCP_BEGIN); 00668 00669 } else { 00670 00671 // place the cursor on the element which was preceding the 00672 // bracket we replaced... 00673 m.gui_SetCursorOnElemEnd(mcursoridx); 00674 } 00675 } 00676 00677 // ok, we have finished.... 00678 data_Check(); 00679 mcGUILOG(wxT("mcPolynomialHelpers::gui_ReplaceBracket - we are now ") 00680 wxT("set to [%s]"), mcTXTTHIS); 00681 } 00682 00683 int mcPolynomialHelpers::data_FindMonomialContaining(int occ, const mcElement &elem) const 00684 { 00685 int n = -1; 00686 00687 for (int i=0; i < data_GetCount(); i++) { 00688 00689 // skip non monomial elements 00690 if (data_Get(i).data_GetType() != mcET_MONOMIAL) continue; 00691 00692 // search, non-recursively, in this monomial 00693 if ((n = mcMonomial(data_Get(i)).data_GetIndexOf(elem)) != -1) { 00694 if (occ == 0) 00695 return n; 00696 occ--; // try with next occurrence 00697 } 00698 } 00699 00700 // could not find any result 00701 return -1; 00702 } 00703 00704 00705 00706 00707 00708 00709 00710 // ---------------------------------------- 00711 // mcPOLYNOMIALGUI 00712 // ---------------------------------------- 00713 00714 bool mcPolynomialHelpers::gui_isArrayEmpty() 00715 { 00716 if (data_isArrayEmpty() || (data_GetCount() == 1 && data_isOp(0))) 00717 return TRUE; 00718 return FALSE; 00719 } 00720 00721 int mcPolynomialHelpers::gui_ExDraw(wxDC &dc, int x, int y, long flags, const wxPoint &pt, int cl) const 00722 { 00723 mcGUILOG(wxT("mcPolynomialHelpers::gui_ExDraw [%s]"), mcTXTTHIS); 00724 int a = gui_GetSelElemCount(); 00725 00726 // if a selection among two or more monomials is present in the polynomial, 00727 // draw it ourselves, if a selection is present but it is limited to one 00728 // monomial only, let that monomial draw it... 00729 if (a > 1) { 00730 00731 // we will care about the selection rectangle drawing... 00732 int mflags = flags & ~mcDRW_ALLOW_TOTAL_SELECTION; 00733 00734 // the selection is "extended": draw only non-selected monomials 00735 int w, n = mcElementArrayHelpers::gui_ExDraw(dc, x, y, mflags, pt, cl); 00736 00737 // draw selection rectangle + selected monomials & 00738 // check if we must change return code 00739 if ((w=gui_DrawSelection(dc, x, y, flags, pt, cl)) != mcDRW_NOACTIVEELEM) 00740 n = w; 00741 return n; 00742 } 00743 00744 return mcElementArrayHelpers::gui_ExDraw(dc, x, y, flags, pt, cl, FALSE, -1, TRUE); 00745 } 00746 00747 void mcPolynomialHelpers::gui_ExOnSelect(wxDC &dc, wxRect &rc, int cl) 00748 { 00749 // select elements using the mcElementArray function 00750 mcElementArrayHelpers::gui_ExOnSelect(dc, rc, cl); 00751 00752 // adjust selection if required, selecting the operators which are 00753 // placed before completely selected monomials 00754 for (int a=gui_GetSelStart(), b=gui_GetSelEnd(); a < b; a++) 00755 if (data_Get(a).gui_isAllSelected()) 00756 if (a > 0 && data_isOp(a-1)) 00757 data_Get(a-1).gui_SelectAll(); 00758 } 00759 00760 int mcPolynomialHelpers::gui_AddNewElement(mcElementType type, const mcKey &key, int pos) 00761 { 00762 //mcElementType m = mcMathCore::Get().isKeyBeginKey(key); 00763 if (pos == -1) pos = data_GetCount(); 00764 00765 // check we are going to add the right type of element !!! 00766 mcASSERT(type == mcET_MONOMIAL || type == mcET_ADDOP || type == mcET_SUBOP, 00767 wxT("Cannot create something which is not a mcOperator or a mcMonomial !!!!")); 00768 mcElementArrayHelpers::gui_AddNewElement(type, key, pos); 00769 00770 // check if we have added a new operator 00771 if (type == mcET_ADDOP || type == mcET_SUBOP) { 00772 if (pos == data_GetCount()-1 || data_isOp(pos+1)) { 00773 00774 // handle the case: 00775 // ... ab| ... user creates a mcAddOp or a mcSubOp 00776 // which is also the case of: 00777 // ... ab|+c ... user creates a mcAddOp or a mcSubOp 00778 pos++; 00779 data_MoveElemRight(pos); 00780 gui_AddNewEmptyMonomial(pos); 00781 00782 } else if (pos > 0 && data_isOp(pos-1)) { 00783 00784 // handle the case: 00785 // ... ab+|bc ... user creates a mcAddOp or a mcSubOp 00786 // 00787 // In this case cursor must not be moved: it is 00788 // already placed on the new monomial !!! 00789 // 00790 data_MoveElemRight(pos); 00791 gui_AddNewEmptyMonomial(pos); 00792 00793 } else if (pos == 0) { 00794 00795 // handle the case: 00796 // |ab+bc+cd ... user creates a mcAddOp or a mcSubOp 00797 // 00798 // In this case, we are going to add an operator in the 00799 // first position of the array !!! 00800 pos++; 00801 } 00802 } 00803 00804 gui_RecalcSize(); 00805 return pos; 00806 } 00807 00808 mcInputRes mcPolynomialHelpers::gui_Input(const mcKey &ev, mcElement *newelem) 00809 { 00810 // in this function we must handle ONLY a special case: a mcAddSubOp 00811 // placed in the first entry of the array, thus working 00812 // as unary operator. 00813 // 00814 // NOTE: if we are wrapping only a mcEmptyBox, then the mcCP_END and 00815 // mcCP_BEGIN flags coincide: since we don't know what mcEmptyBoxes 00816 // return as cursor position (the cursor can be placed only in a 00817 // single position inside a mcEmptyBox and thus it does not make 00818 // sense to refer to a leftmost or rightmost position) 00819 // 00820 if (gui_GetCursorPos().isBegin() || data_isWrappingOnly(mcET_EMPTYBOX)) { 00821 mcElementType n = mcElementHelpers::gui_isKeyBeginKey(ev); 00822 00823 if (n == mcET_ADDOP || n == mcET_SUBOP) { 00824 00825 bool replace = FALSE; 00826 00827 // don't send this to the first (eventually present) monomial... 00828 // instead, add it at the beginning of the array (eventually 00829 // replacing a previously present first operator...) 00830 if (data_GetCount() > 0 && data_isOp(0)) 00831 replace = TRUE; 00832 mcElement &e = data_AddNewElement(n, replace, 0); 00833 00834 // need to recalc the size 00835 e.gui_RecalcSize(); 00836 00837 // do not forget the cursor set on a mcOperator... 00838 if (!replace) mgui_nCursorPos++; 00839 gui_CheckCursorPos(); 00840 00841 gui_RecalcSize(); 00842 return mcIR_OKAY; 00843 } 00844 00845 } 00846 00847 // UNTESTED !!! 00848 mcElementType n = mcElementHelpers::gui_isKeyBeginKey(ev); 00849 if (n == mcET_PARENTHESIS) 00850 gui_OnNewParenthesis(mcBracketHelpers::gui_isLeftParenthesis(ev.GetKeyCode())); 00851 00852 // let the base class function handle everything... 00853 mcInputRes r = mcElementArrayHelpers::gui_Input(ev, newelem); 00854 00855 // this is a special routine for mcParenthesis 00856 if (mgui_bRemoveParenthesis) { 00857 data_ReplaceParentheses(!mgui_bMoveCursorAtBracketBegin); 00858 mgui_bRemoveParenthesis = FALSE; 00859 gui_DeepRecalcSize(); 00860 } 00861 00862 if (mgui_pBracketToReplace != mcEmptyElement) { 00863 gui_ReplaceBracket(mgui_pBracketToReplace, mgui_bRemoveLeftParenthesis); 00864 mgui_pBracketToReplace = NULL; 00865 gui_DeepRecalcSize(); 00866 } 00867 00868 return r; 00869 } 00870 00871 mcInputRes mcPolynomialHelpers::gui_BackInput(const mcKey &key, mcElement *pnewelem, int n) 00872 { 00873 int last; 00874 bool b; 00875 00876 switch (n) { 00877 case mcIR_OKAY: 00878 break; 00879 00880 case mcIR_REPLACE_THIS: 00881 if (mgui_nCursorPos == 0) { 00882 mcMathCore::Get()->SyntaxError(wxT("Cannot data_Delete this element")); 00883 return mcIR_OKAY; 00884 } 00885 00886 // data_Delete the focused element & shift left to close the hole in the array 00887 data_Delete(mgui_nCursorPos); 00888 data_MoveElemLeft(mgui_nCursorPos); 00889 00890 // close last hole with the new element overwriting the old one 00891 data_AddElements(pnewelem, 1, mgui_nCursorPos-1, TRUE); 00892 mgui_nCursorPos--; 00893 (*pnewelem) = NULL; 00894 00895 // do not continue processing of other flags 00896 return mcIR_OKAY; 00897 00898 case mcIR_DELETE_THIS: 00899 00900 if (mgui_nCursorPos == 0 && data_GetCount() > 1) { 00901 // handle the case: 00902 // __|__ + abc ... user data_Deletes the empty box 00903 // 00904 return mcIR_DELETE_PREVIOUS; 00905 } 00906 00907 // data_Delete the current monomial 00908 data_Delete(mgui_nCursorPos); 00909 data_MoveElemLeft(mgui_nCursorPos); 00910 00911 if (mgui_nCursorPos > 0) { 00912 00913 // data_Delete the + or - operator which precedes the data_Deleted monomial 00914 mcASSERT(data_isOp(mgui_nCursorPos-1), wxT("An operator was expected")); 00915 data_Delete(mgui_nCursorPos-1); 00916 data_MoveElemLeft(mgui_nCursorPos-1); 00917 mgui_nCursorPos--; 00918 00919 // check if we have just data_Deleted the first operator of the array 00920 if (mgui_nCursorPos == 0) { 00921 00922 // if we had an operator placed at the beginning of the array, 00923 // and the user want to data_Delete it when the cursor is placed 00924 // over the 00925 data_MoveElemRight(0); 00926 gui_AddNewEmptyMonomial(0); 00927 return mcIR_OKAY; 00928 } 00929 } 00930 00931 // move cursor left (this must be done AFTER the eventual 00932 // remotion of the previous operator !!!!) 00933 mgui_nCursorPos--; 00934 00935 if (mgui_nCursorPos >= 0) { 00936 if (mcMathCore::Get()->m_pCancelKey->MatchKey(key)) 00937 data_Get(mgui_nCursorPos).gui_SetCursorPos(mcCP_BEGIN); 00938 else if (mcMathCore::Get()->m_pDeleteKey->MatchKey(key)) 00939 data_Get(mgui_nCursorPos).gui_SetCursorPos(mcCP_END); 00940 } 00941 00942 // was it the last monomial of the array (and was it containing 00943 // an emptybox) ? 00944 if (data_isArrayEmpty()) 00945 return mcIR_DELETE_THIS; // the array is empty !!! 00946 break; 00947 00948 case mcIR_DELETE_PREVIOUS: 00949 00950 // the focused monomial asked us to data_Delete the previous element, which is 00951 // sure an operator + or -. This means that we must merge the focused 00952 // monomials with the previous one. 00953 00954 if (mgui_nCursorPos == 0) { 00955 00956 // cannot data_Delete the previous element because it doesn't exist !!! 00957 return mcIR_DELETE_PREVIOUS; 00958 } 00959 00960 // what if the monomial asked to data_Delete the first operator in the array ? 00961 if (mgui_nCursorPos == 1) { 00962 00963 // the user can see the first operator and he wants to data_Delete it; 00964 // we cannot data_Delete first operator but we can reset it to a + 00965 // and hid it... 00966 // the user will think that an operator does not exist anymore 00967 // but the appearances deceive... :-) 00968 mcASSERT(data_isOp(0), wxT("If the first element is not an operator, cursor") 00969 wxT("is acutally placed on an operator...")); 00970 data_Delete(0); 00971 data_MoveElemLeft(0); 00972 mgui_nCursorPos--; 00973 return mcIR_OKAY; 00974 } 00975 00976 // merge the two monomials 00977 b = mcMonomial(data_Get(mgui_nCursorPos-2)).gui_MergeWith(data_Get(mgui_nCursorPos)); 00978 mcASSERT(b, wxT("Two monomials should always be able to merge...")); 00979 00980 // data_Delete the old monomial and its operator 00981 data_Delete(mgui_nCursorPos-1); 00982 data_Delete(mgui_nCursorPos); 00983 data_MoveElemLeft(mgui_nCursorPos); 00984 data_MoveElemLeft(mgui_nCursorPos-1); 00985 00986 // move cursor to the monomial 00987 mgui_nCursorPos -= 2; 00988 00989 // do some checks 00990 data_Check(); 00991 gui_CheckCursorPos(); 00992 break; 00993 00994 case mcIR_DELETE_NEXT: 00995 00996 // the focused monomial asked us to data_Delete the next element, which is 00997 // sure an operator + or -. This means that we must merge the focused 00998 // monomials with the next one. 00999 01000 last = data_GetCount()-1; 01001 if (mgui_nCursorPos == last) { 01002 01003 // no elements following... 01004 return mcIR_DELETE_NEXT; 01005 } 01006 01007 // cursor check 01008 mcASSERT(mgui_nCursorPos < last-1, wxT("If the monomial cannot end with an operator ") 01009 wxT("and the cursor is not on the last monomial, it must be placed ") 01010 wxT("on the previous monomial, which should be at data_GetCount()-2")); 01011 01012 // merge the two monomials 01013 b = mcMonomial(data_Get(mgui_nCursorPos)).gui_MergeWith(data_Get(mgui_nCursorPos+2)); 01014 mcASSERT(b, wxT("Two monomials should always be able to merge...")); 01015 mcUNUSED(b); 01016 01017 // data_Delete the old monomial and its operator 01018 data_Delete(mgui_nCursorPos+1); 01019 data_Delete(mgui_nCursorPos+2); 01020 data_MoveElemLeft(mgui_nCursorPos+1); 01021 data_MoveElemLeft(mgui_nCursorPos+1); 01022 01023 // do some checks 01024 data_Check(); 01025 gui_CheckCursorPos(); 01026 break; 01027 01028 case mcIR_DISTRIBUTE: 01029 mcASSERT(pnewelem != NULL && *pnewelem != mcEmptyElement, 01030 wxT("No element to distribute !!")); 01031 01032 if (pnewelem->data_GetType() == mcET_BRACKET) { 01033 01034 // this is the case when the user tries to delete the right 01035 // or left parenthesis of a mcBracket element... 01036 bool left = ((const mcBracket *)pnewelem)->hlp()->mgui_bRemoveLeftBracket; 01037 gui_SetBracketToReplace(*pnewelem, left); 01038 } 01039 break; 01040 01041 default: 01042 mcASSERT(0, wxT("Unhandled return flag")); 01043 } 01044 01045 return mcIR_OKAY; 01046 } 01047 01048 mcInsertRes mcPolynomialHelpers::gui_Insert(const mcElement &toinsert, mcElement *) 01049 { 01050 mcCursorPos cp(data_Get(mgui_nCursorPos).gui_GetCursorPos()); 01051 01052 //if (cp.isInside() || cp.isBeginEnd()) { 01053 01054 mcInsertRes r = data_Get(mgui_nCursorPos).gui_Insert(toinsert, NULL); 01055 01056 /* switch (r) { 01057 case mcINSR_OKAY: 01058 return mcINSR_OKAY; 01059 01060 case mcINSR_REPLACE_THIS: 01061 break; 01062 } 01063 }*/ 01064 01065 return mcINSR_OKAY; 01066 01067 /*if (toinsert.data_GetType() != mcET_POLYNOMIAL) 01068 return data_Get(mgui_nCursorPos).gui_Insert(toinsert, NULL); 01069 */ 01070 return mcINSR_OKAY; 01071 } 01072 01073 void mcPolynomialHelpers::gui_SetCursorPos(const mcCursorPos &code) 01074 { 01075 // do not use default mcElementArrayHelpers::gui_SetCursorPos: it works for the 01076 // all the elements without doing any distinction between operators and 01077 // non operators elements: we need mcElementArrayHelpers::gui_SetCursorPosSkippingOp()... 01078 mcElementArrayHelpers::gui_SetCursorPos/*SkippingOp*/(code); 01079 } 01080 01081 void mcPolynomialHelpers::gui_CheckCursorPos() const 01082 { 01083 // check that cursor is not beyond upper and lower limit 01084 if (data_GetCount() > 0) { 01085 01086 // cursor position must be a valid integer in the range 0, data_GetCount()-1 01087 mcASSERT(data_isValidElem(mgui_nCursorPos), 01088 wxT("Cursor placed on an invalid element !")); 01089 mcASSERT(mgui_nCursorPos >= 0, 01090 wxT("Cursor position undefined")); 01091 mcASSERT(mgui_nCursorPos < data_GetCount(), 01092 wxT("Cursor position is beyond upper limit")); 01093 01094 mcASSERT(!data_Get(mgui_nCursorPos).gui_GetCursorPos().isUndefined(), 01095 wxT("Cursor position undefined")); 01096 01097 } else { 01098 01099 // array is empty; cursor position should be 0 01100 mcASSERT(mgui_nCursorPos == -1, wxT("Array is empty, wrong cursor position")); 01101 } 01102 01103 // check that cursor is not inside an operator 01104 if (!data_isArrayEmpty()) { 01105 mcASSERT(!data_isEmptyEntry(mgui_nCursorPos), wxT("Cursor position is wrong")); 01106 mcASSERT(!data_isOp(mgui_nCursorPos), wxT("Cursor position is wrong")); 01107 } 01108 } 01109 01110 void mcPolynomialHelpers::gui_DoSplit(mcElementType type, const mcKey &key) 01111 { 01112 mcElement ptmp = mcEmptyElement; 01113 01114 mcASSERT(type == mcET_ADDOP || type == mcET_SUBOP, 01115 wxT("The splitter elements can be only mcAddOp or mcSubOp")); 01116 01117 // split the element in two parts; by now, this function 01118 // can be used only by mcNumbers & mcMonomials... 01119 bool b = data_Get(mgui_nCursorPos).gui_Split(&ptmp); 01120 mcASSERT(!b, wxT("A monomial asked us to be deleted ?")); 01121 mcUNUSED(b); // to avoid warnings 01122 01123 // go on only if the element to split support that function 01124 mcASSERT(ptmp != mcEmptyElement, wxT("Tried to split an element which does not support splitting")); 01125 01126 // create an hole in the array and fill it with the second part of 01127 // the splitted monomial 01128 data_MoveElemRight(mgui_nCursorPos+1); 01129 data_Set(mgui_nCursorPos+1, ptmp); 01130 01131 // create another hole between the old and the new monomial 01132 data_MoveElemRight(mgui_nCursorPos+1); 01133 01134 // and fill it with the splitter operator 01135 data_AddNewOp(type, mgui_nCursorPos+1); 01136 01137 // adjust cursor on the new monomial 01138 mgui_nCursorPos +=2; 01139 } 01140 01141 int mcPolynomialHelpers::data_AddNewEmptyMonomial(int pos) 01142 { 01143 // this function uses the begin key of a mcEmptyBox to create 01144 // the new empty monomial: in this way we can use all the 01145 // GUI input rules encoded in mcPolynomialHelpers::gui_math_AddNewElement 01146 // for free.... 01147 if (pos == -1) pos = data_GetCount(); 01148 01149 // add a new monomial containing only an empty box 01150 mcMonomial m; // create a new 01151 mcElement &box = m.data_AddNewElement(mcET_EMPTYBOX); 01152 box.data_AddProperty(mcEP_INITIALIZED); 01153 01154 data_AddElements(&m, 1, pos); 01155 data_Check(); 01156 01157 return pos; 01158 } 01159 01160 void mcPolynomialHelpers::gui_AddNewEmptyMonomial(int pos) 01161 { 01162 // this function uses the begin key of a mcEmptyBox to create 01163 // the new empty monomial: in this way we can use all the 01164 // GUI input rules encoded in mcPolynomialGUI::AddNewElement 01165 // for free.... 01166 mcKey fake(mcEmptyBoxHelpers::sgui_pNewEmptyBox->GetEvent(), TRUE); 01167 if (pos == -1) pos = data_GetCount(); 01168 01169 // add a new monomial containing only an empty box 01170 mgui_nCursorPos = gui_AddNewElement(mcET_MONOMIAL, fake, pos); 01171 } 01172 01173 01174 01175 01176 01177 01178 01179 // ---------------------------------------- 01180 // mcPOLYNOMIALIO 01181 // ---------------------------------------- 01182 01183 wxXml2Node mcPolynomialHelpers::io_GetMathML(bool bdata_GetPresentation) const 01184 { 01185 // if this mcPolynomial contains just one element, we can just return 01186 // the MathML piece of that element without using an MROW 01187 if (data_GetCount() == 1) { 01188 01189 // too easy... :-) 01190 return data_Get(0).io_GetMathML(bdata_GetPresentation); 01191 } 01192 01193 // begin MROW section 01194 wxXml2Node maintag; 01195 maintag.CreateTemp(wxXML_ELEMENT_NODE, wxXml2EmptyDoc, wxT("mrow")); 01196 01197 // for each monomial, also take in count its first operator 01198 for (int i=0; i < data_GetCount(); i++) { 01199 01200 // THIS PIECE OF CODE SHOULD BE USED IF THE OPERATORS WHICH LINK 01201 // THE MONOMIALS ARE CONTAINED IN THE MONOMIAL'S ARRAY: THIS IS 01202 // NOT THE BEHAVIOUR OF THE CURRENT MATH'S STRUCTURE but I do not 01203 // want to data_Delete this code because it could still be useful in 01204 // future !!! 01205 /* data_Get the + or - from this monomial 01206 mcElement p = ((mcMonomial &)data_Get(i))->data_Get(0); 01207 if (i != 0 || p.data_GetType() != mcET_OPERATOR || p->data_GetSubType() != mcET_ADDOP) { 01208 01209 // it's really necessary to insert this operator.... 01210 maintag.math_AddChild(p.io_GetMathML(bdata_GetPresentation)); 01211 }*/ 01212 01213 // get the mrow section from this monomial 01214 wxXml2Node node(data_Get(i).io_GetMathML(bdata_GetPresentation)); 01215 maintag.AddChild(node); 01216 } 01217 01218 return maintag; 01219 } 01220 01221 wxString mcPolynomialHelpers::io_GetInlinedExpr() const 01222 { 01223 wxString str; 01224 01225 // concatenate the inlined expressions which compose the math contents 01226 for (int i=0; i < data_GetCount(); i++) { 01227 01228 // A LITTLE POLYNOMIAL-SPECIFIC BEHAVIOUR: 01229 // since the sign of a monomial is stored both in the monomial's 01230 // coefficient 01231 wxString tmp = data_Get(i).io_GetInlinedExpr(); 01232 //if (!data_isOp(i) && tmp.StartsWith("-")) tmp.Remove(0, 1); 01233 01234 str += tmp; 01235 } 01236 01237 01238 return str; 01239 } 01240 01241 bool mcPolynomialHelpers::io_ImportPresentationMathML(wxXml2Node tag, wxString &err) 01242 { 01243 wxXml2Node p, toinsert = wxXml2EmptyNode; 01244 //mcElement ptmp = NULL; 01245 //int res = mcIR_OKAY; 01246 01247 // BE SURE TO data_Delete EVERYTHING BEFORE IMPORTING !!!! 01248 data_DeleteAll(); 01249 01250 p = tag.GetChildren(); 01251 while (p != wxXml2EmptyNode) { 01252 01253 if (p.GetType() == wxXML_ELEMENT_NODE && p.GetName() == wxT("mo")) { 01254 01255 // this is an operator, like + or -, separing two monomials; 01256 // send it as init tag to the monomial 01257 toinsert = p; 01258 01259 } else if (p.GetType() == wxXML_ELEMENT_NODE && p.GetName() != wxT("mrow")) { 01260 01261 // mcMonomial requires everything to be encapsulated in an MROW, 01262 // but this monomial is not; let's do ourselves 01263 /*wxXml2Node tmp(wxXML_ELEMENT_NODE, wxT("mrow")); 01264 wxXml2Node *firstchild = new wxXml2Node(*p); 01265 tmp.data_SetChildren(firstchild); 01266 01267 if (!pnew.io_ImportPresentationMathML(&tmp, err)) 01268 return FALSE;*/ 01269 p.Encapsulate(wxT("mrow")); 01270 } 01271 01272 if (p.GetType() == wxXML_ELEMENT_NODE && p.GetName() == wxT("mrow")) { 01273 01274 // create a new monomial to parse this node 01275 mcMonomial pnew; 01276 01277 // adds the last MO child of the main tag if it was present 01278 if (toinsert != wxXml2EmptyNode) { 01279 p.GetChildren().AddPrevious(toinsert); 01280 toinsert = wxXml2EmptyNode; 01281 } 01282 01283 // just a normal MROW representing a monomial... 01284 if (!pnew.io_ImportPresentationMathML(p, err)) 01285 return FALSE; 01286 01287 // add our new monomial in this array 01288 data_AddElements(&pnew, 1); 01289 } 01290 01291 // proceed with next 01292 p = p.GetNext(); 01293 } 01294 01295 return TRUE; 01296 } 01297 01298 bool mcPolynomialHelpers::io_ImportInlinedExpr(const wxString &todecode, int *c, 01299 wxString &pErr, int mlimit) 01300 { 01301 wxString token(todecode); 01302 int count, n = 0; 01303 01304 // BE SURE TO data_Delete EVERYTHING BEFORE IMPORTING !!!! 01305 data_DeleteAll(); 01306 01307 while (!token.IsEmpty() && (mlimit < 0 || n < mlimit)) 01308 { 01309 // now, check if we must add an operator... 01310 wxString str = token.GetChar(0); 01311 mcElementType newop = mcElementHelpers::io_isCharBeginChar(str); 01312 if (mcOperatorHelpers::data_isOp(newop)) { 01313 01314 // add the operator and remove it from the token string 01315 data_AddNewElement(newop); 01316 token.Remove(0, 1); 01317 01318 } else { 01319 01320 // if this is not the first time this while() cycle has 01321 // been run and there is no operator to separe previously 01322 // imported monomial from the next one.... then there's a 01323 // BIG problem... 01324 mcASSERT(data_isArrayEmpty(), 01325 wxT("A mcPolynomial must contain mcMonomials *always* ") 01326 wxT("interleaved with mcAddOp/mcSubOps")); 01327 } 01328 01329 // and add it to this array 01330 mcMonomial pnew; 01331 n++; 01332 01333 // import a new monomial 01334 if (!pnew.io_ImportInlinedExpr(token, &count, pErr)) 01335 return FALSE; 01336 01337 // update the token string 01338 data_AddElements(&pnew, 1); 01339 token = token.Right(token.Len()-count); 01340 } 01341 01342 // store the number of characters imported 01343 if (c) *c = todecode.Len()-token.Len(); 01344 01345 // a little exception for parentheses: 01346 // try to replace all mcParenthesis with mcBrackets... 01347 mcIOLOG(wxT("mcPolynomialHelpers::io_ImportInlinedExpr - before pruning brackets: [%s]"), mcTXTTHIS); 01348 data_ReplaceAllParentheses(); 01349 01350 // remove all the mcParenthesis which could not be replaced with 01351 // mcBrackets.... 01352 for (int i=0, max=data_GetNumOfElemType(mcET_MONOMIAL); i < max; i++) { 01353 mcMonomial &m = (mcMonomial &)data_GetElemOfType(i, mcET_MONOMIAL); 01354 01355 // do the hard work... 01356 m.data_DeleteAllElemType(mcET_PARENTHESIS); 01357 m.data_Repair(); 01358 } 01359 01360 mcIOLOG(wxT("mcPolynomialHelpers::io_ImportInlinedExpr - after pruning brackets: [%s]"), mcTXTTHIS); 01361 01362 // extra-work required ? 01363 io_PostProcessChildren(); 01364 01365 return TRUE; 01366 } 01367 01368 01369 01370 01371 01372 // ---------------------------------------- 01373 // mcPOLYNOMIALMATH 01374 // ---------------------------------------- 01375 01376 mcPolynomial mcPolynomialHelpers::math_GetPolynomialWrapper() const 01377 { 01378 mcPolynomial pol(this); 01379 01380 // it is very important to detach pol from us: 01381 // we could modify ourselves, later and this would 01382 // result in an automatic modification of the polynomial 01383 // which we are returning now... 01384 pol.data_MakePrivateCopy(); 01385 01386 return pol; 01387 } 01388 01389 mcArrayEntry mcPolynomialHelpers::math_WrapMonomial(const mcMonomial &mon) 01390 { 01391 // TOTEST: 01392 data_DeleteAll(); 01393 01394 // just add the given monomial to this array 01395 int midx = data_AddElements((mcElement *)(&mon), 1); 01396 01397 // and return a reference to its entry in the array... 01398 data_Check(); 01399 return mcArrayEntry(this, mcMAKEPOL_IDX(midx, 0)); 01400 } 01401 01402 mcArrayEntry mcPolynomialHelpers::math_WrapSimple(const mcElement &p) 01403 { 01404 // we have to do just a little check... 01405 if (p.data_GetType() != mcET_MONOMIAL) { 01406 01407 // create a monomial wrapper for the given element 01408 mcMonomial m; 01409 int idx = m.data_AddElements(&p, 1); 01410 01411 // add the monomial to the array and then return a reference 01412 // not to the monomial we've added but to the element which 01413 // was wrapped into the monomial we wrapped... 01414 mcArrayEntry ret = math_WrapMonomial(m); 01415 ret.data_SetIdx((ret.mdata_idx << 16) | idx); 01416 return ret; 01417 } 01418 01419 // we don't need to wrap anything: it's already a mcMonomial... 01420 return math_WrapMonomial(mcMonomial(p)); 01421 } 01422 01423 mcElementArray mcPolynomialHelpers::math_CreateWrapperFor(const mcElement &toembed) const 01424 { 01425 if (toembed.data_GetType() != mcET_MONOMIAL && 01426 toembed.data_GetType() != mcET_POLYNOMIAL) { 01427 01428 // before creating a mcPolynomial and adding to it "toembed" 01429 // (as mcElementArrayHelpers::CreateWrapperFor does), 01430 // wrap "toembed" in a mcMonomial... 01431 mcMonomial tmp; 01432 tmp.math_WrapSimple(toembed); 01433 return mcElementArrayHelpers::math_CreateWrapperFor(tmp); 01434 } 01435 01436 return mcElementArrayHelpers::math_CreateWrapperFor(toembed); 01437 } 01438 01439 int mcPolynomialHelpers::math_DataToMathIdx(int dataindex) const 01440 { 01441 // discard invalid cases 01442 data_CheckIndex(dataindex); 01443 if (data_isOp(dataindex)) // op are not mapped in math coord 01444 return -1; 01445 01446 // using the shift we are sure that both 4/2 and 5/2 will give as result 2. 01447 // This is required when the array begins with an operator and thus 01448 // the given index can be odd and nonetheless referring to a mcMonomial... 01449 return (dataindex >> 1); 01450 } 01451 01452 int mcPolynomialHelpers::math_MathToDataIdx(int mathindex) const 01453 { 01454 if (mathindex < 0 || mathindex >= math_GetCount()) { 01455 01456 mcMATHLOG(wxT("mcPolynomialHelpers::math_MathToDataIdx [%s] - ") 01457 wxT("invalid conversion required"), mcTXTTHIS); 01458 return -1; // no conversion is possible 01459 } 01460 01461 // Perform a quick conversion taking in count the rule which 01462 // is respected in each valid mcPolynomial: between two monomials 01463 // there is *always* a mcAddOp/mcSubOp which divides them. 01464 // Also takes in count that the operator may contain an operator 01465 // as first entry which could alter the formula... 01466 return mathindex*2 + (int)(data_isOp(0)); 01467 } 01468 01469 01470 01471 01472 01473 01474 01475 01476 01477 // ------------------------------------ 01478 // mcPOLYNOMIALMATH - sign management 01479 // ------------------------------------ 01480 01481 int mcPolynomialHelpers::math_GetSign(int n) const 01482 { 01483 // get the index of the n-th monomial 01484 n = math_MathToDataIdx(n); 01485 mcASSERT(n != -1, wxT("Invalid index !!")); 01486 01487 // if there is no operator at the begin of the array, it's by default +. 01488 if (n == 0) return 1; 01489 mcASSERT(data_isAddSubOp(n-1), 01490 wxT("A polynomial must contain monomials always separated by mcAddOp or mcSubOp")); 01491 01492 return (data_Get(n-1).data_GetType() == mcET_ADDOP) ? 1 : -1; 01493 } 01494 01495 void mcPolynomialHelpers::math_SetSign(int n, int sgn) 01496 { 01497 int i = math_MathToDataIdx(n); 01498 01499 if (i > 0) { 01500 01501 // we are sure that the i-th monomial is not the first 01502 // element of the array: an operator is sure preceding it... 01503 mcASSERT(data_isOp(i-1), wxT("A monomial should always be preceded by an op")); 01504 01505 // change the previous operator 01506 data_AddNewOp(((sgn < 0) ? mcET_SUBOP : mcET_ADDOP), i-1); 01507 01508 } else { 01509 01510 if (sgn < 0) { 01511 01512 // add a new mcSubOp operator at the beginning of the array 01513 data_MoveElemRight(0); 01514 data_AddNewOp(mcET_SUBOP, 0); 01515 //mcMATHLOG("[%s]", mcTXTTHIS); 01516 01517 } else { 01518 01519 // we should add a mcAddOp at the beginning of the array: 01520 // quite useless; just do nothing 01521 } 01522 } 01523 } 01524 bool mcPolynomialHelpers::math_DeleteFirstOp() 01525 { 01526 if (data_isArrayEmpty() || 01527 !data_isOp(0)) 01528 return FALSE; // there is no first operator 01529 01530 if (data_isOp(0) && 01531 data_Get(0).data_GetType() != math_GetNeutralOpType()) 01532 return FALSE; // nothing to delete/that can be deleted 01533 01534 // the first element of the array is a mcAddOp; we can safely remove it 01535 data_Delete(0); 01536 data_MoveElemLeft(0); 01537 return TRUE; 01538 } 01539 01540 mcExpSimRes mcPolynomialHelpers::math_Reorder() 01541 { 01542 mcMATHLOG(wxT("mcPolynomialHelpers::math_Reorder - going to reorder [%s]"), mcTXTTHIS); 01543 01544 // we need to have an array containing *everywhere* 01545 // the pattern OPERATOR + MONOMIAL: the ReorderElements function 01546 // cannot work with variable-lenght patterns... 01547 data_CreateFirstOp(); 01548 int n = math_ReorderElements(data_GetArray(), data_GetCount(), 1, 2); 01549 data_Check(); 01550 01551 // eventually remove the first operator we were forced to add 01552 math_DeleteFirstOp(); 01553 mcMATHLOG(wxT("mcPolynomialHelpers::math_Reorder - result is [%s]"), mcTXTTHIS); 01554 01555 // did we moved anything ? 01556 return (n == 0 ? mcESR_DONE : mcESR_NOTFINISHED); 01557 } 01558 01559 void mcPolynomialHelpers::math_ChangeAllSigns() 01560 { 01561 for (int i=0; i < math_GetCount(); i++) 01562 math_ChangeSign(i); 01563 } 01564 01565 void mcPolynomialHelpers::math_SyncCoeffWithSigns() 01566 { 01567 // scan the array resetting signs 01568 for (int i=0,max=math_GetCount(); i < max; i++) { 01569 01570 mcRealValue coeff = math_Get(i).math_GetCoeff(); 01571 01572 if (coeff < 0) { 01573 01574 // since the coefficient of the monomial is negative, 01575 // we must change not only the mcOperator in front of it, 01576 // but also its coefficient... 01577 math_SetSign(i, -1); // this changes the operator before the monomial 01578 //math_Get(i).math_Abs(); 01579 01580 mcMATHLOG(wxT("mcPolynomialHelpers::math_SyncCoeffWithSigns - I set ") 01581 wxT("the sign of the [%s] monomial (which has coeff [%s]) to NEGATIVE"), 01582 mcTXT(math_Get(i)), mcTXTV(coeff)); 01583 01584 } else if (coeff > 0) { 01585 01586 // the coeff of the monomial is positive 01587 math_SetSign(i, +1); // this changes the operator before the monomial 01588 01589 mcMATHLOG(wxT("mcPolynomialHelpers::math_SyncCoeffWithSigns - I set ") 01590 wxT("the sign of the [%s] monomial (which has coeff [%s]) to POSITIVE"), 01591 mcTXT(math_Get(i)), mcTXTV(coeff)); 01592 01593 } else { 01594 01595 // the coeff of the monomial is exactly zero... 01596 // do nothing since this monomial is useless 01597 } 01598 } 01599 } 01600 01601 const mcNumber &mcPolynomialHelpers::math_GetNumSign(const mcMonomial &tofind, int n) const 01602 { 01603 int pos = math_NonRecursiveFindInChildren(n, tofind.hlp()); 01604 if (pos < 0) return mcEmptyNumber; 01605 01606 // we've found the given monomial, now gets its sign 01607 int sign = math_GetSign(pos); 01608 return (sign == 1 ? *mcNumberHelpers::smath_pOne : *mcNumberHelpers::smath_pMinusOne); 01609 } 01610 01611 void mcPolynomialHelpers::math_PackSign(mcMonomial &m, int occ) const 01612 { 01613 #ifdef EXTENDED_COEFF 01614 mcMonomial num = m.math_GetCoeff(); 01615 #else 01616 mcNumber num = m.math_GetCoeff(); 01617 #endif 01618 mcNumber mult = math_GetNumSign(m, occ); 01619 mcASSERT(mult != mcEmptyElement, wxT("We could not find 'm'")); 01620 01621 num.math_SimpleMultiplyBy(mult); 01622 m.math_SetCoeff(num); 01623 } 01624 01625 01626 01627 01628 01629 // --------------------------------------- 01630 // mcPOLYNOMIALMATH - monomial management 01631 // --------------------------------------- 01632 01633 int mcPolynomialHelpers::math_FindMonomialContaining(const mcElement &elem, 01634 int occ, int *res) const 01635 { 01636 int n = -1; 01637 for (int i=0,max=math_GetCount(); i < max; i++) { 01638 01639 // search, non-recursively, in this monomial 01640 n = math_Get(i).math_GetIndexOf(occ, elem); 01641 if (n != -1) { 01642 01643 // so we need to store the entry of the element we've found ? 01644 if (res) *res = n; 01645 return i; 01646 } 01647 } 01648 01649 // could not find any result 01650 return -1; 01651 } 01652 01653 const mcMonomial &mcPolynomialHelpers::math_GetMonomialContaining(const mcElement &elem, 01654 int occ, int *res) const 01655 { 01656 int idx = math_FindMonomialContaining(elem, occ, res); 01657 01658 if (idx != -1) 01659 return math_Get(idx); 01660 return mcEmptyMonomial; 01661 } 01662 01663 mcMonomial mcPolynomialHelpers::math_GetCoeffOf(int mathidx, const mcElement *toremove, 01664 int ntoremove) const 01665 { 01666 // data_Get a copy of the monomial... 01667 mcMonomial res = math_Get(mathidx); 01668 01669 // ...remove all the elements required from the copy 01670 for (int i=0; i < ntoremove; i++) 01671 res.math_Delete(0, toremove[i], FALSE); 01672 01673 // and pack the sign of the monomial inside it if it's required 01674 if (math_GetSign(mathidx) == -1) math_PackSign(res); 01675 01676 return res; 01677 } 01678 01679 mcMonomial mcPolynomialHelpers::math_GetCoeffOf(const mcSymbolProperties *sym, 01680 const mcPolynomial &exp, int occ) const 01681 { 01682 mcMATHLOG(wxT("mcPolynomialHelpers::math_GetCoeffOf [%s] - searching [%s]^[%s]"), 01683 mcTXTTHIS, mcTXTP(sym), mcTXT(exp)); 01684 01685 // create a temporary object linked to the given symbol 01686 // and with the given exponent 01687 mcSymbol s(sym->data_GetSafeLinkedSym()); 01688 01689 if (exp.math_isWrappingOnly(0.0)) { 01690 01691 int n = -1; 01692 01693 // search the zero-degree term 01694 for (int i=0; i < math_GetCount(); i++) { 01695 if (!math_Get(i).math_Contains(s)) { 01696 01697 n++; 01698 01699 // copy this monomial, which should be the only 01700 // one not to contain the given symbol, 01701 if (n == occ) return mcMonomial(math_Get(i)); 01702 } 01703 } 01704 01705 return mcEmptyMonomial; 01706 } 01707 01708 s.math_SetExp(exp); 01709 01710 // then, find it 01711 int n = -1; 01712 const mcMonomial &res = math_GetMonomialContaining(s, occ, &n); 01713 if (res == mcEmptyMonomial) return mcEmptyMonomial; 01714 01715 // copy it (don't modify the array !!) 01716 mcMonomial m(res); 01717 01718 // we could use data_GetCoeffOf in this way: 01719 // mcMonomial &ret = data_GetCoeffOf(pos, (const mcElement &*)&s, 1); 01720 // mcSAFE_data_Delete(s); 01721 // but since we already know where s is placed (at n-th pos), proceed 01722 // without using the other data_GetCoeffOf (and repeating some code): 01723 m.math_Remove(n, FALSE); 01724 01725 //if (m.math_math_GetSign() == -1) PackSign(m); 01726 //mcASSERT(0, ""); 01727 01728 return m; 01729 } 01730 01731 mcMonomial mcPolynomialHelpers::math_GetCoeffOf(const mcSymbolProperties *sym, 01732 const mcRealValue &exp, int occ) const 01733 { 01734 mcPolynomial tmp; 01735 tmp.math_WrapNumber(exp); 01736 01737 // data_Get a copy of the monomial and remove the symbol we've just found 01738 mcMonomial ret = math_GetCoeffOf(sym, tmp, occ); 01739 //mcSAFE_data_Delete(tmp); 01740 01741 return ret; 01742 } 01743 01744 mcIntegerValue mcPolynomialHelpers::math_GetMaxDegreeFor(const mcSymbolProperties *sym) const 01745 { 01746 mcIntegerValue max = 0; 01747 01748 for (int i=0; i < math_GetCount(); i++) { 01749 01750 // collect the max degree for this symbol from the i-th monomial 01751 mcIntegerValue d = math_Get(i).math_GetMaxDegreeFor(sym); 01752 if (!d.isValid()) return *mcIntegerValue::pNAN; 01753 01754 // and check it against the max degree for all previous monomials 01755 max = max.GetMax(d); 01756 } 01757 01758 mcASSERT(max.isValid(), wxT("Something really wrong")); 01759 return max; 01760 } 01761 01762 mcExpSimRes mcPolynomialHelpers::math_SimplifySolveOp(long flags) 01763 { 01764 bool stilltowork = FALSE; 01765 01766 mcMATHLOG(wxT("mcPolynomialHelpers::math_SimplifySolveOp")); 01767 01768 // cannot store data_GetCount()-1 because elements maybe removed in the loop 01769 for (int i=0; i < math_GetCount(); i++) { 01770 01771 // get left operand 01772 mcMonomial &left = math_Get(i); 01773 mcOperator &lp = math_GetOpPreceding(i); 01774 01775 for (int j=0; j < math_GetCount(); j++) { 01776 01777 // get right one 01778 mcMonomial &right = math_Get(j); 01779 if (i == j) continue; 01780 01781 // get the i-th operator of the array 01782 mcOperator &rp = math_GetOpPreceding(j); 01783 if (rp == mcEmptyElement) continue; 01784 mcMATHLOG(wxT("mcPolynomialHelpers::math_SimplifySolveOp - I'm trying to apply ") 01785 wxT("the op [%s] between the [%s] and [%s] elements"), 01786 mcTXT(rp), mcTXT(left), mcTXT(right)); 01787 01788 // apply the op 01789 mcElement rep = mcEmptyElement; 01790 mcBasicOpRes res; 01791 int sign=1; 01792 01793 if (lp.data_GetType() == rp.data_GetType()) { 01794 01795 mcOperator *op = (mcOperator *)mcElementHelpers::data_GetInstanceOf(mcET_ADDOP); 01796 res = op->math_Apply(left, right, &rep); 01797 if (res == mcBOR_INVALID) 01798 continue; 01799 01800 } else { 01801 01802 mcOperator *op = (mcOperator *)mcElementHelpers::data_GetInstanceOf(mcET_SUBOP); 01803 res = op->math_Apply(left, right, &rep); 01804 if (lp.data_GetType() == mcET_SUBOP) 01805 sign=-1; 01806 if (res == mcBOR_INVALID) 01807 continue; 01808 01809 // set the monomial's sign accordingly to the 01810 // result of the ADD/SUBTRACT operation and 01811 // accordingly with the sign of the monomial 01812 // before the operation 01813 if (left.math_GetCoeff() < 0) { 01814 math_SetSign(i, -1*sign); 01815 math_Get(i).math_Abs(); 01816 } else { 01817 math_SetSign(i, 1*sign); 01818 } 01819 } 01820 01821 // the operator could be applied... 01822 stilltowork = TRUE; 01823 mcMATHLOG(wxT("mcPolynomialHelpers::math_SimplifySolveOp - applied ") 01824 wxT("the op [%s] between the [%s] and [%s] elements"), 01825 mcTXT(rp), mcTXT(left), mcTXT(right)); 01826 01827 // handle res 01828 math_HandleBasicOpRes(res, rep, j); 01829 } 01830 } 01831 01832 if (stilltowork) 01833 return mcESR_NOTFINISHED; 01834 return mcESR_DONE; 01835 //return mcElementArrayHelpers::math_SimplifySolveOp(flags); 01836 } 01837 01838 mcExpSimRes mcPolynomialHelpers::math_Simplify(long flags, mcElement *newelem) 01839 { 01840 mcLOG(wxT("mcPolynomialHelpers::math_Simplify")); 01841 01842 // perform array simplification 01843 mcExpSimRes r = mcElementArrayHelpers::math_Simplify(flags, newelem); 01844 math_DeleteFirstOp(); 01845 if (r != mcESR_DONE) return r; 01846 01847 // additional simplification step: 01848 //if (math_DeleteFirstOp()) // remove the first op when it's useless (+) 01849 // return mcESR_NOTFINISHED; 01850 01851 // additional simplification step #2: 01852 //math_FactoreOut(); 01853 01854 return mcESR_DONE; // there was no first operator to data_Delete... 01855 } 01856 01857 01858 01859 01860 01861 // --------------------------------------- 01862 // mcPOLYNOMIALMATH - basic operations 01863 // --------------------------------------- 01864 01865 mcBasicOpRes mcPolynomialHelpers::math_Add(const mcElement &e, mcElement *pp, bool add) 01866 { 01867 mcMATHLOG(wxT("mcPolynomialHelpers::math_Add [%s] - I'm %s [%s]"), mcTXTTHIS, 01868 (add == TRUE ? wxT("adding") : wxT("subtracting")), mcTXT(e)); 01869 mcPolynomial p(e); 01870 01871 if (p.data_isArrayEmpty()) 01872 return mcBOR_REMOVE_OPERAND; 01873 01874 if (add) { 01875 01876 // don't force the creation of the "+" operator if this array is empty 01877 // or if the given array already has a first op... 01878 if (!this->data_isArrayEmpty() && 01879 !p.data_isOp(0)) { 01880 01881 data_AddNewOp(mcET_ADDOP); 01882 } 01883 01884 // now we can merge with the given polynomial 01885 data_Merge(p); 01886 01887 } else { 01888 01889 mcPolynomial p2(p); 01890 01891 // a - b = a + (-b) ..... 01892 p2.math_ChangeAllSigns(); 01893 mcMATHLOG(wxT("[%s]"), mcTXT(p2)); 01894 math_SimpleAdd(p2); 01895 } 01896 01897 data_Check(); 01898 01899 return mcBOR_REMOVE_OPERAND; 01900 } 01901 01902 mcBasicOpRes mcPolynomialHelpers::math_MultiplyBy(const mcElement &e, mcElement *pp) 01903 { 01904 if (data_isArrayEmpty()) 01905 return mcBOR_REMOVE_OPERAND; 01906 01907 mcPolynomial p(e); 01908 mcPolynomial pnew = mcEmptyElement; 01909 01910 // if this array contains more than one monomial, 01911 // or just a negative element, bracket it. 01912 if (math_GetCount() > 1 || math_GetSign(0) == -1) { 01913 01914 // bracketize everything 01915 mcElementArrayHelpers::math_EmbedInBracket(); 01916 } 01917 01918 // if the given array to multiply contains more than one 01919 // monomial, bracket a copy of it 01920 if (p.math_GetCount() > 1) { 01921 01922 // we cannot modify the given element !!!! 01923 pnew = p; 01924 p = pnew; 01925 01926 // bracket the copy of the given array 01927 p.math_EmbedInBracket(); 01928 //p.math_data_DeleteFirstOp(); 01929 } 01930 01931 // now, both the operands contains one monomial only.... 01932 mcASSERT(p.math_GetCount() == 1, wxT("Something wrong")); 01933 mcASSERT(this->math_GetCount() == 1, wxT("Something wrong")); 01934 01935 // ... and we can now multiply them 01936 mcBasicOpRes r = math_Get(0).math_MultiplyBy(p.math_Get(0), pp); 01937 01938 // clean up if necessary 01939 //if (pnew) data_Delete pnew; 01940 01941 // check that everything is okay 01942 data_Check(); 01943 01944 // handle the returned flag.... 01945 switch (r) { 01946 case mcBOR_INVALID: 01947 case mcBOR_REPLACE_OPERAND: 01948 case mcBOR_REPLACE_BOTH: 01949 mcASSERT(0, wxT("Two monomials which cannot be multiplied ?")); 01950 01951 case mcBOR_REMOVE_OPERAND: 01952 return mcBOR_REMOVE_OPERAND; 01953 01954 default: 01955 mcASSERT(0, wxT("TODO")); 01956 } 01957 01958 return mcBOR_REMOVE_OPERAND; 01959 } 01960 01961 mcBasicOpRes mcPolynomialHelpers::math_DivideBy(const mcElement &pol, mcElement *pp) 01962 { 01963 if (data_isArrayEmpty()) 01964 return mcBOR_REMOVE_OPERAND; 01965 01966 // create a fraction with the current contents as numerator, 01967 // the given polynomial as denominator 01968 mcASSERT(pol.data_GetType() == mcET_POLYNOMIAL, wxT("see math_DivideBy() description...")); 01969 math_EmbedInFraction().data_GetFraction().data_SetDen(pol); 01970 01971 mcMATHLOG(wxT("mcPolynomialHelpers::math_DivideBy - dividing by [%s], result is [%s]"), 01972 mcTXT(pol), mcTXTTHIS); 01973 01974 return mcBOR_REMOVE_OPERAND; 01975 } 01976 01977 01978 01979 01980 01981 01982 // --------------------------------------- 01983 // mcPOLYNOMIALMATH - miscellaneous 01984 // --------------------------------------- 01985 01986 /* 01987 mcElement mcPolynomialHelpers::math_GetLCM(const mcElement &p) const 01988 { 01989 // work on copies 01990 mcPolynomial b(p); 01991 b.math_EmbedInBracket(); 01992 01993 math_SimpleMultiplyBy(b); 01994 //data_Delete b; 01995 01996 return b; 01997 } 01998 */ 01999 02000 void mcPolynomialHelpers::math_DeleteSelection() 02001 { 02002 // data_Delete the elements selected 02003 gui_DeleteSelection(); 02004 data_Check(); 02005 } 02006 02007 mcIntegerValue mcPolynomialHelpers::math_RaiseGetCoeff(int *indexes, int m) 02008 { 02009 mcIntegerValue res = 1; 02010 02011 // we must calculate the coefficient in this way: 02012 // 02013 // ( indexes[0] ) ( indexes[1] ) ( indexes[2] ) 02014 // ( ) ( ) ( ) .... 02015 // ( indexes[1] ) ( indexes[2] ) ( indexes[3] ) 02016 // 02017 for (int x=0; x < m; x++) 02018 res *= mcIntegerValue::GetComb(indexes[x], indexes[x+1]); 02019 02020 return res; 02021 } 02022 02023 bool mcPolynomialHelpers::math_CanBeRaisedTo(const mcPolynomial &pol) const 02024 { 02025 int count = math_GetCount(); 02026 02027 // see mcPolynomialHelpers::math_RaiseChildrenTo about 02028 // the way these cases are handled 02029 if (count == 0 || count == 1) 02030 return TRUE; 02031 02032 // for more children, then we need that the given exponent 02033 // contains just a number 02034 if (!pol.math_isWrappingNumOnly()) 02035 return FALSE; 02036 02037 mcRealValue r(pol.math_GetWrappedNumber()); 02038 02039 if (r.isInteger()) 02040 return TRUE; 02041 return FALSE; 02042 } 02043 02044 void mcPolynomialHelpers::math_RaiseTo(const mcRealValue &r) 02045 { 02046 mcMATHLOG(wxT("mcPolynomialHelpers::math_RaiseChildrenTo [%s] - raising to [%s]"), 02047 mcTXTTHIS, mcTXTV(r)); 02048 mcIntegerValue n = r; 02049 02050 // first of all, handle the simplest cases 02051 if (math_GetCount() == 0) 02052 return; // no elements to modify 02053 02054 if (math_GetCount() == 1) { 02055 02056 // we contain only a single monomial: 02057 // (a)^1432.4432423[...] = a^1432.4432423[...] 02058 math_Get(0).math_RaiseTo(r); 02059 return; 02060 } 02061 02062 // then, check if the given value is okay 02063 if (!r.isInteger()) { 02064 02065 // we are in such a situation: 02066 // (a+b+c+d+...z)^1432.4432423[...] 02067 // that is, we cannot raise this polynomial to a real value: 02068 // we can just bracketize the polynomial and set that value 02069 // as the exponent of the bracket... 02070 math_EmbedInBracketAndRaiseTo(r); 02071 return; 02072 02073 } else if (n == 1) { 02074 02075 // we are raising something to one... 02076 // (a+b+c+...)^1 = a+b+c+... 02077 return; 02078 } 02079 02080 mcMATHLOG(wxT("mcPolynomialHelpers::math_RaiseTo - raising %d monomials to %s"), 02081 math_GetCount(), n.GetStr().c_str()); 02082 int x, m = math_GetCount(), *indexes = new int[m+2]; 02083 02084 // first index must be n, last must be zero 02085 // (like also all other indexes, even if these ones 02086 // will be incremented at the end of the while cycle) 02087 indexes[0] = n.GetInt(); 02088 for (x=1; x < m+2; x++) 02089 indexes[x] = 0; 02090 02091 mcPolynomial res; 02092 bool exit = FALSE; 02093 int level = 1; 02094 while (!exit) { 02095 02096 mcMonomial mx; 02097 02098 // this is the sign of the "mx" monomial: 1=+ -1=- 02099 int sign = 1; 02100 02101 // calc the coeff for this new monomial through the 02102 // formula explained in the "Formulas & Algorithms used" 02103 // section in the docs 02104 mcIntegerValue coeff = math_RaiseGetCoeff(indexes, m); 02105 mx.math_WrapNumber(coeff); 02106 mcMATHLOG(wxT("mcPolynomialHelpers::math_RaiseTo - the coeff of the %d-th monomial is %s"), 02107 res.math_GetCount(), coeff.GetStr().c_str()); 02108 for (int y=0; y < m; y++) { 02109 02110 // get the y-th monomial of *this 02111 mcMonomial tmp(math_Get(y)); 02112 02113 // raise it (update global monomial sign) 02114 int exp = indexes[y]-indexes[y+1]; 02115 02116 // do not create a lot of a^0, b^0 and... 02117 if (exp != 0) { 02118 02119 // ... do not create a lot of a^1, b^1 (create a, b) 02120 if (exp != 1) tmp.math_RaiseTo(mcPolynomial(exp)); 02121 sign *= (int)pow(math_GetSign(y), exp); 02122 02123 // and add it to the new polynomial we are building 02124 mx.math_MultiplyBy(tmp, NULL); 02125 } 02126 } 02127 02128 res.math_SimpleAdd(mx, (sign == 1 ? TRUE : FALSE)); 02129 02130 // advance indexes 02131 if (level < m) { 02132 02133 // advance index level 02134 indexes[level]++; 02135 if (level+1 < m || indexes[level] == indexes[level-1]) 02136 level++; 02137 02138 } else if (level == m) { 02139 02140 // reset those levels which have been completed 02141 level--; 02142 bool startcycle = FALSE; 02143 while (indexes[level-1] <= indexes[level]) { 02144 indexes[level] = 0; 02145 level--; 02146 startcycle = TRUE; 02147 02148 if (level == 0) { 02149 02150 // we have completed the 02151 // outermost cicle and thus 02152 // we have done our duty 02153 exit = TRUE; 02154 break; 02155 } 02156 } 02157 02158 // ok, we can start a new cycle at a new level 02159 if (startcycle) { 02160 indexes[level]++; 02161 level++; 02162 } 02163 } 02164 } 02165 02166 delete indexes; 02167 data_DeepCopy(res.chlp()); 02168 } 02169 02170 mcBasicOpRes mcPolynomialHelpers::math_RaiseTo(const mcPolynomial &p) 02171 { 02172 if (math_CanBeRaisedTo(p)) { 02173 02174 if (math_GetCount() == 0) 02175 return mcBOR_REMOVE_OPERAND; // no elements to modify 02176 02177 if (math_GetCount() == 1) 02178 return math_Get(0).math_RaiseTo(p); 02179 02180 // unwrap the number contained in the given polynomial and 02181 // raise everything to it... 02182 math_RaiseTo(p.math_GetWrappedNumber()); 02183 return mcBOR_REMOVE_OPERAND; 02184 } 02185 02186 // cannot do anything else... 02187 math_EmbedInBracketAndRaiseTo(p); 02188 return mcBOR_REMOVE_OPERAND; 02189 } 02190 /* 02191 void mcPolynomialHelpers::math_Bracketize(int *n, int count) 02192 { 02193 mcBracket br; 02194 02195 int max = math_GetCount(); 02196 for (int i=0; i < count; i++) { 02197 02198 mcASSERT(n[i] < max, wxT("Invalid index")); 02199 02200 // collect this monomial 02201 mcMATHLOG(wxT("mcPolynomialHelpers::math_Factorize - factorizing [%s]"), mcTXT(math_Get(n[i]))); 02202 bool add = (math_GetSign(n[i]) == 1 ? TRUE : FALSE); 02203 br.data_GetContent().math_SimpleAdd(math_Get(n[i]), add); 02204 } 02205 02206 // now remove those monomials added to the bracket 02207 for (int j=0; j < count; j++) { 02208 02209 mcMATHLOG(wxT("mcPolynomialHelpers::math_Factorize - removing [%s]"), mcTXT(math_Get(n[j]-j))); 02210 02211 // we need to offset this index by j since each time we remove 02212 // a monomial all the other ones are shifted left 02213 math_Remove(n[j]-j); 02214 } 02215 02216 // add the bracket to replace them 02217 math_SimpleAdd(br); 02218 }*/ 02219 /* 02220 mcMonomial mcPolynomialHelpers::math_GetFactors() const 02221 { 02222 mcPolynomial res; 02223 02224 res.math_ResetToOne(); 02225 for (int i=0,max=math_GetCount(); i<max; i++) { 02226 mcMonomial factor = math_Get(i).math_GetFactors(); 02227 res.math_Get(0).math_GetLCM(factor); 02228 } 02229 02230 return res; 02231 } 02232 */ 02233 void mcPolynomialHelpers::math_Factorize(int *n, int count) 02234 { 02235 02236 } 02237 02238 mcMonomial mcPolynomialHelpers::math_GetGCDFor(int *n, int count) const 02239 { 02240 mcMonomial gcd(mcEmptyElement); 02241 bool all = FALSE; 02242 02243 if (math_GetCount() == 0) 02244 return mcEmptyElement; 02245 02246 if (count==-1) { 02247 02248 // we want to get the GCD among *all* the monomials 02249 count = math_GetCount(); 02250 all = TRUE; 02251 02252 // take initially as the GCD of the array the first monomial... 02253 gcd = math_Get(0); 02254 02255 } else { 02256 02257 // get as GCD the first given index 02258 mcASSERT(count >= 1, wxT("Invalid count of elements")); 02259 gcd = math_Get(n[0]); 02260 } 02261 02262 for (int i=1; i<count; i++) { 02263 02264 mcMonomial m(mcEmptyElement); 02265 if (all) 02266 m = math_Get(i); 02267 else 02268 m = math_Get(n[i]); 02269 02270 // ... then compute the GCD between the first (i-1)-th already 02271 // processed monomials and the i-th 02272 gcd = gcd.math_GetGCD(m); 02273 } 02274 02275 return gcd; 02276 } 02277 02278 void mcPolynomialHelpers::math_FactoreOut(int *n, int count, bool bForceUseless) 02279 { 02280 // we need at least two monomials... 02281 if (math_GetCount() <= 1) return; 02282 02283 // we've got the GCD for all the monomials of the array: 02284 // we should do nothing if it is 1.0 02285 mcMonomial gcd(math_GetGCDFor(n, count)); 02286 bool gcdisone = gcd.math_isWrappingOnly(1.0); 02287 if (gcdisone && !bForceUseless) 02288 return; 02289 mcMATHLOG(wxT("mcPolynomialHelpers::math_FactoreOut - the GCD ") 02290 wxT("among all my monomials is [%s]"), mcTXT(gcd)); 02291 02292 // BEFORE: 02293 // a + b + c + d ... 02294 // AFTER: 02295 // n*(a/n + b/n + c/n + d/n ...) 02296 // 02297 // where n = GCD(a,b,c,d,...) 02298 // 02299 mcArrayEntry br = math_EmbedInBracket(n, count); 02300 mcPolynomial &contents = br.data_GetBracket().data_GetContent(); 02301 02302 if (gcdisone || contents.math_GetCount() <= 1) 02303 return; 02304 02305 // divide _all_ bracket's monomials by the GCD we've computed... 02306 for (int j=0,max=contents.math_GetCount(); j<max; j++) 02307 contents.math_Get(j).math_SimpleDivideBy(gcd); 02308 02309 // last touch: the factor we've just created must 02310 // multiply the bracket. 02311 mcMonomial &m = (mcMonomial &)math_GetMonomialContaining(br.data_GetRef()); 02312 m.math_SimpleMultiplyBy(gcd); 02313 02314 data_Check(); 02315 } 02316 02317 void mcPolynomialHelpers::math_FactoreOut(const mcSymbolProperties *unk, 02318 const mcPolynomial &pol, 02319 bool bForceUseless) 02320 { 02321 // stop here and avoid a lot of calculus if we contain a single monomial... 02322 if (math_GetCount() <= 1) return; 02323 02324 // we'll create an array as large as this array so we are 02325 // sure that we won't need to extend it... 02326 int *arr = new int[math_GetCount()]; 02327 int count=0; 02328 02329 // fill the array with the indexes of those monomials containing 02330 // the given symbol... 02331 for (int i=0,max=math_GetCount(); i < max; i++) 02332 if (math_Get(i).math_ContainsSymbol(unk, pol)) 02333 arr[count++] = i; 02334 02335 // then, just factore out everything possible from those monomials... 02336 if (count == 0) { 02337 delete [] arr; 02338 return; // no such symbol found 02339 } 02340 02341 math_FactoreOut(arr, count, bForceUseless); 02342 delete [] arr; 02343 } 02344 02345 void mcPolynomialHelpers::math_FactoreOutFreeOf(const mcSymbolProperties *unk, 02346 const mcPolynomial &pol, 02347 bool bForceUseless) 02348 { 02349 // stop here and avoid a lot of calculus if we contain a single monomial... 02350 if (math_GetCount() <= 1) return; 02351 02352 // we'll create an array as large as this array so we are 02353 // sure that we won't need to extend it... 02354 int *arr = new int[math_GetCount()]; 02355 int count=0; 02356 02357 // fill the array with the indexes of those monomials containing 02358 // the given symbol... 02359 for (int i=0,max=math_GetCount(); i < max; i++) 02360 if (!math_Get(i).math_ContainsSymbol(unk, pol)) 02361 arr[count++] = i; 02362 02363 // then, just factore out everything possible from those monomials... 02364 if (count == 0) { 02365 delete [] arr; 02366 return; // no such symbol found 02367 } 02368 02369 math_FactoreOut(arr, count, bForceUseless); 02370 delete [] arr; 02371 } 02372 02373 void mcPolynomialHelpers::math_FactoreOut(const mcSymbolArray *arr) 02374 { 02375 // just factore out all the symbols contained in the given array 02376 for (int i=0; i < arr->data_GetCount(); i++) 02377 math_FactoreOut(arr->data_GetSymbol(i), mcEmptyPolynomial, FALSE); 02378 } 02379 02380 void mcPolynomialHelpers::math_FactoreOutConstants() 02381 { math_FactoreOut(&mcSymbol::arrConstants); } 02382 02383 void mcPolynomialHelpers::math_FactoreOutUnknowns() 02384 { math_FactoreOut(&mcSymbol::arrUnknowns); } 02385 02386 void mcPolynomialHelpers::math_FactoreOutParameters() 02387 { math_FactoreOut(&mcSymbol::arrParameters); } 02388 02389 mcExpSimRes mcPolynomialHelpers::math_HandleExpSimFlag(mcExpSimRes r, mcElement *pnew, int i) 02390 { 02391 // only mcPolynomials can handle this flag... 02392 if (r == mcESR_DISTRIBUTE) { 02393 02394 mcMonomial &m = (mcMonomial &)data_Get(i); 02395 int pnewidx = m.data_GetIndexOf(*pnew); 02396 02397 // this is a flag returned only by a few elements: handle it with 02398 // some specialized code... 02399 if (pnew->data_GetType() == mcET_BRACKET) 02400 math_DistributeBracket(i, pnewidx); 02401 else { 02402 02403 // we have specialized code for this case but this 02404 // one is missing.... 02405 mcASSERT(0, wxT("Unhandled case...")); 02406 } 02407 02408 return mcESR_NOTFINISHED; 02409 } 02410 02411 // only mcPolynomials can handle this flag... 02412 if (r == mcESR_CHANGE_SIGN) { 02413 02414 math_ChangeSign(math_DataToMathIdx(i)); 02415 return mcESR_NOTFINISHED; 02416 } 02417 02418 return mcElementArrayHelpers::math_HandleExpSimFlag(r, pnew, i); 02419 } 02420 02421 void mcPolynomialHelpers::math_DistributeBracket(int mdataidx, int bridx) 02422 { 02423 mcASSERT(data_Get(mdataidx).data_GetType() == mcET_MONOMIAL, 02424 wxT("the first parameter is the data index of the monomial with the bracket to expand")); 02425 int signbeforebr = 1; 02426 02427 // extract the monomial with the bracket to expand 02428 mcMonomial m = data_Detach(mdataidx); // the monomial containing the bracket 02429 data_MoveElemLeft(mdataidx); 02430 mcASSERT(m.data_GetElemIndexOfType(0, mcET_BRACKET) == m.math_MathToDataIdx(bridx), 02431 wxT("the given monomial should contain the bracket to expand at the given math idx")); 02432 02433 // extract the bracket and its contents 02434 mcBracket br = m.math_Get(bridx); // the bracket to distribute 02435 mcPolynomial brcontents = br.data_GetContent(); 02436 mcMATHLOG(wxT("mcPolynomialHelpers::math_DistributeBracket - the bracket's contents are [%s]"), mcTXT(brcontents)); 02437 02438 // remember the type of operator placed before the bracket 02439 if (mdataidx > 0 && data_isAddSubOp(mdataidx-1)) { 02440 signbeforebr = (data_Get(mdataidx-1).data_GetType() == mcET_ADDOP) ? 1 : -1; 02441 data_MoveElemLeft(mdataidx-1); 02442 mdataidx--; 02443 } 02444 02445 // if we are contained in a monomial, then we can use 02446 // the DISTRIBUTIVE property to create a new polynomial 02447 // that we can use to replace our parent: 02448 // 02449 // P + Q + XY(a + b + c)WZ + R + S superparent 02450 // XY(a + b + c)WZ parent 02451 // 02452 // final results: 02453 // 02454 // P + Q + XYaWZ + XYbWZ + XYcWZ + R + S superparent 02455 // XYaWZ + XYbWZ + XYcWZ (*newelem) 02456 // 02457 02458 // second, create pnewcount monomials inside of pnew 02459 int pnewcount = brcontents.math_GetCount(); 02460 int mcount = m.math_GetCount(); 02461 for (int n=0; n < pnewcount; n++) { 02462 02463 // third, init the n-th monomial with a simple "1" 02464 mcMonomial newm; 02465 newm.math_ResetToOne(); 02466 int add = 1; 02467 02468 // four, fill each monomial with the factors of the parent 02469 for (int i=0; i < mcount; i++) { 02470 02471 mcElement tomult = m.data_Get(i); 02472 if (tomult == br) { 02473 02474 // do not multiply by this bracket, but by the n-th element 02475 // contained _inside_ this bracket 02476 tomult = brcontents.math_Get(n); 02477 02478 // remember the sign which is preceding that monomial 02479 add = brcontents.math_GetSign(n); 02480 02481 // multiply by an entire monomial, not just a simple element 02482 newm.math_SimpleMultiplyBy(tomult); 02483 02484 } else { 02485 02486 // tomult should not be a mcElementArray-derived class: 02487 // it should be a simple element. 02488 newm.math_SimpleMultiplyBy(tomult); 02489 } 02490 } 02491 02492 // be sure that the monomial is okay 02493 newm.data_Check(); 02494 02495 // last, add this monomial to the newp 02496 //newp.math_SimpleAdd(&newm, add); 02497 mcElementType t = (add*signbeforebr == 1) ? mcET_ADDOP : mcET_SUBOP; 02498 data_MoveElemRight(mdataidx); 02499 data_Set(mdataidx, mcElementHelpers::data_NewElem(t)); 02500 data_MoveElemRight(mdataidx+1); 02501 data_Set(mdataidx+1, newm); 02502 mdataidx+=2; 02503 } 02504 02505 // ok, tell the parent to use "newp" as replacement 02506 data_Check(); 02507 02508 mcMATHLOG(wxT("mcPolynomialHelpers::math_DistributeBracket - result is [%s]"), mcTXTTHIS); 02509 } 02510 02511 mcMonomial mcPolynomialHelpers::math_GetGCD(const mcElement &p) const 02512 { 02513 mcPolynomial arr(p); 02514 02515 // if we are both containing a single element, our work is quite easy... 02516 if (math_isFactorized() && arr.math_isFactorized()) 02517 return math_Get(0).hlp()->math_GetGCD(arr.math_Get(0)); 02518 02519 // at least one of the two arrays (*this or arr) is containing 02520 // more than a single monomial: GCD has no sense in this case.... 02521 //return *mcMonomialHelpers::smath_pOne; 02522 return math_GetGCDFor(NULL, -1); 02523 } 02524 02525 mcMonomial mcPolynomialHelpers::math_GetLCM(const mcElement &p) const 02526 { 02527 mcPolynomial arr(p); 02528 02529 // if we are both containing a single element, our work is quite easy... 02530 if (math_isFactorized() && arr.math_isFactorized()) 02531 return math_Get(0).hlp()->math_GetLCM(arr.math_Get(0)); 02532 02533 // at least one of the two arrays (*this or arr) is containing 02534 // more than a single monomial: LCM is then the product of these 02535 // two polynomials 02536 mcBracket br1(mcPolynomial(this).math_EmbedInBracket().data_GetRef()); 02537 mcBracket br2(arr.math_EmbedInBracket().data_GetRef()); 02538 02539 mcMonomial res; 02540 res.data_AddElements(&br1, 1); 02541 res.math_SimpleMultiplyBy(br2); 02542 02543 return res; 02544 } 02545 02546 02547 02548 mcArrayEntry mcPolynomialHelpers::math_EmbedInBracket(int *n, int count) 02549 { 02550 if (count == -1) 02551 return mcElementArrayHelpers::math_EmbedInBracket(); 02552 02553 mcPolynomial pol; 02554 mcBracket br; 02555 02556 // select only the given monomials 02557 for (int i=0; i < count; i++) { 02558 02559 // add/subtract the required monomials 02560 bool add = (math_GetSign(n[i]) == 1) ? TRUE : FALSE; 02561 pol.math_SimpleAdd(math_Get(n[i]), add); 02562 02563 // cannot remove now the n[i]-th monomial since otherwise 02564 // we would make invalid the n[i+1], n[i+2]... indexes 02565 math_Remove(n[i]); 02566 for (int j=i+1; j < count; j++) 02567 n[j]--; 02568 } 02569 02570 02571 // allocate a new mcBracket 02572 br.data_SetContent(pol); 02573 02574 // this object will take care of the bracket... 02575 math_SimpleAdd(br); 02576 02577 mcArrayEntry ourb(this, mcMAKEPOL_IDX(data_GetCount()-1, 0)); 02578 mcASSERT(ourb.data_GetRef().data_GetType() == mcET_BRACKET, wxT("What is this ?!?!?")); 02579 02580 return ourb; 02581 } 02582 02583 mcArrayEntry mcPolynomialHelpers::math_GetIndexOf(int occ, const mcMonomial &tofind, 02584 bool positivesign) const 02585 { 02586 // scan the array 02587 for (int i=0,max=math_GetCount(); i<max; i++) { 02588 02589 // not only compare the given monomial with our i-th one, 02590 // but also do check the sign of that monomial 02591 if (math_Get(i).math_Compare(tofind, TRUE) && 02592 positivesign == (math_GetSign(0) != 0)) { 02593 02594 occ--; 02595 if (occ == -1) 02596 return mcArrayEntry(this, mcMAKEPOL_IDX(math_MathToDataIdx(i), 0)); 02597 02598 // search the next occurrence 02599 } 02600 } 02601 02602 return mcEmptyArrayEntry; 02603 }
[ Top ] |