public static Geometry ANT_Outline_ToGeometry(ANT_Outline outline, bool flipY, Matrix4 mtx) { if (outline == null) { return(null); } ANTOutlineGeometry path = new ANTOutlineGeometry(); double x1, y1, x2, y2, x3, y3; int n; // index of contour in outline int first; // index of first point in contour int tag; // current point's state first = 0; ANT_Vector_Array points = outline.points; for (n = 0; n < outline.n_contours; n++) { int last; // index of last point in contour last = outline.contours[n]; int limit = last; outline_v_start.CopyFrom(points[first]); outline_v_last.CopyFrom(points[last]); outline_v_control.CopyFrom(outline_v_start); int point_index = first; ANT_Byte_Array tags_buf = outline.tags; int tags_index = first; tag = ANT.ANT_CURVE_TAG(tags_buf[tags_index + 0]); // A contour cannot start with a cubic control point! if (tag == ANT_CURVE_Tag.ANT_CURVE_TAG_CUBIC) { return(null); } // check first point to determine origin if (tag == ANT_CURVE_Tag.ANT_CURVE_TAG_CONIC) { // first point is conic control. Yes, this happens. if (ANT.ANT_CURVE_TAG(tags_buf[last]) == ANT_CURVE_Tag.ANT_CURVE_TAG_ON) { // start at last point if it is on the curve outline_v_start.CopyFrom(outline_v_last); limit--; } else { // if both first and last points are conic, // start at their middle and record its position // for closure outline_v_start.x = (outline_v_start.x + outline_v_last.x) / 2; outline_v_start.y = (outline_v_start.y + outline_v_last.y) / 2; outline_v_last.CopyFrom(outline_v_start); } point_index--; tags_index--; } x1 = ANT.ANT_int26p6_to_double(outline_v_start.x); y1 = ANT.ANT_int26p6_to_double(outline_v_start.y); if (flipY) { y1 = -y1; } mtx.Transform(ref x1, ref y1); path.MoveTo(x1, y1); while (point_index < limit) { point_index++; ANT_Vector point = points[point_index]; tags_index++; tag = ANT.ANT_CURVE_TAG(tags_buf[tags_index + 0]); switch (tag) { case ANT_CURVE_Tag.ANT_CURVE_TAG_ON: // emit a single line_to { x1 = ANT.ANT_int26p6_to_double(point.x); y1 = ANT.ANT_int26p6_to_double(point.y); if (flipY) { y1 = -y1; } mtx.Transform(ref x1, ref y1); path.LineTo(x1, y1); continue; } case ANT_CURVE_Tag.ANT_CURVE_TAG_CONIC: // consume conic arcs { outline_v_control.x = point.x; outline_v_control.y = point.y; Do_Conic: if (point_index < limit) { point_index++; point = points[point_index]; tags_index++; tag = ANT.ANT_CURVE_TAG(tags_buf[tags_index + 0]); outline_vec.CopyFrom(point); if (tag == ANT_CURVE_Tag.ANT_CURVE_TAG_ON) { x1 = ANT.ANT_int26p6_to_double(outline_v_control.x); y1 = ANT.ANT_int26p6_to_double(outline_v_control.y); x2 = ANT.ANT_int26p6_to_double(outline_vec.x); y2 = ANT.ANT_int26p6_to_double(outline_vec.y); if (flipY) { y1 = -y1; y2 = -y2; } mtx.Transform(ref x1, ref y1); mtx.Transform(ref x2, ref y2); path.Сurve3(x1, y1, x2, y2); continue; } if (tag != ANT_CURVE_Tag.ANT_CURVE_TAG_CONIC) { return(null); } outline_v_middle.x = (outline_v_control.x + outline_vec.x) / 2; outline_v_middle.y = (outline_v_control.y + outline_vec.y) / 2; x1 = ANT.ANT_int26p6_to_double(outline_v_control.x); y1 = ANT.ANT_int26p6_to_double(outline_v_control.y); x2 = ANT.ANT_int26p6_to_double(outline_v_middle.x); y2 = ANT.ANT_int26p6_to_double(outline_v_middle.y); if (flipY) { y1 = -y1; y2 = -y2; } mtx.Transform(ref x1, ref y1); mtx.Transform(ref x2, ref y2); path.Сurve3(x1, y1, x2, y2); outline_v_control.CopyFrom(outline_vec); goto Do_Conic; } x1 = ANT.ANT_int26p6_to_double(outline_v_control.x); y1 = ANT.ANT_int26p6_to_double(outline_v_control.y); x2 = ANT.ANT_int26p6_to_double(outline_v_start.x); y2 = ANT.ANT_int26p6_to_double(outline_v_start.y); if (flipY) { y1 = -y1; y2 = -y2; } mtx.Transform(ref x1, ref y1); mtx.Transform(ref x2, ref y2); path.Сurve3(x1, y1, x2, y2); goto Close; } default: { if (point_index + 1 > limit || ANT.ANT_CURVE_TAG(tags_buf[tags_index + 1]) != ANT_CURVE_Tag.ANT_CURVE_TAG_CUBIC) { return(null); } outline_vec1.x = points[point_index + 0].x; outline_vec1.y = points[point_index + 0].y; outline_vec2.x = points[point_index + 1].x; outline_vec2.y = points[point_index + 1].y; point_index += 2; { point = points[point_index]; } tags_index += 2; if (point_index <= limit) { outline_vec.CopyFrom(point); x1 = ANT.ANT_int26p6_to_double(outline_vec1.x); y1 = ANT.ANT_int26p6_to_double(outline_vec1.y); x2 = ANT.ANT_int26p6_to_double(outline_vec2.x); y2 = ANT.ANT_int26p6_to_double(outline_vec2.y); x3 = ANT.ANT_int26p6_to_double(outline_vec.x); y3 = ANT.ANT_int26p6_to_double(outline_vec.y); if (flipY) { y1 = -y1; y2 = -y2; y3 = -y3; } mtx.Transform(ref x1, ref y1); mtx.Transform(ref x2, ref y2); mtx.Transform(ref x3, ref y3); path.Сurve4(x1, y1, x2, y2, x3, y3); continue; } x1 = ANT.ANT_int26p6_to_double(outline_vec1.x); y1 = ANT.ANT_int26p6_to_double(outline_vec1.y); x2 = ANT.ANT_int26p6_to_double(outline_vec2.x); y2 = ANT.ANT_int26p6_to_double(outline_vec2.y); x3 = ANT.ANT_int26p6_to_double(outline_v_start.x); y3 = ANT.ANT_int26p6_to_double(outline_v_start.y); if (flipY) { y1 = -y1; y2 = -y2; y3 = -y3; } mtx.Transform(ref x1, ref y1); mtx.Transform(ref x2, ref y2); mtx.Transform(ref x3, ref y3); path.Сurve4(x1, y1, x2, y2, x3, y3); goto Close; } } } path.ClosePolygon(); Close: first = last + 1; } return(path); }