protected virtual ToolpathPreviewJoint GenerateMiterJoint(Segment3d segmentBefore, Segment3d segmentAfter, TPrintVertex printVertex, ToolpathPreviewMesh mesh) { var averageDirection = (segmentBefore.Direction + segmentAfter.Direction).Normalized; var scaleFactor = 1 / segmentBefore.Direction.Dot(averageDirection); var frame = new Frame3f(printVertex.Position); frame.AlignAxis(1, ToVector3f(averageDirection)); var joint = new ToolpathPreviewJoint(); joint.InTop = joint.OutTop = mesh.AddVertex(vertexFactory(printVertex, frame.FromFrameP(DiamondCrossSection.Top(printVertex.Dimensions)), brightnessMax)); joint.InRight = joint.OutRight = mesh.AddVertex(vertexFactory(printVertex, frame.FromFrameP(DiamondCrossSection.Right(printVertex.Dimensions)), brightnessMin)); joint.InBottom = joint.OutBottom = mesh.AddVertex(vertexFactory(printVertex, frame.FromFrameP(DiamondCrossSection.Bottom(printVertex.Dimensions)), brightnessMax)); joint.InLeft = joint.OutLeft = mesh.AddVertex(vertexFactory(printVertex, frame.FromFrameP(DiamondCrossSection.Left(printVertex.Dimensions)), brightnessMin)); return(joint); }
void update_measurement() { Frame3f localFrame = meshTarget.GetLocalFrame(CoordSpace.ObjectCoords); Vector3f localP = localFrame.ToFrameP(scene.ToSceneP(measureHitPos)); AxisAlignedBox3f bounds = meshTarget.GetLocalBoundingBox(); Vector3f dv = localP - bounds.Center; dv.y = 0; Line3f line = new Line3f(Vector3f.Zero, Vector3f.AxisY); Vector3f linePos = line.ClosestPoint(localP); Frame3f mFrame = new Frame3f(linePos, Vector3f.AxisY); MeshSO.SectionInfo info = meshTarget.MeasureSection(mFrame); curDimension = info.maxDiameter; Vector3f center = 0.5f * (info.maxDiamPos1 + info.maxDiamPos2); //measureAxisPos = scene.ToWorldP(localFrame.FromFrameP(linePos)); displayPosS = localFrame.FromFrameP(linePos); circleCenterS = localFrame.FromFrameP(center); maxStart = localFrame.FromFrameP(info.maxDiamPos1); maxEnd = localFrame.FromFrameP(info.maxDiamPos2); }
public void UpdateDraw_Spatial(Ray3f ray, Frame3f handFrame) { float fScale = scene.GetSceneScale(); Vector3f newHitPos = handFrame.FromFrameP(handHitVec); smooth_append(preview, scene.SceneFrame.ToFrameP(newHitPos) / fScale, dist_thresh(Width, fScale)); }
// figuring out a decent line width is tricky. Want to be responsive to camera // pos, so line doesn't get super-thick when zoomed in. So we want to measure // screen-space radius. But off-screen vertices are a problem. So, only consider // vertices within a level, pointing-forward view cone (can't be actual view cone // because then line thickness changes as you turn head!). // // Also sub-sample verts for efficiency. Probably we don't need to do this // every frame...but how to distribute? // // ***returns 0*** if we couldn't find any points in view cone public static float EstimateStableCurveWidth(FScene scene, Frame3f curveFrameS, DCurve3 curve, float fVisualAngleDeg) { // do computations in Scene coords..."safest"? Vector3f camPos = scene.ActiveCamera.GetPosition(); Vector3f camForward = scene.ActiveCamera.Forward(); // use level-forward camForward[1] = 0; camForward.Normalize(); camPos = scene.ToSceneP(camPos); camForward = scene.ToSceneN(camForward); const float ViewConeDotThresh = 0.707106f; // 45 degrees int nSubSampleInc = Math.Max(2, curve.VertexCount / 10); float rSum = 0; int iSum = 0; for (int k = 0; k < curve.VertexCount; k += nSubSampleInc) { Vector3f vS = (Vector3f)curve.GetVertex(k); vS = curveFrameS.FromFrameP(vS); Vector3f dv = (vS - camPos).Normalized; if (dv.Dot(camForward) < ViewConeDotThresh) { continue; } float r = VRUtil.GetVRRadiusForVisualAngle(vS, camPos, fVisualAngleDeg); rSum += r; iSum++; } return((rSum == 0) ? 0 : scene.ToWorldDimension(rSum / (float)iSum)); }
/// <summary> /// input ray is in Object (local) coords of so, apply all intermediate /// transforms to get it to Scene coords /// </summary> public static Ray3f ObjectToScene(SceneObject so, Ray3f objectRay) { Ray3f sceneRay = objectRay; SceneObject curSO = so; while (curSO != null) { Frame3f curF = curSO.GetLocalFrame(CoordSpace.ObjectCoords); Vector3f scale = curSO.GetLocalScale(); Vector3f new_o = curF.FromFrameP(sceneRay.Origin * scale); Vector3f new_d = curF.FromFrameV(sceneRay.Direction * scale); sceneRay = new Ray3f(new_o, new_d.Normalized); SOParent parent = curSO.Parent; if (parent is FScene) { return(sceneRay); } curSO = (parent as SceneObject); } if (curSO == null) { DebugUtil.Error("SceneTransforms.ObjectToScene: found null parent SO!"); } return(sceneRay); }
protected override void update_vertices(FScene s) { if (Target.Timestamp == target_timestamp) { return; } target_timestamp = Target.Timestamp; DMesh3 Mesh = Target.Mesh; for (int i = 0; i < VertexCount; ++i) { SurfaceVertexRef r = SurfacePoints[i]; Vector3d vSum = Vector3d.Zero; Frame3f f = Mesh.GetTriFrame(r.tid); Index3i tv = Mesh.GetTriangle(r.tid); for (int j = 0; j < 3; ++j) { f.Origin = (Vector3f)Mesh.GetVertex(tv[j]); Vector3d v = f.FromFrameP(r.offsets[j]); vSum += v; } vSum /= 3; this[i] = SceneTransforms.ObjectToSceneP(Target, vSum); } }
public void UpdateDraw_Ray(Ray3f ray, int nStep) { // scene xform may have changed during steps (eg view rotation), so we // need to reconstruct our local frame Frame3f primCurW = scene.ToWorldFrame(primStartS); // step 1: find radius in plane // step 2: find height from plane float fY = MinDimension; if (nStep == 0) { Vector3f forwardDir = ray.Direction; Vector3f plane_hit = VRUtil.SafeRayPlaneIntersection(ray, forwardDir, primCurW.Origin, primCurW.Y); plane_hit_local = primCurW.ToFrameP(plane_hit); } else if (nStep == 1) { Vector3f plane_hit = primCurW.FromFrameP(plane_hit_local); Line3d l = new Line3d(plane_hit, primCurW.Y); fY = (float)DistLine3Ray3.MinDistanceLineParam(ray, l); } // figure out possible dimensions, clamp to ranges float planeX = MathUtil.SignedClamp(plane_hit_local[0], MinDimension, MaxDimension); float planeZ = MathUtil.SignedClamp(plane_hit_local[2], MinDimension, MaxDimension); float fR_plane = MathUtil.Clamp(plane_hit_local.Length, MinDimension / 2, MaxDimension / 2); fY = MathUtil.SignedClamp(fY, MinDimension, MaxDimension); // update frame primitive.Frame = primCurW; // update dimensions bool bIsCorner = (primitive.Center == CenterModes.Corner); float fScale = 1.0f; // object is not in scene coordinates! if (primitive.Type == MeshPrimitivePreview.PrimType.Cylinder) { primitive.Width = (bIsCorner) ? fR_plane * fScale : 2 * fR_plane * fScale; primitive.Depth = primitive.Width; primitive.Height = fY * fScale; } else if (primitive.Type == MeshPrimitivePreview.PrimType.Box) { primitive.Width = (bIsCorner) ? planeX * fScale : 2 * planeX * fScale; primitive.Depth = (bIsCorner) ? planeZ * fScale : 2 * planeZ * fScale; primitive.Height = fY * fScale; } else if (primitive.Type == MeshPrimitivePreview.PrimType.Sphere) { primitive.Width = (bIsCorner) ? fR_plane * fScale : 2 * fR_plane * fScale; primitive.Depth = primitive.Width; primitive.Height = Mathf.Sign(fY) * primitive.Width; } else { throw new NotImplementedException("DrawPrimitivesTool.UpdateDraw_Ray - type not supported"); } }
override public bool FindRayIntersection(Ray3f ray, out SORayHit hit) { hit = null; Ray sceneRay = GetScene().ToSceneRay(ray); Frame3f frameL = GetLocalFrame(CoordSpace.ObjectCoords); Ray localRay = frameL.ToFrame(sceneRay); float sceneWidth = GetScene().ToSceneDimension(visibleWidth); AxisAlignedBox3d hitBox = localBounds; hitBox.Expand(sceneWidth * 0.5f); Bounds hitBounds = new Bounds((Vector3)hitBox.Center, (Vector3)hitBox.Diagonal); if (hitBounds.IntersectRay(localRay) == false) { return(false); } double rayHitT; if (CurveUtils.FindClosestRayIntersection(curve, sceneWidth * 0.5f, localRay, out rayHitT)) { hit = new SORayHit(); hit.fHitDist = (float)rayHitT; hit.hitPos = localRay.GetPoint(hit.fHitDist); hit.hitPos = GetScene().ToWorldP(frameL.FromFrameP(hit.hitPos)); hit.hitNormal = Vector3.zero; hit.hitGO = root; hit.hitSO = this; return(true); } return(false); }
private void AddRightMiter(TPrintVertex printVertex, ToolpathPreviewMesh mesh, ref Frame3f frameMiter, ref Frame3f frameSegBefore, ToolpathPreviewJoint joint) { double miterScaleFactor = GetMiterScaleFactor(ref frameMiter, ref frameSegBefore); joint.InRight = joint.OutRight = mesh.AddVertex(vertexFactory(printVertex, frameMiter.FromFrameP(DiamondCrossSection.Right(printVertex.Dimensions, miterScaleFactor)), brightnessMin)); }
/// <summary> /// Set the position of the object frame for this SO without moving the mesh in the scene. /// The input frame is the new object frame. So, this is a frame "in scene coordinates" unless /// this object has a parent SceneObject (ie is not a child of Scene directly). In that case /// the frame needs to be specified relative to that SO. An easy way to do this is to via /// obj_pivot = GetLocalFrame(Object).FromFrame( SceneTransforms.SceneToObject(pivot_in_scene) ) /// TODO: specify frame coordpace as input argument? /// </summary> public void RepositionPivot(Frame3f objFrame) { //if (Parent is FScene == false) // throw new NotSupportedException("DMeshSO.RepositionMeshFrame: have not tested this!"); Frame3f curFrame = this.GetLocalFrame(CoordSpace.ObjectCoords); bool bNormals = mesh.HasVertexNormals; // map vertices to new frame foreach (int vid in mesh.VertexIndices()) { Vector3f v = (Vector3f)mesh.GetVertex(vid); v = curFrame.FromFrameP(ref v); v = objFrame.ToFrameP(ref v); mesh.SetVertex(vid, v); if (bNormals) { Vector3f n = mesh.GetVertexNormal(vid); n = curFrame.FromFrameV(ref n); n = objFrame.ToFrameV(ref n); mesh.SetVertexNormal(vid, n); } } // set new object frame SetLocalFrame(objFrame, CoordSpace.ObjectCoords); fast_mesh_update(bNormals, false); post_mesh_modified(); }
private void AddRightSquare(TPrintVertex printVertex, ToolpathPreviewMesh mesh, ref Frame3f frameSegBefore, ref Frame3f frameSegAfter, ToolpathPreviewJoint joint) { joint.InRight = mesh.AddVertex(vertexFactory(printVertex, frameSegBefore.FromFrameP(DiamondCrossSection.Left(printVertex.Dimensions)), brightnessMin)); joint.OutRight = mesh.AddVertex(vertexFactory(printVertex, frameSegAfter.FromFrameP(DiamondCrossSection.Right(printVertex.Dimensions)), brightnessMin)); }
protected override void OnPointUpdated(ControlPoint pt, Frame3f prevFrameS, bool isFirst) { Vector3f basePt = GetPointPosition(BasePointID, CoordSpace.SceneCoords).Origin; Vector3f frontPt = GetPointPosition(FrontPointID, CoordSpace.SceneCoords).Origin; Vector3f topPt = GetPointPosition(TopPointID, CoordSpace.SceneCoords).Origin; lastTargetFrameS = TargetSO.GetLocalFrame(CoordSpace.SceneCoords); Frame3f previewFrameS = lastTargetFrameS; // position next to original object previewFrameS = previewFrameS.Translated(1.1f * (float)meshBounds.Width * Vector3f.AxisX); Vector3f upAxis = (topPt - basePt).Normalized; // construct a frame perp to upAxis at midpoint, and project original and current fw points Frame3f upFrame = new Frame3f((topPt + basePt) * 0.5f, upAxis); Vector3f origFW = upFrame.ProjectToPlane(initialFrontPt, 2); origFW = (origFW - upFrame.Origin).Normalized; Vector3f curFW = upFrame.ProjectToPlane(frontPt, 2); curFW = (curFW - upFrame.Origin).Normalized; //float angle = MathUtil.PlaneAngleSignedD(origFW, curFW, upAxis); start_forward_pt_S = upFrame.FromFrameP(origFW); current_forward_pt_S = upFrame.FromFrameP(curFW); // construct rotation that aligns up axis with y-up Quaternionf upRotate = Quaternionf.FromTo(upAxis, Vector3f.AxisY); previewFrameS.Rotate(upRotate); // now rotate so that forward dir points along -Z //Quaternionf fwRotate = Quaternionf.AxisAngleD(Vector3f.AxisY, angle); //curFW = upRotate * curFW; Quaternionf fwRotate = Quaternionf.FromToConstrained(curFW, -Vector3f.AxisZ, Vector3f.AxisY); previewFrameS.Rotate(fwRotate); previewSO.SetLocalFrame(previewFrameS, CoordSpace.SceneCoords); lastPreviewFrameS = previewFrameS; }
private void update_axis_vertices(PolyCurveSO curveSO) { Vector3d[] verticesS = axisCurveSO.Curve.Vertices.ToArray(); Frame3f curveFrameS = axisCurveSO.GetLocalFrame(CoordSpace.SceneCoords); for (int k = 0; k < verticesS.Length; ++k) { verticesS[k] = curveFrameS.FromFrameP((Vector3f)verticesS[k]); } axisCurve.SetVertices(verticesS); }
private void AddCapBeforeJoint(Vector3d segmentDirection, TPrintVertex printVertex, ToolpathPreviewJoint joint, ToolpathPreviewMesh mesh) { var frame = new Frame3f(printVertex.Position); frame.AlignAxis(1, ToVector3f(segmentDirection)); joint.InTop = mesh.AddVertex(vertexFactory(printVertex, frame.FromFrameP(DiamondCrossSection.Top(printVertex.Dimensions)), brightnessMax)); joint.InRight = mesh.AddVertex(vertexFactory(printVertex, frame.FromFrameP(DiamondCrossSection.Right(printVertex.Dimensions)), brightnessMin)); joint.InBottom = mesh.AddVertex(vertexFactory(printVertex, frame.FromFrameP(DiamondCrossSection.Bottom(printVertex.Dimensions)), brightnessMax)); joint.InLeft = mesh.AddVertex(vertexFactory(printVertex, frame.FromFrameP(DiamondCrossSection.Left(printVertex.Dimensions)), brightnessMin)); mesh.AddTriangle(joint.InBottom, joint.InLeft, joint.InTop); mesh.AddTriangle(joint.InBottom, joint.InTop, joint.InRight); }
public static void ScaleMesh(NGonsCore.geometry3Sharp.mesh.DMesh3 mesh, Frame3f f, Vector3F vScale) { foreach (int vid in mesh.VertexIndices()) { Vector3D v = mesh.GetVertex(vid); Vector3F vScaledInF = f.ToFrameP((Vector3F)v) * vScale; Vector3D vNew = f.FromFrameP(vScaledInF); mesh.SetVertex(vid, vNew); // TODO: normals } }
public static void AppendMeshSO(DMeshSO appendTo, DMeshSO append) { FScene scene = appendTo.GetScene(); if (scene.IsSelected(appendTo)) { scene.Deselect(appendTo); } if (scene.IsSelected(append)) { scene.Deselect(append); } Frame3f f1 = appendTo.GetLocalFrame(CoordSpace.ObjectCoords); Vector3f scale1 = appendTo.GetLocalScale(); Frame3f f2 = append.GetLocalFrame(CoordSpace.ObjectCoords); Vector3f scale2 = append.GetLocalScale(); DMesh3 mesh1 = appendTo.Mesh; DMesh3 mesh2 = append.Mesh; foreach (int vid in mesh2.VertexIndices()) { // convert point in mesh2 to scene coords Vector3f v2 = (Vector3f)mesh2.GetVertex(vid); v2 *= scale2; Vector3f v2s = f2.FromFrameP(v2); // transfer that scene coord into local coords of mesh1 Vector3f v2in1 = f1.ToFrameP(v2s); v2in1 /= scale1; mesh2.SetVertex(vid, v2in1); if (mesh1.HasVertexNormals && mesh2.HasVertexNormals) { Vector3f n = mesh2.GetVertexNormal(vid); Vector3f ns = f2.FromFrameV(n); Vector3f ns2 = f1.ToFrameV(ns); mesh2.SetVertexNormal(vid, ns2); } } MeshEditor editor = new MeshEditor(mesh1); editor.AppendMesh(mesh2); appendTo.NotifyMeshEdited(); // [TODO] change record! scene.RemoveSceneObject(append, false); }
public static void FromFrame(IDeformableMesh mesh, Frame3f f) { int NV = mesh.MaxVertexID; bool bHasNormals = mesh.HasVertexNormals; for (int vid = 0; vid < NV; ++vid) { if (mesh.IsVertex(vid)) { Vector3D vf = mesh.GetVertex(vid); Vector3D v = f.FromFrameP((Vector3F)vf); mesh.SetVertex(vid, v); if (bHasNormals) { Vector3F n = mesh.GetVertexNormal(vid); Vector3F nf = f.FromFrameV(n); mesh.SetVertexNormal(vid, nf); } } } }
public DMeshSO BuildSO(FScene scene, SOMaterial material) { DMesh3 revolveMesh = UnityUtil.UnityMeshToDMesh(meshObject.GetSharedMesh(), false); // move axis frame to center of bbox of mesh, measured in axis frame Frame3f useF = OutputFrame; AxisAlignedBox3f boundsInFrame = (AxisAlignedBox3f)BoundsUtil.BoundsInFrame(revolveMesh.Vertices(), useF); useF.Origin = useF.FromFrameP(boundsInFrame.Center); // transform mesh into this frame MeshTransforms.ToFrame(revolveMesh, useF); // create new so DMeshSO meshSO = new DMeshSO(); meshSO.Create(revolveMesh, material); meshSO.SetLocalFrame(useF, CoordSpace.ObjectCoords); return(meshSO); }
/// <summary> /// input objectF is in Object (local) coords of so, apply all intermediate /// transforms to get it to Scene coords /// </summary> public static Vector3f ObjectToSceneP(SceneObject so, Vector3f objectPt) { SceneObject curSO = so; while (curSO != null) { Frame3f curF = curSO.GetLocalFrame(CoordSpace.ObjectCoords); Vector3f scale = curSO.GetLocalScale(); objectPt = curF.FromFrameP(objectPt * scale); SOParent parent = curSO.Parent; if (parent is FScene) { return(objectPt); } curSO = (parent as SceneObject); } if (curSO == null) { DebugUtil.Error("SceneTransforms.ObjectToSceneP: found null parent SO!"); } return(objectPt); }
// returns max edge length of moved vertices, after deformation public override DeformInfo Apply(Frame3f vNextPos) { // if we did not move brush far enough, don't do anything Vector3D vDelta = (vNextPos.Origin - vPreviousPos.Origin); if (vDelta.Length < 0.0001f) { return new DeformInfo() { maxEdgeLenSqr = 0, minEdgeLenSqr = double.MaxValue } } ; // otherwise apply base deformation DeformF = (idx, t) => { Vector3D v = vPreviousPos.ToFrameP(Curve[idx]); Vector3D vNew = vNextPos.FromFrameP(v); return(Vector3D.Lerp(Curve[idx], vNew, t)); }; return(base.Apply(vNextPos)); } }
/// <summary> /// This is the action we give to the trim-scan tool, to run on accept /// </summary> public static void CropScanFromSelection(DMeshSO so, MeshFaceSelection selection, object tool) { DMesh3 beforeMesh = new DMesh3(so.Mesh); DMesh3 mesh = so.Mesh; // [RMS] if we are using the two-point tool, then we can use the user input points to // try to figure out an up axis, by assuming the first point is on the base of the scan. Steps are: // 1) guess a midpoint. Currently centroid of upper-half of geodesic selection. // 2) construct up axis as (midpoint-basepoint). this axis to Y-up. Vector3f upAxisS = Vector3f.AxisY; TwoPointFaceSelectionTool ptool = tool as TwoPointFaceSelectionTool; if (ptool != null) { var cache = ptool.SelectionCache; Interval1d range = new Interval1d(cache.CurrentScalarThreshold / 2, cache.CurrentScalarThreshold); List <int> triangles = new List <int>(selection.Count); cache.FindTrianglesInScalarInterval(range, triangles); Vector3d c = MeshMeasurements.Centroid(triangles, mesh.GetTriCentroid); Vector3d cS = SceneTransforms.ObjectToSceneP(so, c); Vector3d basePosS = ptool.SourcePositionS.Origin; upAxisS = (Vector3f)(cS - basePosS).Normalized; } // crop scan and fill top hole List <int> borderTris = selection.FindBorderTris(); MeshEditor editor = new MeshEditor(mesh); editor.RemoveTriangles((tid) => { return(selection.IsSelected(tid) == false); }, true); if (OGActions.FillHoleInScan) { SmoothedHoleFill fill = new SmoothedHoleFill(mesh) { TargetEdgeLength = 2.5f, SmoothAlpha = 0.5f, BorderHintTris = borderTris, OffsetDirection = SceneTransforms.SceneToObjectN(so, upAxisS), OffsetDistance = (ptool != null) ? 25.0 : 0.0 }; fill.Apply(); } so.NotifyMeshEdited(); DMesh3 afterMesh = new DMesh3(so.Mesh); so.GetScene().History.PushChange(new ReplaceEntireMeshChange(so, beforeMesh, afterMesh), true); mesh = so.Mesh; // Now we auto-align the scan so it points upwards, and then // recenter pivot and shift to above ground plane if (ptool != null) { Vector3d basePosS = ptool.SourcePositionS.Origin; Quaternionf alignUp = Quaternionf.FromTo(upAxisS, Vector3f.AxisY); // rotate part so that axis points up Frame3f curF = so.GetLocalFrame(CoordSpace.SceneCoords); Frame3f newF = curF.Rotated(alignUp); TransformSOChange alignUpChange = new TransformSOChange(so, curF, newF, CoordSpace.SceneCoords); basePosS = newF.FromFrameP(curF.ToFrameP(basePosS)); // map to new frame so.GetScene().History.PushChange(alignUpChange, false); // recenter pivot at bbox center // [RMS] previously was using vertex centroid, but this is then affected by mesh density // (maybe tri centroid? but bbox makes more sense...and below we assume box center) Vector3d centerL = mesh.CachedBounds.Center; Vector3d centerO = newF.FromFrameP(centerL); Frame3f newPivotO = new Frame3f(centerO); so.GetScene().History.PushChange(new RepositionPivotChangeOp(newPivotO, so), false); // position above ground plane AxisAlignedBox3d bounds = so.Mesh.CachedBounds; float h = (float)bounds.Height; Vector3f o = newPivotO.Origin; Vector3f translateO = new Vector3f(-o.x, h * 0.5f - o.y + BaseHeightAboveGroundPlaneMM, -o.z); //Vector3f translateO = new Vector3f(0, h * 0.5f - o.y + BaseHeightAboveGroundPlaneMM, 0); newPivotO.Translate(translateO); so.GetScene().History.PushChange(new TransformSOChange(so, newPivotO, CoordSpace.ObjectCoords), false); // save base point in frame of scan basePosS += translateO; Vector3d basePosL = SceneTransforms.SceneToObjectP(so, basePosS); OG.Scan.UserBasePoint = basePosL; } so.GetScene().History.PushInteractionCheckpoint(); }
public Vector3D FromGrid(Vector3i gridpoint) { Vector3F pointf = CellSize * (Vector3F)gridpoint; return((Vector3D)GridFrame.FromFrameP(pointf)); }
public override void Generate() { int nRings = Curve.Length; int nRingSize = (NoSharedVertices) ? Slices + 1 : Slices; int nCapVertices = (NoSharedVertices) ? Slices + 1 : 1; if (Capped == false) { nCapVertices = 0; } vertices = new VectorArray3d(nRingSize * nRings + 2 * nCapVertices); uv = new VectorArray2f(vertices.Count); normals = new VectorArray3f(vertices.Count); int nSpanTris = (nRings - 1) * (2 * Slices); int nCapTris = (Capped) ? 2 * Slices : 0; triangles = new IndexArray3i(nSpanTris + nCapTris); float fDelta = (float)((Math.PI * 2.0) / Slices); Frame3f f = Axis; // generate tube for (int ri = 0; ri < nRings; ++ri) { Vector3D v_along = Curve[ri]; Vector3F v_frame = f.ToFrameP((Vector3F)v_along); float uv_along = (float)ri / (float)(nRings - 1); // generate vertices int nStartR = ri * nRingSize; for (int j = 0; j < nRingSize; ++j) { float angle = (float)j * fDelta; // [TODO] this is not efficient...use Matrix3f? Vector3F v_rot = Quaternionf.AxisAngleR(Vector3F.AxisY, angle) * v_frame; Vector3D v_new = f.FromFrameP(v_rot); int k = nStartR + j; vertices[k] = v_new; float uv_around = (float)j / (float)(nRingSize); uv[k] = new Vector2F(uv_along, uv_around); // [TODO] proper normal Vector3F n = (Vector3F)(v_new - f.Origin).Normalized; normals[k] = n; } } // generate triangles int ti = 0; for (int ri = 0; ri < nRings - 1; ++ri) { int r0 = ri * nRingSize; int r1 = r0 + nRingSize; for (int k = 0; k < nRingSize - 1; ++k) { triangles.Set(ti++, r0 + k, r0 + k + 1, r1 + k + 1, Clockwise); triangles.Set(ti++, r0 + k, r1 + k + 1, r1 + k, Clockwise); } if (NoSharedVertices == false) // close disc if we went all the way { triangles.Set(ti++, r1 - 1, r0, r1, Clockwise); triangles.Set(ti++, r1 - 1, r1, r1 + nRingSize - 1, Clockwise); } } if (Capped) { // find avg start loop size Vector3D vAvgStart = Vector3D.Zero, vAvgEnd = Vector3D.Zero; for (int k = 0; k < Slices; ++k) { vAvgStart += vertices[k]; vAvgEnd += vertices[(nRings - 1) * nRingSize + k]; } vAvgStart /= (double)Slices; vAvgEnd /= (double)Slices; Frame3f fStart = f; fStart.Origin = (Vector3F)vAvgStart; Frame3f fEnd = f; fEnd.Origin = (Vector3F)vAvgEnd; // add endcap verts int nBottomC = nRings * nRingSize; vertices[nBottomC] = fStart.Origin; uv[nBottomC] = new Vector2F(0.5f, 0.5f); normals[nBottomC] = -fStart.Z; startCapCenterIndex = nBottomC; int nTopC = nBottomC + 1; vertices[nTopC] = fEnd.Origin; uv[nTopC] = new Vector2F(0.5f, 0.5f); normals[nTopC] = fEnd.Z; endCapCenterIndex = nTopC; if (NoSharedVertices) { // duplicate first loop and make a fan w/ bottom-center int nExistingB = 0; int nStartB = nTopC + 1; for (int k = 0; k < Slices; ++k) { vertices[nStartB + k] = vertices[nExistingB + k]; //uv[nStartB + k] = (Vector2f)Polygon.Vertices[k].Normalized; float angle = (float)k * fDelta; double cosa = Math.Cos(angle), sina = Math.Sin(angle); uv[nStartB + k] = new Vector2F(0.5f * (1.0f + cosa), 0.5f * (1 + sina)); normals[nStartB + k] = normals[nBottomC]; } append_disc(Slices, nBottomC, nStartB, true, Clockwise, ref ti); // duplicate second loop and make fan int nExistingT = nRingSize * (nRings - 1); int nStartT = nStartB + Slices; for (int k = 0; k < Slices; ++k) { vertices[nStartT + k] = vertices[nExistingT + k]; //uv[nStartT + k] = (Vector2f)Polygon.Vertices[k].Normalized; float angle = (float)k * fDelta; double cosa = Math.Cos(angle), sina = Math.Sin(angle); uv[nStartT + k] = new Vector2F(0.5f * (1.0f + cosa), 0.5f * (1 + sina)); normals[nStartT + k] = normals[nTopC]; } append_disc(Slices, nTopC, nStartT, true, !Clockwise, ref ti); } else { append_disc(Slices, nBottomC, 0, true, Clockwise, ref ti); append_disc(Slices, nTopC, nRingSize * (nRings - 1), true, !Clockwise, ref ti); } } }
// [TODO] projection pass // - only project vertices modified by smooth pass? // - and/or verts in set of modified edges? protected virtual void TrackedFaceProjectionPass() { IOrientedProjectionTarget normalTarget = ProjectionTarget as IOrientedProjectionTarget; if (normalTarget == null) { throw new Exception("RemesherPro.TrackedFaceProjectionPass: projection target does not have normals!"); } InitializeBuffersForFacePass(); SpinLock buffer_lock = new SpinLock(); // this function computes rotated position of triangle, such that it // aligns with face normal on target surface. We accumulate weighted-average // of vertex positions, which we will then use further down where possible. Action <int> process_triangle = (tid) => { Vector3d normal; double area; Vector3d centroid; mesh.GetTriInfo(tid, out normal, out area, out centroid); Vector3d projNormal; Vector3d projPos = normalTarget.Project(centroid, out projNormal); Index3i tv = mesh.GetTriangle(tid); Vector3d v0 = mesh.GetVertex(tv.a), v1 = mesh.GetVertex(tv.b), v2 = mesh.GetVertex(tv.c); // ugh could probably do this more efficiently... Frame3f triF = new Frame3f(centroid, normal); v0 = triF.ToFrameP(ref v0); v1 = triF.ToFrameP(ref v1); v2 = triF.ToFrameP(ref v2); triF.AlignAxis(2, (Vector3f)projNormal); triF.Origin = (Vector3f)projPos; v0 = triF.FromFrameP(ref v0); v1 = triF.FromFrameP(ref v1); v2 = triF.FromFrameP(ref v2); double dot = normal.Dot(projNormal); dot = MathUtil.Clamp(dot, 0, 1.0); double w = area * (dot * dot * dot); bool taken = false; buffer_lock.Enter(ref taken); vBufferV[tv.a] += w * v0; vBufferVWeights[tv.a] += w; vBufferV[tv.b] += w * v1; vBufferVWeights[tv.b] += w; vBufferV[tv.c] += w * v2; vBufferVWeights[tv.c] += w; buffer_lock.Exit(); }; // compute face-aligned vertex positions gParallel.ForEach(mesh.TriangleIndices(), process_triangle); // ok now we filter out all the positions we can't change, as well as vertices that // did not actually move. We also queue any edges that moved far enough to fall // under min/max edge length thresholds gParallel.ForEach(mesh.VertexIndices(), (vID) => { vModifiedV[vID] = false; if (vBufferVWeights[vID] < MathUtil.ZeroTolerance) { return; } if (vertex_is_constrained(vID)) { return; } if (VertexControlF != null && (VertexControlF(vID) & VertexControl.NoProject) != 0) { return; } Vector3d curpos = mesh.GetVertex(vID); Vector3d projPos = vBufferV[vID] / vBufferVWeights[vID]; if (curpos.EpsilonEqual(projPos, MathUtil.ZeroTolerancef)) { return; } vModifiedV[vID] = true; vBufferV[vID] = projPos; foreach (int eid in mesh.VtxEdgesItr(vID)) { Index2i ev = Mesh.GetEdgeV(eid); int othervid = (ev.a == vID) ? ev.b : ev.a; Vector3d otherv = mesh.GetVertex(othervid); double old_len = curpos.Distance(otherv); double new_len = projPos.Distance(otherv); if (new_len < MinEdgeLength || new_len > MaxEdgeLength) { queue_edge_safe(eid); } } }); // update vertices ApplyVertexBuffer(true); }
override public void Generate() { if (Polygon == null) { Polygon = Polygon2d.MakeCircle(1.0f, 8); } int Slices = Polygon.VertexCount; int nRings = Vertices.Count; int nRingSize = (NoSharedVertices) ? Slices + 1 : Slices; int nCapVertices = (NoSharedVertices) ? Slices + 1 : 1; if (Capped == false) { nCapVertices = 0; } vertices = new VectorArray3d(nRings * nRingSize + 2 * nCapVertices); uv = new VectorArray2f(vertices.Count); normals = new VectorArray3f(vertices.Count); int nSpanTris = (Vertices.Count - 1) * (2 * Slices); int nCapTris = (Capped) ? 2 * Slices : 0; triangles = new IndexArray3i(nSpanTris + nCapTris); Frame3f fCur = new Frame3f(Frame); Vector3D dv = CurveUtils.GetTangent(Vertices, 0);; fCur.Origin = (Vector3F)Vertices[0]; fCur.AlignAxis(2, (Vector3F)dv); Frame3f fStart = new Frame3f(fCur); // generate tube for (int ri = 0; ri < nRings; ++ri) { // propagate frame if (ri != 0) { Vector3D tan = CurveUtils.GetTangent(Vertices, ri); fCur.Origin = (Vector3F)Vertices[ri]; if (ri == 11) { dv = tan; } fCur.AlignAxis(2, (Vector3F)tan); } float uv_along = (float)ri / (float)(nRings - 1); // generate vertices int nStartR = ri * nRingSize; for (int j = 0; j < nRingSize; ++j) { float uv_around = (float)j / (float)(nRings); int k = nStartR + j; Vector2D pv = Polygon.Vertices[j % Slices]; Vector3D v = fCur.FromFrameP((Vector2F)pv, 2); vertices[k] = v; uv[k] = new Vector2F(uv_along, uv_around); Vector3F n = (Vector3F)(v - fCur.Origin).Normalized; normals[k] = n; } } // generate triangles int ti = 0; for (int ri = 0; ri < nRings - 1; ++ri) { int r0 = ri * nRingSize; int r1 = r0 + nRingSize; for (int k = 0; k < nRingSize - 1; ++k) { triangles.Set(ti++, r0 + k, r0 + k + 1, r1 + k + 1, Clockwise); triangles.Set(ti++, r0 + k, r1 + k + 1, r1 + k, Clockwise); } if (NoSharedVertices == false) // close disc if we went all the way { triangles.Set(ti++, r1 - 1, r0, r1, Clockwise); triangles.Set(ti++, r1 - 1, r1, r1 + nRingSize - 1, Clockwise); } } if (Capped) { // add endcap verts int nBottomC = nRings * nRingSize; vertices[nBottomC] = fStart.Origin; uv[nBottomC] = new Vector2F(0.5f, 0.5f); normals[nBottomC] = -fStart.Z; startCapCenterIndex = nBottomC; int nTopC = nBottomC + 1; vertices[nTopC] = fCur.Origin; uv[nTopC] = new Vector2F(0.5f, 0.5f); normals[nTopC] = fCur.Z; endCapCenterIndex = nTopC; if (NoSharedVertices) { // duplicate first loop and make a fan w/ bottom-center int nExistingB = 0; int nStartB = nTopC + 1; for (int k = 0; k < Slices; ++k) { vertices[nStartB + k] = vertices[nExistingB + k]; uv[nStartB + k] = (Vector2F)Polygon.Vertices[k].Normalized; normals[nStartB + k] = normals[nBottomC]; } append_disc(Slices, nBottomC, nStartB, true, Clockwise, ref ti); // duplicate second loop and make fan int nExistingT = nRingSize * (nRings - 1); int nStartT = nStartB + Slices; for (int k = 0; k < Slices; ++k) { vertices[nStartT + k] = vertices[nExistingT + k]; uv[nStartT + k] = (Vector2F)Polygon.Vertices[k].Normalized; normals[nStartT + k] = normals[nTopC]; } append_disc(Slices, nTopC, nStartT, true, !Clockwise, ref ti); } else { append_disc(Slices, nBottomC, 0, true, Clockwise, ref ti); append_disc(Slices, nTopC, nRingSize * (nRings - 1), true, !Clockwise, ref ti); } } }
public void UpdateDraw_Spatial(Ray3f ray, Frame3f handFrame, int nStep) { // scene xform may have changed during steps (eg view rotation), so we // need to reconstruct our local frame Frame3f primCurW = scene.ToWorldFrame(primStartS); // try snap points SnapResult snap = Snaps.FindHitSnapPoint(ray); bool bHaveSnap = (snap != null); Frame3f snapF = (bHaveSnap) ? scene.ToWorldFrame(snap.FrameS) : Frame3f.Identity; // step 1: find radius in plane if (nStep == 0) { if (bHaveSnap) { plane_hit_local = primCurW.ToFrameP( primCurW.ProjectToPlane(snapF.Origin, 1)); } else { Vector3f forwardDir = ray.Direction; Vector3f plane_hit = VRUtil.SafeRayPlaneIntersection(ray, forwardDir, primCurW.Origin, primCurW.Y); plane_hit_local = primCurW.ToFrameP(plane_hit); } } float fX = MathUtil.SignedClamp(plane_hit_local[0], MinDimension, MaxDimension); float fY = MinDimension; float fZ = MathUtil.SignedClamp(plane_hit_local[2], MinDimension, MaxDimension); float fR_plane = MathUtil.Clamp(plane_hit_local.Length, MinDimension / 2, MaxDimension / 2); // step 2: find height from plane if (nStep == 1) { Vector3f plane_hit = primCurW.FromFrameP(plane_hit_local); Line3d l = new Line3d(plane_hit, primCurW.Y); if (bHaveSnap) { fY = (float)l.Project(snapF.Origin); } else { Vector3f handTip = handFrame.Origin + SceneGraphConfig.HandTipOffset * handFrame.Z; float fHandDist = (float)l.DistanceSquared(handTip); if (fHandDist < fR_plane * 1.5f) { fY = (float)l.Project(handTip); } else { fY = (float)DistLine3Ray3.MinDistanceLineParam(ray, l); } } } // figure out possible dimensions, clamp to ranges fY = MathUtil.SignedClamp(fY, MinDimension, MaxDimension); // update frame primitive.Frame = primCurW; // update dimensions bool bIsCorner = (primitive.Center == CenterModes.Corner); float fScale = 1.0f; // object is not in scene coordinates! if (primitive.Type == MeshPrimitivePreview.PrimType.Cylinder) { primitive.Width = (bIsCorner) ? fR_plane * fScale : 2 * fR_plane * fScale; primitive.Depth = primitive.Width; //primitive.Depth = Mathf.Sign(fZ) * primitive.Width; //primitive.Width = Mathf.Sign(fX) * primitive.Width; primitive.Height = fY * fScale; } else if (primitive.Type == MeshPrimitivePreview.PrimType.Box) { primitive.Width = (bIsCorner) ? fX : 2 * fX * fScale; primitive.Depth = (bIsCorner) ? fZ : 2 * fZ * fScale; primitive.Height = fY * fScale; } else if (primitive.Type == MeshPrimitivePreview.PrimType.Sphere) { primitive.Width = (bIsCorner) ? fR_plane * fScale : 2 * fR_plane * fScale; primitive.Depth = primitive.Height = primitive.Width; //primitive.Depth = Mathf.Sign(fZ) * primitive.Width; //primitive.Width = Mathf.Sign(fX) * primitive.Width; //primitive.Height = Mathf.Sign(fY) * primitive.Width; } else { throw new NotImplementedException("SnapDrawPrimitivesTool.UpdateDraw_Ray - type not supported"); } }