/// <summary> /// Checks these 6 atoms to see if they form a trigonal-bipyramidal shape. /// </summary> /// <param name="atomA">one of the axial atoms</param> /// <param name="atomB">the central atom</param> /// <param name="atomC">one of the equatorial atoms</param> /// <param name="atomD">one of the equatorial atoms</param> /// <param name="atomE">one of the equatorial atoms</param> /// <param name="atomF">the other axial atom</param> /// <returns>true if the geometry is trigonal-bipyramidal</returns> public static bool IsTrigonalBipyramidal(IAtom atomA, IAtom atomB, IAtom atomC, IAtom atomD, IAtom atomE, IAtom atomF) { Vector3 pointA = atomA.Point3D.Value; Vector3 pointB = atomB.Point3D.Value; Vector3 pointC = atomC.Point3D.Value; Vector3 pointD = atomD.Point3D.Value; Vector3 pointE = atomE.Point3D.Value; Vector3 pointF = atomF.Point3D.Value; bool isColinearABF = StereoTool.IsColinear(pointA, pointB, pointF); if (isColinearABF) { // the normal to the equatorial plane Vector3 normal = StereoTool.GetNormal(pointC, pointD, pointE); // get the side of the plane that axis point A is TetrahedralSign handednessCDEA = StereoTool.GetHandedness(normal, pointC, pointF); // get the side of the plane that axis point F is TetrahedralSign handednessCDEF = StereoTool.GetHandedness(normal, pointC, pointA); // in other words, the two axial points (A,F) are on opposite sides // of the equatorial plane CDE return(handednessCDEA != handednessCDEF); } else { return(false); } }
public void ColinearTestWithNonColinearPoints() { Vector3 pointA = new Vector3(1, 1, 1); Vector3 pointB = new Vector3(2, 3, 2); Vector3 pointC = new Vector3(3, 3, 3); Assert.IsFalse(StereoTool.IsColinear(pointA, pointB, pointC)); }
private static TetrahedralSign GetHandedness(Vector3 pointA, Vector3 pointB, Vector3 pointC, Vector3 pointD) { // assumes anti-clockwise for a right-handed system Vector3 normal = StereoTool.GetNormal(pointA, pointB, pointC); // it doesn't matter which of points {A,B,C} is used return(StereoTool.GetHandedness(normal, pointA, pointD)); }
public void ColinearTestWithNearlyColinearPoints() { Vector3 pointA = new Vector3(1, 1, 1); Vector3 pointB = new Vector3(2, (float)2.001, 2); Vector3 pointC = new Vector3(3, 3, 3); Assert.IsTrue(StereoTool.IsColinear(pointA, pointB, pointC)); }
public void SquarePlanarTest() { IAtom atomA = new Atom("C", new Vector3(1, 2, 0)); IAtom atomB = new Atom("C", new Vector3(1, 1, 0)); IAtom atomC = new Atom("C", new Vector3(2, 2, 0)); IAtom atomD = new Atom("C", new Vector3(2, 1, 0)); Assert.IsTrue(StereoTool.IsSquarePlanar(atomA, atomB, atomC, atomD)); }
/// <summary> /// Checks the three supplied points to see if they fall on the same line. /// It does this by finding the normal to an arbitrary pair of lines between /// the points (in fact, A-B and A-C) and checking that its length is 0. /// </summary> /// <param name="ptA"></param> /// <param name="ptB"></param> /// <param name="ptC"></param> /// <returns>true if the tree points are on a straight line</returns> public static bool IsColinear(Vector3 ptA, Vector3 ptB, Vector3 ptC) { Vector3 vectorAB = new Vector3(); Vector3 vectorAC = new Vector3(); Vector3 normal = new Vector3(); StereoTool.GetRawNormal(ptA, ptB, ptC, out normal, out vectorAB, out vectorAC); return(IsColinear(normal)); }
/// <summary> /// Gets the tetrahedral handedness of four atoms - three of which form the /// 'base' of the tetrahedron, and the other the apex. Note that it assumes /// a right-handed coordinate system, and that the points {A,B,C} are in /// a counter-clockwise order in the plane they share. /// </summary> /// <param name="baseAtomA">the first atom in the base of the tetrahedron</param> /// <param name="baseAtomB">the second atom in the base of the tetrahedron</param> /// <param name="baseAtomC">the third atom in the base of the tetrahedron</param> /// <param name="apexAtom">the atom in the point of the tetrahedron</param> /// <returns>the sign of the tetrahedron</returns> public static TetrahedralSign GetHandedness(IAtom baseAtomA, IAtom baseAtomB, IAtom baseAtomC, IAtom apexAtom) { Vector3 pointA = baseAtomA.Point3D.Value; Vector3 pointB = baseAtomB.Point3D.Value; Vector3 pointC = baseAtomC.Point3D.Value; Vector3 pointD = apexAtom.Point3D.Value; return(StereoTool.GetHandedness(pointA, pointB, pointC, pointD)); }
/// <summary> /// Given three points (A, B, C), makes the vectors A-B and A-C, and makes /// the cross product of these two vectors; this has the effect of making a /// third vector at right angles to AB and AC. /// </summary> /// <remarks> /// <note type="note"> /// The returned normal is normalized; that is, it has been divided by its length.</note></remarks> /// <param name="ptA">the 'middle' point</param> /// <param name="ptB">one of the end points</param> /// <param name="ptC">one of the end points</param> /// <returns>the vector at right angles to AB and AC</returns> public static Vector3 GetNormal(Vector3 ptA, Vector3 ptB, Vector3 ptC) { Vector3 vectorAB = new Vector3(); Vector3 vectorAC = new Vector3(); Vector3 normal = new Vector3(); StereoTool.GetRawNormal(ptA, ptB, ptC, out normal, out vectorAB, out vectorAC); Vector3.Normalize(normal); return(normal); }
public void GetStereoCWTest() { IAtom closestAtomToViewer = new Atom("F", new Vector3(1, 1, 1)); IAtom highestCIPPriority = new Atom("I", new Vector3(0, 1, 2)); IAtom middleCIPPriority = new Atom("Br", new Vector3(0, 2, 0)); IAtom nearlylowestCIPPriority = new Atom("Cl", Vector3.Zero); Assert.AreEqual(TetrahedralStereo.Clockwise, StereoTool.GetStereo(closestAtomToViewer, highestCIPPriority, middleCIPPriority, nearlylowestCIPPriority)); }
public void TrigonalBipyramidalTest() { IAtom atomA = new Atom("C", new Vector3(1, 1, 2)); // axis point 1 IAtom atomB = new Atom("C", new Vector3(1, 1, 1)); // center of plane IAtom atomC = new Atom("C", new Vector3(0, 1, 1)); IAtom atomD = new Atom("C", new Vector3(1, 0, 1)); IAtom atomE = new Atom("C", new Vector3(2, 2, 1)); IAtom atomF = new Atom("C", new Vector3(1, 1, 0)); // axis point 2 Assert.IsTrue(StereoTool.IsTrigonalBipyramidal(atomA, atomB, atomC, atomD, atomE, atomF)); }
public void GetNormalFromThreePoints() { // these are, of course, points on these axes, not the axis vectors Vector3 axisXPoint = XAXIS; Vector3 axisYPoint = YAXIS; // the normal of X and Y should be Z Vector3 normal = StereoTool.GetNormal(ORIGIN, axisXPoint, axisYPoint); Assert.IsTrue(Vector3.Distance(ZAXIS, normal) < 0.0001); }
public void SquarePlanarZShapeTest() { // all points are in the XY plane IAtom atomA = new Atom("C", new Vector3(1, 2, 0)); IAtom atomB = new Atom("C", new Vector3(1, 1, 0)); IAtom atomC = new Atom("C", new Vector3(2, 2, 0)); IAtom atomD = new Atom("C", new Vector3(2, 1, 0)); SquarePlanarShape shape = StereoTool.GetSquarePlanarShape(atomA, atomB, atomC, atomD); Assert.AreEqual(SquarePlanarShape.ZShape, shape); }
public void TetrahedralMinusAtomsBelowXYTest() { // below the XY plane IAtom baseA = new Atom("C", new Vector3(0, 0, -1)); IAtom baseB = new Atom("C", new Vector3(1, 0, -1)); IAtom baseC = new Atom("C", new Vector3(1, 1, -1)); IAtom negativeApex = new Atom("C", new Vector3(0.5, 0.5, -2)); TetrahedralSign tetSign = StereoTool.GetHandedness(baseA, baseB, baseC, negativeApex); Assert.AreEqual(TetrahedralSign.Minus, tetSign); }
public void OctahedralTest() { IAtom atomA = new Atom("C", new Vector3(2, 2, 2)); // axis point 1 IAtom atomB = new Atom("C", new Vector3(2, 2, 1)); // center of plane IAtom atomC = new Atom("C", new Vector3(1, 3, 1)); IAtom atomD = new Atom("C", new Vector3(3, 3, 1)); IAtom atomE = new Atom("C", new Vector3(3, 1, 1)); IAtom atomF = new Atom("C", new Vector3(1, 3, 1)); IAtom atomG = new Atom("C", new Vector3(2, 2, 0)); // axis point 2 Assert.IsTrue(StereoTool.IsOctahedral(atomA, atomB, atomC, atomD, atomE, atomF, atomG)); }
public void TetrahedralPlusAtomsAboveXYClockwiseTest() { // above the XY plane IAtom baseA = new Atom("C", new Vector3(0, 0, 1)); IAtom baseB = new Atom("C", new Vector3(1, 0, 1)); IAtom baseC = new Atom("C", new Vector3(1, 1, 1)); IAtom positiveApex = new Atom("C", new Vector3(0.5, 0.5, 2)); TetrahedralSign tetSign = StereoTool.GetHandedness(baseC, baseB, baseA, positiveApex); Assert.AreEqual(TetrahedralSign.Minus, tetSign); }
public void AllCoplanarTest() { Vector3 pointA = new Vector3(1, 1, 0); Vector3 pointB = new Vector3(2, 1, 0); Vector3 pointC = new Vector3(1, 2, 0); Vector3 pointD = new Vector3(2, 2, 0); Vector3 pointE = new Vector3(3, 2, 0); Vector3 pointF = new Vector3(3, 3, 0); Vector3 normal = StereoTool.GetNormal(pointA, pointB, pointC); Assert.IsTrue(StereoTool.AllCoplanar(normal, pointA, pointB, pointC, pointD, pointE, pointF)); }
private static bool IsSquarePlanar(Vector3 pointA, Vector3 pointB, Vector3 pointC, Vector3 pointD, out Vector3 normal) { // define a plane using ABC, also checking that the are not colinear Vector3 vectorAB = new Vector3(); Vector3 vectorAC = new Vector3(); GetRawNormal(pointA, pointB, pointC, out normal, out vectorAB, out vectorAC); if (StereoTool.IsColinear(normal)) { return(false); } // check that F is in the same plane as CDE return(StereoTool.AllCoplanar(normal, pointC, pointD)); }
/// <summary> /// Take four atoms, and return <see cref="TetrahedralStereo.Clockwise"/> or <see cref="TetrahedralStereo.AntiClockwise"/>. /// The first atom is the one pointing towards the observer. /// </summary> /// <param name="atom1">the atom pointing towards the observer</param> /// <param name="atom2">the second atom (points away)</param> /// <param name="atom3">the third atom (points away)</param> /// <param name="atom4">the fourth atom (points away)</param> /// <returns>clockwise or anticlockwise</returns> public static TetrahedralStereo GetStereo(IAtom atom1, IAtom atom2, IAtom atom3, IAtom atom4) { // a normal is calculated for the base atoms (2, 3, 4) and compared to // the first atom. PLUS indicates ACW. TetrahedralSign sign = StereoTool.GetHandedness(atom2, atom3, atom4, atom1); if (sign == TetrahedralSign.Plus) { return(TetrahedralStereo.AntiClockwise); } else { return(TetrahedralStereo.Clockwise); } }
/// <summary> /// <para>Given four atoms (assumed to be in the same plane), returns the /// arrangement of those atoms in that plane.</para> /// /// <para>The 'shapes' returned represent arrangements that look a little like /// the characters 'U', '4', and 'Z'.</para> /// </summary> /// <param name="atomA">an atom in the plane</param> /// <param name="atomB">an atom in the plane</param> /// <param name="atomC">an atom in the plane</param> /// <param name="atomD">an atom in the plane</param> /// <returns>the shape (U/4/Z)</returns> public static SquarePlanarShape GetSquarePlanarShape(IAtom atomA, IAtom atomB, IAtom atomC, IAtom atomD) { Vector3 pointA = atomA.Point3D.Value; Vector3 pointB = atomB.Point3D.Value; Vector3 pointC = atomC.Point3D.Value; Vector3 pointD = atomD.Point3D.Value; // normalA normalB normalC are right-hand normals for the given // triangles // A-B-C, B-C-D, C-D-A Vector3 normalA = new Vector3(); Vector3 normalB = new Vector3(); Vector3 normalC = new Vector3(); // these are temporary vectors that are re-used in the calculations Vector3 tmpX = new Vector3(); Vector3 tmpY = new Vector3(); // the normals (normalA, normalB, normalC) are calculated StereoTool.GetRawNormal(pointA, pointB, pointC, out normalA, out tmpX, out tmpY); StereoTool.GetRawNormal(pointB, pointC, pointD, out normalB, out tmpX, out tmpY); StereoTool.GetRawNormal(pointC, pointD, pointA, out normalC, out tmpX, out tmpY); // normalize the normals Vector3.Normalize(normalA); Vector3.Normalize(normalB); Vector3.Normalize(normalC); // sp1 up up up U-shaped // sp2 up up Down 4-shaped // sp3 up Down Down Z-shaped var aDotB = Vector3.Dot(normalA, normalB); double aDotC = Vector3.Dot(normalA, normalC); double bDotC = Vector3.Dot(normalB, normalC); if (aDotB > 0 && aDotC > 0 && bDotC > 0) { // UUU or DDD return(SquarePlanarShape.UShape); } else if (aDotB > 0 && aDotC < 0 && bDotC < 0) { // UUD or DDU return(SquarePlanarShape.FourShape); } else { // UDD or DUU return(SquarePlanarShape.ZShape); } }
/// <summary> /// Check that all the points in the list are coplanar (in the same plane) /// as the plane defined by the planeNormal and the pointInPlane. /// </summary> /// <param name="planeNormal">the normal to the plane</param> /// <param name="pointInPlane">any point know to be in the plane</param> /// <param name="points">an array of points to test</param> /// <returns>false if any of the points is not in the plane</returns> public static bool AllCoplanar(Vector3 planeNormal, Vector3 pointInPlane, params Vector3[] points) { foreach (var point in points) { double distance = StereoTool.SignedDistanceToPlane(planeNormal, pointInPlane, point); if (distance < PlaneTolerance) { continue; } else { return(false); } } return(true); }
public void NegativePointPlaneDistanceTest() { // the normal for the Y-Z plane is X Vector3 planeNormal = XAXIS; Vector3.Normalize(planeNormal); // an arbitrary point in the Y-Z plane Vector3 pointInPlane = new Vector3(0, 1, 1); // make a negative point on the X axis = opposite direction to normal Vector3 pointToMeasureNeg = new Vector3(-2, 0, 0); double distance = StereoTool.SignedDistanceToPlane(planeNormal, pointInPlane, pointToMeasureNeg); Assert.AreEqual(-2.0, distance, 0.1); }