//---------------------------------------------------------------------------- void TerrainPage::RemoveJunglerPoints (Jungler *jungler, APoint center, float radius, int num) { if (!jungler) return; // 范围内个数 std::vector<int> indexs; for (int i=0; i<jungler->GetNum(); i++) { const APoint &pos = jungler->GetPos(i); AVector dir = pos - center; if (dir.Length() < radius) { indexs.push_back(i); } } std::vector<int> indexsRemoves; for (int i=0; i<(int)indexs.size(); i++) { float fRand = (float)num/(float)indexsRemoves.size(); float fR = Mathf::IntervalRandom(0.0f, 1.0f); if (fR <= fRand) { indexsRemoves.push_back(indexs[i]); } } jungler->Remove(indexsRemoves); }
//---------------------------------------------------------------------------- void SceneNodeCtrl::OnMouseWheel(RenderStep *renderStep, float wheelDelta) { Camera *camera = renderStep->GetCamera(); float rmax = camera->GetRMax(); APoint camPosition = camera->GetPosition(); APoint ctrlPosition = GetPosition(); AVector diff = ctrlPosition - camPosition; float diffLength = diff.Length(); if (mLookType != LT_PERSPECTIVE) { if (0.0f != rmax) { mCtrlsGroup->WorldTransform.SetUniformScale(rmax*0.11f); mCtrlsGroup->Update(Time::GetTimeInSeconds(), false); } } else { float scale = diffLength*0.04f; if (scale == 0.0f) scale = 0.0001f; if (scale < 1.0f) scale = 1.0f; mCtrlsGroup->WorldTransform.SetUniformScale(scale); mCtrlsGroup->Update(Time::GetTimeInSeconds(), false); } }
//---------------------------------------------------------------------------- void Soundable::UpdateWorldData(double applicationTime, double elapsedTime) { Movable::UpdateWorldData(applicationTime, elapsedTime); if (mSound) mSound->SetPosition(WorldTransform.GetTranslate()); const APoint &listenPos = SoundSystem::GetSingleton().GetListenerPos(); if (!Is3D()) { AVector dir = WorldTransform.GetTranslate() - listenPos; if (!mDistanceUseX) dir.X() = 0.0f; if (!mDistanceUseY) dir.Y() = 0.0f; if (!mDistanceUseZ) dir.Z() = 0.0f; float dist = dir.Length(); SoundableController *sCtrl = DynamicCast<SoundableController>(GetEffectableController()); const SoundableObject *sObj = sCtrl->GetSoundableObject(); if (sObj) { float curVolume = sObj->Volume; float volume = curVolume; if (dist < mMinDistance) { volume = curVolume; } else if (mMinDistance<=dist && dist<=mMaxDistance) { float range = mMaxDistance - mMinDistance; if (range <= 0.0f) range = 0.0f; volume = curVolume * (1.0f - (dist - mMinDistance)/range); } else if (dist > mMaxDistance) { volume = 0.0f; } if (mSound) { mSound->SetVolume(volume); } } } }
//---------------------------------------------------------------------------- AVector SteeringBehavior::FollowPath () { AVector dist = mPath->GetCurrentWayPoint() - mActor->GetPosition(); float length = dist.Length(); if (length < mWayPointSeekDistSq) mPath->SetNextWayPoint(); if (!mPath->IsFinished()) { return Seek(mPath->GetCurrentWayPoint()); } else { return Arrive(mPath->GetCurrentWayPoint(), DM_NORMAL); } }
//---------------------------------------------------------------------------- AVector SteeringBehavior::Arrive (APoint toPosition, DecelerateMode mode) { AVector toTarget = toPosition - mActor->GetPosition(); float dist = toTarget.Length(); if (dist > 0) { const double decelerationTweaker = 0.3f; double speed = dist / ((double)mode * decelerationTweaker); speed = min(speed, mActor->GetMaxSpeed()); AVector desiredVelocity = toTarget * speed/dist; return (desiredVelocity - mActor->GetVelocity()); } return AVector(); }
//---------------------------------------------------------------------------- float CurveSegment::Curvature (float u) const { AVector velocity = PU(u); float speedSqr = velocity.SquaredLength(); if (speedSqr >= Mathf::ZERO_TOLERANCE) { AVector acceleration = PUU(u); AVector cross = velocity.Cross(acceleration); float numer = cross.Length(); float denom = Mathf::Pow(speedSqr, 1.5f); return numer/denom; } else { // Curvature is indeterminate, just return 0. return 0.0f; } }
//---------------------------------------------------------------------------- void DlodNode::SelectLevelOfDetail (const Camera* camera) { mWorldLodCenter = WorldTransform*mModelLodCenter; int i; for (i = 0; i < mNumLevelsOfDetail; ++i) { mWorldMinDist[i] = WorldTransform.GetUniformScale()*mModelMinDist[i]; mWorldMaxDist[i] = WorldTransform.GetUniformScale()*mModelMaxDist[i]; } SetActiveChild(SN_INVALID_CHILD); AVector diff = mWorldLodCenter - camera->GetPosition(); float dist = diff.Length(); for (i = 0; i < mNumLevelsOfDetail; ++i) { if (mWorldMinDist[i] <= dist && dist < mWorldMaxDist[i]) { SetActiveChild(i); break; } } }
//---------------------------------------------------------------------------- void Picker::ExecuteRecursive (Movable* object, bool &hasMeshPicked) { if (object) { if (!object->IsDoPick()) return; if (!object->IsShow() && !object->IsPickIngoreCullingMode()) return; } Triangles* mesh = DynamicCast<Triangles>(object); if (mesh) { if (!mesh->GetVertexBuffer()) return; if (mesh->WorldBound.TestIntersection(mOrigin, mDirection, mTMin, mTMax)) { if (mesh->IsUseBoundPick()) { AVector dir = mesh->GetWorldTransform().GetTranslate() - mOrigin; float length = dir.Length(); PickRecord record; record.Intersected = mesh; record.T = length; Records.push_back(record); } else { // 将射线从世界坐标系转换到模型坐标系。 APoint ptmp; if (!mesh->IsSkinCtrlSetWroldTrans) ptmp = mesh->WorldTransform.Inverse()*mOrigin; else ptmp = mesh->BoundWorldTransform.Inverse()*mOrigin; Vector3f modelOrigin(ptmp[0], ptmp[1], ptmp[2]); AVector vtmp; if (!mesh->IsSkinCtrlSetWroldTrans) vtmp = mesh->WorldTransform.Inverse()*mDirection; else vtmp = mesh->BoundWorldTransform.Inverse()*mDirection; Vector3f modelDirection(vtmp[0], vtmp[1], vtmp[2]); Line3f line(modelOrigin, modelDirection); // 访问方位数据 VertexBufferAccessor vba(mesh); int numTriangles = mesh->GetNumTriangles(); for (int i = 0; i < numTriangles; ++i) { int v0, v1, v2; if (!mesh->GetTriangle(i, v0, v1, v2)) { continue; } Vector3f vertex0 = vba.Position<Vector3f>(v0); Vector3f vertex1 = vba.Position<Vector3f>(v1); Vector3f vertex2 = vba.Position<Vector3f>(v2); Triangle3f triangle(vertex0, vertex1, vertex2); IntrLine3Triangle3f calc(line, triangle); if (calc.Find()) { float lineParameter = calc.GetLineParameter(); if (mTMin<=lineParameter && lineParameter<=mTMax) { PickRecord record; record.Intersected = mesh; record.T = calc.GetLineParameter(); record.Triangle = i; record.Bary[0] = calc.GetTriBary0(); record.Bary[1] = calc.GetTriBary1(); record.Bary[2] = calc.GetTriBary2(); Vector3f edg1 = vertex1 - vertex0; Vector3f edg2 = vertex2 - vertex0; Vector3f normal = edg1.UnitCross(edg2); float dotVal = line.Direction.Dot(normal); if (dotVal > Mathf::ZERO_TOLERANCE) { normal *= -1.0f; } record.LocalNormal = normal; record.WorldPos = mOrigin + mDirection * record.T; Records.push_back(record); if (mIsDoMovPickCall) { hasMeshPicked = true; mesh->OnPicked(mPickInfo); } } } } } } else { if (mIsDoMovPickCall) mesh->OnNotPicked(mPickInfo); } return; } SwitchNode* switchNode = DynamicCast<SwitchNode>(object); if (switchNode) { bool newHasChildPicked = false; int activeChild = switchNode->GetActiveChild(); if (activeChild != SwitchNode::SN_INVALID_CHILD) { if (switchNode->WorldBound.TestIntersection(mOrigin, mDirection, mTMin, mTMax)) { Movable* child = switchNode->GetChild(activeChild); if (child) { ExecuteRecursive(child, newHasChildPicked); } if (newHasChildPicked) { hasMeshPicked = true; } if (mIsDoMovPickCall) { if (hasMeshPicked) { switchNode->OnPicked(mPickInfo); } else { switchNode->OnNotPicked(mPickInfo); } } } else { if (mIsDoMovPickCall) switchNode->OnNotPicked(mPickInfo); } } return; } Node* node = DynamicCast<Node>(object); if (node) { bool newHasChildPicked = false; if (node->WorldBound.TestIntersection(mOrigin, mDirection, mTMin, mTMax)) { Movable *movPriority = 0; if (node->IsDoPickPriority()) { for (int i=0; i<node->GetNumChildren(); i++) { Movable *mov = node->GetChild(i); if (mov && mov->IsNotPickedParentChildrenNotPicked()) movPriority = mov; } } // 做优先检测 bool doLastPick = false; if (movPriority) { ExecuteRecursive (movPriority, doLastPick); } else { doLastPick = true; } if (doLastPick) { for (int i = 0; i < node->GetNumChildren(); ++i) { Movable* child = node->GetChild(i); if (child && child!=movPriority) { ExecuteRecursive(child, newHasChildPicked); } } if (newHasChildPicked) { hasMeshPicked = true; } if (mIsDoMovPickCall) { if (newHasChildPicked) { node->OnPicked(mPickInfo); } else { node->OnNotPicked(mPickInfo); } } } } else { if (mIsDoMovPickCall) node->OnNotPicked(mPickInfo); } } }
//---------------------------------------------------------------------------- void InputPushTransformController::OnEvent(Event *event) { if (!Active) return; if (!IsPlaying()) return; Movable *mov = DynamicCast<Movable>(GetControlledable()); if (!mov) return; if (InputEventSpace::IsEqual(event, InputEventSpace::LevelView)) { mIsPressedValid = false; } else if (InputEventSpace::IsEqual(event, InputEventSpace::MousePressed) || InputEventSpace::IsEqual(event,InputEventSpace::TouchPressed)) { InputEventData data = event->GetData<InputEventData>(); mIsPressedValid = true; mSampingTiming = 0.0f; mPressedTime = (float)Time::GetTimeInSeconds(); mPressedPos = data.MTPos; if (mConvertCallback) { mConvertCallback(mPressedPos, (int)data.MTPos.X(), (int)data.MTPos.Z()); } mCurTouchPos = mPressedPos; mLastTouchPos = mCurTouchPos; mLastSamplePos = mCurTouchPos; SetVelocity(AVector::ZERO); } else if (InputEventSpace::IsEqual(event, InputEventSpace::MouseReleased) || InputEventSpace::IsEqual(event, InputEventSpace::TouchReleased)) { InputEventData data = event->GetData<InputEventData>(); mSampingTiming = 0.0f; if (!mIsPressedValid) return; mIsPressedValid = false; mReleasedTime = (float)Time::GetTimeInSeconds(); mReleasedPos = data.MTPos; if (mConvertCallback) { mConvertCallback(mPressedPos, (int)data.MTPos.X(), (int)data.MTPos.Z()); } float deltaTime = mReleasedTime - mPressedTime; if (deltaTime <= 0.0f) deltaTime = 1.0f; //AVector speed = mReleasedPos - mPressedPos; //speed /= deltaTime; AVector speed = mTouchMoveSpeed; float judge = 0.0f; if (mLockDir != AVector::ZERO) { judge = mLockDir.Dot(speed); } else { judge = speed.Length(); } judge = Mathf::FAbs(judge); if (judge >= mPushTriggerSpeed) { if (mLockDir != AVector::ZERO) { speed.X() *= mLockDir.X(); speed.Y() *= mLockDir.Y(); speed.Z() *= mLockDir.Z(); } SetReleaseVelocity(speed * judge); } if (IsSmallTransScope() && GetSmallTransDir() != AVector::ZERO) { SetReleaseVelocity(AVector::ZERO); } } else if (InputEventSpace::IsEqual(event, InputEventSpace::MouseMoved) || InputEventSpace::IsEqual(event, InputEventSpace::TouchMoved)) { InputEventData data = event->GetData<InputEventData>(); if (!mIsPressedValid) return; mCurTouchPos = data.MTPos; if (mConvertCallback) { mConvertCallback(mPressedPos, (int)data.MTPos.X(), (int)data.MTPos.Z()); } AVector moveDis = mCurTouchPos - mLastTouchPos; APoint pos = mov->LocalTransform.GetTranslate(); pos += moveDis; TransScope(pos); mov->LocalTransform.SetTranslate(pos); mLastTouchPos = mCurTouchPos; } else if (InputEventSpace::IsEqual(event, InputEventSpace::TouchCancelled)) { mIsPressedValid = false; } }
//---------------------------------------------------------------------------- void SceneNodeCtrl::OnMotion(bool leftDown, RenderStep *renderStep, PX2::APoint posNow, PX2::APoint posBefore) { PX2_UNUSED(leftDown); PX2_UNUSED(renderStep); Renderer *renderer = renderStep->GetRenderer(); Camera *camera = renderStep->GetCamera(); // 光标移动更新 if (DT_NONE == mDragType) { GeoObjFactory factory; DragType dt = GetDragType(renderStep, posNow); Movable *ctrlMov = 0; Float4 colorYellowAlpha = Float4(1.0f, 1.0f, 0.0f, 0.3f); if (DT_X == dt) { ctrlMov = GetCurrentCtrlX(); factory.UpdateCtrlColor(renderer, ctrlMov, Float4::YELLOW); } else if (DT_Y == dt) { ctrlMov = GetCurrentCtrlY(); factory.UpdateCtrlColor(renderer, ctrlMov, Float4::YELLOW); } else if (DT_Z == dt) { ctrlMov = GetCurrentCtrlZ(); factory.UpdateCtrlColor(renderer, ctrlMov, Float4::YELLOW); } else if (DT_XY == dt) { factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXY(), colorYellowAlpha); factory.UpdateCtrlColor1(renderer, GetCurrentCtrlYZ(), Float4::ZERO); factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXZ(), Float4::ZERO); } else if (DT_YZ == dt) { factory.UpdateCtrlColor1(renderer, GetCurrentCtrlYZ(), colorYellowAlpha); factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXY(), Float4::ZERO); factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXZ(), Float4::ZERO); } else if (DT_XZ == dt) { factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXZ(), colorYellowAlpha); factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXY(), Float4::ZERO); factory.UpdateCtrlColor1(renderer, GetCurrentCtrlYZ(), Float4::ZERO); } else if (DT_XYZ == dt) { factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXYZ(), Float4::YELLOW); } else if (DT_NONE == dt) { factory.UpdateCtrlColor(renderer, GetCurrentCtrlX(), Float4::RED); factory.UpdateCtrlColor(renderer, GetCurrentCtrlY(), Float4::GREEN); factory.UpdateCtrlColor(renderer, GetCurrentCtrlZ(), Float4::BLUE); factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXY(), Float4::ZERO); factory.UpdateCtrlColor1(renderer, GetCurrentCtrlYZ(), Float4::ZERO); factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXZ(), Float4::ZERO); factory.UpdateCtrlColor1(renderer, GetCurrentCtrlXYZ(), Float4::WHITE); } if (DT_NONE == dt) { Event *ent = EditEventSpace::CreateEventX(EditEventSpace::SceneNodeDrag); ent->SetData<int>(0); EventWorld::GetSingleton().BroadcastingLocalEvent(ent); } else { Event *ent = EditEventSpace::CreateEventX(EditEventSpace::SceneNodeDrag); ent->SetData<int>(1); EventWorld::GetSingleton().BroadcastingLocalEvent(ent); } } if (DT_NONE == mDragType) return; else { Event *ent = EditEventSpace::CreateEventX(EditEventSpace::SceneNodeDrag); ent->SetData<int>(1); EventWorld::GetSingleton().BroadcastingLocalEvent(ent); } int numObjs = PX2_SELECTION.GetNumObjects(); if (0 == numObjs) return; // get pickPoint with the plane TriMesh *meshHelp = PX2_GR.GetXYPlane(); if (DT_X == mDragType) { if (LT_PERSPECTIVE == mLookType || LT_TOP == mLookType) meshHelp = PX2_GR.GetXYPlane(); else if (LT_FRONT == mLookType) meshHelp = PX2_GR.GetXZPlane(); } else if (DT_Y == mDragType) { meshHelp = PX2_GR.GetXYPlane(); } else if (DT_Z == mDragType) { AVector cameraDir = camera->GetDVector(); cameraDir.Normalize(); float dotVal = Mathf::FAbs(cameraDir.Dot(AVector::UNIT_X)); if (dotVal > 0.7f) { meshHelp = PX2_GR.GetYZPlane(); } else { meshHelp = PX2_GR.GetXZPlane(); } } else if (DT_XY == mDragType) { meshHelp = PX2_GR.GetXYPlane(); } else if (DT_YZ == mDragType) { meshHelp = PX2_GR.GetYZPlane(); } else if (DT_XZ == mDragType) { meshHelp = PX2_GR.GetXZPlane(); } else if (DT_XYZ == mDragType) { meshHelp = PX2_GR.GetXYPlane(); } meshHelp->WorldTransform.SetTranslate(GetPosition()); // get pick ray APoint rayOrigin_Now; AVector rayDir_Now; renderStep->GetPickRay(posNow.X(), posNow.Z(), rayOrigin_Now, rayDir_Now); APoint rayOrigin_Before; AVector rayDir_Before; renderStep->GetPickRay(posBefore.X(), posBefore.Z(), rayOrigin_Before, rayDir_Before); // pick Picker pickerNow; pickerNow.Execute(meshHelp, rayOrigin_Now, rayDir_Now, 0.0f, Mathf::MAX_REAL); float lengthNow = pickerNow.GetClosestToZero().T; APoint positionNow(rayOrigin_Now + rayDir_Now*lengthNow); Picker pickerOrigin; pickerOrigin.Execute(meshHelp, rayOrigin_Before, rayDir_Before, 0.0f, Mathf::MAX_REAL); float lengthBefore = pickerOrigin.GetClosestToZero().T; APoint positionBefore(rayOrigin_Before + rayDir_Before*lengthBefore); if (pickerNow.Records.empty() || pickerOrigin.Records.empty()) return; AVector transMoved = positionNow - positionBefore; AVector transDir = transMoved; transDir.Normalize(); float transValue = 0.0f; float transValue1 = 0.0f; AVector transVec; AVector rolateVec; AVector dirX = mDirX; AVector dirY = mDirY; AVector dirZ = mDirZ; if (DT_X == mDragType) { transValue = transMoved.Dot(dirX); transVec = dirX * transValue; rolateVec.X() = transMoved.Length() *(1.0f - Mathf::FAbs(transDir.Dot(dirX))); AVector vec = transDir.Cross(dirX); rolateVec.X() *= Mathf::Sign(vec.Z()); } else if (DT_Y == mDragType) { transValue = transMoved.Dot(dirY); transVec = dirY * transValue; rolateVec.Y() = transMoved.Length() *(1.0f - Mathf::FAbs(transDir.Dot(dirY))); AVector vec = transDir.Cross(dirY); rolateVec.Y() *= Mathf::Sign(vec.Z()); } else if (DT_Z == mDragType) { transValue = transMoved.Dot(dirZ); transVec = dirZ * transValue; rolateVec.Z() = transMoved.Length() *(1.0f - Mathf::FAbs(transDir.Dot(dirZ))); rolateVec.Z() *= Mathf::Sign(posNow.X() - posBefore.X()); } else if (DT_XY == mDragType) { transValue = transMoved.Dot(dirX); transValue1 = transMoved.Dot(dirY); transVec = dirX * transValue + dirY * transValue1; } else if (DT_YZ == mDragType) { transValue = transMoved.Dot(dirY); transValue1 = transMoved.Dot(dirZ); transVec = dirY * transValue + dirZ * transValue1; } else if (DT_XZ == mDragType) { transValue = transMoved.Dot(dirX); transValue1 = transMoved.Dot(dirZ); transVec = dirX * transValue + dirZ * transValue1; } else if (DT_XYZ == mDragType) { float transValue0 = Mathf::FAbs(transMoved.Dot(dirX)); float transValue1 = Mathf::FAbs(transMoved.Dot(dirY)); float transValue2 = Mathf::FAbs(transMoved.Dot(dirZ)); float trans = (transValue0 + transValue1 + transValue2) / 3.0f; trans *= Mathf::Sign(transMoved.Y()); transVec = AVector(trans, trans, trans); } if (CT_SCALE == mCtrlType) transVec *= 0.5f; HMatrix parentMat = mParentRotateMat.Inverse(); transVec = parentMat * transVec; if (CT_TRANSLATE == mCtrlType) { PX2_SELECTION.Translate(transVec); UpdateCtrlTrans(); } else if (CT_ROLATE == mCtrlType) { PX2_SELECTION.AddRolate(rolateVec); } else if (CT_SCALE == mCtrlType) { if (DT_XYZ == mDragType) PX2_SELECTION.AddScale(transVec); } Object *obj = PX2_SELECTION.GetFirstObject(); if (obj) { Event *ent = EditEventSpace::CreateEventX( EditEventSpace::ObjectTransformChanged); ent->SetData<Object*>(obj); EventWorld::GetSingleton().BroadcastingLocalEvent(ent); } mCtrlsGroup->Update(Time::GetTimeInSeconds(), false); }
//---------------------------------------------------------------------------- void FreeFormDeformation::OnMouseMove (int x, int y) { // Change to right-handed coordinates. y = GetHeight() - 1 - y; // Construct a pick ray. Te want to move the control point from its // current location to this ray. APoint origin; AVector direction; if (!mRenderer->GetPickRay(x, y, origin, direction)) { return; } // Let E be the camera world origin, D be the camera world direction, and // U be the pick ray world direction. Let C0 be the current location of // the picked point and let C1 be its desired new location. We need to // choose t for which C1 = E + t*U. Two possibilities are provided here, // both requiring computing: Diff = C0 - E. AVector diff = mOldWorldPos - mCamera->GetPosition(); float t; #if 0 // The new world position is chosen to be at a distance along the pick // ray that is equal to the distance from the camera location to the old // world position. That is, we require // Length(C0-E) = Length(C1-E) = Length(t*U) = t. t = diff.Length(); #else // The new world position is in the same plane perpendicular to the // camera direction as the old world position is. This plane is // Dot(D,X-C0) = 0, in which case we need // 0 = Dot(D,C1-C0) = Dot(D,E+t*U-C0) = Dot(D,E-C0) + t*Dot(D,U) // Solving for t, we have // t = Dot(D,C0-E)/Dot(D,U) t = mCamera->GetDVector().Dot(diff)/mCamera->GetDVector().Dot(direction); #endif APoint newWorldPos = origin + t*direction; // Move the control point to the new world location. The technical // problem is that we need to modify the world coordinates for the // selected control point. Thus, we need to determine how to change the // local translation in order to produce the correct world translation. Node* parent = (Node*)mSelected->GetParent(); diff = newWorldPos - mOldWorldPos; AVector localDiff = parent->WorldTransform.Inverse()*diff; mSelected->LocalTransform.SetTranslate( mSelected->LocalTransform.GetTranslate() + localDiff); mSelected->Update(); mOldWorldPos = newWorldPos; // Modify the control point itself. It is known that the name string // has three single-digit numbers separated by blanks. const std::string& name = mSelected->GetName(); int i0 = (int)(name[0] - '0'); int i1 = (int)(name[2] - '0'); int i2 = (int)(name[4] - '0'); APoint trn = mSelected->LocalTransform.GetTranslate(); mVolume->SetControlPoint(i0, i1, i2, Vector3f(trn[0], trn[1], trn[2])); // TO DO. We need only update mesh vertices that are affected by the // change in one control point. This requires working with the B-spline // basis function and knowing which (u,v,w) to evaluate at (i.e. determine // the local control region). UpdateMesh(); // TO DO. Only need to update neighboring lines. UpdatePolysegments(); }