# Is it possible to determine if a line segment is present between two points on a 3d graphic object?

Hello everyone. I'm working on a program which plots 3D molecular structures and associated point group symmetries. I've had some issues figuring out how to fill in the remaining single bonds of a six member ring (aromatic class) after the user dictates where double bonds should be placed. These aromatics are basically 6 member cycle graphs for the purposes of my problem. Is there any way to evaluate two coordinates (atoms) on a 3d graphic object (molecule) and check if a line segment (bond) has already been added between them? By necessity any pi (double) bond should only be connected to the adjacent, (non pi-bonded) atom. So for example if there was a pi bond present between Atoms 1 and 2 of a ring then we should have single bonds between A6-A1 and A2-A3. The code below is how I am currently approaching that problem.

A1,A2,A3,A4,A6 are fixed, three dimensional coordinates associated with each position on the ring.

Bonds = str(input('Enter pi bond atomic pair in format "A1-A2" or type PLOT: '))

while (Bonds != 'PLOT'):
Bonds2 = Bonds.split('-')
for bond in Bonds2:
if bond == 'A1':
pi_list.append(A1)
elif bond == 'A2':
pi_list.append(A2)
elif bond == 'A3':
pi_list.append(A3)
elif bond == 'A4':
pi_list.append(A4)
elif bond == 'A5':
pi_list.append(A5)
elif bond == 'A6':
pi_list.append(A6)
if pi_list != []:
x += pi_bond(x,pi_list, pi_list)
for atom in Coords:
for pi_atom in pi_list:
if (atom != pi_list) and (atom != pi_list) and (float(distance(pi_atom,atom))==float(distance(A1,A2))):
x += single_bond(pi_atom, atom)
pi_list.clear()

if (Bonds == 'PLOT'):
break
Bonds = str(input('Enter additional pi bonds or type PLOT: '))


Can anyone think of a more elegant way to approach this?

Here is the function I am currently using to add a double bond between two points:

def pi_bond(x,Cx,Cy):
X = 0.05
if Cx == Cy:
Ca = Cx-X
Cb = Cx+X
Cc = Cy-X
Cd = Cy+X
Cx1 = (Cx, Ca, Cx)
Cx2 = (Cx, Cb, Cx)
Cy1 = (Cy, Cc, Cy)
Cy2 = (Cy, Cd, Cy)
x += LineSegment(Cx1, Cy1, 1, color='white', axes=False, frame=False)
x += LineSegment(Cx2, Cy2, 1, color='white', axes=False, frame=False)
return x
else:
Ca = Cx-X
Cb = Cx+X
Cc = Cy-X
Cd = Cy+X
Cx1 = (Cx, Cx, Ca)
Cx2 = (Cx, Cx, Cb)
Cy1 = (Cy, Cy, Cc)
Cy2 = (Cy, Cy, Cd)
x += LineSegment(Cx1, Cy1, 1, color='white', axes=False, frame=False)
x += LineSegment(Cx2, Cy2, 1, color='white', axes=False, frame=False)
return x

edit retag close merge delete

I would maintain all of the data for the molecule without doing any plotting, for example as a dictionary. Then it's easy to add and delete entries. When you're ready to plot, create the plot.

Am I understanding correctly that you're suggesting I create a default position dictionary that would like something like:

graph = { A1 : [A2, A6], A2 : [A1, A3], A3 : [A2, A4], A4: [A3, A5], A5: [A4, A6], A6: [A5, A1] }


This way when a user adds a pi bond pair ie A1-A2 I can delete the pairing from the default dictionary and add them to a second dictionary for double bonds or something to that effect. Much more elegant. Thank you for the suggestion.

Oh, and to try to answer your original question: I don't know of any way to determine whether a line segment is present in a graphics object. I am not an expert in the graphics part of Sage, though.

I think this will be a much better approach and I imagine any answer to that question would have taken me down a much more complicated rabbit hole.

I have fixed the issue and updated the code. Thank you again.

Sort by » oldest newest most voted

Using John Palmieri's suggestion I created a default dictionary of single bonds and an empty dictionary for pi bonds:

When a pi bond pair is added to Pi_Dict, the pairing from Sigma_Dict is deleted

I was not aware that lists could be entered into dictionaries and this will make my work much easier.

Updated code:

import sys
from sage.plot.plot3d.shapes import LineSegment, Sphere
from sage.plot.colors import rainbow
from sage.plot.plot3d.implicit_plot3d import implicit_plot3d
from sage.plot.plot3d.shapes2 import text3d
from sage.repl.rich_output.pretty_print import show

Radii = {'O': 0.73, 'N': 0.75, 'C': 0.77, 'He': 0.32, 'H': 0.37, 'S': 1.02, 'Cl': 0.99,
'F': 0.71, 'Xe': 1.30, 'Si': 1.11, 'B': 0.82, 'P': 1.06, 'Br': 1.14}

Valency = {'O': 6, 'N': 5, 'C': 4, 'He': 0, 'H': 1, 'S': 6, 'Cl': 7,
'F': 7, 'Xe': 8, 'Si': 4, 'B': 3, 'P': 5, 'Br': 7}

Colors = {'O': 'red', 'N': 'green', 'C': 'black', 'He': 'cyan', 'H': 'white', 'S': 'yellow',
'Si': 'purple', 'Xe': 'pink', 'F': 'blue', 'Cl': 'green', 'B': 'pink', 'P': 'orange',
'Br': 'red'}

X = int(input('Enter x axis shift or press enter for default: '))

def distance(A,B):
D = float(((B-A)**2 + (B-A)**2 + (B-A)**2)**(1/2))
return D
def Normalize(x):
x = (float(x)/0.77)*0.20
return x

O = (X,0,0)

A2 = (X, 1, 0.559)
A3 = (X, 1, -0.559)
A5 = (X, -1, -0.559)
A6 = (X, -1, 0.559)
A1 = (X, 0, distance(A2,A3))
A4 = (X, 0,-1*distance(A2,A3))

Sigma_Dict = { 'A1-A2' : [A1,A2], 'A2-A3' : [A2,A3], 'A3-A4' : [A3,A4], 'A4-A5' : [A4,A5], 'A5-A6' : [A5,A6], 'A1-A6' : [A1, A6] }

Pi_Dict = { 'A1-A2' : [A1,A2], 'A5-A6' : [A5,A6], 'A3-A4': [A3,A4] }

Atomic_Position = { A1: 'Br', A2: 'C', A3: 'Cl', A4: 'C', A5: 'B', A6: 'C' }

def bond_split(AxAy):
x = AxAy
y = AxAy
return(x,y)

def pi_bond(Cx,Cy):
X = 0.05
if Cx == Cy:
Ca = Cx-X
Cb = Cx+X
Cc = Cy-X
Cd = Cy+X
Cx1 = (Cx, Ca, Cx)
Cx2 = (Cx, Cb, Cx)
Cy1 = (Cy, Cc, Cy)
Cy2 = (Cy, Cd, Cy)
D = LineSegment(Cx1, Cy1, 1, color='white', axes=False, frame=False)
D += LineSegment(Cx2, Cy2, 1, color='white', axes=False, frame=False)
return (D)
else:
Ca = Cx-X
Cb = Cx+X
Cc = Cy-X
Cd = Cy+X
Cx1 = (Cx, Cx, Ca)
Cx2 = (Cx, Cx, Cb)
Cy1 = (Cy, Cy, Cc)
Cy2 = (Cy, Cy, Cd)
D = LineSegment(Cx1, Cy1, 1, color='white', axes=False, frame=False)
D += LineSegment(Cx2, Cy2, 1, color='white', axes=False, frame=False)
return (D)

Benzene = Sphere(.000001, color='white').translate(O)

for atom in Atomic_Position:

for pi in Pi_Dict:
if pi in Sigma_Dict:
del Sigma_Dict[pi]

for pi in Pi_Dict:
Benzene += pi_bond(bond_split(Pi_Dict[pi]),bond_split(Pi_Dict[pi]))

for bond in Sigma_Dict:
Benzene += LineSegment(bond_split(Sigma_Dict[bond]),bond_split(Sigma_Dict[bond]), 1, color= 'white' )

show(Benzene)

more