static bool SameCoord(EdgeLine a, EdgeLine b) { //TODO: review this again return((a.P == b.P || a.P == b.Q) && (a.Q == b.P || a.Q == b.Q)); }
public static void dbugGetScaledXY(this EdgeLine edge, out double px, out double py, out double qx, out double qy, float scale) { px = edge.PX * scale; py = edge.PY * scale; // qx = edge.QX * scale; qy = edge.QY * scale; }
/// <summary> /// which one is min,max /// </summary> /// <param name="min"></param> /// <param name="max"></param> static void GetMinMax(EdgeLine edge, out Vector2 min, out Vector2 max) { Vector2 a_pos = new Vector2((float)edge.PX, (float)edge.PY); Vector2 b_pos = new Vector2((float)edge.QX, (float)edge.QY); min = Vector2.Min(a_pos, b_pos); max = Vector2.Max(a_pos, b_pos); }
public GlyphBone(GlyphBoneJoint a, EdgeLine tipEdge) { JointA = a; TipEdge = tipEdge; Vector2 midPoint = tipEdge.GetMidPoint(); _len = Math.Sqrt(a.CalculateSqrDistance(midPoint)); EvaluateSlope(); }
internal void SetTipEdge_P(EdgeLine e) { #if DEBUG if (_tipEdge_p != null) { throw new System.NotSupportedException(); } #endif e.IsTip = true; this._tipEdge_p = e; }
internal void SetControlEdge(EdgeLine controlEdge) { //check if edge is connect to p or q #if DEBUG if (!controlEdge.IsInside) { } #endif //---------------- if (_glyphPoint_P == controlEdge._glyphPoint_P) { #if DEBUG if (_ctrlEdge_P != null && _ctrlEdge_P != controlEdge) { } #endif //map this p to p of the control edge _ctrlEdge_P = controlEdge; } else if (_glyphPoint_P == controlEdge.Q) { #if DEBUG if (_ctrlEdge_P != null && _ctrlEdge_P != controlEdge) { } #endif _ctrlEdge_P = controlEdge; } else if (_glyphPoint_Q == controlEdge._glyphPoint_P) { #if DEBUG if (_ctrlEdge_Q != null && _ctrlEdge_Q != controlEdge) { } #endif _ctrlEdge_Q = controlEdge; } else if (_glyphPoint_Q == controlEdge.Q) { #if DEBUG if (_ctrlEdge_Q != null && _ctrlEdge_Q != controlEdge) { } #endif _ctrlEdge_Q = controlEdge; } else { //? } }
static void FindPerpendicular(EdgeLine outsideEdge, EdgeLine inside) { System.Numerics.Vector2 m0 = inside.GetMidPoint(); System.Numerics.Vector2 cut_fromM0; if (MyMath.FindPerpendicularCutPoint(outsideEdge, new System.Numerics.Vector2(m0.X, m0.Y), out cut_fromM0)) { ((OutsideEdgeLine)outsideEdge).SetControlEdge(inside); } else { } outsideEdge._earlyInsideAnalysis = inside._earlyInsideAnalysis = true; }
/// <summary> /// find cut point and check if the cut point is on the edge /// </summary> /// <param name="edge"></param> /// <param name="p2"></param> /// <param name="cutResult"></param> /// <returns></returns> public static bool FindPerpendicularCutPoint(EdgeLine edge, Vector2 p2, out Vector2 cutResult) { cutResult = FindPerpendicularCutPoint( new Vector2((float)edge.PX, (float)edge.PY), new Vector2((float)edge.QX, (float)edge.QY), p2); //also check if result cutpoint is on current line segment or not Vector2 min, max; GetMinMax(edge, out min, out max); return(cutResult.X >= min.X && cutResult.X <= max.X && cutResult.Y >= min.Y && cutResult.Y <= max.Y); }
public void CalculateBounds(ref float minX, ref float minY, ref float maxX, ref float maxY) { for (int e = edges.Length - 1; e >= 0; --e) { EdgeLine edge = edges[e]; // x MyMath.FindMinMax(ref minX, ref maxX, (float)edge.PX); MyMath.FindMinMax(ref minX, ref maxX, (float)edge.QX); // y MyMath.FindMinMax(ref minY, ref maxY, (float)edge.PY); MyMath.FindMinMax(ref minY, ref maxY, (float)edge.QY); } }
internal void SetTipEdge_Q(EdgeLine e) { #if DEBUG if (_tipEdge_q != null) { throw new System.NotSupportedException(); } if (_tipEdge_q != null && _tipEdge_q == _tipEdge_p) { throw new System.NotSupportedException(); } #endif e.IsTip = true; _tipEdge_q = e; }
static EdgeLine FindAnotherOutsideEdge(GlyphTriangle tri, EdgeLine knownOutsideEdge) { if (tri.e0.IsOutside && tri.e0 != knownOutsideEdge) { return(tri.e0); } if (tri.e1.IsOutside && tri.e1 != knownOutsideEdge) { return(tri.e1); } if (tri.e2.IsOutside && tri.e2 != knownOutsideEdge) { return(tri.e2); } return(null); }
/// <summary> /// find nb triangle that has the same edgeLine /// </summary> /// <param name="tri"></param> /// <returns></returns> static bool FindSameCoordEdgeLine(GlyphTriangle tri, EdgeLine edgeLine, out EdgeLine foundEdge) { foundEdge = null; if (tri == null) { return(false); } if (SameCoord(foundEdge = tri.e0, edgeLine) || SameCoord(foundEdge = tri.e1, edgeLine) || SameCoord(foundEdge = tri.e2, edgeLine)) { return(true); } foundEdge = null; //not found return(false); }
internal void CreateGlyphEdges() { int lim = flattenPoints.Count - 1; GlyphPoint p = null, q = null; OutsideEdgeLine edgeLine = null; _edges = new List <OutsideEdgeLine>(); // for (int i = 0; i < lim; ++i) { //in order ... p = flattenPoints[i]; q = flattenPoints[i + 1]; if ((edgeLine = EdgeLine.FindCommonOutsideEdge(p, q)) != null) { //from p point to q //so ... //edgeLine is outwardEdge for p. //edgeLine is inwardEdge for q. //p.OutwardEdge = q.InwardEdge = edgeLine; _edges.Add(edgeLine); } else { //? } } //close p = flattenPoints[lim]; q = flattenPoints[0]; if ((edgeLine = EdgeLine.FindCommonOutsideEdge(p, q)) != null) { //from p point to q //so ... //edgeLine is outwardEdge for p. //edgeLine is inwardEdge for q. //p.OutwardEdge = q.InwardEdge = edgeLine; _edges.Add(edgeLine); } else { //not found } }
/// <summary> /// check if the 2 triangle is matching or not /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> static bool IsMatchingEdge(EdgeLine a, EdgeLine b) { //x-axis if ((a.PX == b.PX && a.QX == b.QX) || (a.PX == b.QX && a.QX == b.PX)) { //pass x-axis // //y_axis if ((a.PY == b.PY && a.QY == b.QY) || (a.PY == b.QY && a.QY == b.PY)) { return(true); } } //otherwise... return(false); }
/// <summary> /// add information about each edge of a triangle, compare to the contactEdge of a ownerEdgeJoint /// </summary> /// <param name="triangle"></param> /// <param name="boneJoint"></param> /// <param name="knownInsideEdge"></param> static EdgeLine CreateTipEdgeIfNeed( double cent_slopAngle, GlyphTriangle triangle, EdgeLine knownInsideEdge) { int outsideCount; EdgeLine outside0, outside1, outside2, anotherInsideEdge; ClassifyTriangleEdges( triangle, knownInsideEdge, out anotherInsideEdge, out outside0, out outside1, out outside2, out outsideCount); switch (outsideCount) { default: throw new NotSupportedException(); case 0: case 1: break; case 3: throw new NotImplementedException(); //TODO: implement this case 2: //tip end //find which edge should be 'tip edge' //in this version we compare each edge slope to centroid line slope. //the most diff angle should be opposite edge (to the centroid) => tip edge //------------------------------------------------------------------------- EdgeLine tipEdge, notTipEdge; SelectMostProperTipEdge(cent_slopAngle, outside0, outside1, out tipEdge, out notTipEdge); return(tipEdge); } return(null); }
void AnalyzeInsideEdge(EdgeLine d0, EdgeLine d1, EdgeLine d2) { if (d0._earlyInsideAnalysis) { return; } if (!d0.IsInside) { return; } //------------------------------------------------- //maybeInsideEdge is Inside *** //check another if (d1.IsInside) { if (d2.IsInside) { //3 inside edges } else { //1 outside edge (d2) //2 inside edges (d0,d1) //find a perpendicular line FindPerpendicular(d2, d0); FindPerpendicular(d2, d1); } } else if (d2.IsInside) { if (d1.IsInside) { //3 inside edges } else { //1 outside edge (d1) //2 inside edges (d0,d2) FindPerpendicular(d1, d0); FindPerpendicular(d1, d2); } } }
void AnalyzeOutsideEdge(EdgeLine d, float centroidX, float centroidY) { //check if edge slope if (!d.IsOutside) return; //--------------------------- switch (d.SlopeKind) { case LineSlopeKind.Horizontal: //check if upper or lower //compare mid point with the centroid d.IsUpper = d.GetMidPoint().Y > centroidY; break; case LineSlopeKind.Vertical: d.IsLeftSide = d.GetMidPoint().X < centroidX; break; } }
public GlyphTriangle(DelaunayTriangle tri) { this._tri = tri; //--------------------------------------------- TriangulationPoint p0 = _tri.P0; TriangulationPoint p1 = _tri.P1; TriangulationPoint p2 = _tri.P2; //we do not store triangulation points (p0,p1,02) //an EdgeLine is created after we create GlyphTriangles. //triangulate point p0->p1->p2 is CCW *** e0 = NewEdgeLine(p0, p1, tri.EdgeIsConstrained(tri.FindEdgeIndex(p0, p1))); e1 = NewEdgeLine(p1, p2, tri.EdgeIsConstrained(tri.FindEdgeIndex(p1, p2))); e2 = NewEdgeLine(p2, p0, tri.EdgeIsConstrained(tri.FindEdgeIndex(p2, p0))); //if the order of original glyph point is CW //we may want to reverse the order of edge creation : //p2->p1->p0 //link back tri.userData = this; //---------------- //early analyze AnalyzeInsideEdge(e0, e1, e2); AnalyzeInsideEdge(e1, e0, e2); AnalyzeInsideEdge(e2, e0, e1); //at this point, //we should know the direction of this triangle //then we known that if this triangle is left/right/upper/lower of the 'stroke' line float cent_x, cent_y; this.CalculateCentroid(out cent_x, out cent_y); AnalyzeOutsideEdge(e0, cent_x, cent_y); AnalyzeOutsideEdge(e1, cent_x, cent_y); AnalyzeOutsideEdge(e2, cent_x, cent_y); }
/// <summary> /// add information about edges to each triangle and create BoneJoint and Tip /// </summary> public GlyphBoneJoint AnalyzeEdgesAndCreateBoneJoint() { #if DEBUG if (p == q) { throw new NotSupportedException(); } #endif //2 contact triangles share GlyphBoneJoint. //-------------------------------------- //[C] //Find relation between edges of 2 triangle p and q //.... //pick up a edge of p and compare to all edge of q //do until complete GlyphBoneJoint boneJoint = null; InsideEdgeLine p_edge, q_edge; if (FindCommonInsideEdges(p, q, out p_edge, out q_edge)) { //create joint boneJoint = new GlyphBoneJoint(p_edge, q_edge); double slopeAngle = CalculateCentroidPairSlopeNoDirection(this); // EdgeLine foundTipEdge = null; if ((foundTipEdge = CreateTipEdgeIfNeed(slopeAngle, p, p_edge)) != null) { //P boneJoint.SetTipEdge_P(foundTipEdge); } if ((foundTipEdge = CreateTipEdgeIfNeed(slopeAngle, q, q_edge)) != null) { //Q boneJoint.SetTipEdge_Q(foundTipEdge); } } return(boneJoint); }
internal GlyphBoneJoint( InsideEdgeLine p_contact_edge, InsideEdgeLine q_contact_edge) { //both p and q is INSIDE, contact edge this._p_contact_edge = p_contact_edge; this._q_contact_edge = q_contact_edge; //this is original x,y Vector2 midpos = p_contact_edge.GetMidPoint(); this._fitX = midpos.X; this._fitY = midpos.Y; #if DEBUG if (p_contact_edge.inside_joint != null || q_contact_edge.inside_joint != null) { throw new System.NotSupportedException(); } #endif p_contact_edge.inside_joint = this; q_contact_edge.inside_joint = this; }
static InsideEdgeLine FindCommonInsideEdge(GlyphTriangle a, EdgeLine b_edge) { //2 contact triangles share GlyphBoneJoint. //compare 3 side of a's edge to b_edge if (b_edge.IsOutside) { return(null); } // if (IsMatchingEdge(a.e0, b_edge)) { return((InsideEdgeLine)a.e0); } if (IsMatchingEdge(a.e1, b_edge)) { return((InsideEdgeLine)a.e1); } if (IsMatchingEdge(a.e2, b_edge)) { return((InsideEdgeLine)a.e2); } return(null); }
static void SelectMostProperTipEdge( double slopeAngle, EdgeLine outside0, EdgeLine outside1, out EdgeLine tipEdge, out EdgeLine notTipEdge) { //slop angle in rad double diff0 = Math.Abs(outside0.GetSlopeAngleNoDirection() - slopeAngle); double diff1 = Math.Abs(outside1.GetSlopeAngleNoDirection() - slopeAngle); if (diff0 > diff1) { tipEdge = outside0; notTipEdge = outside1; } else { tipEdge = outside1; notTipEdge = outside0; } }
internal static bool ContainsTriangle(this EdgeLine edge, GlyphTriangle p) { return(p.e0 == edge || p.e1 == edge || p.e2 == edge); }
internal static double GetSlopeAngleNoDirection(this EdgeLine line) { return(Math.Abs(Math.Atan2(Math.Abs(line.QY - line.PY), Math.Abs(line.QX - line.PX)))); }
public static Vector2 GetMidPoint(this EdgeLine line) { return(new Vector2((float)((line.PX + line.QX) / 2), (float)((line.PY + line.QY) / 2))); }
static void ClassifyTriangleEdges( GlyphTriangle triangle, EdgeLine knownInsideEdge, out EdgeLine anotherInsideEdge, out EdgeLine outside0, out EdgeLine outside1, out EdgeLine outside2, out int outsideCount) { outsideCount = 0; outside0 = outside1 = outside2 = anotherInsideEdge = null; if (triangle.e0.IsOutside) { switch (outsideCount) { case 0: outside0 = triangle.e0; break; case 1: outside1 = triangle.e0; break; case 2: outside2 = triangle.e0; break; } outsideCount++; } else { //e0 is not known inside edge if (triangle.e0 != knownInsideEdge) { anotherInsideEdge = triangle.e0; } } // if (triangle.e1.IsOutside) { switch (outsideCount) { case 0: outside0 = triangle.e1; break; case 1: outside1 = triangle.e1; break; case 2: outside2 = triangle.e1; break; } outsideCount++; } else { if (triangle.e1 != knownInsideEdge) { anotherInsideEdge = triangle.e1; } } // if (triangle.e2.IsOutside) { switch (outsideCount) { case 0: outside0 = triangle.e2; break; case 1: outside1 = triangle.e2; break; case 2: outside2 = triangle.e2; break; } outsideCount++; } else { if (triangle.e2 != knownInsideEdge) { anotherInsideEdge = triangle.e2; } } }
/// <summary> /// adjust vertical fitting value /// </summary> void ReCalculateFittingValues() { //(1) //clear all prev adjust value for (int i = _contours.Count - 1; i >= 0; --i) { List <GlyphPoint> pnts = _contours[i].flattenPoints; for (int m = pnts.Count - 1; m >= 0; --m) { pnts[m].ResetFitAdjustValues(); } } //adjust the value when we move to new pixel scale (pxscale) //if we known adjust values for that pxscale before( and cache it) //we can use that without recalculation //-------------------- //(2) //select Horizontal BoneGroups for Vertical fitting: //for veritical fitting, we apply fitting value to each group. //each group may not need the same value. //-------------------- List <BoneGroup> selectedHBoneGroups = _groupingHelper.SelectedHorizontalBoneGroups; for (int i = selectedHBoneGroups.Count - 1; i >= 0; --i) { BoneGroup boneGroup = selectedHBoneGroups[i]; if (boneGroup._lengKind == BoneGroupSumLengthKind.Short) { continue; } EdgeLine[] h_edges = boneGroup.edges; if (h_edges == null) { continue; } // int edgeCount = h_edges.Length; //we need to calculate the avg of the glyph point //and add a total summary to this FitDiffCollector y_fitDiffCollector = new FitDiffCollector(); float groupLen = boneGroup.approxLength; // for (int e = edgeCount - 1; e >= 0; --e) { EdgeLine ee = h_edges[e]; //p y_fitDiffCollector.Collect(MyMath.CalculateDiffToFit(ee.P.Y * _pxScale), groupLen); //q y_fitDiffCollector.Collect(MyMath.CalculateDiffToFit(ee.Q.Y * _pxScale), groupLen); } float avg_ydiff = y_fitDiffCollector.CalculateProperDiff(); for (int e = edgeCount - 1; e >= 0; --e) { //TODO: review here again EdgeLine ee = h_edges[e]; ee.P.FitAdjustY = avg_ydiff; //assign px scale specific fit value ee.Q.FitAdjustY = avg_ydiff; //assign px scale specific fit value } } //--------------------------------------------------------- //(3) //vertical group for horizontal fit: //this different from the vertical fitting. //we calculate the value as a whole. //and apply it as a whole in later state List <BoneGroup> verticalGroups = _groupingHelper.SelectedVerticalBoneGroups; FitDiffCollector x_fitDiffCollector = new FitDiffCollector(); int j = verticalGroups.Count; for (int i = 0; i < j; ++i) { //1. the verticalGroup list is sorted, left to right //2. analyze in order left-> right BoneGroup boneGroup = verticalGroups[i]; if (boneGroup._lengKind != BoneGroupSumLengthKind.Long) { //in this case we focus on long-length bone group only continue; } EdgeLine[] v_edges = boneGroup.edges; if (v_edges == null) { continue; } int edgeCount = v_edges.Length; //we need to calculate the avg of the glyph point //and add a total summary to this float groupLen = boneGroup.approxLength; for (int e = 0; e < edgeCount; ++e) { EdgeLine ee = v_edges[e]; //TODO: review this //if (ee.IsLeftSide) //{ //focus on leftside edge //p x_fitDiffCollector.Collect(MyMath.CalculateDiffToFit(ee.P.X * _pxScale), groupLen); //q x_fitDiffCollector.Collect(MyMath.CalculateDiffToFit(ee.Q.X * _pxScale), groupLen); //} } //TODO: review here *** break; //only left most first long group ? } //(4) _avg_x_fitOffset = x_fitDiffCollector.CalculateProperDiff(); }
protected abstract void OnTriangle(int triAngleId, EdgeLine e0, EdgeLine e1, EdgeLine e2, double centroidX, double centroidY);
static bool ContainsEdge(GlyphTriangle tri, EdgeLine edge) { return(tri.e0 == edge || tri.e1 == edge || tri.e2 == edge); }
protected abstract void OnGlyphEdgeN(EdgeLine edge);