IAtom n3 = neighbours.get(2); IAtom n4 = neighbours.get(3); Stereo stereo = getStereo(n1, n2, n3, n4); IAtom[] ligands = new IAtom[]{n1, n2, n3, n4}; ITetrahedralChirality stereoCenter
private static boolean isSquarePlanar(Point3d pointA, Point3d pointB, Point3d pointC, Point3d pointD, Vector3d normal) { // define a plane using ABC, also checking that the are not colinear Vector3d vectorAB = new Vector3d(); Vector3d vectorAC = new Vector3d(); getRawNormal(pointA, pointB, pointC, normal, vectorAB, vectorAC); if (StereoTool.isColinear(normal)) return false; // check that F is in the same plane as CDE return StereoTool.allCoplanar(normal, pointC, pointD); }
Point3d pointF = atomF.getPoint3d(); boolean isColinearABF = StereoTool.isColinear(pointA, pointB, pointF); if (isColinearABF) { Vector3d normal = StereoTool.getNormal(pointC, pointD, pointE); TetrahedralSign handednessCDEA = StereoTool.getHandedness(normal, pointC, pointF); TetrahedralSign handednessCDEF = StereoTool.getHandedness(normal, pointC, pointA);
private static TetrahedralSign getHandedness(Point3d pointA, Point3d pointB, Point3d pointC, Point3d pointD) { // assumes anti-clockwise for a right-handed system Vector3d normal = StereoTool.getNormal(pointA, pointB, pointC); // it doesn't matter which of points {A,B,C} is used return StereoTool.getHandedness(normal, pointA, pointD); }
/** * 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. * * @param ptA * @param ptB * @param ptC * @return true if the tree points are on a straight line */ public static boolean isColinear(Point3d ptA, Point3d ptB, Point3d ptC) { Vector3d vectorAB = new Vector3d(); Vector3d vectorAC = new Vector3d(); Vector3d normal = new Vector3d(); StereoTool.getRawNormal(ptA, ptB, ptC, normal, vectorAB, vectorAC); return isColinear(normal); }
/** * Take four atoms, and return Stereo.CLOCKWISE or Stereo.ANTI_CLOCKWISE. * The first atom is the one pointing towards the observer. * * @param atom1 the atom pointing towards the observer * @param atom2 the second atom (points away) * @param atom3 the third atom (points away) * @param atom4 the fourth atom (points away) * @return clockwise or anticlockwise */ public static Stereo 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 Stereo.ANTI_CLOCKWISE; } else { return Stereo.CLOCKWISE; } }
boolean isColinearABG = isColinear(pointA, pointB, pointG); if (!isColinearABG) return false; isSquarePlanar(pointC, pointD, pointE, pointF, normal);
@Test public void allCoplanarTest() { Point3d pointA = new Point3d(1, 1, 0); Point3d pointB = new Point3d(2, 1, 0); Point3d pointC = new Point3d(1, 2, 0); Point3d pointD = new Point3d(2, 2, 0); Point3d pointE = new Point3d(3, 2, 0); Point3d pointF = new Point3d(3, 3, 0); Vector3d normal = StereoTool.getNormal(pointA, pointB, pointC); Assert.assertTrue(StereoTool.allCoplanar(normal, pointA, pointB, pointC, pointD, pointE, pointF)); }
private static TetrahedralSign getHandedness(Vector3d planeNormal, Point3d pointInPlane, Point3d testPoint) { double distance = signedDistanceToPlane(planeNormal, pointInPlane, testPoint); // The point-plane distance is the absolute value, // the sign of the distance gives the side of the plane the point is on // relative to the plane normal. if (distance > 0) { return TetrahedralSign.PLUS; } else { return TetrahedralSign.MINUS; } }
@Test public void colinearTestWithNonColinearPoints() { Point3d pointA = new Point3d(1, 1, 1); Point3d pointB = new Point3d(2, 3, 2); Point3d pointC = new Point3d(3, 3, 3); Assert.assertFalse(StereoTool.isColinear(pointA, pointB, pointC)); }
private static boolean isSquarePlanar(Point3d pointA, Point3d pointB, Point3d pointC, Point3d pointD) { return isSquarePlanar(pointA, pointB, pointC, pointD, new Vector3d()); }
@Test public void getNormalFromThreePoints() { // these are, of course, points on these axes, not the axis vectors Point3d axisXPoint = new Point3d(XAXIS); Point3d axisYPoint = new Point3d(YAXIS); // the normal of X and Y should be Z Vector3d normal = StereoTool.getNormal(ORIGIN, axisXPoint, axisYPoint); assertEquals(ZAXIS, normal, 0.0001); }
@Test public void squarePlanarUShapeTest() { // all points are in the XY plane IAtom atomA = new Atom("C", new Point3d(1, 2, 0)); IAtom atomB = new Atom("C", new Point3d(1, 1, 0)); IAtom atomC = new Atom("C", new Point3d(2, 1, 0)); IAtom atomD = new Atom("C", new Point3d(2, 2, 0)); SquarePlanarShape shape = StereoTool.getSquarePlanarShape(atomA, atomB, atomC, atomD); Assert.assertEquals(SquarePlanarShape.U_SHAPE, shape); }
/** * <p>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.</p> * * <p>NOTE : the returned normal is normalized; that is, it has been * divided by its length.</p> * * @param ptA the 'middle' point * @param ptB one of the end points * @param ptC one of the end points * @return the vector at right angles to AB and AC */ public static Vector3d getNormal(Point3d ptA, Point3d ptB, Point3d ptC) { Vector3d vectorAB = new Vector3d(); Vector3d vectorAC = new Vector3d(); Vector3d normal = new Vector3d(); StereoTool.getRawNormal(ptA, ptB, ptC, normal, vectorAB, vectorAC); normal.normalize(); return normal; }
/** * 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. * * @param baseAtomA the first atom in the base of the tetrahedron * @param baseAtomB the second atom in the base of the tetrahedron * @param baseAtomC the third atom in the base of the tetrahedron * @param apexAtom the atom in the point of the tetrahedron * @return the sign of the tetrahedron */ public static TetrahedralSign getHandedness(IAtom baseAtomA, IAtom baseAtomB, IAtom baseAtomC, IAtom apexAtom) { Point3d pointA = baseAtomA.getPoint3d(); Point3d pointB = baseAtomB.getPoint3d(); Point3d pointC = baseAtomC.getPoint3d(); Point3d pointD = apexAtom.getPoint3d(); return StereoTool.getHandedness(pointA, pointB, pointC, pointD); }
/** * Check that all the points in the list are coplanar (in the same plane) * as the plane defined by the planeNormal and the pointInPlane. * * @param planeNormal the normal to the plane * @param pointInPlane any point know to be in the plane * @param points an array of points to test * @return false if any of the points is not in the plane */ public static boolean allCoplanar(Vector3d planeNormal, Point3d pointInPlane, Point3d... points) { for (Point3d point : points) { double distance = StereoTool.signedDistanceToPlane(planeNormal, pointInPlane, point); if (distance < PLANE_TOLERANCE) { continue; } else { return false; } } return true; }
@Test public void colinearTestWithNearlyColinearPoints() { Point3d pointA = new Point3d(1, 1, 1); Point3d pointB = new Point3d(2, 2.001, 2); Point3d pointC = new Point3d(3, 3, 3); Assert.assertTrue(StereoTool.isColinear(pointA, pointB, pointC)); }
/** * Checks these four atoms for square planarity. * * @param atomA an atom in the plane * @param atomB an atom in the plane * @param atomC an atom in the plane * @param atomD an atom in the plane * @return true if all the atoms are in the same plane */ public static boolean isSquarePlanar(IAtom atomA, IAtom atomB, IAtom atomC, IAtom atomD) { Point3d pointA = atomA.getPoint3d(); Point3d pointB = atomB.getPoint3d(); Point3d pointC = atomC.getPoint3d(); Point3d pointD = atomD.getPoint3d(); return isSquarePlanar(pointA, pointB, pointC, pointD); }
@Test public void squarePlanar4ShapeTest() { // all points are in the XY plane IAtom atomA = new Atom("C", new Point3d(1, 2, 0)); IAtom atomB = new Atom("C", new Point3d(2, 1, 0)); IAtom atomC = new Atom("C", new Point3d(2, 2, 0)); IAtom atomD = new Atom("C", new Point3d(1, 1, 0)); SquarePlanarShape shape = StereoTool.getSquarePlanarShape(atomA, atomB, atomC, atomD); Assert.assertEquals(SquarePlanarShape.FOUR_SHAPE, shape); }
StereoTool.getRawNormal(pointA, pointB, pointC, normalA, tmpX, tmpY); StereoTool.getRawNormal(pointB, pointC, pointD, normalB, tmpX, tmpY); StereoTool.getRawNormal(pointC, pointD, pointA, normalC, tmpX, tmpY);