// 被上面函数引用,用来计算手臂的slicer private void GetMostMatchedArmSlicer(ref SlicerRecord chestshoul, SlicerRecord Aend, ref SlicerRecord nArm0) { double target = Math.Abs(Aend.radius - nArm0.radius); SlicerRecord ret = null; int currLoopTimes = 100; Vector3d rootCentre = Aend.slicerCenter; double currInterval = (rootCentre - nArm0.slicerCenter).Length() / currLoopTimes; for (int i = 0; i < currLoopTimes; i++) { Vector3d refSkeNode = rootCentre + ((double)i / currLoopTimes) * (nArm0.slicerCenter - rootCentre); Vector3d refNodeNormal0 = ((double)i / currLoopTimes) * Aend.slicerNormal + (1 - (double)i / currLoopTimes) * nArm0.slicerNormal; Plane nodePlane0 = new Plane(refSkeNode, refNodeNormal0); SlicerRecord t1 = new SlicerRecord(segMesh, nodePlane0); TrickForSegment.BuildNewArmTopslicer(chestshoul, t1, out SlicerRecord torsoIntp); if (torsoIntp != null && Math.Abs(Aend.radius - torsoIntp.radius) < target) { target = Math.Abs(Aend.radius - torsoIntp.radius); ret = torsoIntp; } } if (ret != null) { nArm0 = ret; } }
/// <summary> /// 环切切片得到角度均匀的环片 /// </summary> /// <param name="s"></param> /// <param name="n"></param> /// <returns></returns> public List <SlicerRecordUniform> RadialSlicerCut(List <SlicerRecord> s, int n) { int[] nSeq = Enumerable.Range(0, n).ToArray(); double[] piSeq = Enumerable.Repeat <double>(2 * Math.PI, n).ToArray(); double[] phi = piSeq.Zip(nSeq, (x, y) => x * y / n).ToArray(); List <SlicerRecordUniform> ret = new List <SlicerRecordUniform>(); for (int i = 0; i < s.Count; i++) { List <Vector3d> tempnp = new List <Vector3d>(); SlicerRecord tempSR = s[i]; Vector3d plcen = s[i].slicerCenter; Vector3d slicernv = s[i].slicerNormal; // 这里的参考旋转轴需要实时改变,针对不同的模型,与下面的radiaRay变量搭配 // 可以使用3个轴的,也可以使用8个象限的旋转轴 Vector3d radialSpinAx = new Vector3d(0, 1, 0); double cost = radialSpinAx.Dot(slicernv); // cost is cos(t) //List<Vector3d> debugNormal = new List<Vector3d>(); for (int k = 0; k < n; k++) { double maxDist = double.MinValue; Vector3d radialRay = new Vector3d(Math.Cos(phi[k]), 0, Math.Sin(phi[k])); Vector3d radialPlaneNormal = new Vector3d(Math.Cos(phi[k]), 0, -Math.Sin(phi[k])); Vector3d newRay = Vector3d.RotationRodriguesMethod(radialSpinAx.Cross(slicernv), radialRay, cost).Normalize(); Plane halfCutPlane = new Plane(plcen, newRay.Cross(slicernv)); //debugNormal.Add(newRay); //int dir = slicernv.Dot(new Vector3d(0, 1, 0)) > 0 ? 1 : -1; // 这个阶段是为了找到隔断的点 Vector3d maxOutP = new Vector3d(); for (int j = 0; j < tempSR.lineList.Count; j++) { Vector3d p1 = tempSR.pointInfoList[tempSR.lineList[j].p1].p; Vector3d p2 = tempSR.pointInfoList[tempSR.lineList[j].p2].p; double tempP1Planedist = PointPlaneDistance(p1, halfCutPlane); double tempP2Planedist = PointPlaneDistance(p2, halfCutPlane); if (tempP2Planedist * tempP1Planedist > 0) { continue; // 检测交叉 } Vector3d outP = (p1 * Math.Abs(tempP2Planedist) + p2 * Math.Abs(tempP1Planedist)) / (Math.Abs(tempP1Planedist) + Math.Abs(tempP2Planedist)); if ((outP - plcen).Dot(newRay) < 0) { continue; // 检测射线方向 } if ((outP - plcen).Length() > maxDist) { maxDist = (outP - plcen).Length(); maxOutP = outP; } } if (maxOutP != (Vector3d) new Vector3d()) { tempnp.Add(maxOutP); } } ret.Add(new SlicerRecordUniform(tempnp, plcen)); } return(ret); }
private void AddtionCreateSlicer(List <SlicerRecord>[] bodySlicerGroup) // 增加大腿与手臂 { SlicerRecord bottomTorso = bodySlicerGroup[(int)bodypart.Torso].Last(); SlicerRecord leg0top = bodySlicerGroup[(int)bodypart.Leg_0].First(); SlicerRecord leg1top = bodySlicerGroup[(int)bodypart.Leg_1].First(); SlicerRecord chestshoul = TrickForSegment.chestshoul; TrickForSegment.BuildSeperateLimbSlicer(leg0top, leg1top, out SlicerRecord nLeg0, out SlicerRecord nLeg1); // Arm SlicerRecord arm0top = bodySlicerGroup[(int)bodypart.Arm_0].First(); SlicerRecord arm1top = bodySlicerGroup[(int)bodypart.Arm_1].First(); //for(int i =0;i< bodySlicerGroup[(int)bodypart.Torso].Count; i++) //{ TrickForSegment.BuildTorsoWithArmCutting(bodySlicerGroup[(int)bodypart.Torso], ref arm0top); TrickForSegment.BuildTorsoWithArmCutting(bodySlicerGroup[(int)bodypart.Torso], ref arm1top); bodySlicerGroup[(int)bodypart.Arm_0][0] = arm0top; bodySlicerGroup[(int)bodypart.Arm_1][0] = arm1top; //TrickForSegment.BuildTorsoSlicerCutByArm(torsoI, arm1top, out torsoI); //bodySlicerGroup[(int)bodypart.Torso][i] = torsoI; //} //TrickForSegment.BuildNewArmTopslicer(chestshoul, arm0top, out SlicerRecord nArm0); //TrickForSegment.BuildNewArmTopslicer(chestshoul, arm1top, out SlicerRecord nArm1); //GetMostMatchedArmSlicer(ref chestshoul,bodySlicerGroup[(int)bodypart.Arm_0][1],ref nArm0); //GetMostMatchedArmSlicer(ref chestshoul,bodySlicerGroup[(int)bodypart.Arm_1][1],ref nArm1); bodySlicerGroup[(int)bodypart.Head][0] = new SlicerRecord(bodySlicerGroup[(int)bodypart.Torso][0]); // 将躯干的slicer置换到头部 bodySlicerGroup[(int)bodypart.Head][0].slicerNormal = -bodySlicerGroup[(int)bodypart.Head][0].slicerNormal; bodySlicerGroup[(int)bodypart.Leg_0][0] = nLeg0; bodySlicerGroup[(int)bodypart.Leg_1][0] = nLeg1; // add torso slicer in the bottom of torso TrickForSegment.BuildCombinedTorsoSlicer(leg0top, leg1top, out SlicerRecord torsoRoot); List <SlicerRecord> Torsoseq = new List <SlicerRecord>(); Vector3d rootCentre = torsoRoot.slicerCenter; int currLoopTimes = (int)(Math.Floor((rootCentre - bottomTorso.slicerCenter).Length() / interval)); double currInterval = (rootCentre - bottomTorso.slicerCenter).Length() / currLoopTimes; for (int i = 1; i < currLoopTimes; i++) { Vector3d refSkeNode = rootCentre + ((double)i / currLoopTimes) * (bottomTorso.slicerCenter - rootCentre); Vector3d refNodeNormal0 = ((double)i / currLoopTimes) * bottomTorso.slicerNormal + (1 - (double)i / currLoopTimes) * leg0top.slicerNormal; Vector3d refNodeNormal1 = ((double)i / currLoopTimes) * bottomTorso.slicerNormal + (1 - (double)i / currLoopTimes) * leg1top.slicerNormal; Plane nodePlane0 = new Plane(refSkeNode, refNodeNormal0); Plane nodePlane1 = new Plane(refSkeNode, refNodeNormal1); SlicerRecord t0 = new SlicerRecord(segMesh, nodePlane1); SlicerRecord t1 = new SlicerRecord(segMesh, nodePlane0); TrickForSegment.BuildCombinedTorsoSlicer(t0, t1, out SlicerRecord torsoIntp); Torsoseq.Add(torsoIntp); } Torsoseq.Reverse(); Torsoseq.Add(torsoRoot); bodySlicerGroup[(int)bodypart.Torso].AddRange(Torsoseq); }
public SlicerRecord(SlicerRecord ins1) { this.slicerNormal = ins1.slicerNormal; this.slicerCenter = ins1.slicerCenter; this.skeletonNodepos = ins1.skeletonNodepos; this.radius = ins1.radius; this.perimeter = ins1.perimeter; this.pointInfoList = new List <PointRecord>(ins1.pointInfoList.ToArray()); this.lineList = new List <Lineindex>(ins1.lineList.ToArray()); }
public static void BuildSeperateLimbSlicer(SlicerRecord s1, SlicerRecord s2, out SlicerRecord outS1, out SlicerRecord outS2) { if (CreateTwoHalfSlicer(s1, s2, -(s1.slicerNormal + s2.slicerNormal).Normalize(), out HalfSlicerRecord s1h, out HalfSlicerRecord s2h)) { outS1 = new SlicerRecord(s1h); outS2 = new SlicerRecord(s2h); }
private static void DisplaySlicer(SlicerRecord sli) { float skeletonNodeSize = 6.0f; float[] newcolor = ColorHelper.byte2float(Color.Gold); // draw center GL.glPointSize(skeletonNodeSize); GL.glColor3f(newcolor[0], newcolor[1], newcolor[2]); GL.glBegin(GL.GL_POINTS); GL.glVertex3d(sli.slicerCenter.x, sli.slicerCenter.y, sli.slicerCenter.z); GL.glEnd(); newcolor = ColorHelper.byte2float(Color.Black); // mark skeleton node GL.glPointSize(skeletonNodeSize + 3); GL.glColor3f(newcolor[0], newcolor[1], newcolor[2]); GL.glBegin(GL.GL_POINTS); GL.glVertex3d(sli.skeletonNodepos.x, sli.skeletonNodepos.y, sli.skeletonNodepos.z); GL.glEnd(); // draw points newcolor = ColorHelper.byte2float(Color.Orange); for (int i = 0; i < sli.pointInfoList.Count; i++) { GL.glPointSize(skeletonNodeSize); GL.glColor3f(newcolor[0], newcolor[1], newcolor[2]); GL.glBegin(GL.GL_POINTS); GL.glVertex3d(sli.pointInfoList[i].p.x, sli.pointInfoList[i].p.y, sli.pointInfoList[i].p.z); GL.glEnd(); } // draw lines and mark mesh triangles newcolor = ColorHelper.byte2float(Color.Orange); float[] facemark = ColorHelper.byte2float(Color.Pink); for (int i = 0; i < sli.lineList.Count; i++) { GL.glColor3f(newcolor[0], newcolor[1], newcolor[2]); GL.glLineWidth(2.0f); GL.glBegin(GL.GL_LINES); int p1 = sli.lineList[i].p1; int p2 = sli.lineList[i].p2; GL.glVertex3d(sli.pointInfoList[p1].p.x, sli.pointInfoList[p1].p.y, sli.pointInfoList[p1].p.z); GL.glVertex3d(sli.pointInfoList[p2].p.x, sli.pointInfoList[p2].p.y, sli.pointInfoList[p2].p.z); GL.glEnd(); } }
public HalfSlicerRecord(SlicerRecord slicer, int i1, int i2) { this.slicerNormal = slicer.slicerNormal; if (i2 - i1 == slicer.pointInfoList.Count - 1) { this.pointInfoList = slicer.pointInfoList; this.lineList = slicer.lineList; } else // normal { this.lineList = slicer.lineList.GetRange(i1, i2 - i1 + 1); // 添加从i1开始的数据,一直添加到i2 this.pointInfoList = slicer.pointInfoList.GetRange(i1, i2 - i1 + 1); if (i2 == slicer.pointInfoList.Count - 1) // 即最后一位的索引 { // add slicer fid and p this.pointInfoList.Add(new PointRecord(slicer.pointInfoList[0].p, slicer.lineList[0].fid)); } else { this.pointInfoList.Add(new PointRecord(slicer.pointInfoList[i2].p, slicer.lineList[i2].fid)); } } }
/// <summary> /// 这个函数是用来对手臂上的分片进行特殊处理的,是CreateSlicerSequence的分支,后面还需要对躯干与手臂进行交叉 /// </summary> /// <param name="bdt"></param> /// <param name="interval"></param> /// <param name="slicerSeq"></param> private void CreateArmSlicerSequence(bodypart bdt, double interval, List <SlicerRecord> slicerSeq) { List <int> skeletonSeq = partSkelSeq[(int)bdt]; int foreArmIndex = skeletonSeq.Count / 8 - 1; Vector3d torso2ArmDir = skeRcd.nodePosList[skeletonSeq[foreArmIndex]] - skeRcd.nodePosList[skeletonSeq[0]]; // 得到初始的法向量 Vector3d armEndDir = skeRcd.nodePosList[skeletonSeq[skeletonSeq.Count - 1]] - skeRcd.nodePosList[skeletonSeq[skeletonSeq.Count - 2]]; // 得到末端的法向量 #region get the length of skeleton and compute two intervals of relative slicer sknode. double pSkeLen = 0.0; for (int i = 0; i < skeletonSeq.Count - 1; i++) { pSkeLen += (skeRcd.nodePosList[skeletonSeq[i + 1]] - skeRcd.nodePosList[skeletonSeq[i]]).Length(); } interval = pSkeLen / (Math.Floor(pSkeLen / interval)) + interval / 200; double oxterInterval = interval / 5; // 寻找腋窝的interval 细化 #endregion //Vector3d nodeNV; Vector3d nodepos; Plane nodePlane; List <KeyValuePair <int, int> > skeEndIndex = new List <KeyValuePair <int, int> >(); // 因为起点的slicer并不需要所以直接舍弃 double globalPos = oxterInterval; // 整个骨架序列线段中的位置 double skeLineAddup = 0.0; // 单个骨架线中的位置 int skeLineIndex = 0; // 骨架序列索引 do { int currStartIndex = 0; int currEndIndex = 1; double currLineLen = (skeRcd.nodePosList[1] - skeRcd.nodePosList[0]).Length(); for (; skeLineAddup < globalPos; skeLineIndex++) { currStartIndex = skeletonSeq[skeLineIndex]; currEndIndex = skeletonSeq[skeLineIndex + 1]; currLineLen = (skeRcd.nodePosList[currEndIndex] - skeRcd.nodePosList[currStartIndex]).Length(); skeLineAddup += currLineLen; }// 循环停止的结果:skeLineAddup>=globalPos skeLineIndex指向超过globalpos的那个线段 if (skeEndIndex.Count == 0 || currEndIndex != skeEndIndex.Last().Key) { skeEndIndex.Add(new KeyValuePair <int, int>(currEndIndex, skeLineIndex - 1)); nodepos = (1 - (skeLineAddup - globalPos) / currLineLen) * (skeRcd.nodePosList[currEndIndex] - skeRcd.nodePosList[currStartIndex]) + skeRcd.nodePosList[currStartIndex]; //nodeNV = skeRcd.nodePosList[currEndIndex] - skeRcd.nodePosList[currStartIndex]; 这里注释了 nodePlane = new Plane(nodepos, torso2ArmDir); slicerSeq.Add(new SlicerRecord(segMesh, nodePlane)); } globalPos += oxterInterval; } while (globalPos < pSkeLen); // find oxter slicer Diff2rdPrune(slicerSeq, out int outstart); // outstart 就是腋窝的index // 进行手臂的分片生成 SlicerRecord temp = slicerSeq[outstart]; slicerSeq.Clear(); slicerSeq.Add(temp); double armLength = 0.0; for (int i = skeEndIndex[outstart].Value; i < skeletonSeq.Count - 1; i++) { armLength += (skeRcd.nodePosList[skeletonSeq[i + 1]] - skeRcd.nodePosList[skeletonSeq[i]]).Length(); } double foreArmLength = armLength / 3 * 2; interval = armLength / (Math.Floor(armLength / interval)) + interval / 200; Vector3d nodeNV; globalPos = interval; // 整个骨架序列线段中的位置 skeLineAddup = 0.0; // 单个骨架线中的位置 skeLineIndex = skeEndIndex[outstart].Value; // 骨架序列索引 do { int currStartIndex = skeletonSeq[skeLineIndex]; int currEndIndex = skeletonSeq[skeLineIndex + 1]; double currLineLen = (skeRcd.nodePosList[currEndIndex] - skeRcd.nodePosList[currStartIndex]).Length(); for (; skeLineAddup < globalPos; skeLineIndex++) { currStartIndex = skeletonSeq[skeLineIndex]; currEndIndex = skeletonSeq[skeLineIndex + 1]; currLineLen = (skeRcd.nodePosList[currEndIndex] - skeRcd.nodePosList[currStartIndex]).Length(); skeLineAddup += currLineLen; }// 循环停止的结果:skeLineAddup>=globalPos skeLineIndex指向超过globalpos的那个线段 nodepos = (1 - (skeLineAddup - globalPos) / currLineLen) * (skeRcd.nodePosList[currEndIndex] - skeRcd.nodePosList[currStartIndex]) + skeRcd.nodePosList[currStartIndex]; if (skeLineAddup < foreArmLength) { nodeNV = (skeLineAddup * (skeRcd.nodePosList[currEndIndex] - skeRcd.nodePosList[currStartIndex]) + (foreArmLength - skeLineAddup) * torso2ArmDir) / (foreArmLength); //这里注释了 } else { nodeNV = (skeRcd.nodePosList[currEndIndex] - skeRcd.nodePosList[currStartIndex]).Normalize(); } nodePlane = new Plane(nodepos, nodeNV); slicerSeq.Add(new SlicerRecord(segMesh, nodePlane)); globalPos += interval * (1 / nodeNV.Normalize().Dot((skeRcd.nodePosList[currEndIndex] - skeRcd.nodePosList[currStartIndex]).Normalize())); } while (globalPos < armLength); // final cut slicer nodeNV = skeRcd.nodePosList[skeletonSeq[skeletonSeq.Count - 1]] - skeRcd.nodePosList[skeletonSeq[skeletonSeq.Count - 2]]; nodePlane = new Plane(skeRcd.nodePosList[skeletonSeq.Last()], nodeNV); slicerSeq.Add(new SlicerRecord(segMesh, nodePlane)); }
private void DisplaySlicer(SlicerRecord sli) { float skeletonNodeSize = 6.0f; float[] newcolor = ColorHelper.byte2float(Color.Gold); // draw center GL.glPointSize(skeletonNodeSize); GL.glColor3f(newcolor[0], newcolor[1], newcolor[2]); GL.glBegin(GL.GL_POINTS); GL.glVertex3d(sli.slicerCenter.x, sli.slicerCenter.y, sli.slicerCenter.z); GL.glEnd(); newcolor = ColorHelper.byte2float(Color.Black); // mark skeleton node GL.glPointSize(skeletonNodeSize + 3); GL.glColor3f(newcolor[0], newcolor[1], newcolor[2]); GL.glBegin(GL.GL_POINTS); GL.glVertex3d(sli.skeletonNodepos.x, sli.skeletonNodepos.y, sli.skeletonNodepos.z); GL.glEnd(); // draw points newcolor = ColorHelper.byte2float(Color.Orange); for (int i = 0; i < sli.pointInfoList.Count; i++) { GL.glPointSize(skeletonNodeSize); GL.glColor3f(newcolor[0], newcolor[1], newcolor[2]); GL.glBegin(GL.GL_POINTS); GL.glVertex3d(sli.pointInfoList[i].p.x, sli.pointInfoList[i].p.y, sli.pointInfoList[i].p.z); GL.glEnd(); } // draw lines and mark mesh triangles newcolor = ColorHelper.byte2float(Color.Orange); float[] facemark = ColorHelper.byte2float(Color.Pink); for (int i = 0; i < sli.lineList.Count; i++) { GL.glColor3f(newcolor[0], newcolor[1], newcolor[2]); GL.glLineWidth(2.0f); GL.glBegin(GL.GL_LINES); int p1 = sli.lineList[i].p1; int p2 = sli.lineList[i].p2; GL.glVertex3d(sli.pointInfoList[p1].p.x, sli.pointInfoList[p1].p.y, sli.pointInfoList[p1].p.z); GL.glVertex3d(sli.pointInfoList[p2].p.x, sli.pointInfoList[p2].p.y, sli.pointInfoList[p2].p.z); GL.glEnd(); } //unsafe //{ // fixed (double* np = segMesh.FaceNormal) // fixed (double* vp = segMesh.VertexPos) // { // for (int i = 0; i < sli.lineList.Count; i++) // { // int fi = sli.lineList[i].fid; // GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL); // GL.glColor3f(facemark[0], facemark[1], facemark[2]); // GL.glEnableClientState(GL.GL_VERTEX_ARRAY); // GL.glNormal3dv(np + fi); // GL.glVertex3dv(vp + segMesh.FaceIndex[fi] * 3); // GL.glVertex3dv(vp + segMesh.FaceIndex[fi + 1] * 3); // GL.glVertex3dv(vp + segMesh.FaceIndex[fi + 2] * 3); // GL.glEnd(); // } // } //} }