void inverse( double** a, int nRows, int nCols) { int i,j,k; double* w = new double[nCols]; double** v = allocate2DDouble( nRows, nCols); double** temp = allocate2DDouble( nRows, nCols ); for( i=0; i<nRows; i++) memset( v[i], 0, sizeof(double) * nCols ); memset( w, 0, sizeof(double) * nCols ); // SVD copyMatrix( a, temp, nRows, nCols); svdcmp(temp, nRows, nCols, w, v); for( i=0; i<nCols; i++) { if( !nearzero( w[i] ) ) w[i] = 1.0 / w[i]; } for( i=0; i<nCols; i++) for( j=0; j<nRows; j++) { temp[j][i] = temp[j][i] * w[i]; } for( i=0; i<nRows; i++) memset( a[i], 0, sizeof(double) * nCols ); for( i=0; i<nRows; i++) for( j=0; j<nCols; j++) for( k=0; k<nCols; k++) { a[i][j] += temp[i][k] * v[j][k]; // coz' v is not transposed } SAFEDELARR( w ); if( v != NULL ) { for( i=0; i<nRows; i++ ) SAFEDELARR( v[i] ); SAFEDELARR( v ); } if( temp != NULL ) { for( i=0; i<nRows; i++ ) SAFEDELARR( temp[i] ); SAFEDELARR( temp ); } }
// // R_classifyDynaSeg // // The seg is either left, right, or on the partition line. // static int R_classifyDynaSeg(const dynaseg_t *part, const dynaseg_t *seg, double pdx, double pdy) { double dx2, dy2, dx3, dy3, a, b; // check line against partition dx2 = part->psx - seg->psx; dy2 = part->psy - seg->psy; dx3 = part->psx - seg->pex; dy3 = part->psy - seg->pey; a = pdy * dx2 - pdx * dy2; b = pdy * dx3 - pdx * dy3; if(!(a*b >= 0) && !nearzero(a) && !nearzero(b)) { double x = 0.0, y = 0.0; // line is split R_ComputeIntersection(part, seg, x, y); // find distance from line start to split point dx2 = seg->psx - x; dy2 = seg->psy - y; if(nearzero(dx2) && nearzero(dy2)) a = 0.0; else { double l = dx2*dx2 + dy2*dy2; if(l < 4.0) a = 0.0; } dx3 = seg->pex - x; dy3 = seg->pey - y; if(nearzero(dx3) && nearzero(dy3)) b = 0.0; else { double l = dx3*dx3 + dy3*dy3; if(l < 4.0) b = 0.0; } } int val = 0; if(nearzero(a)) // start is on the partition val |= START_ON; else if(a < 0.0) // start is on left val |= START_LEFT; else // start is on right val |= START_RIGHT; if(nearzero(b)) // end is on partition val |= END_ON; else if(b < 0.0) // end is on left val |= END_LEFT; else // end is on right val |= END_RIGHT; return val; }
// // R_selectPartition // // This routine decides the best dynaseg to use as a nodeline by attempting to // minimize the number of splits it would cause in remaining dynasegs. // // Credit to Raphael Quinet and DEU. // // Rewritten by Lee Killough for significant performance increases. // (haleyjd - using gotos, naturally ;) // static dynaseg_t *R_selectPartition(dseglist_t segs) { dseglink_t *rover; dynaseg_t *best = NULL; int bestcost = INT_MAX; int cnt = 0; // count the number of segs on the input list for(rover = segs; rover; rover = rover->dllNext) ++cnt; // Try each seg as a partition line for(rover = segs; rover; rover = rover->dllNext) { dynaseg_t *part = *rover; dseglink_t *crover; int cost = 0, tot = 0, diff = cnt; // haleyjd: add one seg worth of cost to non-orthogonal lines if(part->seg.linedef->slopetype > ST_VERTICAL) cost += FACTOR; // Check partition against all segs for(crover = segs; crover; crover = crover->dllNext) { dynaseg_t *check = *crover; // classify both end points double a = part->pdy * check->psx - part->pdx * check->psy + part->ptmp; double b = part->pdy * check->pex - part->pdx * check->pey + part->ptmp; if(!(a*b >= 0)) // oppositely signed? { if(!nearzero(a) && !nearzero(b)) // not within epsilon of 0? { // line is split double l = check->len; double d = (l * a) / (a - b); // distance from intersection if(d >= 2.0) { cost += FACTOR; // killough: This is the heart of my pruning idea - it // catches bad segs early on. if(cost > bestcost) goto prune; ++tot; } else if(l - d < 2.0 ? check->pdx * part->pdx + check->pdy * part->pdy < 0 : b < 0) goto leftside; } else goto leftside; } else if(a <= 0 && (!nearzero(a) || (nearzero(b) && check->pdx * part->pdx + check->pdy * part->pdy < 0))) { leftside: diff -= 2; } } // end for // Take absolute value; diff is being used to obtain the min/max values // by way of min(a, b) = (a + b - abs(a - b)) / 2 if((diff -= tot) < 0) diff = -diff; // Make sure at least one seg is on each side of the partition if(tot + cnt > diff && (cost += diff) < bestcost) { // we have a new better choice bestcost = cost; best = part; // remember the best seg } prune: ; // early exit and skip past the tests above } // end for // haleyjd: failsafe. Maybe there's just one left in the list. I'm not // taking any chances that the above algorithm might freak out when that // becomes the case. I KNOW the list is not empty. if(!best) best = *segs; return best; // All finished, return best seg }