def create(self, generator, mins, maxs, material, roundDecimals, temp=False): wallWidth = self.wallWidth.getValue() if wallWidth < 1: return [] numSides = self.numSides.getValue() if numSides < 3: return [] # Very similar to the cylinder, except that we have multiple solids this time width = maxs.x - mins.x length = maxs.y - mins.y height = maxs.z - mins.z center = (maxs + mins) / 2 majorOut = width / 2 majorIn = majorOut - wallWidth minorOut = length / 2 minorIn = minorOut - wallWidth angle = 2 * math.pi / numSides # Calc the X,Y for the inner and outer ellipses outer = [] inner = [] for i in range(numSides): a = i * angle x = center.x + majorOut * math.cos(a) y = center.y + minorOut * math.sin(a) z = mins.z outer.append(LEUtils.roundVector(Point3(x, y, z), roundDecimals)) x = center.x + majorIn * math.cos(a) y = center.y + minorIn * math.sin(a) inner.append(LEUtils.roundVector(Point3(x, y, z), roundDecimals)) color = LEUtils.getRandomSolidColor() # Create the solids solids = [] z = LEUtils.roundVector(Point3(0, 0, height), roundDecimals) for i in range(numSides): faces = [] next = (i + 1) % numSides faces.append( [outer[i], outer[i] + z, outer[next] + z, outer[next]]) faces.append( [inner[next], inner[next] + z, inner[i] + z, inner[i]]) faces.append( [outer[next], outer[next] + z, inner[next] + z, inner[next]]) faces.append([inner[i], inner[i] + z, outer[i] + z, outer[i]]) faces.append( [inner[next] + z, outer[next] + z, outer[i] + z, inner[i] + z]) faces.append([inner[i], outer[i], outer[next], inner[next]]) solids.append( self.makeSolid(generator, faces, material, temp, color)) return solids
def __pickColor(self): self.origColor = LEUtils.strToQColor(self.getItemData()) color = LEUtils.strToQColor(self.getItemData()) colorDlg = QtWidgets.QColorDialog(color, self) colorDlg.setOptions(QtWidgets.QColorDialog.DontUseNativeDialog) colorDlg.setModal(True) colorDlg.currentColorChanged.connect(self.adjustToColorAndSetData) colorDlg.finished.connect(self.__colorDlgFinished) colorDlg.open() colorDlg.blockSignals(True) colorDlg.setCurrentColor(color) colorDlg.blockSignals(False) self.colorDlg = colorDlg
def getObjectsUnderMouse(self): vp = base.viewportMgr.activeViewport if not vp: return [] entries = vp.click(self.Mask) if not entries or len(entries) == 0: return [] objects = [] key = self.Key for i in range(len(entries)): # Our entries have been sorted by distance, so use the first (closest) one. entry = entries[i] np = entry.getIntoNodePath().findNetPythonTag(key) if not np.isEmpty(): # Don't backface cull if there is a billboard effect on or above this node if entry.hasSurfaceNormal() and not LEUtils.hasNetBillboard( entry.getIntoNodePath()): surfNorm = entry.getSurfaceNormal(vp.cam).normalized() rayDir = entry.getFrom().getDirection().normalized() if surfNorm.dot(rayDir) >= 0: # Backface cull continue obj = np.getPythonTag(key) actual = self.getActualObject(obj, entry) objects.append((actual, entry)) return objects
def create(self, generator, mins, maxs, material, roundDecimals, temp=False): faces = LEUtils.getBoxFaces(mins, maxs, roundDecimals) return [self.makeSolid(generator, faces, material, temp)]
def create(self, generator, mins, maxs, material, roundDecimals, temp=False): numSides = self.numSides.getValue() if numSides < 3: return [] # Cylinders can be elliptical so use both major and minor rather than just the radius # NOTE: when a low number (< 10ish) of faces are selected this will cause the cylinder to not touch all edges of the box. width = maxs.x - mins.x length = maxs.y - mins.y height = maxs.z - mins.z center = (mins + maxs) / 2 major = width / 2 minor = length / 2 angle = 2 * math.pi / numSides # Calculate the X and Y points for the ellipse points = [] for i in range(numSides): a = i * angle xval = center.x + major * math.cos(a) yval = center.y + minor * math.sin(a) zval = mins.z points.append( LEUtils.roundVector(Point3(xval, yval, zval), roundDecimals)) faces = [] z = LEUtils.roundVector(Point3(0, 0, height), roundDecimals) for i in range(numSides): next = (i + 1) % numSides faces.append( [points[i], points[i] + z, points[next] + z, points[next]]) # Add the elliptical top and bottom faces faces.append(points) faces.append([x + z for x in reversed(points)]) solid = self.makeSolid(generator, faces, material, temp) return [solid]
def create(self, generator, mins, maxs, material, roundDecimals, temp=False): # The lower Z plane will be base center = (mins + maxs) / 2 c1 = LEUtils.roundVector(Point3(mins.x, mins.y, mins.z), roundDecimals) c2 = LEUtils.roundVector(Point3(maxs.x, mins.y, mins.z), roundDecimals) c3 = LEUtils.roundVector(Point3(maxs.x, maxs.y, mins.z), roundDecimals) c4 = LEUtils.roundVector(Point3(mins.x, maxs.y, mins.z), roundDecimals) c5 = LEUtils.roundVector(Point3(center.x, center.y, maxs.z), roundDecimals) faces = [[c1, c2, c3, c4], [c2, c1, c5], [c3, c2, c5], [c4, c3, c5], [c1, c4, c5]] return [self.makeSolid(generator, faces, material, temp)]
def __init__(self, widget, axis): TransformWidgetAxis.__init__(self, widget, axis) segs = LineSegs() segs.setThickness(2) vertices = LEUtils.circle(0, 0, 1, 64) for i in range(len(vertices)): x1, y1 = vertices[i] x2, y2 = vertices[(i + 1) % len(vertices)] segs.moveTo(x1, 0, y1) segs.drawTo(x2, 0, y2) self.axisCircle = self.attachNewNode(segs.create()) self.axisCircle.setAntialias(AntialiasAttrib.MLine)
def mouseDown(self): vp = base.viewportMgr.activeViewport if not vp: return if vp.is3D(): # If we clicked in the 3D viewport, try to intersect with an existing MapObject # and immediately place the entity at the intersection point. If we didn't click on any # MapObject, place the entity on the grid where we clicked. entries = vp.click(GeomNode.getDefaultCollideMask()) if entries and len(entries) > 0: for i in range(len(entries)): entry = entries[i] # Don't backface cull if there is a billboard effect on or above this node if not LEUtils.hasNetBillboard(entry.getIntoNodePath()): surfNorm = entry.getSurfaceNormal(vp.cam).normalized() rayDir = entry.getFrom().getDirection().normalized() if surfNorm.dot(rayDir) >= 0: # Backface cull continue # We clicked on an object, use the contact point as the # location of our new entity. self.pos = entry.getSurfacePoint(self.doc.render) self.hasPlaced = True # Create it! self.confirm() break else: # Didn't click on an object, intersect our mouse ray with the grid plane. plane = LPlane(0, 0, 1, 0) worldMouse = vp.viewportToWorld(vp.getMouse()) theCamera = vp.cam.getPos(render) # Ensure that the camera and mouse positions are on opposite # sides of the plane, or else the entity would place behind us. sign1 = plane.distToPlane(worldMouse) >= 0 sign2 = plane.distToPlane(theCamera) >= 0 if sign1 != sign2: pointOnPlane = Point3() ret = plane.intersectsLine(pointOnPlane, theCamera, worldMouse) if ret: # Our mouse intersected the grid plane. Place an entity at the plane intersection point. self.pos = pointOnPlane self.hasPlaced = True self.confirm() return # The user clicked in the 2D viewport, draw the visualization where they clicked. self.showVis() self.updatePosFromViewport(vp) self.mouseIsDown = True self.hasPlaced = True
def create(self, generator, mins, maxs, material, roundDecimals, temp=False): numSides = self.numSides.getValue() if numSides < 3: return [] # This is all very similar to the cylinder brush. width = maxs.x - mins.x length = maxs.y - mins.y center = (mins + maxs) / 2 major = width / 2 minor = length / 2 angle = 2 * math.pi / numSides points = [] for i in range(numSides): a = i * angle xval = center.x + major * math.cos(a) yval = center.y + minor * math.sin(a) zval = mins.z points.append( LEUtils.roundVector(Point3(xval, yval, zval), roundDecimals)) faces = [] point = LEUtils.roundVector(Point3(center.x, center.y, maxs.z), roundDecimals) for i in range(numSides): next = (i + 1) % numSides faces.append([points[i], point, points[next]]) faces.append(points) solid = self.makeSolid(generator, faces, material, temp) return [solid]
def getPointOnGizmo(self): vp = base.viewportMgr.activeViewport if not vp or not vp.is3D(): return axis = self.widget.activeAxis.axisIdx gray = self.getGizmoRay(axis) mray = vp.getMouseRay() # Move into world space mray.xform(vp.cam.getMat(NodePath())) distance = LEUtils.closestDistanceBetweenLines(gray, mray) return gray.origin + (gray.direction * -gray.t)
def create(self, generator, mins, maxs, material, roundDecimals, temp=False): useCentroid = self.useCentroid.getValue() center = (mins + maxs) / 2 # The lower Z plane will be the triangle, with the lower Y value getting the two corners c1 = LEUtils.roundVector(Point3(mins.x, mins.y, mins.z), roundDecimals) c2 = LEUtils.roundVector(Point3(maxs.x, mins.y, mins.z), roundDecimals) c3 = LEUtils.roundVector(Point3(center.x, maxs.y, mins.z), roundDecimals) if useCentroid: c4 = Point3((c1.x + c2.x + c3.x) / 3, (c1.y + c2.y + c3.y) / 3, maxs.z) else: c4 = LEUtils.roundVector(Point3(center.x, center.y, maxs.z), roundDecimals) faces = [[c1, c2, c3], [c4, c1, c3], [c4, c3, c2], [c4, c2, c1]] return [self.makeSolid(generator, faces, material, temp)]
def __init__(self, parent, item, model): BaseEditor.__init__(self, parent, item, model) self.lineEdit = QtWidgets.QLineEdit("", self) self.lineEdit.returnPressed.connect(self.__confirmColorText) self.layout().addWidget(self.lineEdit) self.colorLbl = QtWidgets.QLabel("", self) self.colorLbl.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Preferred) self.layout().addWidget(self.colorLbl) self.editButton = QtWidgets.QPushButton("Pick Color", self) self.editButton.clicked.connect(self.__pickColor) self.layout().addWidget(self.editButton) self.colorDlg = None self.adjustToColor(LEUtils.strToQColor(self.getItemData()))
def create(self, generator, mins, maxs, material, roundDecimals, temp=False): solids = [] numSides = self.numSides.getValue() if numSides < 3: return solids wallWidth = self.wallWidth.getValue() if wallWidth < 1: return solids arc = self.arc.getValue() if arc < 1: return solids startAngle = self.startAngle.getValue() if startAngle < 0 or startAngle > 359: return solids addHeight = self.addHeight.getValue() curvedRamp = self.curvedRamp.getValue() tiltAngle = self.tiltAngle.getValue() if abs(tiltAngle % 180) == 90: return solids tiltInterp = curvedRamp and self.tiltInterp.getValue() # Very similar to the pipe brush, except with options for start angle, arc, height, and tilt. width = maxs.x - mins.x length = maxs.y - mins.y height = maxs.z - mins.z majorOut = width / 2 majorIn = majorOut - wallWidth minorOut = length / 2 minorIn = minorOut - wallWidth start = deg2Rad(startAngle) tilt = deg2Rad(tiltAngle) angle = deg2Rad(arc) / numSides center = (mins + maxs) / 2 # Calculate the coordinates of the inner and outer ellipses' points. outer = [] inner = [] for i in range(numSides + 1): a = start + i * angle h = i * addHeight interp = 1 if tiltInterp: interp = math.cos(math.pi / numSides * (i - numSides / 2)) tiltHeight = wallWidth / 2 * interp * math.tan(tilt) xval = center.x + majorOut * math.cos(a) yval = center.y + minorOut * math.sin(a) zval = mins.z if curvedRamp: zval += h + tiltHeight outer.append( LEUtils.roundVector(Point3(xval, yval, zval), roundDecimals)) xval = center.x + majorIn * math.cos(a) yval = center.y + minorIn * math.sin(a) zval = mins.z if curvedRamp: zval += h - tiltHeight inner.append( LEUtils.roundVector(Point3(xval, yval, zval), roundDecimals)) color = LEUtils.getRandomSolidColor() # create the solids z = LEUtils.roundVector(Point3(0, 0, height), roundDecimals) for i in range(numSides): faces = [] # Since we are triangulating/splitting each arch segment, we need to generate 2 brushes per side if curvedRamp: # The splitting orientation depends on the curving direction of the arch if addHeight >= 0: faces.append([ outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] ]) faces.append([ outer[i + 1], outer[i + 1] + z, inner[i] + z, inner[i] ]) faces.append( [inner[i], inner[i] + z, outer[i] + z, outer[i]]) faces.append( [outer[i] + z, inner[i] + z, outer[i + 1] + z]) faces.append([outer[i + 1], inner[i], outer[i]]) else: faces.append([ inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] ]) faces.append([ outer[i], outer[i] + z, inner[i + 1] + z, inner[i + 1] ]) faces.append( [inner[i], inner[i] + z, outer[i] + z, outer[i]]) faces.append( [inner[i + 1] + z, outer[i] + z, inner[i] + z]) faces.append([inner[i], outer[i], inner[i + 1]]) solids.append( self.makeSolid(generator, faces, material, temp, color)) faces.clear() if addHeight >= 0: faces.append([ inner[i + 1], inner[i + 1] + z, inner[i] + z, inner[i] ]) faces.append([ inner[i], inner[i] + z, outer[i + 1] + z, outer[i + 1] ]) faces.append([ outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] ]) faces.append( [inner[i + 1] + z, outer[i + 1] + z, inner[i] + z]) faces.append([inner[i], outer[i + 1], inner[i + 1]]) else: faces.append([ outer[i], outer[i] + z, outer[i + 1] + z, outer[i + 1] ]) faces.append([ inner[i + 1], inner[i + 1] + z, outer[i] + z, outer[i] ]) faces.append([ outer[i + 1], outer[i + 1] + z, inner[i + 1] + z, inner[i + 1] ]) faces.append( [outer[i] + z, inner[i + 1] + z, outer[i + 1] + z]) faces.append([outer[i + 1], inner[i + 1], outer[i]]) solids.append( self.makeSolid(generator, faces, material, temp, color)) else: h = Vec3.unitZ() * i * addHeight faces.append([ outer[i] + h, outer[i] + z + h, outer[i + 1] + z + h, outer[i + 1] + h ]) faces.append([ inner[i + 1] + h, inner[i + 1] + z + h, inner[i] + z + h, inner[i] + h ]) faces.append([ outer[i + 1] + h, outer[i + 1] + z + h, inner[i + 1] + z + h, inner[i + 1] + h ]) faces.append([ inner[i] + h, inner[i] + z + h, outer[i] + z + h, outer[i] + h ]) faces.append([ inner[i + 1] + z + h, outer[i + 1] + z + h, outer[i] + z + h, inner[i] + z + h ]) faces.append([ inner[i] + h, outer[i] + h, outer[i + 1] + h, inner[i + 1] + h ]) solids.append( self.makeSolid(generator, faces, material, temp, color)) return solids
def create(self, generator, mins, maxs, material, roundDecimals, temp=False): numSides = self.numSides.getValue() if numSides < 3: return [] roundDecimals = 2 # Don't support rounding width = maxs.x - mins.x length = maxs.y - mins.y height = maxs.z - mins.z center = (maxs + mins) / 2 major = width / 2 minor = length / 2 heightRadius = height / 2 angleV = deg2Rad(180) / numSides angleH = deg2Rad(360) / numSides faces = [] bottom = LEUtils.roundVector(Point3(center.x, center.y, mins.z), roundDecimals) top = LEUtils.roundVector(Point3(center.x, center.y, maxs.z), roundDecimals) for i in range(numSides): # Top -> bottom zAngleStart = angleV * i zAngleEnd = angleV * (i + 1) zStart = heightRadius * math.cos(zAngleStart) zEnd = heightRadius * math.cos(zAngleEnd) zMultStart = math.sin(zAngleStart) zMultEnd = math.sin(zAngleEnd) for j in range(numSides): # Go around the circle in X/Y xyAngleStart = angleH * j xyAngleEnd = angleH * ((j + 1) % numSides) xyStartX = major * math.cos(xyAngleStart) xyStartY = minor * math.sin(xyAngleStart) xyEndX = major * math.cos(xyAngleEnd) xyEndY = minor * math.sin(xyAngleEnd) a = LEUtils.roundVector( Point3(xyStartX * zMultStart, xyStartY * zMultStart, zStart) + center, roundDecimals) b = LEUtils.roundVector( Point3(xyEndX * zMultStart, xyEndY * zMultStart, zStart) + center, roundDecimals) c = LEUtils.roundVector( Point3(xyEndX * zMultEnd, xyEndY * zMultEnd, zEnd) + center, roundDecimals) d = LEUtils.roundVector( Point3(xyStartX * zMultEnd, xyStartY * zMultEnd, zEnd) + center, roundDecimals) if i == 0: # Top faces are triangles faces.append([top, c, d]) elif i == (numSides - 1): # Bottom faces are also triangles faces.append([bottom, a, b]) else: # Inner faces are quads faces.append([a, b, c, d]) return [self.makeSolid(generator, faces, material, temp)]
def snapToGrid(self, point): if GridSettings.GridSnap: return LEUtils.snapToGrid(GridSettings.DefaultStep, point) return point
def pickRandomColor(self): # Picks a random shade of blue/green for this solid. self.setColor(LEUtils.getRandomSolidColor())
def __confirmColorText(self): self.setModelData(self.model, self.item.index()) self.adjustToColor(LEUtils.strToQColor(self.lineEdit.text()))
def computeValueText(self): return LEUtils.boolToStr(self.flagsItem.prop.hasFlags(self.spawnFlag.value))
def setModelData(self, model, index): model.setData(index, LEUtils.boolToStr(self.check.isChecked()), QtCore.Qt.EditRole)
def keyPressEvent(self, event): button = LEUtils.keyboardButtonFromQtKey(event.key()) if button: self.inputDevice.buttonDown(button)
def keyReleaseEvent(self, event): button = LEUtils.keyboardButtonFromQtKey(event.key()) if button: self.inputDevice.buttonUp(button)
def setEditorData(self, index): val = LEUtils.strToBool(self.getItemData()) self.check.blockSignals(True) self.check.setChecked(val) self.check.blockSignals(False)
def invRotate(self, point): quat = Quat() quat.setHpr(self.getViewHpr()) return LEUtils.makeForwardAxis(point, quat)