0% found this document useful (0 votes)
25 views12 pages

3d Vpython Application

The document describes a 3D editor tool created with VPython. It defines an editor class with methods for drawing a grid, setting up the scene, creating and manipulating 3D objects, and toggling features like snapping and grouping. Sliders and menus are used to control object properties.

Uploaded by

Desmond Umebeh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
25 views12 pages

3d Vpython Application

The document describes a 3D editor tool created with VPython. It defines an editor class with methods for drawing a grid, setting up the scene, creating and manipulating 3D objects, and toggling features like snapping and grouping. Sliders and menus are used to control object properties.

Uploaded by

Desmond Umebeh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 12

GlowScript 2.

9 VPython
# Basic 3D Editor Tool
# A POC that vpython resources could be explored further and used to create a 3D
editor tool
# Development inprogress

# by Desmond Umebeh 7/5/2020


# Email: desmondumebeh@[Link]

#############################################Program
Classes#########################################################

# Editor class
class editor:

def __init__(self,objInstance):

self.GRID_TOTAL_LENGTH = 10
self.GRID_STEP_SIZE = 0.5
self.GRID_HALF_LENGTH = self.GRID_TOTAL_LENGTH/2
[Link] = self.GRID_HALF_LENGTH+self.GRID_STEP_SIZE
[Link] = [] # hold objects which makeup the grid
[Link] = 0.02*self.GRID_STEP_SIZE; #height
[Link] = 0.02*self.GRID_STEP_SIZE; #width
[Link] = canvas(background=[Link]) # Setup scene default
background color
[Link] = True # switch to enable scene background color
toggle
[Link] = False # snap to grid switch
[Link] = False # rotate switch
[Link] = False # object grouping switch
[Link] = None # track current mouse position on the
scene
[Link] = None # track last mouse position on the scene
[Link] = objInstance # hold an instance of class object3D
[Link] = None #Hold content of loaded file
[Link] = [] #Holds list of objects on the scene

#editor class method: Draw grid


def drawGrid(self):
for eachStraightLine_Back in range(-self.GRID_HALF_LENGTH, [Link],
self.GRID_STEP_SIZE):
[Link](box( pos=vector(eachStraightLine_Back,0,-
self.GRID_HALF_LENGTH),

size=vector(self.GRID_TOTAL_LENGTH,[Link],[Link]),
axis=vector(0,1,0), color =
[Link](.9),pickable = False)) #draw boxes and add to grindline list

for eachCrossedLine_Back in range(-self.GRID_HALF_LENGTH, [Link],


self.GRID_STEP_SIZE):
[Link](box( pos=vector(0,eachCrossedLine_Back,-
self.GRID_HALF_LENGTH),

size=vector(self.GRID_TOTAL_LENGTH,[Link],[Link]),
axis=vector(1,0,0), color =
[Link](.9),pickable = False)) #draw boxes and add to grindline list

####################################################show bottom
grid############################################################
for eachStraightLine_Bottom in range(-self.GRID_HALF_LENGTH,
[Link], self.GRID_STEP_SIZE):
[Link](box( pos=vector(eachStraightLine_Bottom,-
self.GRID_HALF_LENGTH,0),

size=vector(self.GRID_TOTAL_LENGTH,[Link],[Link]),
axis=vector(0,0,1), color =
[Link](.9),pickable = False)) #draw boxes and add to grindline list

for eachCrossedLine_Bottom in range(-self.GRID_HALF_LENGTH, [Link],


self.GRID_STEP_SIZE):
[Link](box( pos=vector(0,-
self.GRID_HALF_LENGTH,eachCrossedLine_Bottom),

size=vector(self.GRID_TOTAL_LENGTH,[Link],[Link]),
color = [Link](.9),pickable = False))
#draw boxes and add to grindline list

####################################################show right
grid#############################################################
for eachStraightLine_Right in range(-self.GRID_HALF_LENGTH, [Link],
self.GRID_STEP_SIZE):

[Link](box( pos=vector(self.GRID_HALF_LENGTH,0,eachStraightLine_Righ
t),

size=vector(self.GRID_TOTAL_LENGTH,[Link],[Link]),
axis=vector(0,1,0), color =
[Link](.9),pickable = False)) #draw boxes and add to grindline list

for eachCrossedLine_Bottom in range(-self.GRID_HALF_LENGTH, [Link],


self.GRID_STEP_SIZE):

[Link](box( pos=vector(self.GRID_HALF_LENGTH,eachCrossedLine_Bottom,
0),

size=vector(self.GRID_TOTAL_LENGTH,[Link],[Link]),
axis=vector(0,0,1), color =
[Link](.9),pickable = False)) #draw boxes and add to grindline list

#editor class method: setup editor initial scene


def setScene(self):
[Link]= 9.5; # Prevent scene autoscaling
[Link] = vec(-11.216, -1.99808e-16, 12.0396) #set camera
position
[Link] = vec(11.216, 1.99808e-16, -12.0396) #set camera
axis

#editor class method: draw 3D axes


def draw3DAxisLines(self):
xAxis = arrow(pos=vec(5,-5,-5), axis=vec(-12,0,0), shaftwidth = 0.05,
headwidth = .5, headlength =1, color=[Link],pickable = False)
#draw x-axis idicator
xAxisText = text(text='x', color=[Link], pos=vec(-6.5,-4.5,-5),
billboard = True) #x-axis label

yAxis = arrow(pos=vec(5,-5,-5), axis=vec(0,12,0), shaftwidth = 0.05,


headwidth = .5, headlength =1, color=[Link],pickable =
False) #draw y-axis indicator
yAxisText = text(text='y', color=[Link], pos=vec(4.2,6.5,-5),
billboard = True) #y-axis label

zAxis = arrow(pos=vec(5,-5,-5), axis=vec(0,0,12), shaftwidth = 0.05,


headwidth = .5, headlength =1, color=[Link],pickable =
False) #draw z-axis indicator
zAxisText = text(text='z', color=[Link], pos=vec(5.2,-4.2,6.5),
billboard = True) #z-axis label

#editor class method: implement snap to grid


def snap(self, objectPos):
objectPos.x = self.GRID_STEP_SIZE*round(objectPos.x/self.GRID_STEP_SIZE)
#modify x pos in steps of 0.5units
objectPos.y = self.GRID_STEP_SIZE*round(objectPos.y/self.GRID_STEP_SIZE)
#modify y pos in steps of 0.5units
objectPos.z = self.GRID_STEP_SIZE*round(objectPos.z/self.GRID_STEP_SIZE)
#modify z pos in steps of 0.5units
return objectPos # return snapped position

#editor class method: allow toggle of snap to grid switch


def checkSnap(self):
if ![Link]():
[Link] = True
else:
[Link] = False

#editor class method: get snap switch state


def isSnap(self):
return [Link]

#editor class method: get object grouping switch state


def isGroupEnable(self):
return [Link]

#editor class method: allow toggle of object grouping switch


def groupObj(self):
if ![Link]():
[Link] = True
else:
[Link] = False

#editor class method: check object boundaries within grid


def enableObjScope(self,object):
if ((object.x <= (self.GRID_HALF_LENGTH)) & (object.x >= -
(self.GRID_HALF_LENGTH)) & (object.y <= (self.GRID_HALF_LENGTH))
& (object.y >= -(self.GRID_HALF_LENGTH)) & (object.z <=
(self.GRID_HALF_LENGTH)) & (object.z >= -(self.GRID_HALF_LENGTH))): #limit object
scope to grid
return True

#editor class method: toggle editor scene color between day & night
def toggleScene(self):
if [Link]: #check if switch is set to true
[Link]= [Link] #change editor scene color to white
[Link] = False #change switch to false
[Link] ="Night" #change displayed text on widget to
"Night"
else: #otherwise
[Link]= [Link] #change editor scene color to black
[Link] = True #change switch to true
[Link]="Day" #change displayed text on widget to
"Day"

#editor class method: get current object picked by mouse pointer


def getCurrentObj(self):
theObj = [Link]
return theObj

#editor class method: get editor grid half length


def getGridHalfLength(self):
return self.GRID_HALF_LENGTH

#editor class method: create user selected object from menu widget
def createObj(self):
[Link]([Link]) #call create method of class
object3D to draw object
[Link] = 0 #reset widget menu

#editor class method: change selected object color


def changeColor(self):
if [Link]() != None: #check selected object, ignore if none

[Link]([Link](),[Link])#call objColor
method of class object3D to change to selected color
[Link] = 0 #reset widget menu

#editor class method: adjust sliders to match current object properties


def resetSliders(self):
if isinstance([Link](),sphere): #check if current object is
sphere
self.length_slider.value = 0 #reset length slider value to zero
self.height_slider.value = 0 #reset height slider value to zero
self.width_slider.value = 0 #reset width slider value to zero
self.length_slider.disabled = True #gray out length slider
self.height_slider.disabled = True #gray out height slider
self.width_slider.disabled = True #gray out width slider
self.radius_slider.disabled = False #enable radius slider
else:
self.radius_slider.value = 0 #reset radius slider value to zero
self.length_slider.disabled = False #enable length slider
self.height_slider.disabled = False #enable height slider
self.width_slider.disabled = False #enable width slider
self.radius_slider.disabled = True #gray out radius slider

#editor class method: adjust object dimesions to slider values


def radiusSlide(self):
[Link]().radius = self.radius_slider.value #set object radius
to radius_slider value

def lengthSlide(self):
[Link]().length = self.length_slider.value #set object length
to length_slider value

def heightSlide(self):
[Link]().height = self.height_slider.value #set object height
to height_slider value

def widthSlide(self):
[Link]().width = self.width_slider.value #set object width to
width_slider value

#editor class method: Adjust sliders to inhereit current object dimension


values
def getObjSliderSet(self):
self.radius_slider.value = [Link]().radius
self.length_slider.value = [Link]().length
self.width_slider.value = [Link]().width
self.height_slider.value = [Link]().height
self.opacity_slider.value = [Link]().opacity

#editor class method: toggle rotate switch


def checkRotate(self):
if ![Link]:
[Link] = True
else:
[Link] = False

#editor class method: get rotate switch state


def isRotate(self):
return [Link]

#editor class method: set last mouse position


def setLastMousePos(self):
[Link] = [Link](normal=vec(0,0,1)) #get
and project mouse position to xy plane when right click button pressed

#editor class method: object rotation


def rotateObj(self,object):
[Link] = [Link](normal=vec(0,0,1))
#project current mouse position onto a 2D plane
[Link] = [Link] - [Link] # defines
the resultant vector

# if ([Link]!= None):
[Link](angle=(-[Link])*0.1, axis=[Link](vec(0,0,1)))
#rotate object
[Link] = [Link] #update last mouse
position

#editor class method: Clear selected object


def clearObj(self):
# [Link]([Link]())
if [Link]() != None:
[Link]([Link]()) #delete current object

#editor class method: return mouse position


def getMousePosition(self):
return [Link]
#editor class method: object cloning
def cloneObj(self):
if [Link]() != None:
[Link]().clone(pos =vec(-2,0,0)) #clones current object.

#editor class method: modify current object opacity


def objOpacity(self):
if [Link]() != None:
[Link]().opacity = self.opacity_slider.value #set object
transparency to opacity slider value

#editor class method: File Operations


def readFile(self):
if [Link] == 1:
[Link] = 0 #reset menu
print_options(delete=True) #clear printing region
[Link] = read_local_file([Link].title_anchor) #trigger read
operation

print("-------------------------------------------------------------------")
print("File Name: "+[Link]) # The file name
print("File Size: "+[Link]+"kb") # File size in bytes
print("File Type: "+[Link]) # What kind of file
print("Creation Date: " + [Link]) # Creation date if
available

print("-------------------------------------------------------------------")
print([Link]) # The file contents
print("################ End #################")

if [Link] == 2:
[Link] = 0 #reset menu
xfile = winput(prompt ="Import JavaScript File",
type = "string", text = "Enter directory") #create
a widget input allowing user to enter file directory
self.get_library(xfile) #import javascript file

#editor class method: resused method, points to actual called method for each
widget
def clickThrough(self, thisWidget):
eval([Link])

#editor class method: class widgets


def widgetControl(self, editor_object):

[Link] = button(text="Day", pos=[Link].title_anchor,


bind=editor_object.clickThrough, editor_object=editor_object,

method="thisWidget.editor_object.toggleScene()") #Switch scene background color

[Link] = menu( choices=['Choose a 3D


object','Sphere','Box','Cylinder','Cone'], bind=editor_object.clickThrough,
editor_object=editor_object,
method="thisWidget.editor_object.createObj()") #Creates object menu, allows user
select oject to display
[Link].append_to_caption(' ')
[Link] = menu( choices=['Choose object color','Red', 'Green',
'Blue','default'],bind=editor_object.clickThrough,
editor_object=editor_object,
method="thisWidget.editor_object.changeColor()" )#Modify object color
[Link].append_to_caption(' ')

[Link] = checkbox(bind=editor_object.clickThrough, text='Snap to


grid',editor_object=editor_object,

method="thisWidget.editor_object.checkSnap()")#Enable snap to grid feature


[Link].append_to_caption(' ')

[Link] = checkbox(bind=editor_object.clickThrough,
text='Group Objects',editor_object=editor_object,

method="thisWidget.editor_object.groupObj()")#Trigger the compound object feature


[Link].append_to_caption(' ')

[Link] = checkbox(bind=editor_object.clickThrough,
text='Rotate Object',editor_object=editor_object,

method="thisWidget.editor_object.checkRotate()")#Enable rotation
[Link].append_to_caption('\n\n')

self.radius_slider = slider( bind=editor_object.clickThrough, min=0.1,


max=5,editor_object=editor_object,

method="thisWidget.editor_object.radiusSlide()")#Radius slider bar


[Link].append_to_caption('Radius\n')

self.length_slider = slider( bind=editor_object.clickThrough, min=0.1,


max=10,editor_object=editor_object,

method="thisWidget.editor_object.lengthSlide()")#Length slider bar


[Link].append_to_caption('Length ')

self.height_slider = slider( bind=editor_object.clickThrough , min=0.1,


max=10,editor_object=editor_object,

method="thisWidget.editor_object.heightSlide()")#Height slider bar


[Link].append_to_caption('Height ')

self.width_slider = slider( bind=editor_object.clickThrough, min=0.1,


max=10,editor_object=editor_object,

method="thisWidget.editor_object.widthSlide()")#Width slider bar


[Link].append_to_caption('Width\n\n')

self.opacity_slider = slider( bind=editor_object.clickThrough, min=0.2,


max=1,editor_object=editor_object,

method="thisWidget.editor_object.objOpacity()")#call method to adjust object


opacity
[Link].append_to_caption('Opacity\n\n')

[Link] = menu( pos =[Link].title_anchor, choices=['File


Operation','Load File', 'Import File'],bind=editor_object.clickThrough,
editor_object=editor_object,
method="thisWidget.editor_object.readFile()" )#File operation
[Link] = button(text="Clone Object",
bind=editor_object.clickThrough,
editor_object=editor_object,
method="thisWidget.editor_object.cloneObj()") #Trigger object cloning
[Link].append_to_caption(' ')

[Link] = button(text="Delete", bind=editor_object.clickThrough,


editor_object=editor_object,
method="thisWidget.editor_object.clearObj()") #call method to delete currrent
object

########################################################class
trackLine##########################################################################
#
class trackLine:
def __init__(self,editorInstance):
[Link] = editorInstance
[Link] = label( pos=[Link], text=[Link],
box = False,visible = False, opacity = 0)

#Define track lines on all 3 dimensional axis, not visible by default


[Link] = box(pos=vector(0,0,0),
size=vector([Link].GRID_HALF_LENGTH,5*[Link]
ht,
5*[Link]), color =
[Link], visible = False, axis = vector(1,0,0))
[Link] = box(pos=vector(0,0,0),
size=vector([Link].GRID_HALF_LENGTH,5*[Link]
ht,
5*[Link]), color =
[Link], visible = False, axis = vector(0,1,0))
[Link] = box(pos=vector(0,0,0),
size=vector([Link].GRID_HALF_LENGTH,5*[Link]
ht,
5*[Link]), color =
[Link], visible = False, axis = vector(0,0,1))

#trackLine class method: show track lines


def showTrackLine(self,obj):
[Link] = True #Turn on x-axis track line visibility
[Link] = True #Turn on y-axis track line visibility
[Link] = True #Turn on z-axis track line visibility

#Calculate and track object position along the x-axis


[Link].x = (([Link].GRID_HALF_LENGTH +
[Link].x)/2)
[Link].y = ([Link].y)
[Link].z = ([Link].z)
[Link].x = [Link].GRID_HALF_LENGTH - [Link].x

#Calculate and track object position along the y-axis


[Link].x = ([Link].x)
[Link].y = (-[Link].GRID_HALF_LENGTH +
[Link].y)/2
[Link].z = ([Link].z)
[Link].x = [Link].GRID_HALF_LENGTH + [Link].y
#Calculate and track object position along the z-axis
[Link].x = ([Link].x)
[Link].y = ([Link].y)
[Link].z = (-[Link].GRID_HALF_LENGTH +
[Link].z)/2
[Link].x = [Link].GRID_HALF_LENGTH + [Link].z

#trackLine class method: display object position label on scene


def showObjPos(self,obj):
[Link] = True
[Link] = [Link]
[Link].x = [Link].x
[Link].y = [Link].y
[Link].z = [Link].z

#trackLine class method: disable object track line


def removeTrackLine(self):
[Link] = False #Turn on x-axis track line visibility
[Link] = False #Turn on y-axis track line visibility
[Link] = False #Turn on z-axis track line visibility

#trackLine class method: disable object position label


def removeObjPos(self):
[Link] = False

############################################################Class
object3D##########################################################

class object3D:

def __init__ (self):


[Link] = 0.5 #default object radius
[Link] = 0.5 #default object length
[Link] = 0.5 #default object height
[Link] = 0.5 #default object width

#object3D class method: draw selected object


def create(self,index):

if index==1:
return sphere(pos=vec(0,0,0), radius = [Link], visible = True,
pickable = True)
if index==2:
return box(pos=vec(0,0,0), length=[Link],height=[Link],
width=[Link], visible = True, pickable = True) #display sphere on grid
if index==3:
return cylinder(pos=vec(0,0,0), radius = [Link], axis=
vec([Link],[Link],[Link]), visible = True, pickable = True)
#display
if index==4:
return cone(pos=vector(0,0,0),radius = [Link], axis=
vec([Link],[Link],[Link]), visible = True, pickable = True)
#display sphere on grid

#object3D class method: modify object color


def objColor(self,obj,index):
if index ==1:
[Link] = [Link] #set red
if index ==2:
[Link] = [Link] #set green
if index ==3:
[Link] = [Link] #set blue
if index == 4:
[Link] = vec(1,1,1) #set to default gray color

#object3D class method: delete object


def removeObj(self,obj):
[Link] = False
[Link] = False
del obj

#object3D class method: get object type


def objType(self,obj):
return type(obj)

######################################Program
Main########################################################

myObj3D = object3D() #create an instance of object3D class


thisEditor = editor(myObj3D) #instantiate an editor
[Link]() #create and setup scene
[Link]() #draw 3D grid on scene
thisEditor.draw3DAxisLines() #draw 3D lines on scene
[Link](thisEditor) #setup associated widgets
obj = None # object pointer
thisTrackLine = trackLine(thisEditor) #instantiate trackline

#Binding functions
[Link]("mousemove",movemoveActions) # Call function to modify curent
object position using the mouse
[Link]("mouseup",mouseupActions)
[Link]("mousedown", mousedownActions)
[Link]('keydown',keydownActions) # Call function to modify current
object position using the keyboard direction keys
[Link]('keyup',mouseupActions) #Call dragFalse to disable object
position modification.

def mousedownActions():
global obj #allow modification to be made to object pointer
obj = [Link]() #assign current object to object pointer
[Link]() #adjust sliders to match current object properties
[Link]() #Adjust sliders to inhereit current object
dimension values
[Link]() #get and project mouse position to xy plane when
user press right mouse button

if [Link](): #check if user enabled rotation


[Link]() #disable trackline on scene
else:
[Link](obj) #show current object position label

if [Link](): #checks if user enabled object grouping


if [Link]() != None: #check if an object is selected
[Link]([Link]()) #add user
selected object to object list for grouping

def movemoveActions():
global obj #allow modification to be made to object pointer
temp=[Link]() #temproary hold mouse position

if [Link](): #check if snap to grid is enabled by user


temp = [Link](temp) #if true, round mouse position to snap on grid
intersections

if [Link](temp): #check if mouse position falls within grid


defined boundaries
if [Link](): #check if user enabled rotation
[Link]() #disable trackline on scene if rotation is
enabled
[Link](obj) #rotate the object
else:
[Link]=temp #update object position to mouse position on the grid if
rotation is disabled
[Link](obj) #display object trackline
[Link](obj) #display object position label

def mouseupActions():
global obj #allow modification to be made to object pointer
[Link]() #remove object track lines
[Link](obj) #remove object position label

def keydownActions():
global obj #allow modification to be made to object pointer
if obj != None: #check if object is selected
temp = [Link] #assign object position to a temproary variable
dv = 0.05 #object move step value using keyboard
theKey = keysdown() #get the pressed key
if 'left' in theKey: #check if left directional key is pressed
temp.x-=dv #move object towards the left on thex-axis at step value of
0.05
if (temp.x < -[Link]()): #check grid boundaries
temp.x+=dv #if boundary value is surpassed modify to last value
within grid boundary
if 'right' in theKey: #check if right directional key is pressed
temp.x+=dv #move object towards the right on thex-axis at step value of
0.05
if (temp.x > [Link]()): #check grid boundaries
temp.x-=dv #if boundary value is surpassed modify to last value
within grid boundary
if 'alt' in theKey: #check if 'alt' key is pressed
if 'up' in theKey: #check if up directional key is pressed with the alt
key
temp.z-=dv #move object away from the user along z-axis at step
value of 0.05
if (temp.z < -[Link]()): #check grid
boundaries
temp.z+=dv #if boundary value is surpassed modify to last value
within grid boundary
if 'down' in theKey: #check if down directional key is pressed with the
alt key
temp.z+=dv #move object towards the user along z-axis at step value
of 0.05
if (temp.z > [Link]()): #check grid
boundaries
temp.z-=dv #if boundary value is surpassed modify to last value
within grid boundary
elif 'up' in theKey: #check if up directional key is pressed
temp.y+=dv #move object upwards on the y-axis at step value of 0.05
if (temp.y > [Link]()): #check grid boundaries
temp.y-=dv #if boundary value is surpassed modify to last value
within grid boundary
elif 'down' in theKey: #check if down directional key is pressed
temp.y-=dv #move object downwards on the y-axis at step value of 0.05
if (temp.y < -[Link]()): #check grid boundaries
temp.y+=dv #if boundary value is surpassed modify to last value
within grid boundary

# group objects in objList


if 'ctrl' in theKey: #check if ctrl key is pressed by user
compound([Link]) #group objects contained in list if
ctrl key is pressed
[Link] = [] # clear object list

#delete object if delete key is pressed


if 'delete' in theKey:
[Link](obj) #delete object
obj = None
[Link]() #disable trackline
[Link](obj) #disable object position

[Link]=temp #update object position


[Link](obj)#show 3D trackline
[Link](obj) #print object position label on scene

You might also like