double ON_Sum::SortAndSum( int count, double* a ) { // note that the arrays passed to ON_Sum::SortAndSum() are all // homogeneous in sign double s = 0.0; if ( count > 0 ) { if ( count >= 2 ) { ON_SortDoubleArray( ON::quick_sort, a, count ); //double a0 = fabs(a[0]); //double a1 = fabs(a[count-1]); m_sum_err += ON_EPSILON*( fabs(a[count-1]) + count*fabs(a[0]) ); } if ( a[count] < 0.0 ) { a += count-1; while (count--) s += *a--; } else { while (count--) s += *a++; } } return s; }
int ON_Brep::SplitEdgeAtParameters( int edge_index, int edge_t_count, const double* edge_t ) { // Default kink_tol_radians MUST BE ON_PI/180.0. // // The default kink tol must be kept in sync with the default for // TL_Brep::SplitKinkyFace() and ON_Brep::SplitKinkyFace(). // See comments in TL_Brep::SplitKinkyFace() for more details. if (0 == edge_t_count) return 0; if (0 == edge_t) return 0; if (edge_index < 0 || edge_index >= m_E.Count()) return 0; ON_BrepEdge& E = m_E[edge_index]; if (E.m_c3i < 0) return 0; ON_Curve* curve = m_C3[E.m_c3i]; if (!curve) return 0; ON_Interval Edomain; if ( !E.GetDomain(&Edomain.m_t[0],&Edomain.m_t[1]) ) return 0; if ( !Edomain.IsIncreasing() ) return 0; // get a list of unique and valid splitting parameters ON_SimpleArray<double> split_t(edge_t_count); { for (int i = 0; i < edge_t_count; i++) { double e = edge_t[i]; if ( !ON_IsValid(e) ) { ON_ERROR("Invalid edge_t[] value"); continue; } if ( e <= Edomain.m_t[0] ) { ON_ERROR("edge_t[] <= start of edge domain"); continue; } if ( e >= Edomain.m_t[1] ) { ON_ERROR("edge_t[] >= end of edge domain"); continue; } split_t.Append(e); } if ( split_t.Count() > 1 ) { // sort split_t[] and remove duplicates ON_SortDoubleArray( ON::heap_sort, split_t.Array(), split_t.Count() ); int count = 1; for ( int i = 1; i < split_t.Count(); i++ ) { if ( split_t[i] > split_t[count-1] ) { if ( i > count ) split_t[count] = split_t[i]; count++; } } split_t.SetCount(count); } } if (split_t.Count() <= 0) return 0; // Reverse split_t[] so the starting segment of the original // edge m_E[edge_index] is the one at m_E[edge_index]. split_t.Reverse(); ON_Curve* new_curve = TuneupSplitteeHelper(m_E[edge_index].ProxyCurve()); if ( 0 != new_curve ) { m_E[edge_index].m_c3i = AddEdgeCurve(new_curve); m_E[edge_index].SetProxyCurve(new_curve); new_curve = 0; } int eti, ti; int successful_split_count = 0; for (int i=0; i<split_t.Count(); i++) { double t0, t1; m_E[edge_index].GetDomain(&t0, &t1); if (t1 - t0 < 10.0*ON_ZERO_TOLERANCE) break; //6 Dec 2002 Dale Lear: // I added the relative edge_split_s and trm_split_s tests to detect // attempts to trim a nano-gnats-wisker off the end of a trim. double edge_split_s = ON_Interval(t0,t1).NormalizedParameterAt(split_t[i]); double trim_split_s = 0.5; if (split_t[i] - t0 <= ON_ZERO_TOLERANCE || edge_split_s <= ON_SQRT_EPSILON ) { // this split is not possible continue; } if (t1 - split_t[i] <= ON_ZERO_TOLERANCE || edge_split_s >= 1.0-ON_SQRT_EPSILON) { // this split is not possible continue; } // trim_t[] = corresponding trim parameters ON_SimpleArray<double> trim_t(m_E[edge_index].m_ti.Count()); for ( eti = 0; eti < m_E[edge_index].m_ti.Count(); eti++) { ti = m_E[edge_index].m_ti[eti]; if ( ti < 0 || ti >= m_T.Count() ) continue; ON_BrepTrim& trim = m_T[ti]; if ( 0 == i ) { // On the first split, make sure the trim curve is up to snuff. new_curve = TuneupSplitteeHelper(trim.ProxyCurve()); if (new_curve) { trim.m_c2i = AddTrimCurve(new_curve); trim.SetProxyCurve(new_curve); new_curve = 0; } } double t = ON_UNSET_VALUE; if (!GetTrimParameter(ti, split_t[i], &t) || !ON_IsValid(t)) break; trim_t.Append(t); const ON_Interval trim_domain = trim.Domain(); trim_split_s = trim_domain.NormalizedParameterAt(t); if ( trim_split_s <= ON_SQRT_EPSILON || t - trim_domain[0] <= ON_ZERO_TOLERANCE ) break; if ( trim_split_s >= 1.0-ON_SQRT_EPSILON || trim_domain[1] - t <= ON_ZERO_TOLERANCE ) break; } if ( trim_t.Count() != m_E[edge_index].m_ti.Count() ) continue; if (!SplitEdge(edge_index, split_t[i], trim_t)) { continue; } // SplitEdge generally adjusts proxy domains instead // of trimming the orginal curve. These DuplicateCurve() // calls make a new curve whose domain exactly matches // the edge. for ( int epart = 0; epart < 2; epart++ ) { ON_BrepEdge* newE = (0 == epart) ? &m_E[edge_index] : m_E.Last(); if ( 0 == newE ) continue; new_curve = TuneupEdgeOrTrimRealCurve(*newE,true); if (new_curve) { newE->m_c3i = AddEdgeCurve(new_curve); newE->SetProxyCurve(new_curve); } for ( eti = 0; eti < newE->m_ti.Count(); eti++ ) { ti = newE->m_ti[eti]; if ( ti < 0 || ti >= m_T.Count() ) continue; ON_BrepTrim& trim = m_T[ti]; new_curve = TuneupEdgeOrTrimRealCurve(trim,false); if (new_curve) { trim.m_c2i = AddTrimCurve(new_curve); trim.SetProxyCurve(new_curve); } } } successful_split_count++; } return successful_split_count; }