// After we split an edge, we have created a new edge and a new vertex. // The edge needs to inherit the constraint on the other pre-existing edge that we kept. // In addition, if the edge vertices were both constrained, then we /might/ // want to also constrain this new vertex, possibly project to constraint target. void update_after_split(int edgeID, int va, int vb, DMesh3.EdgeSplitInfo splitInfo) { bool bPositionFixed = false; if (constraints != null && constraints.HasEdgeConstraint(edgeID)) { // inherit edge constraint constraints.SetOrUpdateEdgeConstraint(splitInfo.eNewBN, constraints.GetEdgeConstraint(edgeID)); // [RMS] update vertex constraints. Note that there is some ambiguity here. // Both verts being constrained doesn't inherently mean that the edge is on // a constraint, that's why these checks are only applied if edge is constrained. // But constrained edge doesn't necessarily mean we want to inherit vert constraints!! // // although, pretty safe to assume that we would at least disable flips // if both vertices are constrained to same line/curve. So, maybe this makes sense... // // (perhaps edge constraint should be explicitly tagged to resolve this ambiguity??) // vert inherits Fixed if both orig edge verts Fixed, and both tagged with same SetID VertexConstraint ca = constraints.GetVertexConstraint(va); VertexConstraint cb = constraints.GetVertexConstraint(vb); if (ca.Fixed && cb.Fixed) { int nSetID = (ca.FixedSetID > 0 && ca.FixedSetID == cb.FixedSetID) ? ca.FixedSetID : VertexConstraint.InvalidSetID; constraints.SetOrUpdateVertexConstraint(splitInfo.vNew, new VertexConstraint(true, nSetID)); bPositionFixed = true; } // vert inherits Target if both source verts and edge have same Target if (ca.Target != null && ca.Target == cb.Target && constraints.GetEdgeConstraint(edgeID).Target == ca.Target) { constraints.SetOrUpdateVertexConstraint(splitInfo.vNew, new VertexConstraint(ca.Target)); project_vertex(splitInfo.vNew, ca.Target); bPositionFixed = true; } } if (EnableInlineProjection && bPositionFixed == false && target != null) { project_vertex(splitInfo.vNew, target); } }
// resolve vertex constraints for collapsing edge eid=[a,b]. Generally we would // collapse a to b, and set the new position as 0.5*(v_a+v_b). However if a *or* b // are constrained, then we want to keep that vertex and collapse to its position. // This vertex (a or b) will be returned in collapse_to, which is -1 otherwise. // If a *and* b are constrained, then things are complicated (and documented below). protected bool can_collapse_vtx(int eid, int a, int b, out int collapse_to) { collapse_to = -1; if (constraints == null) { return(true); } VertexConstraint ca = constraints.GetVertexConstraint(a); VertexConstraint cb = constraints.GetVertexConstraint(b); // no constraint at all if (ca.Fixed == false && cb.Fixed == false && ca.Target == null && cb.Target == null) { return(true); } // handle a or b fixed if (ca.Fixed == true && cb.Fixed == false) { collapse_to = a; return(true); } if (cb.Fixed == true && ca.Fixed == false) { collapse_to = b; return(true); } // if both fixed, and options allow, treat this edge as unconstrained (eg collapse to midpoint) // [RMS] tried picking a or b here, but something weird happens, where // eg cylinder cap will entirely erode away. Somehow edge lengths stay below threshold?? if (AllowCollapseFixedVertsWithSameSetID && ca.FixedSetID >= 0 && ca.FixedSetID == cb.FixedSetID) { return(true); } // handle a or b w/ target if (ca.Target != null && cb.Target == null) { collapse_to = a; return(true); } if (cb.Target != null && ca.Target == null) { collapse_to = b; return(true); } // if both vertices are on the same target, and the edge is on that target, // then we can collapse to either and use the midpoint (which will be projected // to the target). *However*, if the edge is not on the same target, then we // cannot collapse because we would be changing the constraint topology! if (cb.Target != null && ca.Target != null && ca.Target == cb.Target) { if (constraints.GetEdgeConstraint(eid).Target == ca.Target) { return(true); } } return(false); }