private ContourLine TrackUnclosedContour(int crtTriangle, enumEdgeType crtEdge, double contValue) { if (_triangleIsUsed.IsTrue(crtTriangle)) { return(null); } ContourLine cntLine = new ContourLine(contValue); UpdateClassIndex(cntLine); enumEdgeType firstEdge = crtEdge; int firstTriangle = crtTriangle; enumEdgeType[] otherEdges = new enumEdgeType[2]; int edgeIdx = ToEdgeIndex(crtTriangle, crtEdge); bool edgeUsed = _edgeIsUsed.IsTrue(edgeIdx); PointF vpt = TryGetVPoint(crtTriangle, crtEdge, contValue); if (vpt.IsEmpty || edgeUsed) { return(null); } _edgeIsUsed.SetStatus(edgeIdx, true); return(TrackClosedContourFromEdge(crtTriangle, crtEdge, contValue, vpt, (idx) => { return IsBorderTriangle(idx); }, 2)); }
private int GetNextTriangle(int crtTriangle, ref enumEdgeType crtEdge) { bool isRightTop = crtTriangle % 2 != 0; int span = (_gridWidth * 2 + 1); try { switch (crtEdge) { case enumEdgeType.A: if (isRightTop) { crtTriangle = crtTriangle - span; } else { crtTriangle = crtTriangle + span; } break; case enumEdgeType.B: if (isRightTop) { crtTriangle = crtTriangle + 1; } else { crtTriangle = crtTriangle - 1; } break; case enumEdgeType.C: if (isRightTop) { crtTriangle = crtTriangle - 1; } else { crtTriangle = crtTriangle + 1; } break; } } finally { if (crtTriangle > _triangleCount - 1 || crtTriangle < 0) { crtTriangle = -1; } } return(crtTriangle); }
private int ToEdgeIndex(int crtTriangle, enumEdgeType crtEdge) { int pixelRow = crtTriangle / _triWidth; int pixelCol = crtTriangle % _triWidth / 2; bool isLeftBottom = crtTriangle % 2 == 0; int idx = 0; if (pixelRow == 0) { idx = _gridWidth + pixelCol * 3; } else { idx = pixelRow * (_gridWidth * 3 + 1) + _gridWidth + pixelCol * (_gridWidth - 1); } if (isLeftBottom) { switch (crtEdge) { case enumEdgeType.A: return(idx + 1); case enumEdgeType.B: return(idx); case enumEdgeType.C: return(idx + 2); } } else { switch (crtEdge) { case enumEdgeType.A: if (pixelRow == 0) { return(pixelCol); } else { return(idx - _gridWidth * 3); } case enumEdgeType.B: return(idx + 3); case enumEdgeType.C: return(idx + 2); } } return(-1); }
private void SetOthterEdges(enumEdgeType crtEdge, ref enumEdgeType[] otherEdges) { if (crtEdge == enumEdgeType.A) { otherEdges[0] = enumEdgeType.B; otherEdges[1] = enumEdgeType.C; } else if (crtEdge == enumEdgeType.B) { otherEdges[0] = enumEdgeType.A; otherEdges[1] = enumEdgeType.C; } else if (crtEdge == enumEdgeType.C) { otherEdges[0] = enumEdgeType.A; otherEdges[1] = enumEdgeType.B; } }
/* * var factor = (float)((value - edge.P1.Value) / (edge.P2.Value - edge.P1.Value)); * result.X = edge.P1.X + factor * (edge.P2.X - edge.P1.X); * result.Y = edge.P1.Y + factor * (edge.P2.Y - edge.P1.Y); */ protected override PointF GetVPoint(enumEdgeType edgeType, int pixelIdxV1, int pixelIdxV2, double contValue) { float factor = (float)(contValue - _bandValues[pixelIdxV1]) / (_bandValues[pixelIdxV2] - _bandValues[pixelIdxV1]); int y = pixelIdxV1 / _width; //row int x = pixelIdxV1 % _width; //col switch (edgeType) { case enumEdgeType.A: return(new PointF(x + factor, y)); case enumEdgeType.B: return(new PointF(x, y + factor)); case enumEdgeType.C: return(new PointF(x + factor, y + factor)); } return(PointF.Empty); }
private bool IsBorderEdge(int idxTriangle, enumEdgeType edge) { if (idxTriangle % _triWidth == 0 && edge == enumEdgeType.B) //left { return(true); } else if ((idxTriangle + 1) % _triWidth == 0 && edge == enumEdgeType.B) //right { return(true); } else if (idxTriangle / _triWidth == 0 && edge == enumEdgeType.A) //top { return(true); } else if (idxTriangle / _triWidth == _gridHeight - 1 && edge == enumEdgeType.A) //bottom { return(true); } return(false); }
private ContourLine TrackClosedContour(int crtTriangle, enumEdgeType crtEdge, double contValue) { if (_triangleIsUsed.IsTrue(crtTriangle)) { return(null); } int edgeIdx = 0; enumEdgeType firstEdge = crtEdge; int firstTriangle = crtTriangle; enumEdgeType[] otherEdges = new enumEdgeType[2] { enumEdgeType.B, enumEdgeType.C }; PointF vpt = PointF.Empty; vpt = TryGetVPoint(crtTriangle, crtEdge, contValue); edgeIdx = ToEdgeIndex(crtTriangle, crtEdge); if (vpt.IsEmpty || _edgeIsUsed.IsTrue(edgeIdx)) { for (int i = 0; i < 2; i++) { crtEdge = otherEdges[i]; vpt = TryGetVPoint(crtTriangle, crtEdge, contValue); edgeIdx = ToEdgeIndex(crtTriangle, crtEdge); if (!vpt.IsEmpty && !_edgeIsUsed.IsTrue(edgeIdx)) { break; } } } if (vpt.IsEmpty || _edgeIsUsed.IsTrue(edgeIdx)) { //当前三角形三条边均不存在等值点,标记为已使用 _triangleIsUsed.SetStatus(crtTriangle, true); return(null); } return(TrackClosedContourFromEdge(crtTriangle, crtEdge, contValue, vpt, (idx) => { return idx == firstTriangle || IsBorderTriangle(idx); }, 6)); }
protected abstract PointF GetVPoint(enumEdgeType edgeType, int pixelIdxV1, int pixelIdxV2, double contValue);
private PointF TryGetVPoint(int crtTriangle, enumEdgeType crtEdge, double contValue) { int pixelRow = crtTriangle / _triWidth; int pixelCol = crtTriangle % _triWidth / 2; bool isRightTop = crtTriangle % 2 != 0;//是右上三角形 if (isRightTop) { pixelCol += 1; } else { pixelRow += 1; } int pixelIdx = pixelRow * _width + pixelCol; int pixelIdxV1 = pixelIdx, pixelIdxV2 = pixelIdx; switch (crtEdge) { case enumEdgeType.A: if (isRightTop) { pixelIdxV1 -= 1; } else { pixelIdxV2 += 1; } break; case enumEdgeType.B: if (isRightTop) { pixelIdxV2 += _width; } else { pixelIdxV1 -= _width; } break; case enumEdgeType.C: if (isRightTop) { pixelIdxV1 -= 1; pixelIdxV2 += _width; } else { pixelIdxV1 -= _width; pixelIdxV2 += 1; } break; } if (!CheckIsContained(_bandValues[pixelIdxV1], _bandValues[pixelIdxV2], ToTValue(contValue))) { return(PointF.Empty); } PointF vpt = GetVPoint(crtEdge, pixelIdxV1, pixelIdxV2, contValue); //经过采样 if (_sample > 1) { vpt.X *= _sample; vpt.Y *= _sample; } return(vpt); }
private ContourLine TrackClosedContourFromEdge(int crtTriangle, enumEdgeType crtEdge, double contValue, PointF vpt, Func <int, bool> isStop, int minPoints) { bool isSharePointed = false; bool edgeUsed = false; ContourLine cntLine = new ContourLine(contValue); UpdateClassIndex(cntLine); enumEdgeType[] otherEdges = new enumEdgeType[2]; int edgeIdx = 0; bool isClosed = false; while (true) { //等值线进入当前三角形 if (!isSharePointed) { cntLine.AddPoint(vpt); } //查找等值线离开当前三角形的出口点 SetOthterEdges(crtEdge, ref otherEdges); crtEdge = otherEdges[0]; edgeIdx = ToEdgeIndex(crtTriangle, crtEdge); edgeUsed = _edgeIsUsed.IsTrue(edgeIdx); vpt = !edgeUsed?TryGetVPoint(crtTriangle, crtEdge, contValue) : PointF.Empty; if (vpt.IsEmpty)//该边不包含等值点或者已被使用 { crtEdge = otherEdges[1]; edgeIdx = ToEdgeIndex(crtTriangle, crtEdge); edgeUsed = _edgeIsUsed.IsTrue(edgeIdx); vpt = !edgeUsed?TryGetVPoint(crtTriangle, crtEdge, contValue) : PointF.Empty; if (vpt.IsEmpty)//没有找到出口 { break; } else { cntLine.AddPoint(vpt); _edgeIsUsed.SetStatus(edgeIdx, true); } } else { cntLine.AddPoint(vpt); _edgeIsUsed.SetStatus(edgeIdx, true); } //标记当前三角形已经使用 _triangleIsUsed.SetStatus(crtTriangle, true); //查找当前三角形相连的三角形作为当前三角形 crtTriangle = GetNextTriangle(crtTriangle, ref crtEdge); //退出条件 if (crtTriangle == -1) { break; } edgeIdx = ToEdgeIndex(crtTriangle, crtEdge); _edgeIsUsed.SetStatus(edgeIdx, false);//两个三角形的共享边标记为未使用 if (isStop(crtTriangle)) { isClosed = true; _edgeIsUsed.SetStatus(edgeIdx, true); break; } if (_triangleIsUsed.IsTrue(crtTriangle)) { break; } isSharePointed = true; } if (_isOutputUncompleted) { return(cntLine.Count >= minPoints ? cntLine : null); } else { if (isClosed) { return(cntLine.Count >= minPoints ? cntLine : null); } return(null); } }