public static Line2D ParseLine(string lineText) { string[] splitLine = lineText.Split(' '); Line2D line = new Line2D(); try { line.Start = new Vector3<double>(double.Parse(splitLine[0]), double.Parse(splitLine[1]), 1); line.End = new Vector3<double>(double.Parse(splitLine[2]), double.Parse(splitLine[3]), 1); } catch (FormatException ex) { Console.WriteLine("ERROR: Line in incorrect format!"); Console.WriteLine(ex.ToString()); } return line; }
// Using the cohen sutherland algorithm private Line2D ClipLine(Line2D line) { Line2D newLine = new Line2D(); newLine.Start = new Vector3<double>(line.Start[0], line.Start[1], 1); newLine.End = new Vector3<double>(line.End[0], line.End[1], 1); BitCodes code1 = GetCode(newLine.Start); BitCodes code2 = GetCode(newLine.End); while (true) { if ((code1 | code2) == BitCodes.Middle) { //Hooray we don't need to clip! return newLine; } else if ((code1 & code2) != BitCodes.Middle) { //Line2D totally outside area return null; } else { //More complicated... //at least one endpoint is outside //Need to check for flipped bits //can use xor byte temp = (byte)(code1 ^ code2); byte bitNumber = 4; //If the codes are not either of the trivial cases, at least one bit must be flipped. //Therefore this loop cannot go infinite while (temp != 1) { temp = (byte)(temp >> 1); bitNumber--; } //Pick which point to work on double x = 0; double y = 0; BitCodes workingCode = code1; switch (bitNumber) { case 1: if ((code2 & BitCodes.Top) != 0) workingCode = code2; // y0 > WT and y1 <= WT // yc = WT // xc = ((WT - y0)/(y1 - y0))*(x1 - x0) + x0 x = ((m_yMax - newLine.Start[1]) / (newLine.End[1] - newLine.Start[1])) * (newLine.End[0] - newLine.Start[0]) + newLine.Start[0]; y = m_yMax; break; case 2: if ((code2 & BitCodes.Bottom) != 0) workingCode = code2; // y0 < WB and y1 >= WB // yc = WB // xc = ((WB - y0)/(y1 - y0))*(x1 - x0) + x0 x = ((m_yMin - newLine.Start[1]) / (newLine.End[1] - newLine.Start[1])) * (newLine.End[0] - newLine.Start[0]) + newLine.Start[0]; y = m_yMin; break; case 3: if ((code2 & BitCodes.Right) != 0) workingCode = code2; // x0 > WR and x2 <= WR // xc = WR // yc = ((WR - x0)/(x1 - x0))*(y1 - y0) + y0 y = ((m_xMax - newLine.Start[0]) / (newLine.End[0] - newLine.Start[0])) * (newLine.End[1] - newLine.Start[1]) + newLine.Start[1]; x = m_xMax; break; case 4: if ((code2 & BitCodes.Left) != 0) workingCode = code2; // x0 < WL and x1 >= WL // xc = WL // yc = ((WL - x0)/(x1 - x0))*(y1 - y0) + y0 y = ((m_xMin - newLine.Start[0]) / (newLine.End[0] - newLine.Start[0])) * (newLine.End[1] - newLine.Start[1]) + newLine.Start[1]; x = m_xMin; break; } if (code1 == workingCode) { newLine.Start[0] = x; newLine.Start[1] = y; code1 = GetCode(newLine.Start); } else { newLine.End[0] = x; newLine.End[1] = y; code2 = GetCode(newLine.End); } } } }
//Functions that are commented "Based on textbook algorithm" were inspired by ntroduction to Computer Graphics(Foley, Van Dam, et al) //All these functions rely on the polygon being specified in counterclockwise vertex ordering. //Based on textbook algorithm // Calculates the intersection of the line formed by two vertices and a line. private Vector3<double> Intersect(Vector3<double> begin, Vector3<double> end, Line2D clipEdge) { Vector3<double> ret = new Vector3<double>(); if (clipEdge.Start.Y == clipEdge.End.Y) { ret.X = begin.X + (clipEdge.Start.Y - begin.Y) * (end.X - begin.X) / (end.Y - begin.Y); ret.Y = clipEdge.Start.Y; } else { ret.X = clipEdge.Start.X; ret.Y = begin.Y + (clipEdge.Start.X - begin.X) * (end.Y - begin.Y) / (end.X - begin.X); } return ret; }
//Based on textbook algorithm //Implements the sutherlandHodgman polygon clipping algorithm. This function will only //clip the polygon against one clip edge at a time. Therefore, to clip the entire polygon, we feed the output //of this command into the input of another call to this with a different clip edge and keep // doing this until we run out of clip edges private List<Vector3<double>> SutherlandHodgman(List<Vector3<double>> inVertices, Line2D clipEdge) { List<Vector3<double>> output = new List<Vector3<double>>(); Vector3<double> s = inVertices.Last(); Vector3<double> p; for(int i = 0; i < inVertices.Count; i++) { p = inVertices[i]; if (Inside(p, clipEdge)) { if (Inside(s, clipEdge)) { output.Add(p); } else { output.Add(Intersect(s, p, clipEdge)); output.Add(p); } } else if(Inside(s, clipEdge)) { output.Add(Intersect(s, p, clipEdge)); } s = p; } return output; }
//Based on textbook algorithm //Determines if a point is inside a given line (inside defined as being to the left of the clipEdge while oriented in the direction of the clip edge) private bool Inside(Vector3<double> test, Line2D clipEdge) { if (clipEdge.End.X > clipEdge.Start.X) if (test.Y >= clipEdge.Start.Y) return true; if (clipEdge.End.X < clipEdge.Start.X) if (test.Y <= clipEdge.Start.Y) return true; if (clipEdge.End.Y > clipEdge.Start.Y) if (test.X <= clipEdge.End.X) return true; if (clipEdge.End.Y < clipEdge.Start.Y) if (test.X >= clipEdge.End.X) return true; return false; }