/// <summary> /// Maintain halfspaces in ascending opening angle order /// Called after each add, which puts a new halfspace at the /// end of the arraylist. "Bubble" the new addition to its proper /// place. Also assign a "Sign" from to this Convex /// One of: Positive, negative, zero, mixed. /// </summary> /// <param name="sign">The sign of the most recently added halfspace</param> private void sortandsign(Halfspace.Sign sign) { int i; int cnt; Halfspace hs; Halfspace hsprev; Object o; cnt = _halfspaces.Count; for(i = cnt-1; i>0; i--){ hs = (Halfspace) _halfspaces[i]; hsprev = (Halfspace) _halfspaces[i-1]; if (hs.hangle > hsprev.hangle){ // New halfspace has wider angle than previous one // so we are done! break; } else { // new halfspace needs to trade places with previous one o = hsprev; _halfspaces[i-1] = hs; _halfspaces[i] = o; } } // Done sorting, now update sign if(cnt == 1){ this._sign = sign; return; } switch(this._sign){ case Halfspace.Sign.Negative: if (sign == Halfspace.Sign.Positive) this._sign = Halfspace.Sign.Mixed; break; case Halfspace.Sign.Positive: if (sign == Halfspace.Sign.Negative) this._sign = Halfspace.Sign.Mixed; break; case Halfspace.Sign.Zero: this._sign = sign; break; case Halfspace.Sign.Mixed: // Mixed stays mixed break; } }
private void prune() { // NEW: Check if this halfspace is the whole sphere, if so, remove it. int clen = _halfspaces.Count; bool hasPositive = false; bool hasNegative = false; bool hasZero = false; bool[] removethese = new bool[clen]; bool removeall = false; if (clen < 1) return; for (int i = 0; i < clen; i++) { Halfspace hi = (Halfspace)_halfspaces[i]; removethese[i] = false; if (clen > 1 && hi.isUniversal()) { // _halfspaces.RemoveAt(i); removethese[i] = true; } if (hi.isNull()) { removeall = true; break; } } if (removeall) { _halfspaces.Clear(); hasZero = true; // force consistency. } else { for (int i = clen - 1; i >= 0; i--) { if (removethese[i]) { _halfspaces.RemoveAt(i); } else { Halfspace hi = (Halfspace)_halfspaces[i]; switch (hi.sign) { case Halfspace.Sign.Negative: hasNegative = true; break; case Halfspace.Sign.Positive: hasPositive = true; break; case Halfspace.Sign.Zero: hasZero = true; break; } } } } if (hasPositive && hasNegative) { _sign = Halfspace.Sign.Mixed; } else if (hasPositive) { _sign = Halfspace.Sign.Positive; } else if (hasNegative) { _sign = Halfspace.Sign.Negative; } else { _sign = Halfspace.Sign.Zero; } if (_sign == Halfspace.Sign.Zero && !hasZero) { throw new Exception("Convex.prune() internal inconsistency"); } // end new. }
private void init(){ _halfspaces = new ArrayList(); // will change _corners = new ArrayList(); _sign = Halfspace.Sign.Zero; _boundingCircle = new Halfspace(); _htm = new HtmTrixel(); }
private void clear(){ _halfspaces = null; _corners = null; _sign = Halfspace.Sign.Zero; _boundingCircle = null; _htm = new HtmTrixel(); }
public void OLDsimplify() { prune(); // remove redundant halfspaces, adjust sign. if (_halfspaces.Count < 1) return; if (_sign == Halfspace.Sign.Zero) { simplify0(); // treat ZERO convexes separately return; } int i, j; int clen; bool redundancy = true; while (redundancy) { redundancy = false; clen = _halfspaces.Count; for (i = 0; i < clen; i++) { Halfspace hi = (Halfspace)_halfspaces[i]; for (j = 0; j < i; j++) { Halfspace hj = (Halfspace)_halfspaces[j]; Halfspace.Position iPosj; // don't bother with two zero constraints if (hi.sign == Halfspace.Sign.Zero && hj.sign == Halfspace.Sign.Zero) continue; // both pos or zero if ((hi.sign == Halfspace.Sign.Positive || hi.sign == Halfspace.Sign.Zero) && (hj.sign == Halfspace.Sign.Positive || hj.sign == Halfspace.Sign.Zero)) { // was: if ( (iPosj = testConstraints(i,j)) == 0 ) continue; // intersection if ((iPosj = hi.relativePosition(hj)) == Halfspace.Position.Intersecting) continue; if (iPosj == Halfspace.Position.Disjoint) { // disjoint ! convex is empty _halfspaces.Clear(); return; } // one is redundant if (iPosj == Halfspace.Position.Surrounds) { // was: constraints_.erase(constraints_.en d()-i-1); // was later:constraints_.erase(constraints_.begin()+i); _halfspaces.RemoveAt(i); } else if (iPosj == Halfspace.Position.Contained) { // was: constraints_.erase(constraints_.en d()-j-1); // later: was constraints_.erase(constraints_.begin()+j); _halfspaces.RemoveAt(j); } else continue; // intersection redundancy = true; // we did cut out a constraint -> do the loop again break; } // both neg if ((hi.sign == Halfspace.Sign.Negative) && (hj.sign == Halfspace.Sign.Negative)) { //was: if ( (iposj = testConstraints(i,j)) <= 0 ) continue; // ok iPosj = hi.relativePosition(hj); if (iPosj == Halfspace.Position.Intersecting || iPosj == Halfspace.Position.Disjoint) continue; // one is redundant if (iPosj == Halfspace.Position.Surrounds) { //was: constraints_.erase(constraints_.en d()-1-j); // later was:constraints_.erase(constraints_.begin()+j); _halfspaces.RemoveAt(j); } else if (iPosj == Halfspace.Position.Contained) { //was : constraints_.erase(constraints_.en d()-1-i); // later was: constraints_.erase(constraints_.begin()+i); _halfspaces.RemoveAt(i); } else continue; // intersection redundancy = true; // we did cut out a constraint -> do the loop again break; } // one neg, one pos/zero // was:if( (iposj = testConstraints(i,j)) == 0) continue; // ok: intersect if ((iPosj = hi.relativePosition(hj)) == Halfspace.Position.Intersecting) continue; if (iPosj == Halfspace.Position.Disjoint) { // neg is redundant if (hi.sign == Halfspace.Sign.Negative) { //was: constraints_.erase(constraints_.en d()-1-i); //was later:constraints_.erase(constraints_.begin()+i); _halfspaces.RemoveAt(i); } else { //was: constraints_.erase(constraints_.en d()-1-j); // was later: constraints_.erase(constraints_.begin()+j); _halfspaces.RemoveAt(j); } redundancy = true; // we did cut out a constraint -> do the loop again break; } // if the negative constraint is inside the positive: continue if ((hi.sign == Halfspace.Sign.Negative && iPosj == Halfspace.Position.Contained) || (hj.sign == Halfspace.Sign.Negative && iPosj == Halfspace.Position.Surrounds)) continue; // positive constraint in negative: convex is empty! _halfspaces.Clear(); return; } // for (i...) if (redundancy) break; } }// while(redundancy) // reset the sign of the convex _sign = ((Halfspace)_halfspaces[0]).sign; for (i = 1; i < _halfspaces.Count; i++) { Halfspace hi = (Halfspace)_halfspaces[i]; switch (_sign) { case Halfspace.Sign.Negative: if (hi.sign == Halfspace.Sign.Positive) _sign = Halfspace.Sign.Mixed; break; case Halfspace.Sign.Positive: if (hi.sign == Halfspace.Sign.Negative) _sign = Halfspace.Sign.Mixed; break; case Halfspace.Sign.Zero: _sign = hi.sign; break; case Halfspace.Sign.Mixed: break; } } if (_halfspaces.Count == 1) // for one constraint, it is itself the BC _boundingCircle.copy((Halfspace)_halfspaces[0]); else if (_sign == Halfspace.Sign.Positive) _boundingCircle.copy((Halfspace)_halfspaces[0]); }
//// ////////////////////////// SIMPLIFICATION ///////////////////// // // // ///////////SIMPLIFY///////////////////////////////////// // simplify: // /// <summary> /// We have the following decision tree for the /// simplification of convexes: /// /// Always test two constraints against each other. We have /// /// * If both halfspaces are Positive or Zero /// # If they intersect: keep both /// # If one lies inside the other: drop the *larger* one /// # Else: disjunct. Clear the convex, stop. /// /// * If both constraints are Negative /// # If they intersect or are disjunct: ok /// # Else: one lies in the other, drop smaller 'hole' /// /// * Mixed: one Positive one Negative /// # No intersection, disjunct: Positive is redundant /// # Intersection: keep both /// # POS inside NEG: empty convex, stop. /// # NEG inside POS: keep both. /// Eliminate reduntand Halfspaces /// /// Simplification eliminates redundant Halfspaces. /// For example, a halfspace that completely surrounds /// another halfspace is eliminated. If two halfspaces /// in the Convex are disjoint, then the Convex is empty /// </summary> public void simplify() { prune(); // remove redundant halfspaces, adjust sign. if (_halfspaces.Count < 1) return; if(_sign == Halfspace.Sign.Zero) { simplify0(); // treat zERO convexes separately return; } int i,j; int clen; bool restart = true; while(restart) { restart = false; clen = _halfspaces.Count; for(i = 0; i < clen; i++) { Halfspace hi = (Halfspace) _halfspaces[i]; for (j = 0; j < i; j++) { Halfspace hj = (Halfspace)_halfspaces[j]; Halfspace.Position iPosj; // don't bother with two zero constraints if (hi.sign == Halfspace.Sign.Zero && hj.sign == Halfspace.Sign.Zero) continue; // No longer need to look at sign of halfspace, relativeposition does the work iPosj = hi.relativePosition(hj); if (iPosj == Halfspace.Position.Intersecting) continue; if (iPosj == Halfspace.Position.Disjoint) { // disjoint ! convex is empty _halfspaces.Clear(); return; } if (iPosj == Halfspace.Position.Surrounds) { _halfspaces.RemoveAt(i); restart = true; break; } else if (iPosj == Halfspace.Position.Contained) { _halfspaces.RemoveAt(j); restart = true; break; } } // for j if(restart) break; } // for i }// while(redundancy) // reset the sign of the convex _sign = ((Halfspace) _halfspaces[0]).sign; for(i = 1; i < _halfspaces.Count; i++) { Halfspace hi = (Halfspace) _halfspaces[i]; switch(_sign){ case Halfspace.Sign.Negative: if(hi.sign == Halfspace.Sign.Positive) _sign = Halfspace.Sign.Mixed; break; case Halfspace.Sign.Positive: if(hi.sign == Halfspace.Sign.Negative) _sign = Halfspace.Sign.Mixed; break; case Halfspace.Sign.Zero: _sign = hi.sign; break; case Halfspace.Sign.Mixed: break; } } if (_halfspaces.Count == 1) // for one constraint, it is itself the BC _boundingCircle.copy((Halfspace) _halfspaces[0]); else if (_sign == Halfspace.Sign.Positive) _boundingCircle.copy((Halfspace) _halfspaces[0]); }