def drawDnaSingleRibbon( glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point=None, ribbon1_direction=None, peakDeviationFromCenter=9.5, ribbonThickness=2.0, ribbon1Color=None, stepColor=None): """ @see: drawDnaRibbons (method in this file) @see: DnaStrand_GraphicsMode._drawHandles() """ if 0: # debug code, useful to see where the argument points are located # [bruce 080422] draw_debug_text(glpane, endCenter1, "endCenter1") draw_debug_text(glpane, endCenter2, "endCenter2") draw_debug_text(glpane, ribbon1_start_point, "ribbon1_start_point") #Try to match the rubberband display style as closely as possible to #either the glpane's current display or the chunk display of the segment #being edited. The caller should do the job of specifying the display style #it desires. As of 2008-02-20, this method only supports following display #styles --Tubes, Ball and Stick, CPK and lines. the sphere radius #for ball and stick or CPK is calculated approximately. if displayStyle == diTrueCPK: SPHERE_RADIUS = 3.5 ribbonThickness = 2.0 elif displayStyle == diTUBES: SPHERE_RADIUS = 0.01 ribbonThickness = 5.0 elif displayStyle == diLINES: #Lines display and all other unsupported display styles SPHERE_RADIUS = 0.01 ribbonThickness = 1.0 else: #ball and stick display style. All other unsupported displays #will be rendered in ball and stick display style SPHERE_RADIUS = 1.0 ribbonThickness = 3.0 if stepColor is None: stepColor = env.prefs[DarkBackgroundContrastColor_prefs_key] ribbonLength = vlen(endCenter1 - endCenter2) #Don't draw the vertical line (step) passing through the startpoint unless #the ribbonLength is at least equal to the duplexRise. # i.e. do the drawing only when there are at least two ladder steps. # This prevents a 'revolving line' effect due to the single ladder step at # the first endpoint. It also means the dna duplex axis can be determined # below from the two endpoints. if ribbonLength < duplexRise: return unitVectorAlongLength = norm(endCenter2 - endCenter1) glDisable(GL_LIGHTING) ##glPushMatrix() ##glTranslatef(endCenter1[0], endCenter1[1], endCenter1[2]) ##pointOnAxis = V(0, 0, 0) pointOnAxis = endCenter1 axial_shift = V(0.0, 0.0, 0.0) # might be changed below # [these might be discarded and recomputed just below; # the case where they aren't is (and I think was) untested. # -- bruce 080422 comment] vectorAlongLadderStep = cross(-lineOfSightVector, unitVectorAlongLength) unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 if ribbon1_start_point is not None: # [revise the meaning of these values to give the coordinate system # with the right phase in which to draw the ribbon. # bruce 080422 bugfix] vectorAlongLadderStep0 = ribbon1_start_point - endCenter1 # note: this might not be perpendicular to duplex axis. # fix by subtracting off the parallel component. # but add the difference back to every point below. vectorAlongLadderStep = vectorAlongLadderStep0 - \ dot( unitVectorAlongLength, vectorAlongLadderStep0 ) * unitVectorAlongLength axial_shift = (vectorAlongLadderStep0 - vectorAlongLadderStep) # note: even using this, there is still a small glitch in the # location of the first drawn sphere vs. the ribbon point... don't # know why. [bruce 080422] unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 pass del vectorAlongLadderStep ###=== #Following limits the arrowHead Size to the given value. When you zoom out, #the rest of ladder drawing becomes smaller (expected) and the following #check ensures that the arrowheads are drawn proportionately. # (Not using a 'constant' to do this as using glpaneScale gives better #results) if glpaneScale > 40: arrowDrawingScale = 40 else: arrowDrawingScale = glpaneScale #Formula .. Its a Sine Wave. # y(x) = A.sin(2*pi*f*x + phase_angle) ------[1] # where -- # f = 1/T # A = Amplitude of the sine wave (or 'peak deviation from center') # y = y coordinate of the sine wave -- distance is in Angstroms # x = the x coordinate # phase_angle is computed for each wave. We know y at x =0. For example, # for ribbon_1, , at x = 0, y = A. Putting these values in equation [1] # we get the phase_angle. x = 0.0 T = duplexRise * basesPerTurn # The 'Period' of the sine wave # (i.e. peak to peak distance between consecutive crests) numberOfBasesDrawn = 0 theta_offset = 0 ## phase_angle_ribbon_1 = HALF_PI ## theta_ribbon_1 = (TWICE_PI * x / T) + phase_angle_ribbon_1 #Initialize ribbon1_point # [note: might not be needed, since identical to first point # computed during loop, but present code uses it to initialize # previous_ribbon1_point during loop [bruce 080422 comment]] ribbon1_point = _compute_ribbon_point( pointOnAxis + axial_shift, basesPerTurn, duplexRise, unitVectorAlongLength, unitVectorAlongLadderStep, unitDepthVector, peakDeviationFromCenter, numberOfBasesDrawn, theta_offset) while x < ribbonLength: #Draw the axis point. drawPoint(stepColor, pointOnAxis) previousPointOnAxis = pointOnAxis previous_ribbon1_point = ribbon1_point ribbon1_point = _compute_ribbon_point( pointOnAxis + axial_shift, basesPerTurn, duplexRise, unitVectorAlongLength, unitVectorAlongLadderStep, unitDepthVector, peakDeviationFromCenter, numberOfBasesDrawn, theta_offset) if x == duplexRise and ribbon1_direction == -1: # For ribbon_2 we need to draw an arrow head for y at x = 0. # To do this, we need the 'next ribbon_2' point in order to # compute the appropriate vectors. So when x = duplexRise, the # previous_ribbon2_point is nothing but y at x = 0. arrowLengthVector2 = norm(ribbon1_point - previous_ribbon1_point) arrowHeightVector2 = cross(-lineOfSightVector, arrowLengthVector2) drawArrowHead(ribbon1Color, previous_ribbon1_point, arrowDrawingScale, -arrowHeightVector2, -arrowLengthVector2) # Draw sphere over previous_ribbon1_point and not ribbon1_point. # This is so we don't draw a sphere over the last point on ribbon1 # (instead, it is drawn as an arrowhead after the while loop). drawsphere(ribbon1Color, previous_ribbon1_point, SPHERE_RADIUS, SPHERE_DRAWLEVEL, opacity=SPHERE_OPACITY) drawline(stepColor, pointOnAxis, ribbon1_point) #Increment the pointOnAxis and x pointOnAxis = pointOnAxis + unitVectorAlongLength * duplexRise x += duplexRise numberOfBasesDrawn += 1 if previous_ribbon1_point: drawline(ribbon1Color, previous_ribbon1_point, ribbon1_point, width=ribbonThickness, isSmooth=True) arrowLengthVector1 = norm(ribbon1_point - previous_ribbon1_point) arrowHeightVector1 = cross(-lineOfSightVector, arrowLengthVector1) pass continue # while x < ribbonLength if ribbon1_direction == 1: #Arrow head for endpoint of ribbon_1. drawArrowHead(ribbon1Color, ribbon1_point, arrowDrawingScale, arrowHeightVector1, arrowLengthVector1) #The second axis endpoint of the dna is drawn as a transparent sphere. #Note that the second axis endpoint is NOT NECESSARILY endCenter2 . In fact # those two are equal only at the ladder steps. In other case (when the # ladder step is not completed), the endCenter1 is ahead of the #'second axis endpoint of the dna' drawsphere(AXIS_ENDPOINT_SPHERE_COLOR, previousPointOnAxis, AXIS_ENDPOINT_SPHERE_RADIUS, AXIS_ENDPOINT_SPHERE_DRAWLEVEL, opacity=AXIS_ENDPOINT_SPHERE_OPACITY) ##glPopMatrix() glEnable(GL_LIGHTING) return # from drawDnaSingleRibbon
def viewBack(self): cmd = greenmsg("Back View: ") info = 'Current view is Back View' env.history.message(cmd + info) self.glpane.rotateView(Q(V(0, 1, 0), math.pi))
def viewRight(self): cmd = greenmsg("Right View: ") info = 'Current view is Right View' env.history.message(cmd + info) self.glpane.rotateView(Q(V(0, 1, 0), -math.pi / 2))
def viewNormalTo(self): # """ Set view to the normal vector of the plane defined by 3 or more selected atoms or a jig's (Motor or RectGadget) axis. """ cmd = greenmsg("Set View Normal To: ") chunks = self.assy.selmols jigs = self.assy.getSelectedJigs() atoms = self.assy.selatoms_list() #following fixes bug 1748 ninad 061003. if len(chunks) > 0 and len(atoms) == 0: # Even though chunks have an axis, it is not necessarily the same # axis attr stored in the chunk. Get the chunks atoms and let # compute_heuristic_axis() recompute them. for c in range(len(chunks)): atoms += chunks[c].atoms.values() elif len(jigs) == 1 and len(atoms) == 0: # Warning: RectGadgets have no atoms. We handle this special case below. atoms = jigs[0].atoms elif len(atoms) < 3: # There is a problem when allowing only 2 selected atoms. # Changing requirement to 3 atoms fixes bug 1418. mark 060322 msg = redmsg( "Please select some atoms, jigs, and/or chunks, covering at least 3 atoms" ) print "ops_view.py len(atoms) = ", len(atoms) env.history.message(cmd + msg) return # This check is needed for jigs that have no atoms. Currently, this # is the case for RectGadgets (ESP Image and Grid Plane) only. if len(atoms): pos = A(map(lambda a: a.posn(), atoms)) nears = [self.glpane.out, self.glpane.up] axis = compute_heuristic_axis(pos, 'normal', already_centered=False, nears=nears, dflt=None) else: # We have a jig with no atoms. axis = jigs[0].getaxis() # Get the jig's axis. # If axis is pointing into the screen, negate (reverse) axis. if dot(axis, self.glpane.lineOfSight) > 0: axis = -axis if not axis: msg = orangemsg( "Warning: Normal axis could not be determined. No change in view." ) env.history.message(cmd + msg) return # Compute the destination quat (q2). q2 = Q(V(0, 0, 1), axis) q2 = q2.conj() self.glpane.rotateView(q2) info = 'View set to normal vector of the plane defined by the selected atoms.' env.history.message(cmd + info)
def viewFlipViewHorz(self): """ Flip view horizontally. """ self.glpane.rotateView(self.glpane.quat + Q(V(1, 0, 0), math.pi))
def __up(self, _q=V(0, 1, 0)): return self.quat.unrot(_q)
def __out(self, _q=V(0, 0, 1)): return self.quat.unrot(_q)
def compute_memo(self, chunk): """If drawing chunk in this display mode can be optimized by precomputing some info from chunk's appearance, compute that info and return it. If this computation requires preference values, access them as env.prefs[key], and that will cause the memo to be removed (invalidated) when that preference value is changed by the user. This computation is assumed to also depend on, and only on, chunk's appearance in ordinary display modes (i.e. it's invalidated whenever havelist is). There is not yet any way to change that, so bugs will occur if any ordinarily invisible chunk info affects this rendering, and potential optimizations will not be done if any ordinarily visible info is not visible in this rendering. These can be fixed if necessary by having the real work done within class Chunk's _recompute_ rules, with this function or drawchunk just accessing the result of that (and sometimes causing its recomputation), and with whatever invalidation is needed being added to appropriate setter methods of class Chunk. If the real work can depend on more than chunk's ordinary appearance can, the access would need to be in drawchunk; otherwise it could be in drawchunk or in this method compute_memo. """ # for this example, we'll turn the chunk axes into a cylinder. # Since chunk.axis is not always one of the vectors chunk.evecs (actually chunk.poly_evals_evecs_axis[2]), # it's best to just use the axis and center, then recompute a bounding cylinder. if not chunk.atoms: return None # Put up hourglass cursor to indicate we are busy. Restore the cursor below. Mark 060621. QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) env.history.message( self.cmdname + "Computing surface. Please wait...") # Mark 060621. env.history.h_update( ) # Update history widget with last message. # Mark 060623. _report_psurface_import_status() # prints only once per session if _psurface_import_worked: # cpp surface stuff center = chunk.center bcenter = chunk.abs_to_base(center) rad = 0.0 margin = 0 radiuses = [] spheres = [] atoms = [] coltypes = [] for a in chunk.atoms.values(): col = a.drawing_color() ii = 0 for ic in range(len(coltypes)): ct = coltypes[ic] if ct == col: break ii += 1 if ii >= len(coltypes): coltypes.append(col) atoms.append(ii) dispjunk, ra = a.howdraw(diTrueCPK) if ra > margin: margin = ra radiuses.append(ra) p = a.posn() - center spheres.append(p) r = p[0]**2 + p[1]**2 + p[2]**2 if r > rad: rad = r rad = sqrt(rad) radius = rad + margin cspheres = [] from utilities.debug_prefs import debug_pref, Choice_boolean_True use_colors = debug_pref( "surface: use colors?", Choice_boolean_True ) #bruce 060927 (old code had 0 for use_colors) for i in range(len(spheres)): st = spheres[i] / radius rt = radiuses[i] / radius # cspheres.append((st[0],st[1],st[2],rt,use_colors)) cspheres.append((st[0], st[1], st[2], rt, atoms[i])) #cspheres.append((-0.3,0,0,0.3,1)) #cspheres.append((0.3,0,0,0.3,2)) color = chunk.drawing_color() if color is None: color = V(0.5, 0.5, 0.5) # create surface level = 3 if rad > 6: level = 4 ps = psurface # 0 - sphere triangles # 1 - torus rectangles # 2 - omega rectangles method = 2 ((em, pm, am), nm) = ps.CreateSurface(cspheres, level, method) cm = [] if True: # True for color for i in range(len(am)): cm.append(coltypes[am[i]]) else: for i in range(len(am)): cm.append((0.5, 0.5, 0.5)) tm = (em, pm, cm) else: # python surface stuff center = chunk.center bcenter = chunk.abs_to_base(center) rad = 0.0 s = Surface() margin = 0 for a in chunk.atoms.values(): dispjunk, ra = a.howdraw(diTrueCPK) if ra > margin: margin = ra s.radiuses.append(ra) p = a.posn() - center s.spheres.append(Triple(p[0], p[1], p[2])) r = p[0]**2 + p[1]**2 + p[2]**2 if r > rad: rad = r rad = sqrt(rad) radius = rad + margin for i in range(len(s.spheres)): s.spheres[i] /= radius s.radiuses[i] /= radius color = chunk.drawing_color() if color is None: color = V(0.5, 0.5, 0.5) # create surface level = 3 if rad > 6: level = 4 ts = getSphereTriangles(level) #ts = s.TorusTriangles(0.7, 0.3, 20) tm = s.SurfaceTriangles(ts) nm = s.SurfaceNormals() QApplication.restoreOverrideCursor( ) # Restore the cursor. Mark 060621. env.history.message(self.cmdname + "Done.") # Mark 060621. return (bcenter, radius, color, tm, nm)
class test_globals: ALWAYS_GL_UPDATE = True # redraw as often as possible SPIN = True # spin the view on each redraw ... SPINQUAT = Q(V(1, 0, 0), V(0, 0, 1)) / 90.0 # ... by 1 degree per frame printFrames = True # print frames-per-second to console
def drawGPGrid(glpane, color, line_type, w, h, uw, uh, up, right): """ Draw grid lines for a Grid Plane. glpane = the glpane color = grid line and unit text color line_type is: 0=None, 1=Solid, 2=Dashed or 3=Dotted w = width h = height uw = width spacing between grid lines uh = height spacing between grid lines """ if line_type == NO_LINE: return if uw > w: uw = w if uh > h: uh = h Z_OFF = 0.0 #0.001 glDisable(GL_LIGHTING) glColor3fv(color) hw = w / 2.0 hh = h / 2.0 #glEnable(GL_LINE_SMOOTH) #glEnable(GL_BLEND) #glBlendFunc(GL_SRC_ALPHA, GL_ONE)#_MINUS_SRC_ALPHA) if line_type > 1: glEnable(GL_LINE_STIPPLE) if line_type == DASHED_LINE: glLineStipple(1, 0x00FF) # dashed elif line_type == DOTTED_LINE: glLineStipple(1, 0x0101) # dotted else: print "drawGPGrid(): line_type '", line_type, \ "' is not valid. Drawing dashed grid line." glLineStipple(1, 0x00FF) # dashed glBegin(GL_LINES) #Draw horizontal lines y1 = 0 while y1 > -hh: glVertex3f(-hw, y1, Z_OFF) glVertex3f(hw, y1, Z_OFF) y1 -= uh y1 = 0 while y1 < hh: glVertex3f(-hw, y1, Z_OFF) glVertex3f(hw, y1, Z_OFF) y1 += uh #Draw vertical lines x1 = 0 while x1 < hw: glVertex3f(x1, hh, Z_OFF) glVertex3f(x1, -hh, Z_OFF) x1 += uw x1 = 0 while x1 > -hw: glVertex3f(x1, hh, Z_OFF) glVertex3f(x1, -hh, Z_OFF) x1 -= uw glEnd() if line_type > 1: glDisable(GL_LINE_STIPPLE) # Draw unit labels for gridlines (in nm). text_color = color import sys if sys.platform == "darwin": # WARNING: Anything smaller than 9 pt on Mac OS X results in # un-rendered text. Not sure why. -- piotr 080616 font_size = 9 else: font_size = 8 text_offset = 0.5 # Offset from edge of border, in Angstroms. # Draw unit text labels for horizontal lines (nm) y1 = 0 while y1 > -hh: y1 -= uh drawtext("%g" % (-y1 / 10.0), text_color, V(hw + text_offset, y1, 0.0), font_size, glpane) drawtext("%g" % (-y1 / 10.0), text_color, V(hw + text_offset, y1, 0.0), font_size, glpane) y1 = 0 while y1 < hh: drawtext("%g" % (-y1 / 10.0), text_color, V(hw + text_offset, y1, 0.0), font_size, glpane) y1 += uh drawtext("%g" % (-y1 / 10.0), text_color, V(hw + text_offset, y1, 0.0), font_size, glpane) # Draw unit text labels for vertical lines (nm). x1 = 0 while x1 < hw: drawtext("%g" % (x1 / 10.0), text_color, V(x1, hh + text_offset, 0.0), font_size, glpane) x1 += uw drawtext("%g" % (x1 / 10.0), text_color, V(x1, hh + text_offset, 0.0), font_size, glpane) x1 = 0 while x1 > -hw: drawtext("%g" % (x1 / 10.0), text_color, V(x1, hh + text_offset, 0.0), font_size, glpane) x1 -= uw drawtext("%g" % (x1 / 10.0), text_color, V(x1, hh + text_offset, 0.0), font_size, glpane) glEnable(GL_LIGHTING) return
def _draw(self, hCenter = None, highlighted = False): """ Draw the resize handle. It does the actual drawing work. @param hCenter: The center of the handle. If None, use the handle's I{center} property. @type hCenter: L{V} or None @param highlighted: This argument determines if the handle is drawn in the highlighted color. @type highlighted: bool @see: {self.draw} where this method is called. """ if hCenter: if self.center != hCenter: self.center = hCenter #Use glpane's scale for drawing the handle. This makes sure that # the handle is non-zoomable. side = self.glpane.scale * 0.018 glPushMatrix() #Translate to the center of the handle glTranslatef(self.center[0], self.center[1], self.center[2]) #Bruce suggested undoing the glpane.quat rotation and plane quat #rotation before drawing the handle geometry. -- ninad 20070525 parent_q = self.parent.quat if parent_q: glRotatef(-parent_q.angle * ONE_RADIAN, parent_q.x, parent_q.y, parent_q.z) glpane_q = self.glpane.quat glRotatef(-glpane_q.angle * ONE_RADIAN, glpane_q.x, glpane_q.y, glpane_q.z) drawPlane(env.prefs[selectionColor_prefs_key], side, side, self.textureReady, 0.9, SOLID = True, pickCheckOnly = self.pickCheckOnly) handle_hw = side/2.0 #handle's half width handle_hh = side/2.0 #handle's half height handle_corner = [V(-handle_hw, handle_hh, 0.0), V(-handle_hw, -handle_hh, 0.0), V( handle_hw, -handle_hh, 0.0), V( handle_hw, handle_hh, 0.0)] if highlighted: drawLineLoop(orange, handle_corner, width = 6) else: drawLineLoop( black, handle_corner, width = 2) glPopMatrix()
def build(self, name, assy, position, mol=None, createPrinted=False): """ Build a nanotube from the parameters in the Property Manger dialog. """ endPoint1, endPoint2 = self.getEndPoints() cntAxis = endPoint2 - endPoint1 length = vlen(cntAxis) # This can take a few seconds. Inform the user. # 100 is a guess. --Mark 051103. if not createPrinted: # If it's a multi-wall tube, only print the "Creating" message once. if length > 100.0: env.history.message("This may take a moment...") PROFILE = False if PROFILE: sw = Stopwatch() sw.start() xyz = self.xyz if mol == None: mol = Chunk(assy, name) atoms = mol.atoms mlimits = self.mlimits # populate the tube with some extra carbons on the ends # so that we can trim them later self.populate(mol, length + 4 * self.maxlen) # Apply twist and distortions. Bends probably would come # after this point because they change the direction for the # length. I'm worried about Z distortion because it will work # OK for stretching, but with compression it can fail. BTW, # "Z distortion" is a misnomer, we're stretching in the Y # direction. for atm in atoms.values(): # twist x, y, z = atm.posn() twistRadians = self.twist * z c, s = cos(twistRadians), sin(twistRadians) x, y = x * c + y * s, -x * s + y * c atm.setposn(V(x, y, z)) for atm in atoms.values(): # z distortion x, y, z = atm.posn() z *= (self.zdist + length) / length atm.setposn(V(x, y, z)) length += self.zdist for atm in atoms.values(): # xy distortion x, y, z = atm.posn() radius = self.getRadius() x *= (radius + 0.5 * self.xydist) / radius y *= (radius - 0.5 * self.xydist) / radius atm.setposn(V(x, y, z)) # Judgement call: because we're discarding carbons with funky # valences, we will necessarily get slightly more ragged edges # on nanotubes. This is a parameter we can fiddle with to # adjust the length. My thought is that users would prefer a # little extra length, because it's fairly easy to trim the # ends, but much harder to add new atoms on the end. LENGTH_TWEAK = self.getBondLength() # trim all the carbons that fall outside our desired length # by doing this, we are introducing new singlets for atm in atoms.values(): x, y, z = atm.posn() if (z > .5 * (length + LENGTH_TWEAK) or z < -.5 * (length + LENGTH_TWEAK)): atm.kill() # Apply bend. Equations are anomalous for zero bend. if abs(self.bend) > pi / 360: R = length / self.bend for atm in atoms.values(): x, y, z = atm.posn() theta = z / R x, z = R - (R - x) * cos(theta), (R - x) * sin(theta) atm.setposn(V(x, y, z)) def trimCarbons(): """ Trim all the carbons that only have one carbon neighbor. """ for i in range(2): for atm in atoms.values(): if not atm.is_singlet() and len(atm.realNeighbors()) == 1: atm.kill() trimCarbons() # If we're not picky about endings, we don't need to trim carbons if self.endings == "Capped": # buckyball endcaps addEndcap(mol, length, self.getRadius()) if self.endings == "Hydrogen": # hydrogen terminations for atm in atoms.values(): atm.Hydrogenate() elif self.endings == "Nitrogen": # nitrogen terminations. # This option has been removed from the "Endings" combo box # in the PM. 2008-05-02 --mark dstElem = PeriodicTable.getElement('N') atomtype = dstElem.find_atomtype('sp2') for atm in atoms.values(): if len(atm.realNeighbors()) == 2: atm.Transmute(dstElem, force=True, atomtype=atomtype) # Translate structure to desired position for atm in atoms.values(): v = atm.posn() atm.setposn(v + position) if PROFILE: t = sw.now() env.history.message( greenmsg("%g seconds to build %d atoms" % (t, len(atoms.values())))) if self.numwalls > 1: n += int(self.spacing * 3 + 0.5) # empirical tinkering self.build(name, assy, endPoint1, endPoint2, position, mol=mol, createPrinted=True) # Orient the nanotube. if self.numwalls == 1: # This condition ensures that MWCTs get oriented only once. self._orient(mol, endPoint1, endPoint2) return mol
def add(element, x, y, z, atomtype='sp2'): atm = Atom(element, V(x, y, z), mol) atm.set_atomtype_but_dont_revise_singlets(atomtype) return atm
def drawDnaRibbons(glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point=None, ribbon2_start_point=None, ribbon1_direction=None, ribbon2_direction=None, peakDeviationFromCenter=9.5, ribbonThickness=2.0, ribbon1Color=None, ribbon2Color=None, stepColor=None): """ Draw DNA ribbons where each strand is represented as a ribbon. DNA ribbons are drawn as sine waves with appropriate phase angles, with the phase angles computed in this method. @param endCenter1: Axis end 1 @type endCenter1: B{V} @param endCenter2: Axis end 2 @type endCenter2: B{V} @param basesPerTurn: Number of bases in a full turn. @type basesPerTurn: float @param duplexRise: Center to center distance between consecutive steps @type duplexRise: float @param glpaneScale: GLPane scale used in scaling arrow head drawing @type glpaneScale: float @param lineOfSightVector: Glpane lineOfSight vector, used to compute the the vector along the ladder step. @type: B{V} @param displayStyle: Rubberband display style (specified as an integer) see comment in the method below. See also GLPane.displayMode. @type displayStyle: int @param peakDeviationFromCenter: Distance of a peak from the axis Also known as 'Amplitude' of a sine wave. @type peakDeviationFromCenter: float @param ribbonThickness: Thickness of each of the the two ribbons @type ribbonThickness: float @param ribbon1Color: Color of ribbon1 @param ribbon2Color: Color of ribbon2 @see: B{DnaLineMode.Draw } (where it is used) for comments on color convention TODO: as of 2008-04-22 - Need more documentation - This method is long mainly because of a number of custom drawing See if that can be refactored e.g. methods like _drawRibbon1/strand1, drawRibbon2 / strand2 etc. - Further optimization / refactoring (low priority) """ #Try to match the rubberband display style as closely as possible to #either the glpane's current display or the chunk display of the segment #being edited. The caller should do the job of specifying the display style #it desires. As of 2008-02-20, this method only supports following display #styles --Tubes, Ball and Stick, CPK and lines. the sphere radius #for ball and stick or CPK is calculated approximately. if displayStyle == diTrueCPK: SPHERE_RADIUS = 3.5 ribbonThickness = 2.0 elif displayStyle == diTUBES: SPHERE_RADIUS = 0.01 ribbonThickness = 5.0 elif displayStyle == diLINES: #Lines display and all other unsupported display styles SPHERE_RADIUS = 0.01 ribbonThickness = 1.0 else: #ball and stick display style. All other unsupported displays #will be rendered in ball and stick display style SPHERE_RADIUS = 1.0 ribbonThickness = 3.0 ribbonLength = vlen(endCenter1 - endCenter2) #Don't draw the vertical line (step) passing through the startpoint unless #the ribbonLength is at least equal to the duplexRise. # i.e. do the drawing only when there are at least two ladder steps. # This prevents a 'revolving line' effect due to the single ladder step at # the first endpoint if ribbonLength < duplexRise: return unitVectorAlongLength = norm(endCenter2 - endCenter1) ###=== pointOnAxis = endCenter1 axial_shift_1 = V(0.0, 0.0, 0.0) # might be changed below axial_shift_2 = V(0.0, 0.0, 0.0) # [these might be discarded and recomputed just below; # the case where they aren't is (and I think was) untested. # -- bruce 080422 comment] vectorAlongLadderStep = cross(-lineOfSightVector, unitVectorAlongLength) unitVectorAlongLadderStep = norm(vectorAlongLadderStep) unitDepthVector = cross(unitVectorAlongLength, unitVectorAlongLadderStep) ## * -1 numberOfBasesDrawn = 0 theta_offset = 0 x = 0 ### #Formula .. Its a Sine Wave. # y(x) = A.sin(2*pi*f*x + phase_angle) ------[1] # where -- # f = 1/T # A = Amplitude of the sine wave (or 'peak deviation from center') # y = y coordinate of the sine wave -- distance is in Angstroms # x = the x coordinate # phase_angle is computed for each wave. We know y at x =0. For example, # for ribbon_1, , at x = 0, y = A. Putting these values in equation [1] # we get the phase_angle. Similarly, for ribbon_2, at x = 0, y = -6 # Putting these values will give use the phase_angle_2. # Note that for ribbon2_point, we subtract the value of equation [1] from # the point on axis. x = 0.0 T = duplexRise * basesPerTurn # The 'Period' of the sine wave # (i.e. peak to peak distance between consecutive crests) amplitude = peakDeviationFromCenter amplitudeVector = unitVectorAlongLadderStep * amplitude depthVector = unitDepthVector * amplitude # Note: to reduce the effect of perspective view on rung direction, # we could multiply depthVector by 0.1 or 0.01. But this would lessen # the depth realism of line/sphere intersections. [bruce 080216] ### if ribbon1_start_point is not None: ribbon1_point = ribbon1_start_point else: if ribbon2_start_point is not None: ribbon1_point = _get_ribbon_point_on_other_ribbon( ribbon2_start_point, ribbon2_direction, endCenter1, unitVectorAlongLength) else: phase_angle_ribbon_1 = HALF_PI theta_ribbon_1 = (TWICE_PI * x / T) + phase_angle_ribbon_1 #Initialize ribbon1_point and ribbon2_point ribbon1_point = pointOnAxis + \ amplitudeVector * sin(theta_ribbon_1) + \ depthVector * cos(theta_ribbon_1) ribbon1_direction = +1 drawDnaSingleRibbon( glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point=ribbon1_point, ribbon1_direction=ribbon1_direction, peakDeviationFromCenter=peakDeviationFromCenter, ribbonThickness=ribbonThickness, ribbon1Color=ribbon1Color, stepColor=stepColor) if ribbon2_start_point is not None: ribbon2_point = ribbon2_start_point else: if ribbon1_start_point is not None: ribbon2_point = _get_ribbon_point_on_other_ribbon( ribbon1_start_point, ribbon1_direction, endCenter1, unitVectorAlongLength) else: phase_angle_ribbon_2 = asin(-6.0 / (amplitude)) theta_ribbon_2 = (TWICE_PI * x / T) - phase_angle_ribbon_2 ribbon2_point = pointOnAxis - \ amplitudeVector * sin(theta_ribbon_2) + \ depthVector * cos(theta_ribbon_2) ribbon2_direction = -1 drawDnaSingleRibbon( glpane, endCenter1, endCenter2, basesPerTurn, duplexRise, # maybe: don't pass these three args, get from glpane # instead? [bruce 080422 comment] glpaneScale, lineOfSightVector, displayStyle, ribbon1_start_point=ribbon2_point, ribbon1_direction=ribbon2_direction, peakDeviationFromCenter=peakDeviationFromCenter, ribbonThickness=ribbonThickness, ribbon1Color=ribbon2Color, stepColor=stepColor) del vectorAlongLadderStep return
def __right(self, _q=V(1, 0, 0)): return self.quat.unrot(_q)
class EditNanotube_ResizeHandle(DraggableHandle_AlongLine): """ Provides a resize handle for editing the length of an existing NanotubeSegment. """ #Handle color will be changed depending on whether the the handle is grabbed #So this is a 'State variable and its value is used in 'appearance' #(given as an optional argument to 'Sphere') handleColor = State(Color, olive) #The state ref that determines the radius (of the sphere) of this handle. #See EditNanotube_EditCommand._determine_resize_handle_radius() for more #details sphereRadius = Option(StateRef, 1.2) #Stateusbar text. Variable needs to be renamed in superclass. sbar_text = Option(str, "Drag the handle to resize the segment", doc="Statusbar text on mouseover") #Command object specified as an 'Option' during instantiation of the class #see EditNanotube_EditCommand class definition. command = Option(Action, doc='The Command which instantiates this handle') #Current position of the handle. i.e. it is the position of the handle #under the mouse. (its differert than the 'orifinal position) #This variable is used in self.command.graphicsMode to draw a rubberband #line and also to specify the endPoint2 of the structure while modifying #it. See EditNanotube_EditCommand.modifyStructure for details. currentPosition = _self.origin + _self.direction * _self.height_ref.value #Fixed end of the structure (self.command.struct) ..meaning that end won't #move while user grabbs and draggs this handle (attached to a the other #'moving endPoint) . This variable is used to specify endPoint1 of the #structure while modifyin it. See EditNanotube_EditCommand.modifyStructure #and self.on_release for details. fixedEndOfStructure = Option(Point, V(0, 0, 0)) #If this is false, the 'highlightable' object i.e. this handle #won't be drawn. See DraggableHandle.py for the declararion of #the delegate(that defines a Highlightable) We define a If_Exprs to check #whether to draw the highlightable object. should_draw = State(bool, True) appearance = Overlay( Sphere(_self.sphereRadius, handleColor, center=ORIGIN), Arrow(color=handleColor, arrowBasePoint=ORIGIN + _self.direction * 2.0 * _self.sphereRadius, tailPoint=ORIGIN, tailRadius=_self.sphereRadius * 0.3, scale=_self.command.glpane.scale)) HHColor = env.prefs[hoverHighlightingColor_prefs_key] appearance_highlighted = Option( Drawable, Overlay( Sphere(_self.sphereRadius, HHColor, center=ORIGIN), Arrow(color=HHColor, arrowBasePoint=ORIGIN + _self.direction * 2.0 * _self.sphereRadius, tailPoint=ORIGIN, tailRadius=_self.sphereRadius * 0.3, scale=_self.command.glpane.scale))) def on_press(self): """ Actions when handle is pressed (grabbed, during leftDown event) @see: B{SelectChunks.GraphicsMode.leftDown} @see: B{EditNanotube_EditCommand.grabbedHandle} @see: B{EditNanotube_GraphicsMode.Draw} (which uses some attributes of the current grabbed handle of the command. @see: B{DragHandle_API} """ #Change the handle color when handle is grabbed. See declaration of #self.handleColor in the class definition. self.handleColor = env.prefs[selectionColor_prefs_key] #assign 'self' as the curent grabbed handle of the command. self.command.grabbedHandle = self def on_drag(self): """ Method called while dragging this handle . @see: B{DragHandle_API} """ #Does nothing at the moment. pass def on_release(self): """ This method gets called during leftUp (when the handle is released) @see: B{EditNanotube_EditCommand.modifyStructure} @see: self.on_press @see: B{SelectChunks.GraphicsMode.leftUp} @see: B{DragHandle_API} """ self.handleColor = olive if self.command and hasattr(self.command, 'modifyStructure'): self.command.modifyStructure() #Clear the grabbed handle attribute (the handle is no longer #grabbed) self.command.grabbedHandle = None def hasValidParamsForDrawing(self): """ Returns True if the handles origin and direction are not 'None'. @see: NanotubeSesgment_GraphicsMode._draw_handles() where the caller uses this to decide whether this handle can be drawn without a problem. """ #NOTE: Better to do it in the drawing code of this class? #But it uses a delegate to draw stuff (see class Highlightable) #May be we should pass this method to that delegate as an optional #argument -- Ninad 2008-04-02 #NOTES: See also: #delegate in class DraggableHandle defined as -- #delegate = If_Exprs(_self.should_draw, Highlightable(....)) if self.origin is None: self.should_draw = False else: self.should_draw = True return self.should_draw
def __left(self, _q=V(-1, 0, 0)): return self.quat.unrot(_q)
def leftADown(self, objectUnderMouse, event): """ Method called during mouse left down . It sets some parameters necessary for rotating the structure around its own axis (during a left drag to follow) In graphics modes such as RotateChunks_GraphicsMode, rotating entities around their own axis is acheived by holding down 'A' key and then left dragging , thats why the method is named as 'leftADrag' (A= Axis) """ ma = V(0, 0, 0) if self.command and self.command.struct: ma = self.command.struct.getAxisVector() self._axis_for_constrained_motion = self.command.struct.getAxisVector() #@see: NanotubeSegment.get_all_content_chunks() for details about #what it returns. See also NanotubeSegment.isAncestorOf() which #is called in self.leftDown to determine whether the NanotubeSegment #user is editing is an ancestor of the selobj. (it also considers #'logical contents' while determining whether it is an ancestor. #-- Ninad 2008-03-11 self._movablesForLeftDrag = self.command.struct.get_all_content_chunks( ) ma = norm(V(dot(ma, self.o.right), dot(ma, self.o.up))) self.Zmat = A([ma, [-ma[1], ma[0]]]) obj = objectUnderMouse if obj is None: # Cursor over empty space. self.emptySpaceLeftDown(event) #Left A drag is not possible unless the cursor is over a #selected object. So make sure to let self.leftAError method sets #proper flag so that left-A drag won't be done in this case. return if isinstance(obj, Atom): self._translateAlongAxis = True self._rotateAboutAxis = False self._freeDragWholeStructure = False elif 0: #@@@ isinstance(obj, Atom): # Rotate about axis not supported. self._translateAlongAxis = False self._rotateAboutAxis = True self._freeDragWholeStructure = False #The self._commonCenterForrotation is a point on segment axis #about which the whole segment will be rotated. Specifying this #as a common center for rotation fixes bug 2578. We determine this #by selecting the center of the axis atom that is connected #(bonded) to the strand atom being left dragged. Using this as a #common center instead of the avaraging the center of the segment #axis atoms has an advantage. We compute the rotation offset 'dy' #with reference to the strand atom being dragged, so it seems more #appropriate to use the nearest axis center for segment rotation #about axis. But what happens if the axis is not straigt but is #curved? Should we select the averaged center of all axis atoms? #..that may not be right. Or should we take _average center_ of #a the following axis atoms --strand atoms axis_neighbors and #axis atom centers directly connected to this axis atom. # -- Ninad 2008-03-25 self._commonCenterForRotation = obj.axis_neighbor().posn() elif isinstance(obj, Bond): self._translateAlongAxis = False self._rotateAboutAxis = False self._freeDragWholeStructure = True self.o.SaveMouse(event) self.dragdist = 0.0 return
def __down(self, _q=V(0, -1, 0)): return self.quat.unrot(_q)
def leftDrag(self, event): """ Method called during Left drag event. """ if self.mouse_within_stickiness_limit(event, DRAG_STICKINESS_LIMIT): # [let this happen even for drag_handlers -- bruce 060728] return self.current_obj_clicked = False #If there is a drag handler (e.g. a segment resize handle is being #dragged, call its drag method and don't proceed further. #NOTE: #In SelectChunks_GraphicsMode.leftDrag, there is a condition statement #which checks if self.drag_handler is in assy.getSelecteedMovables #I don't know why it does that... I think it always assums that the #drag handler is officially a node in the MT? In our case, #the drag handler is a 'Highlightable' object (actually #an instance of 'EditNanotube_ResizeHandle' (has superclass from #exprs module ..which implements API for a highlightable object #So it doesn't get registered in the selectMovables list. Thats why #we are not calling _superclass.leftDrag. The above mentioned #method in the superclass needs to be revised -- Ninad 2008-02-01 if self.drag_handler is not None: self.dragHandlerDrag(self.drag_handler, event) return #If the cursor was not over something that belonged to structure #being edited (example - atom or bond of a differnt NanotubeSegment) #don't do left drag.(left drag will work only for the NanotubeSegment #eing edited) if self.cursor_over_when_LMB_pressed != 'Structure Being Edited': return #Duplicates some code from SelectChunks_GraphicsMode.leftDrag #see a to do comment below in this method if self.cursor_over_when_LMB_pressed == 'Empty Space': self.emptySpaceLeftDrag(event) return if self.o.modkeys is not None: # If a drag event has happened after the cursor was over an atom # and a modkey is pressed, do a 2D region selection as if the # atom were absent. self.emptySpaceLeftDown(self.LMB_press_event) #bruce 060721 question: why don't we also do emptySpaceLeftDrag # at this point? return #TODO: This duplicates some code from SelectChunks_GraphicsMode.leftDrag #Following code will never be called if a handle is grabbed. #Thus, it instructs what to do for other cases (when user is not moving #the draggable handles) #First, don't draw handles (set the flag here so that self.Draw_other knows #not to draw handles) This skips unnecessary computation of new handle #position during left dragging. The flag is reset to True in leftUp if self.command and self.command.handles: if self.command.grabbedHandle is None: self._handleDrawingRequested = False #Copies AND modifies some code from Move_GraphicsMode for doing #leftDrag translation or rotation. w = self.o.width + 0.0 h = self.o.height + 0.0 deltaMouse = V(event.pos().x() - self.o.MousePos[0], self.o.MousePos[1] - event.pos().y()) a = dot(self.Zmat, deltaMouse) dx, dy = a * V(self.o.scale / (h * 0.5), 2 * math.pi / w) offset = None if self._translateAlongAxis: offset = dx * self._axis_for_constrained_motion for mol in self._movablesForLeftDrag: mol.move(offset) if self._rotateAboutAxis: rotation_quat = Q(self._axis_for_constrained_motion, -dy) self.o.assy.rotateSpecifiedMovables( rotation_quat, movables=self._movablesForLeftDrag, commonCenter=self._commonCenterForRotation) if self._freeDragWholeStructure: try: point = self.dragto(self.movingPoint, event) offset = point - self.movingPoint self.o.assy.translateSpecifiedMovables( offset, movables=self._movablesForLeftDrag) self.movingPoint = point except: #may be self.movingPoint is not defined in leftDown? #(e.g. _superclass.leftDown doesn't get called or as a bug? ) print_compact_traceback( "bug:unable to free drag the whole segment") if offset: # Update the nanotube endpoints. endPt1, endPt2 = self.command.struct.nanotube.getEndPoints() endPt1 += offset endPt2 += offset self.command.struct.nanotube.setEndPoints(endPt1, endPt2) self.dragdist += vlen(deltaMouse) #k needed?? [bruce 070605 comment] self.o.SaveMouse(event) self.o.assy.changed() #ninad060924 fixed bug 2278 self.o.gl_update() return
def __lineOfSight(self, _q=V(0, 0, -1)): return self.quat.unrot(_q)
def _hashAtomPos(self, pos): return int(dot(V(1000000, 1000, 1), floor(pos * 1.2)))
def viewFlipViewVert(self): """ Flip view vertically. """ self.glpane.rotateView(self.glpane.quat + Q(V(0, 1, 0), math.pi))
def _createStructure(self): """ Creates and returns the structure (in this case a L{Group} object that contains the DNA strand and axis chunks. @return : group containing that contains the DNA strand and axis chunks. @rtype: L{Group} @note: This needs to return a DNA object once that model is implemented """ params = self._gatherParameters() # No error checking in build_struct, do all your error # checking in gather_parameters numberOfBases, \ dnaForm, \ dnaModel, \ basesPerTurn, \ duplexRise, \ endPoint1, \ endPoint2 = params if numberOfBases < 2: #Don't create a duplex with only one or 0 bases! #Reset a few variables. This should be done by calling a separate #method on command (there is similar code in self.createStructures) #as well. self.mouseClickPoints = [] self.graphicsMode.resetVariables() msg = redmsg("Cannot preview/insert a DNA duplex with less than 2 base pairs.") self.propMgr.updateMessage(msg) self.dna = None # Fixes bug 2530. Mark 2007-09-02 return None else: msg = "Click two more endpoints to insert another DNA duplex." self.propMgr.updateMessage(msg) #If user enters the number of basepairs and hits preview i.e. endPoint1 #and endPoint2 are not entered by the user and thus have default value #of V(0, 0, 0), then enter the endPoint1 as V(0, 0, 0) and compute #endPoint2 using the duplex length. #Do not use '==' equality check on vectors! its a bug. Use same_vals # or Veq instead. if Veq(endPoint1 , endPoint2) and Veq(endPoint1, V(0, 0, 0)): endPoint2 = endPoint1 + \ self.win.glpane.right * \ getDuplexLength('B-DNA', numberOfBases) if dnaForm == 'B-DNA': if dnaModel == 'PAM3': dna = B_Dna_PAM3_Generator() elif dnaModel == 'PAM5': dna = B_Dna_PAM5_Generator() else: print "bug: unknown dnaModel type: ", dnaModel else: raise PluginBug("Unsupported DNA Form: " + dnaForm) self.dna = dna # needed for done msg # self.name needed for done message if self.create_name_from_prefix: # create a new name name = self.name = gensym(self.prefix, self.win.assy) # (in _build_struct) self._gensym_data_for_reusing_name = (self.prefix, name) else: # use externally created name self._gensym_data_for_reusing_name = None # (can't reuse name in this case -- not sure what prefix it was # made with) name = self.name # Create the model tree group node. # Make sure that the 'topnode' of this part is a Group (under which the # DNa group will be placed), if the topnode is not a group, make it a # a 'Group' (applicable to Clipboard parts).See part.py # --Part.ensure_toplevel_group method. This is an important line # and it fixes bug 2585 self.win.assy.part.ensure_toplevel_group() if self._parentDnaGroup is None: print_compact_stack("bug: Parent DnaGroup in InsertDna_EditCommand"\ "is None. This means the previous command "\ "was not 'BuildDna_EditCommand' Ignoring for now") if self._fallbackDnaGroup is None: self._createFallbackDnaGroup() dnaGroup = self._fallbackDnaGroup else: dnaGroup = self._parentDnaGroup dnaSegment = DnaSegment(self.name, self.win.assy, dnaGroup, editCommand = self ) try: # Make the DNA duplex. <dnaGroup> will contain three chunks: # - Strand1 # - Strand2 # - Axis dna.make(dnaSegment, numberOfBases, basesPerTurn, duplexRise, endPoint1, endPoint2) #set some properties such as duplexRise and number of bases per turn #This information will be stored on the DnaSegment object so that #it can be retrieved while editing this object. #This works with or without dna_updater. Now the question is #should these props be assigned to the DnaSegment in #dnaDuplex.make() itself ? This needs to be answered while modifying #make() method to fit in the dna data model. --Ninad 2008-03-05 #WARNING 2008-03-05: Since self._modifyStructure calls #self._createStructure() If in the near future, we actually permit #modifying a #structure (such as dna) without actually recreating the whole #structre, then the following properties must be set in #self._modifyStructure as well. Needs more thought. props = (duplexRise, basesPerTurn) dnaSegment.setProps(props) return dnaSegment except (PluginBug, UserError): # Why do we need UserError here? Mark 2007-08-28 dnaSegment.kill_with_contents() raise PluginBug("Internal error while trying to create DNA duplex.")
def viewRotateMinus90(self): # Added by Mark. 051013. """ Decrement the current view by 90 degrees around the vertical axis. """ self.glpane.rotateView(self.glpane.quat + Q(V(0, 1, 0), -math.pi / 2))
Bruce 071105 revised init code, and split PAM3 and PAM5 data into separate files. """ from geometry.VQT import V, A, norm from utilities.constants import DIAMOND_BOND_LENGTH _DIRECTIONAL_BOND_ELEMENTS_chemical = ('X',) # mark 071014 # == # the formations of bonds -- standard offsets # (note: these are public symbols that can also be used in # element data files for pseudoatoms) uvec = norm(V(1,1,1)) tetra4 = uvec * A([[1,1,1], [-1,1,-1], [-1,-1,1], [1,-1,-1]]) tetra3 = uvec * A([[-1,1,-1], [-1,-1,1], [1,-1,-1]]) oxy2 = A([[-1,0,0], [0.2588, -0.9659, 0]]) tetra2 = A([[-1,0,0], [0.342, -0.9396, 0]]) straight = A([[-1,0,0], [1,0,0]]) flat = A([[-0.5,0.866,0], [-0.5,-0.866,0], [1,0,0]]) onebond = A([[1,0,0]]) # for use with valence-1 elements # mark 060129. New default colors for Alpha 7. _defaultRadiusAndColor = { "X": (1.1, [0.8, 0.0, 0.0]), "H" : (1.2, [0.78, 0.78, 0.78]), "He" : (1.4, [0.42, 0.45, 0.55]), "Li" : (4.0, [0.0, 0.5, 0.5]), "Be" : (3.0, [0.98, 0.67, 1.0]),
def viewBottom(self): cmd = greenmsg("Bottom View: ") info = 'Current view is Bottom View' env.history.message(cmd + info) self.glpane.rotateView(Q(V(1, 0, 0), -math.pi / 2))
from utilities import debug_flags from model.jigs import Jig from geometry.VQT import V, Q, A, cross, vlen, norm, twistor_angle from operations.bond_chains import grow_bond_chain from model.bond_constants import V_SINGLE from model.bond_constants import V_DOUBLE from model.bond_constants import V_TRIPLE from model.bond_constants import V_AROMATIC from model.bond_constants import V_GRAPHITE from model.bond_constants import V_CARBOMERIC DFLT_OUT = V( 0.0, -0.6, 0.8 ) # these are rotated from standard out = V(0,0,1), up = V(0,1,0) but still orthonormal DFLT_UP = V(0.0, 0.8, 0.6) # _recompile_counter is useful for development, and is harmless otherwise try: _recompile_counter except: _recompile_counter = 1 else: # increment the counter only when the module got recompiled, not just when it got reloaded from the same .pyc file if __file__.endswith(".py"): _recompile_counter += 1 print "_recompile_counter incremented to", _recompile_counter else: pass ## print "_recompile_counter unchanged at", _recompile_counter
def viewTop(self): cmd = greenmsg("Top View: ") info = 'Current view is Top View' env.history.message(cmd + info) self.glpane.rotateView(Q(V(1, 0, 0), math.pi / 2))
def planepoint(v, i, j, k): mat = V(polyMat[i], polyMat[j], polyMat[k]) vec = V(v[i], v[j], v[k]) return solve_linear_equations(mat, vec)