public System.Drawing.Bitmap CropImageRGB24(System.Drawing.Bitmap BitmapSrc) { try { // Create BitmapDst System.Drawing.Bitmap BitmapDst = new System.Drawing.Bitmap(Width, Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); // Convert to BitmapData BitmapData DataSrc = BitmapSrc.LockBits(new System.Drawing.Rectangle(0, 0, BitmapSrc.Width, BitmapSrc.Height), ImageLockMode.ReadWrite, BitmapSrc.PixelFormat); BitmapData DataDst = BitmapDst.LockBits(new System.Drawing.Rectangle(0, 0, BitmapDst.Width, BitmapDst.Height), ImageLockMode.ReadWrite, BitmapDst.PixelFormat); // 필요 요소 정의 byte bitsPerPixel = GetBitsPerPixel(BitmapSrc.PixelFormat); int SizeSrc = DataSrc.Stride * DataSrc.Height; int SizeDst = DataDst.Stride * DataDst.Height; byte[] ArraySrc = new byte[SizeSrc]; byte[] ArrayDst = new byte[SizeDst]; // Data copy from DataSrc to ArraySrc[] System.Runtime.InteropServices.Marshal.Copy(DataSrc.Scan0, ArraySrc, 0, SizeSrc); // Marshal.Copy로 memcopy마냥 쓸 수 있구먼 // ArrayDst[] 채우기 for (int j = 0; j < Height; j++) { for (int i = 0; i < Width; i++) { // Pose Matrix (회전 후 이동) fPoint point = PoseMatrix(i, j, LeftTopX, LeftTopY, Angle, Width, Height); int srcx = (int)point.x; int srcy = (int)point.y; // srcx와 srcy가 소스 밖의 점이면 0으로 넣자 if (srcx >= 0 && srcx <= BitmapSrc.Width && srcy >= 0 && srcy <= BitmapSrc.Height) { ArrayDst[i * 3 + 0 + j * DataDst.Stride] = ArraySrc[srcx * 3 + 0 + srcy * DataSrc.Stride]; ArrayDst[i * 3 + 1 + j * DataDst.Stride] = ArraySrc[srcx * 3 + 1 + srcy * DataSrc.Stride]; ArrayDst[i * 3 + 2 + j * DataDst.Stride] = ArraySrc[srcx * 3 + 2 + srcy * DataSrc.Stride]; } else { ArrayDst[i * 3 + 0 + j * DataDst.Stride] = 0; ArrayDst[i * 3 + 1 + j * DataDst.Stride] = 0; ArrayDst[i * 3 + 2 + j * DataDst.Stride] = 0; } } } // Array에서 BitmapData로 Copy System.Runtime.InteropServices.Marshal.Copy(ArrayDst, 0, DataDst.Scan0, ArrayDst.Length); BitmapSrc.UnlockBits(DataSrc); BitmapDst.UnlockBits(DataDst); return(BitmapDst); } catch (Exception) { throw; } }
public static fPoint OperateDict(Dictionary <fPoint, long> dct, fPoint aproxPoint) { long minX = aproxPoint.X + -20; long minY = aproxPoint.Y + -20; long minZ = aproxPoint.Z + -20; long maxX = aproxPoint.X + (20); long maxY = aproxPoint.Y + (20); long maxZ = aproxPoint.Z + (20); long maxBois = 0; fPoint lePoint = new fPoint(0, 0, 0); for (long i = minX; i < maxX + 1; i++) { for (long j = minY; j < maxY + 1; j++) { for (long k = minZ; k < maxZ + 1; k++) { int currBois = dct.Where(r => ManhattanDist(r.Key, new fPoint(i, j, k)) <= r.Value).Count(); if (currBois > maxBois) { maxBois = currBois; lePoint = new fPoint(i, j, k); } } } } return(lePoint); }
public Ball(fPoint pos, fVector vector, bool beep) : this(pos, vector) { // Initializes the vector of the ball if it is 0 if (this.vector.x == 0 && this.vector.y == 0) { this.vector = fVector.getRandom(); } }
public List <FlatWithPositions> GetFlatBetweenZY(int z, int y) { var result = new List <FlatWithPositions>(); var p = new fPoint(z * multiplicator, y * multiplicator); foreach (var flat in flats) { bool b = false; if (flat.Points.Count() == 4) { var v1 = vertices[flat.Points[0].VertexId - 1]; var v2 = vertices[flat.Points[1].VertexId - 1]; var v3 = vertices[flat.Points[2].VertexId - 1]; var v4 = vertices[flat.Points[3].VertexId - 1]; b = PointInTriangle(p, new fPoint(v1.Z, v1.Y), new fPoint(v2.Z, v2.Y), new fPoint(v3.Z, v3.Y) ) && PointInTriangle(p, new fPoint(v3.Z, v3.Y), new fPoint(v4.Z, v4.Y), new fPoint(v1.Z, v1.Y) ); } else if (flat.Points.Count() == 3) { var v1 = vertices[flat.Points[0].VertexId - 1]; var v2 = vertices[flat.Points[1].VertexId - 1]; var v3 = vertices[flat.Points[2].VertexId - 1]; b = PointInTriangle(p, new fPoint(v1.Z, v1.Y), new fPoint(v2.Z, v2.Y), new fPoint(v3.Z, v3.Y) ); } if (b) { var f = new FlatWithPositions(); f.FlatId = flats.IndexOf(flat); foreach (var posi in flat.Points) { var vert = vertices[posi.VertexId - 1]; f.Positions.Add(new Position3D { X = vert.X / multiplicator, Y = vert.Y / multiplicator * -1.0f, Z = vert.Z / multiplicator, }); } result.Add(f); } } return(result); }
public Ball(fPoint pos, fVector vector) { this.pos = pos; this.vector = vector; // Initializes the vector of the ball if it is 0 if (this.vector.x == 0 && this.vector.y == 0) { this.vector = fVector.getRandom(); } }
bool PointInTriangle(fPoint pt, fPoint v1, fPoint v2, fPoint v3) { float d1, d2, d3; bool has_neg, has_pos; d1 = sign(pt, v1, v2); d2 = sign(pt, v2, v3); d3 = sign(pt, v3, v1); has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0); has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0); return(!(has_neg && has_pos)); }
//在鼠标按下的时候触发的事件 public void DrawStart() { fPoint currentPoint = new fPoint(fx, fy); switch (selectedTool) { case Tools.pointer: break; //橡皮擦为白色的50宽度的铅笔 case Tools.pen: case Tools.eraser: pointQueue.Enqueue(currentPoint); gl.Begin(OpenGL.GL_POINTS); { gl.Vertex(fx, fy, 0f); } gl.End(); gl.Flush(); break; case Tools.line: pointQueue.Enqueue(currentPoint); //gl.genbuffers(1, buffers); //gl.bindbuffer(buffers[0], opengl.gl_color_buffer_bit); break; case Tools.circle: case Tools.rec: pointQueue.Enqueue(currentPoint); break; case Tools.poly: if (pointQueue.Count != 0) { gl.Begin(OpenGL.GL_LINES); { gl.Vertex(currentPoint.fx, currentPoint.fy, 0f); gl.Vertex(pointQueue.Peek().fx, pointQueue.Peek().fy); } gl.End(); pointQueue.Clear(); } break; } isDrawing = true; }
public static Dictionary <fPoint, long> reduceDict(int factor) { Dictionary <fPoint, long> dctReturn = new Dictionary <fPoint, long>(); foreach (var bot in dctNanoBots) { long newCordX = bot.Key.X / factor; long newCordY = bot.Key.Y / factor; long newCordZ = bot.Key.Z / factor; long val = bot.Value / factor; fPoint simplePoint = new fPoint(newCordX, newCordY, newCordZ); if (dctReturn.ContainsKey(simplePoint) == false) { dctReturn.Add(simplePoint, val); } } return(dctReturn); }
// 회전 And 이동 매트릭스 테스트 static fPoint PoseMatrix(float Model_x, float Model_y, float LeftTopX, float LeftTopY, float Degree, int width, int height) { try { // 각도를 라디안으로 변환 double Radian = Degree * Math.PI / 180; float Cos = (float)Math.Cos(Radian); float Sin = (float)Math.Sin(Radian); // 1. 배열 만들기 float[] PoseArray = new float[] { Cos, -Sin, LeftTopX + width / 2, Sin, Cos, LeftTopY + height / 2, 0, 0, 1 }; float[] PointArray = new float[] { Model_x - width / 2, Model_y - height / 2, 1 }; // 2. 배열로 Mat 만들기 Mat PoseMat = new Mat(3, 3, MatType.CV_32FC1, PoseArray); Mat PointMat = new Mat(3, 1, MatType.CV_32FC1, PointArray); // 3. 계산하기 Mat PosePoint = PoseMat * PointMat; float[] Result = new float[3 * 1]; PosePoint.GetArray(0, 0, Result); fPoint fpoint = new fPoint(); fpoint.x = Result[0]; // x좌표 fpoint.y = Result[1]; // y좌표 return(fpoint); } catch (Exception) { throw; } }
}//fillSelection() #endregion /// <summary> /// Returns true if the point falls on the rotate-marker of the passed shape; otherwise false. /// WARNING: Makes excessive use of hardcoded numbers. /// </summary> /// <param name="potentialShapes"></param> /// <returns></returns> private bool onRotateMarker(PowerPoint.Shape testShape, fPoint cursor) { float hDisp = 0; // the horizontal displacement from the center of the shape float vDisp = 15; // the height above the top of the bounding box that the center of the marker is. float margin = 8; // the margin (as radius, but like a square) around the center of the marker that we will accept hits on. // the coords (unrotated) of the marker's center. fPoint markCenter = new fPoint(testShape.Left + (testShape.Width / 2) + hDisp, testShape.Top - vDisp); // get the coords of the point fPoint rotCursor = rotatePointWithShape(cursor, testShape); //FIXME TEST DEBUG -- adds a shape to the (unrotated) location of where it thinks the marker is //pptController.addShapeToCurrSlide(MsoAutoShapeType.msoShapeRectangle, markCenter.x - margin, markCenter.y - margin, margin * 2, margin * 2); // see if they're close if ((Math.Abs(rotCursor.x - markCenter.x) <= margin) && (Math.Abs(rotCursor.y - markCenter.y) <= margin)) { return(true); } return(false); }
public static void Run() { string[] linesInput = File.ReadAllLines(Util.ReadFromInputFolder(23)); foreach (string line in linesInput) { string[] posCoords = line.Between("<", ">").Split(','); long signalStrength = Convert.ToInt64(line.Between("r=").Trim()); long xPoint = Convert.ToInt64(posCoords[0]); long yPoint = Convert.ToInt64(posCoords[1]); long zPoint = Convert.ToInt64(posCoords[2]); fPoint BotPosition = new fPoint(xPoint, yPoint, zPoint); dctNanoBots.Add(BotPosition, signalStrength); } var strongestNano = dctNanoBots.OrderByDescending(r => r.Value).First(); Console.WriteLine("Part 1: " + dctNanoBots.Where(r => ManhattanDist(r.Key, strongestNano.Key) <= strongestNano.Value).Count()); Console.WriteLine("Loading part 2, should take 1 minute"); // Reduces the lookout on the points to make complexity manageable // Finds best match for this small region // Amplifies the result to set it up for the next factor fPoint lePoint = new fPoint(); for (int factor = 10000000; factor >= 1; factor /= 10) { lePoint = OperateDict(reduceDict(factor), lePoint); lePoint.X *= 10; lePoint.Y *= 10; lePoint.Z *= 10; } string answer = ManhattanDist(new fPoint(0, 0, 0), lePoint).ToString(); answer = answer.Remove(answer.Length - 1); //remove last character for the last extra computation Console.WriteLine("Part 2: " + answer); }
public static long ManhattanDist(fPoint a, fPoint b) { return(Math.Abs(a.X - b.X) + Math.Abs(a.Y - b.Y) + Math.Abs(a.Z - b.Z)); }
/// <summary> /// LoadNPCSpawn /// </summary> private static void LoadMonsterSpawn() { bool l_bIsReturn = false; Session l_Session = new Session( BaseDatabase.Domain ); l_Session.BeginTransaction(); { do { ////////////////////////////////////////////////////////////////////////// // 获取刷怪点(怪物)信息 Query l_QuerySpawnMonsters = new Query( l_Session, "Select SpawnMonsters instances" ); QueryResult l_SpawnMonstersResult = l_QuerySpawnMonsters.Execute(); if ( l_SpawnMonstersResult == null ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_SpawnMonstersResult == null error!" ); l_bIsReturn = true; break; } for ( int iIndex = 0; iIndex < l_SpawnMonstersResult.Count; iIndex++ ) { SpawnMonsters l_SpawnMonster = l_SpawnMonstersResult[iIndex] as SpawnMonsters; if ( l_SpawnMonster == null ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_SpawnMonster == null error!" ); l_bIsReturn = true; break; } ConstructorInfo l_ConstructorInfo = s_ROSEMobilePool[l_SpawnMonster.MobileGUID]; if ( l_ConstructorInfo == null ) { Debug.WriteLine( string.Format( "Program.LoadMonsterSpawn(...) - l_ConstructorInfo == null error(SpawnMonsters.SpawnGuid = {0})!", l_SpawnMonster.SpawnGuid ) ); l_bIsReturn = true; break; } ROSEMobile l_ROSEMobile = l_ConstructorInfo.Invoke( null ) as ROSEMobile; if ( l_ROSEMobile == null ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_ROSEMobile == null error!" ); l_bIsReturn = true; break; } Regex l_Regex = new Regex( @"(\d+)+", RegexOptions.Compiled ); // 分析 Points "3|5000,5000|5100,5000|5000,5100" MatchCollection l_MatchCollectionPoints = l_Regex.Matches( l_SpawnMonster.Points ); if ( l_MatchCollectionPoints == null ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_MatchCollectionPoints == null error!" ); l_bIsReturn = true; break; } if ( l_MatchCollectionPoints.Count < 1 ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_MatchCollectionPoints.Count < 1 error!" ); l_bIsReturn = true; break; } Match l_MatchPointCount = l_MatchCollectionPoints[0]; Group l_GroupPointCount = l_MatchPointCount.Groups[1]; int l_iPointCount = -1; Int32.TryParse( l_GroupPointCount.ToString(), out l_iPointCount ); if ( l_iPointCount < 0 ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_iPointCount < 0 error!" ); l_bIsReturn = true; break; } if ( l_MatchCollectionPoints.Count != ( l_iPointCount * 2 + 1 ) ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_MatchCollectionPoints.Count != ( l_iPointCount * 2 + 1 ) error!" ); l_bIsReturn = true; break; } List<fPoint> l_PointList = new List<fPoint>(); for ( int iIndex2 = 1; iIndex2 < l_MatchCollectionPoints.Count; ++iIndex2 ) { Match l_MatchX = l_MatchCollectionPoints[iIndex2]; Group l_GroupX = l_MatchX.Groups[1]; int l_iResultX = 0; Int32.TryParse( l_GroupX.ToString(), out l_iResultX ); Match l_MatchY = l_MatchCollectionPoints[++iIndex2]; Group l_GroupY = l_MatchY.Groups[1]; int l_iResultY = 0; Int32.TryParse( l_GroupY.ToString(), out l_iResultY ); fPoint l_Point = new fPoint(); l_Point.x = l_iResultX; l_Point.y = l_iResultY; l_PointList.Add( l_Point ); } fPoint l_RandPoint = RandInPoly( l_PointList.ToArray() ); l_ROSEMobile.X = (int)l_RandPoint.x; l_ROSEMobile.Y = (int)l_RandPoint.y; BaseMap l_BaseMap = s_BaseWorld.GetMap( l_SpawnMonster.MapID ); if ( l_BaseMap == null ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_BaseMap == null error!" ); l_bIsReturn = true; break; } //l_BaseMap.OnEnter( l_ROSEMobile ); } if ( l_bIsReturn == true ) break; ////////////////////////////////////////////////////////////////////////// // 获取刷怪点(NPC)信息 Query l_QuerySpawnNPCs = new Query( l_Session, "Select SpawnNPCs instances" ); QueryResult l_SpawnNPCsResult = l_QuerySpawnNPCs.Execute(); if ( l_SpawnNPCsResult == null ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_SpawnNPCsResult == null error!" ); l_bIsReturn = true; break; } for ( int iIndex = 0; iIndex < l_SpawnNPCsResult.Count; iIndex++ ) { SpawnNPCs l_SpawnNPCs = l_SpawnNPCsResult[iIndex] as SpawnNPCs; if ( l_SpawnNPCs == null ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_SpawnNPCs == null error!" ); l_bIsReturn = true; break; } ConstructorInfo l_ConstructorInfo = s_ROSEMobilePool[l_SpawnNPCs.NPCGuid]; if ( l_ConstructorInfo == null ) { Debug.WriteLine( string.Format( "Program.LoadMonsterSpawn(...) - l_ConstructorInfo == null error(SpawnNPCs.SpawnGuid = {0})!", l_SpawnNPCs.SpawnGuid ) ); l_bIsReturn = true; break; } ROSEMobile l_ROSEMobile = l_ConstructorInfo.Invoke( null ) as ROSEMobile; if ( l_ROSEMobile == null ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_ROSEMobile == null error!" ); l_bIsReturn = true; break; } l_ROSEMobile.X = (int)l_SpawnNPCs.PositionX; l_ROSEMobile.Y = (int)l_SpawnNPCs.PositionY; //l_ROSEMobile.Direction = l_SpawnNPCs.Direction; BaseMap l_BaseMap = s_BaseWorld.GetMap( l_SpawnNPCs.MapID ); if ( l_BaseMap == null ) { Debug.WriteLine( "Program.LoadMonsterSpawn(...) - l_BaseMap == null error!" ); l_bIsReturn = true; break; } //l_BaseMap.OnEnter( l_ROSEMobile ); } } while ( false ); } l_Session.Commit(); if ( l_bIsReturn == true ) throw new Exception( "读取刷怪点数据 错误!" ); LOGs.WriteLine( LogMessageType.MSG_INFO, "信息: 刷怪点数据读取完成!" ); }
float sign(fPoint p1, fPoint p2, fPoint p3) { return((p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y)); }
/// <summary> /// 给出在多边形内的一个随机点 /// </summary> /// <param name="point">多边形的各个点</param> /// <param name="pointCount">多边形点数</param> /// <returns>多边形内的一个随机点</returns> private static fPoint RandInPoly( fPoint[] point ) { // 多边形内三角形数(以第一个点为公共点) int l_iTriangleCount = point.Length - 2; // 多边形内三角形的逐步累计的面积 float[] l_Areas = new float[l_iTriangleCount]; // 多边形的总共面积 float l_fTotalArea = 0.0f; for ( int iIndex = 0; iIndex < l_iTriangleCount; iIndex++ ) { l_fTotalArea += AreaOfTriangle( point[0], point[iIndex + 1], point[iIndex + 2] ); l_Areas[iIndex] = l_fTotalArea; } float l_fRandArea = 0.0f; do { l_fRandArea = (float)Utility.RandomDouble() * l_fTotalArea; } while ( l_fRandArea == 0.0f ); int l_iIndex = 0; for ( l_iIndex = 0; l_iIndex < l_iTriangleCount; l_iIndex++ ) { if ( l_fRandArea <= l_Areas[l_iIndex] ) break; } return RandInTriangle( point[0], point[l_iIndex + 1], point[l_iIndex + 2] ); }
/// <summary> /// when shapes are stacked in layers, it's difficult to access the shapes hidden under the /// first item. SelectNext enables the user to access those objects with a single tap - it /// cycles through all the shapes that fall under this mouseDown. /// TODO FIXME: right now, if other gestures -- for example, moving or deleting shapes -- happen between /// calls to this method, we may try to access shapes that are no longer under the cursor or perhaps /// now nonexistant. /// </summary> /// <param name="x">x coordinate</param> /// <param name="y">y coordinate</param> /// <returns>the Shape to be selected</returns> internal PowerPoint.Shape selectNext(fPoint p, bool doSelect) { // if we tapped on the same point the last time we tapped (with small margin), just go through the list and select the next thing //TODO FIXME - don't hardcode the margin in if (p.isNear(lastSelectedPoint, 2)) { // if it's empty, clear selection if (shapesAtCurrentPoint.Count == 0) { if (doSelect) { selectShape(null, true); } return(null); } //then, if we've decremented past the end of layeredShapeCounter, loop around if (layeredShapeCounter < 0) { layeredShapeCounter = shapesAtCurrentPoint.Count - 1; } // then, select the shape at the counter and decrement for next time if (doSelect) { selectShape(shapesAtCurrentPoint[layeredShapeCounter], false); } layeredShapeCounter--; return(shapesAtCurrentPoint[layeredShapeCounter]); } // remember what point we just tapped at lastSelectedPoint = p; // Reset the list of shapes at the tapped point shapesAtCurrentPoint.Clear(); // get all the shapes List <PowerPoint.Shape> totalShapes = pptController.allShapes(); // List<PowerPoint.Shape> choices = new List<PowerPoint.Shape>(); // to store possible candidates // go through each shape and add it to the list if it's there foreach (PowerPoint.Shape currentShape in totalShapes) { if (pptController.pointOnShape(p, currentShape)) { shapesAtCurrentPoint.Add(currentShape); } } layeredShapeCounter = shapesAtCurrentPoint.Count - 1; // # of Shapes: 0 = clear selection // : 1 = add it to selection // : >1= add (last added) to selection and move counter to previous one PowerPoint.Shape shape; if (layeredShapeCounter == -1) { shape = null; if (doSelect) { selectShape(null, true); } setFeedback("No object selected - please tap on top of a valid object"); } else { shape = shapesAtCurrentPoint[layeredShapeCounter]; if (doSelect) { selectShape(shape, false); } layeredShapeCounter--; //and decrement the counter // DEBUG FEEDBACK FIXME // setFeedback("Object selected; w=" + shape.Width.ToString() + " h=" + shape.Height.ToString() + " r=" + shape.Rotation.ToString() + // " hf=" + shape.HorizontalFlip.ToString() + " vf=" + shape.VerticalFlip.ToString() + layeredShapeCounter); } // call up an button to display recognition alternatives of that particular textbox // set up such that regardless of input doSelect, a textbox will be selected if clicked if (shape.Type == MsoShapeType.msoTextBox) { displayButton(shape); } return(shape); }
//先介绍一下三维中的两点之间距离之式,和二维的几乎一样:d = sqrt((x0-x1)^2 + (y0-y1)^2 + (z0-z1)^2) // //再介绍叉乘,中心内容!叉乘在定义上有:两个向量进行叉乘得到的是一个向量,方向垂直于这两个向量构成的平面,大小等于这两个向量组成的平行四边形的面积. // //在直角座标系[O;i,j,k]中,i、j、k分别为X轴、Y轴、Z轴上向量的单位向量.设P0(0,0,0),P1(x1,y1,z1),P2(x2,y2,z2).因为是从原点出发,所以向量P0P1可简记为P1,向量P0P2可简记为P2.依定义有: // // |i j k | //P1×P2 = |x1 y1 z1| // |x2 y2 z2| // //展开,得到: //上式 = iy1z2 + jz1x2 + kx1y2 - ky1x2 - jx1z2 - iz1y2 // = (y1z2 - y2z1)i + (x2z1 - x1z2)j + (x1y2 - x2y1)k // //按规定,有:单位向量的模为1.可得叉积的模为: //|P1×P2| = y1z2 - y2z1 + x2z1 - x1z2 + x1y2 - x2y1 // = (y1z2 + x2z1 + x1y2) - (y2z1 + x1z2 + x2y1) // //开始正式内容.我们设三角形的三个顶点为A(x0,y0,z0),B(x1,y1,z1),C(x2,y2,z2).我们将三角形的两条边AB和AC看成是向量.然后,我们以A为原点,进行坐标平移,得到向量B(x1-x0,y1-y0,z1-z0),向量C(x2-x0,y2-y0,z2-z0). // //①在三维的情况下,直接代入公式,可得向量B和向量C叉乘结果的模为: //|B×C| = ((y1-y0)*(z2-z0) + (z1-z0)*(x2-x0) + (x1-x0)*(y2-y0)) - ((y2-y0)*(z1-z0) + (z2-z0)*(x1-x0) + (x2-x0)*(y1-y0)) // | 1 1 1 | // = |x1-x0 y1-y0 z1-z0| // |x2-x0 y2-y0 z2-z0| //它的一半即为所要求的三角形面积S. // //还有一种比较简单的写法.将向量AB和AC平移至原点后,设向量B为(x1,y1,z1),向量C为(x2,y2,z2),则他们的叉乘所得向量P为(x,y,z),其中: // |y1 z1| |z1 x1| |x1 y1| //x = | | y = | | z = | | // |y2 z2| |z2 x2| |x2 y2| //然后用三维中的两点之间距离公式,求出(x,y,z)与(0,0,0)的距离,即为向量P的模,它的一半就是所要求的面积了. //以上公式都很好记:x分量由y,z分量组成,y分量由z,x分量组成,z分量由x,y分量组成,恰好是循环的.坐标平移一下就好了. // //②在二维的情况下,我们可以取z = 0这个平面,即令z1 = z2 = 0,且 //|P1×P2| = x1y2 - x2y1 // |x1 y1| // = | | // |x2 y2| //所以: //|B×C| = (x1-x0)*(y2-y0)-(x2-x0)*(y1-y0) // |x1-x0 y1-y0| // = | | // |x2-x0 y2-y0| //它的一半即为所要求的三角形的面积S. // //注意,用行列式求出来的面积是带符号的.如果A,B,C是按顺时针方向给出,则S为负;按逆时针方向给出,则S为正. //以二维的情况为例,三维亦同: // //A(0,0) B(0,1) C(1,0) (A,B,C按顺时针方向给出) //S = ((x1-x0)*(y2-y0)-(x2-x0)*(y1-y0))/2; // = ((0 - 0)*(0 - 0)-(1 - 0)*(1 - 0))/2 // = -0.5 // //A(1,0) B(0,1) C(0,0) (A,B,C按逆时针方向给出) //S = ((x1-x0)*(y2-y0)-(x2-x0)*(y1-y0))/2; // = ((0 - 1)*(0 - 0)-(0 - 1)*(1 - 0))/2 // = 0.5 // //如果你不需要符号的话,再求一下绝对值就好了.这样也不用去管给出的点的顺序了. //以上是利用叉乘.其实还有一招,那就是海伦公式: //利用两点之间距离公式,求出三角形的三边长a,b,c后,令p = (a+b+c)/2.再套入以下公式就可以求出三角形的面积S : //S = sqrt(p*(p-a)*(p-b)*(p-c)) //看起来好像比上面的都要简单…… -.-b 各位看客不要打我! //推荐:在二维的时候使用叉乘公式,三维的时候使用海伦公式~~~不过如果是需要符号的情况时,就只能使用行列式的计算公式了. /// <summary> /// 给出三角形的面积 /// </summary> /// <param name="point1"></param> /// <param name="point2"></param> /// <param name="point3"></param> /// <returns></returns> private static float AreaOfTriangle( fPoint point0, fPoint point1, fPoint point2 ) { return Math.Abs( ( ( point1.x - point0.x ) * ( point2.y - point0.y ) - ( point2.x - point0.x ) * ( point1.y - point0.y ) ) / 2 ) ; }
//在鼠标抬起时触发的事件 //通过读取 pointQueue 内的上一个点的数据连线 public void DrawEnd() { isDrawing = false; switch (selectedTool) { case Tools.pointer: break; case Tools.pen: case Tools.eraser: pointQueue.Clear(); break; case Tools.line: gl.Begin(OpenGL.GL_LINES); { gl.Vertex(fx, fy, 0f); gl.Vertex(pointQueue.Peek().fx, pointQueue.Peek().fy, 0f); } pointQueue.Clear(); gl.End(); break; case Tools.circle: //使用参数函数 x = Acos; y = Bsin画椭圆 double lenA = Math.Abs(fx - pointQueue.Peek().fx) / 2.0; double lenB = Math.Abs(fy - pointQueue.Peek().fy) / 2.0; fPoint center = new fPoint((fx + pointQueue.Peek().fx) / 2.0, (fy + pointQueue.Peek().fy) / 2.0); int n = 90; //精度,以n边的多边形代替椭圆 gl.Begin(OpenGL.GL_POLYGON); { for (double alpha = 0; alpha < Math.PI * 2; alpha += Math.PI / n) { gl.Vertex(center.fx + Math.Cos(alpha) * lenA, center.fy + Math.Sin(alpha) * lenB, 0f); } } gl.End(); pointQueue.Clear(); break; case Tools.rec: gl.Begin(OpenGL.GL_POLYGON); { gl.Vertex(fx, fy, 0f); gl.Vertex(fx, pointQueue.Peek().fy, 0f); gl.Vertex(pointQueue.Peek().fx, pointQueue.Peek().fy, 0f); gl.Vertex(pointQueue.Peek().fx, fy, 0f); } gl.End(); pointQueue.Clear(); break; case Tools.poly: //检测是否刚刚双击 if (!toClearPoly) { pointQueue.Enqueue(new fPoint(fx, fy)); } else { pointQueue.Clear(); toClearPoly = false; } break; } }
/// <summary> /// 判断点point是否是三角形内 point0,point1,point2为三角形的三个顶点 /// </summary> /// <param name="point0"></param> /// <param name="point1"></param> /// <param name="point2"></param> /// <param name="point"></param> /// <returns></returns> private static bool PointInTriangle( fPoint point0, fPoint point1, fPoint point2, fPoint point ) { float iReturn0 = VectorMultiply( point0, point, point1 ); float iReturn1 = VectorMultiply( point1, point, point2 ); float iReturn2 = VectorMultiply( point2, point, point0 ); if ( iReturn0 * iReturn1 * iReturn2 == 0 ) return false; if ( ( iReturn0 > 0 && iReturn1 > 0 && iReturn2 > 0 ) || ( iReturn0 < 0 && iReturn1 < 0 && iReturn2 < 0 ) ) return true; return false; }
/// <summary> /// 判断三点是否共线函数 /// </summary> /// <param name="point0"></param> /// <param name="point1"></param> /// <param name="point2"></param> /// <returns></returns> private static bool PointOnSameLine( fPoint point0, fPoint point1, fPoint point2 ) { return ( VectorMultiply( point0, point1, point2 ) == 0 ); }
//功能: 用户输入4个坐标(平面坐标系x轴正方向向左,y正方向向上),判断前3个坐标是否可以作为三角形的3个顶点; // 如果能,同时判断第四个坐标是否在这个三角形内 (不包括在边上和顶点上) // //说明: 程序中涉及到两个函数PoOnSameLine和PoRelative. // 其中函数PoOnSameLine是用来判断三点是否共线,函数PoRelative返回点与直线的关系, // 两个函数都要用到向量叉积公式: // 向量A和向量B的叉积是一个向量,记作A×B,方向可以用右用定则得出,其模|A×B| = |A||B|sin& (&是A与B的夹角) // | i , j , k | // 向量叉积的坐标表示为:A*B = | a1, a2, a3 | (其中i,j,k分别为单位向量; A = [a1,a2,a3], B = [b1,b2,b3]) // | b1, b2, b3 | // // 判断三点是否共线的算法如下: // 设三角形的三个顶点为A(x1,y1),B(x2,y2),和C(x3,y3), // 以A为共同点分别连接B和C,得出向量AB和AC,坐标表示为 AB = (x2-x1,y2-y1), AC = (x3-x1,y3-y1) // | x2 - x1, y2 - y1 | // AB*AC = | x3 - x1, y3 - y1 | // = (x2 - x1)(y3 - y1) - (y2 - y1)(x3 - x1) // 由|A||B|sin&=0得,如果AB×AC=0则点A,B,C在同一条直线上(共顶点A且夹角为零) // // 判断第四个点与直线的关系算法: // 设三角形按逆时针方向的三个顶点分别为A,B,C,第四个点为P,我们按逆时针方向连接ABC,得到三个向量分别为AB,BC,CA, // 再分别以A,B,C为顶点,连接P,得到向量AP,BP,CP,分别计算AB×AP,BC×BP,CA×CP的值,结果为三个新向量N1,N2和N3, // 根据N*的方向可得出点P与向量AB,BC,CA的位置关系,我们以左侧或右侧来描述 // 根据位置关系,对于点P,如果他同时位于向量的AB,BC和CA的同一侧(左侧或右侧)即向量N同号(不为零),则点在三角形内, // 否则在三角形外(如果叉乘为零则点位于向量上),该判定还可上升到凸多边形的情况. /// <summary> /// 返回向量叉乘,公共点为point0 /// </summary> /// <param name="point0"></param> /// <param name="point1"></param> /// <param name="point2"></param> /// <returns></returns> private static float VectorMultiply( fPoint point0, fPoint point1, fPoint point2 ) { return ( ( point1.x - point0.x ) * ( point2.y - point0.y ) - ( point2.x - point0.x ) * ( point1.y - point0.y ) ); }
/// <summary> /// 给出在三角形内的一个随机点 /// </summary> /// <param name="point1"></param> /// <param name="point2"></param> /// <param name="point3"></param> /// <returns></returns> private static fPoint RandInTriangle( fPoint point0, fPoint point1, fPoint point2 ) { float floatA = 0.0f; do { floatA = (float)Utility.RandomDouble(); } while ( floatA == 0.0f ); float floatB = 0.0f; do { floatB = (float)Utility.RandomDouble(); } while ( floatB == 0.0f || floatB + floatA >= 1.0 ); float floatC = 1 - floatA - floatB; fPoint l_ReturnPoint = new fPoint(); l_ReturnPoint.x = ( point0.x * floatA ) + ( point1.x * floatB ) + ( point2.x * floatC ); l_ReturnPoint.y = ( point0.y * floatA ) + ( point1.y * floatB ) + ( point2.y * floatC ); return l_ReturnPoint; }