def get_bifurcation_triple_point(p1x, p1d, p2x, p2d, p3x, p3d): ''' Get coordinates and derivatives of triple point between p1, p2 and p3 with derivatives. :param p1x..p3d: Point coordinates and derivatives, numbered anticlockwise around triple point. All derivatives point away from triple point. Returned d1 points from triple point to p2, d2 points from triple point to p3. :return: x, d1, d2 ''' trx1 = interpolateCubicHermite(p1x, mult(p1d, -2.0), p2x, mult(p2d, 2.0), 0.5) trx2 = interpolateCubicHermite(p2x, mult(p2d, -2.0), p3x, mult(p3d, 2.0), 0.5) trx3 = interpolateCubicHermite(p3x, mult(p3d, -2.0), p1x, mult(p1d, 2.0), 0.5) trx = [ (trx1[c] + trx2[c] + trx3[c])/3.0 for c in range(3) ] td1 = interpolateLagrangeHermiteDerivative(trx, p1x, p1d, 0.0) td2 = interpolateLagrangeHermiteDerivative(trx, p2x, p2d, 0.0) td3 = interpolateLagrangeHermiteDerivative(trx, p3x, p3d, 0.0) n12 = cross(td1, td2) n23 = cross(td2, td3) n31 = cross(td3, td1) norm = normalize([ (n12[c] + n23[c] + n31[c]) for c in range(3) ]) sd1 = smoothCubicHermiteDerivativesLine([ trx, p1x ], [ normalize(cross(norm, cross(td1, norm))), p1d ], fixStartDirection=True, fixEndDerivative=True)[0] sd2 = smoothCubicHermiteDerivativesLine([ trx, p2x ], [ normalize(cross(norm, cross(td2, norm))), p2d ], fixStartDirection=True, fixEndDerivative=True)[0] sd3 = smoothCubicHermiteDerivativesLine([ trx, p3x ], [ normalize(cross(norm, cross(td3, norm))), p3d ], fixStartDirection=True, fixEndDerivative=True)[0] trd1 = mult(sub(sd2, add(sd3, sd1)), 0.5) trd2 = mult(sub(sd3, add(sd1, sd2)), 0.5) return trx, trd1, trd2
def get_curve_circle_points(x1, xd1, x2, xd2, r1, rd1, r2, rd2, xi, dmag, side, elementsCountAround): ''' :param dmag: Magnitude of derivative on curve. :param side: Vector in side direction of first node around. Need not be unit or exactly normal to curve at xi. :return: x[], d1[] around, d2[] along ''' cx = interpolateCubicHermite(x1, xd1, x2, xd2, xi) cxd = interpolateCubicHermiteDerivative(x1, xd1, x2, xd2, xi) mag_cxd = magnitude(cxd) cxd2 = interpolateCubicHermiteSecondDerivative(x1, xd1, x2, xd2, xi) mag_cxd2 = magnitude(cxd2) r = interpolateCubicHermite([ r1 ], [ rd1 ], [ r2 ], [ rd2 ], xi)[0] rd = interpolateCubicHermiteDerivative([ r1 ], [ rd1 ], [ r2 ], [ rd2 ], xi)[0] axis1 = normalize(cxd) axis3 = normalize(cross(axis1, side)) axis2 = cross(axis3, axis1) x, d1 = createCirclePoints(cx, mult(axis2, r), mult(axis3, r), elementsCountAround) curvatureVector = mult(cxd2, 1.0/(mag_cxd*mag_cxd)) d2 = [] radialGrowth = rd/(mag_cxd*r) for e in range(elementsCountAround): radialVector = sub(x[e], cx) dmagFinal = dmag*(1.0 - dot(radialVector, curvatureVector)) # add curvature and radius change components: d2.append(add(mult(cxd, dmagFinal/mag_cxd), mult(radialVector, dmagFinal*radialGrowth))) return x, d1, d2
def mouseMoveEvent(self, event): if self._model.isStateAlign() and self._alignKeyPressed and ( self._lastMousePos is not None): pos = [event.x(), event.y()] delta = [ pos[0] - self._lastMousePos[0], pos[1] - self._lastMousePos[1] ] result, eye = self._sceneviewer.getEyePosition() result, lookat = self._sceneviewer.getLookatPosition() result, up = self._sceneviewer.getUpVector() lookatToEye = vectorops.sub(eye, lookat) eyeDistance = vectorops.magnitude(lookatToEye) front = vectorops.div(lookatToEye, eyeDistance) right = vectorops.cross(up, front) if self._active_button == QtCore.Qt.LeftButton: mag = vectorops.magnitude(delta) prop = vectorops.div(delta, mag) axis = vectorops.add(vectorops.mult(up, prop[0]), vectorops.mult(right, prop[1])) angle = mag * 0.002 self._model.rotateModel(axis, angle) elif self._active_button == QtCore.Qt.MiddleButton: result, l, r, b, t, near, far = self._sceneviewer.getViewingVolume( ) viewportWidth = self.width() viewportHeight = self.height() if viewportWidth > viewportHeight: eyeScale = (t - b) / viewportHeight else: eyeScale = (r - l) / viewportWidth offset = vectorops.add( vectorops.mult(right, eyeScale * delta[0]), vectorops.mult(up, -eyeScale * delta[1])) self._model.offsetModel(offset) elif self._active_button == QtCore.Qt.RightButton: factor = 1.0 + delta[1] * 0.0005 if factor < 0.9: factor = 0.9 self._model.scaleModel(factor) self._lastMousePos = pos else: super(AlignmentSceneviewerWidget, self).mouseMoveEvent(event)
def mouse_move_event(self, event): if self._lastMousePos is not None: pixel_scale = self._scene_viewer.get_pixel_scale() pos = [event.x() * pixel_scale, event.y() * pixel_scale] delta = [pos[0] - self._lastMousePos[0], pos[1] - self._lastMousePos[1]] mag = vectorops.magnitude(delta) if mag <= 0.0: return result, eye = self._zinc_sceneviewer.getEyePosition() result, lookat = self._zinc_sceneviewer.getLookatPosition() result, up = self._zinc_sceneviewer.getUpVector() lookatToEye = vectorops.sub(eye, lookat) eyeDistance = vectorops.magnitude(lookatToEye) front = vectorops.div(lookatToEye, eyeDistance) right = vectorops.cross(up, front) viewportWidth = self._scene_viewer.width() viewportHeight = self._scene_viewer.height() if self._active_button == QtCore.Qt.LeftButton: prop = vectorops.div(delta, mag) axis = vectorops.add(vectorops.mult(up, prop[0]), vectorops.mult(right, prop[1])) angle = mag * 0.002 self._model.rotateModel(axis, angle) elif self._active_button == QtCore.Qt.MiddleButton: result, l, r, b, t, near, far = self._zinc_sceneviewer.getViewingVolume() if viewportWidth > viewportHeight: eyeScale = (t - b) / viewportHeight else: eyeScale = (r - l) / viewportWidth offset = vectorops.add(vectorops.mult(right, eyeScale * delta[0]), vectorops.mult(up, -eyeScale * delta[1])) self._model.offsetModel(offset) elif self._active_button == QtCore.Qt.RightButton: factor = 1.0 + delta[1] * 0.0005 if factor < 0.9: factor = 0.9 self._model.scaleModel(factor) self._lastMousePos = pos
def extractImageCorners(directory, filename): """ Extract the image corners from an image that is assumed to be a DICOM image. Corners are returned as: [bl, br, tl, tr] :param directory: the directory where the file given with filename exists. :param filename: the filename of the file to interrogate. :return: the corners of the image [bl, br, tl, tr] """ ds = dicom.read_file(os.path.join(directory, filename)) pixel_spacing = ds.PixelSpacing # delta_i = float(0.1) # delta_j = float(0.1) delta_i = float(pixel_spacing[0]) delta_j = float(pixel_spacing[1]) orient = [float(iop) for iop in ds.ImageOrientationPatient] pos = [float(ipp) for ipp in ds.ImagePositionPatient] rows = ds.Rows columns = ds.Columns # vectorops version orient_1 = orient[:3] orient_2 = orient[3:] pos_o = pos[:] pos = vectorops.sub( pos_o, vectorops.mult( vectorops.add(vectorops.mult(orient_1, 0.5), vectorops.mult(orient_2, 0.5)), delta_i)) A = [[orient[0] * delta_i, orient[3] * delta_j, 0, pos[0]], [orient[1] * delta_i, orient[4] * delta_j, 0, pos[1]], [orient[2] * delta_i, orient[5] * delta_j, 0, pos[2]], [0, 0, 0, 1]] b_tl = [0, 0, 0, 1] b_tr = [rows, 0, 0, 1] b_bl = [0, columns, 0, 1] b_br = [rows, columns, 0, 1] tl = vectorops.mxvectormult(A, b_tl) tr = vectorops.mxvectormult(A, b_tr) bl = vectorops.mxvectormult(A, b_bl) br = vectorops.mxvectormult(A, b_br) return [bl[:3], br[:3], tl[:3], tr[:3]]
def transform_coordinates(field: Field, rotation_scale, offset, time=0.0) -> bool: """ Transform finite element field coordinates by matrix and offset, handling nodal derivatives and versions. Limited to nodal parameters, rectangular cartesian coordinates :param field: the coordinate field to transform :param rotation_scale: square transformation matrix 2-D array with as many rows and columns as field components. :param offset: coordinates offset. :param time: time value. :return: True on success, otherwise false. """ ncomp = field.getNumberOfComponents() if (ncomp != 2) and (ncomp != 3): print('transform_coordinates: field has invalid number of components') return False if (len(rotation_scale) != ncomp) or (len(offset) != ncomp): print( 'transform_coordinates: invalid matrix number of columns or offset size' ) return False for matRow in rotation_scale: if len(matRow) != ncomp: print('transform_coordinates: invalid matrix number of columns') return False if field.getCoordinateSystemType( ) != Field.COORDINATE_SYSTEM_TYPE_RECTANGULAR_CARTESIAN: print('transform_coordinates: field is not rectangular cartesian') return False fe_field = field.castFiniteElement() if not fe_field.isValid(): print('transform_coordinates: field is not finite element field type') return False success = True fm = field.getFieldmodule() fm.beginChange() cache = fm.createFieldcache() cache.setTime(time) nodes = fm.findNodesetByFieldDomainType(Field.DOMAIN_TYPE_NODES) node_template = nodes.createNodetemplate() node_iter = nodes.createNodeiterator() node = node_iter.next() while node.isValid(): node_template.defineFieldFromNode(fe_field, node) cache.setNode(node) for derivative in [ Node.VALUE_LABEL_VALUE, Node.VALUE_LABEL_D_DS1, Node.VALUE_LABEL_D_DS2, Node.VALUE_LABEL_D2_DS1DS2, Node.VALUE_LABEL_D_DS3, Node.VALUE_LABEL_D2_DS1DS3, Node.VALUE_LABEL_D2_DS2DS3, Node.VALUE_LABEL_D3_DS1DS2DS3 ]: versions = node_template.getValueNumberOfVersions( fe_field, -1, derivative) for v in range(versions): result, values = fe_field.getNodeParameters( cache, -1, derivative, v + 1, ncomp) if result != RESULT_OK: success = False else: new_values = vectorops.matrix_vector_mult( rotation_scale, values) if derivative == Node.VALUE_LABEL_VALUE: new_values = vectorops.add(new_values, offset) result = fe_field.setNodeParameters( cache, -1, derivative, v + 1, new_values) if result != RESULT_OK: success = False node = node_iter.next() fm.endChange() if not success: print('transform_coordinates: failed to get/set some values') return success
def translateModel(self, relativeOffset): self._alignSettings["offset"] = add(self._alignSettings["offset"], relativeOffset) self._applyAlignSettings()
def make_tube_bifurcation_points(paCentre, pax, pad2, c1Centre, c1x, c1d2, c2Centre, c2x, c2d2): ''' Gets first ring of coordinates and derivatives between parent pa and children c1, c2, and over the crotch between c1 and c2. :return rox, rod1, rod2, cox, cod1, cod2 ''' paCount = len(pax) c1Count = len(c1x) c2Count = len(c2x) pac1Count, pac2Count, c1c2Count = get_tube_bifurcation_connection_elements_counts(paCount, c1Count, c2Count) # convert to number of nodes, includes both 6-way points pac1NodeCount = pac1Count + 1 pac2NodeCount = pac2Count + 1 c1c2NodeCount = c1c2Count + 1 paStartIndex = 0 c1StartIndex = 0 c2StartIndex = 0 pac1x = [ None ]*pac1NodeCount pac1d1 = [ None ]*pac1NodeCount pac1d2 = [ None ]*pac1NodeCount for n in range(pac1NodeCount): pan = (paStartIndex + n) % paCount c1n = (c1StartIndex + n) % c1Count x1, d1, x2, d2 = pax[pan], mult(pad2[pan], 2.0), c1x[c1n], mult(c1d2[c1n], 2.0) pac1x [n] = interpolateCubicHermite(x1, d1, x2, d2, 0.5) pac1d1[n] = [ 0.0, 0.0, 0.0 ] pac1d2[n] = mult(interpolateCubicHermiteDerivative(x1, d1, x2, d2, 0.5), 0.5) paStartIndex2 = paStartIndex + pac1Count c1StartIndex2 = c1StartIndex + pac1Count c2StartIndex2 = c2StartIndex + c1c2Count pac2x = [ None ]*pac2NodeCount pac2d1 = [ None ]*pac2NodeCount pac2d2 = [ None ]*pac2NodeCount for n in range(pac2NodeCount): pan = (paStartIndex2 + n) % paCount c2n = (c2StartIndex2 + n) % c2Count x1, d1, x2, d2 = pax[pan], mult(pad2[pan], 2.0), c2x[c2n], mult(c2d2[c2n], 2.0) pac2x [n] = interpolateCubicHermite(x1, d1, x2, d2, 0.5) pac2d1[n] = [ 0.0, 0.0, 0.0 ] pac2d2[n] = mult(interpolateCubicHermiteDerivative(x1, d1, x2, d2, 0.5), 0.5) c1c2x = [ None ]*c1c2NodeCount c1c2d1 = [ None ]*c1c2NodeCount c1c2d2 = [ None ]*c1c2NodeCount for n in range(c1c2NodeCount): c1n = (c1StartIndex2 + n) % c1Count c2n = (c2StartIndex2 - n) % c2Count # note: reversed x1, d1, x2, d2 = c2x[c2n], mult(c2d2[c2n], -2.0), c1x[c1n], mult(c1d2[c1n], 2.0) c1c2x [n] = interpolateCubicHermite(x1, d1, x2, d2, 0.5) c1c2d1[n] = [ 0.0, 0.0, 0.0 ] c1c2d2[n] = mult(interpolateCubicHermiteDerivative(x1, d1, x2, d2, 0.5), 0.5) # get hex triple points hex1, hex1d1, hex1d2 = get_bifurcation_triple_point( pax[paStartIndex], mult(pad2[paStartIndex], -1.0), c1x[c1StartIndex], c1d2[c1StartIndex], c2x[c1StartIndex], c2d2[c2StartIndex]) hex2, hex2d1, hex2d2 = get_bifurcation_triple_point( pax[paStartIndex2], mult(pad2[paStartIndex2], -1.0), c2x[c2StartIndex2], c2d2[c2StartIndex2], c1x[c1StartIndex2], c1d2[c1StartIndex2]) # smooth around loops through hex points to get d1 loop1x = [ hex2 ] + pac2x[1:-1] + [ hex1 ] loop1d1 = [ [ -d for d in hex2d2 ] ] + pac2d1[1:-1] + [ hex1d1 ] loop2x = [ hex1 ] + pac1x[1:-1] + [ hex2 ] loop2d1 = [ [ -d for d in hex1d2 ] ] + pac1d1[1:-1] + [ hex2d1 ] loop1d1 = smoothCubicHermiteDerivativesLine(loop1x, loop1d1, fixStartDirection=True, fixEndDirection=True, magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) loop2d1 = smoothCubicHermiteDerivativesLine(loop2x, loop2d1, fixStartDirection=True, fixEndDirection=True, magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) # smooth over "crotch" between c1 and c2 crotchx = [ hex2 ] + c1c2x[1:-1] + [ hex1 ] crotchd1 = [ add(hex2d1, hex2d2) ] + c1c2d1[1:-1] + [ [ (-hex1d1[c] - hex1d2[c]) for c in range(3) ] ] crotchd1 = smoothCubicHermiteDerivativesLine(crotchx, crotchd1, fixStartDerivative=True, fixEndDerivative=True, magnitudeScalingMode=DerivativeScalingMode.HARMONIC_MEAN) rox = [ hex1 ] + pac1x[1:-1] + [ hex2 ] + pac2x[1:-1] rod1 = [ loop1d1[-1] ] + loop2d1[1:] + loop1d1[1:-1] rod2 = [ [ -d for d in loop2d1[ 0] ] ] + pac1d2[1:-1] + [ [ -d for d in loop1d1[0] ] ] + pac2d2[1:-1] cox = crotchx [1:-1] cod1 = crotchd1[1:-1] cod2 = c1c2d2[1:-1] return rox, rod1, rod2, cox, cod1, cod2, paStartIndex, c1StartIndex, c2StartIndex
def mouseMoveEvent(self, event): if self._editNode: mousePos = [event.x(), event.y()] nodeset = self._editNode.getNodeset() fieldmodule = nodeset.getFieldmodule() with ChangeManager(fieldmodule): meshEditsNodeset = self._model.getOrCreateMeshEditsNodesetGroup( nodeset) meshEditsNodeset.addNode(self._editNode) editCoordinateField = coordinateField = self._editGraphics.getCoordinateField( ) localScene = self._editGraphics.getScene( ) # need set local scene to get correct transformation if coordinateField.getCoordinateSystemType( ) != Field.COORDINATE_SYSTEM_TYPE_RECTANGULAR_CARTESIAN: editCoordinateField = fieldmodule.createFieldCoordinateTransformation( coordinateField) editCoordinateField.setCoordinateSystemType( Field.COORDINATE_SYSTEM_TYPE_RECTANGULAR_CARTESIAN) fieldcache = fieldmodule.createFieldcache() fieldcache.setNode(self._editNode) componentsCount = coordinateField.getNumberOfComponents() result, initialCoordinates = editCoordinateField.evaluateReal( fieldcache, componentsCount) if result == RESULT_OK: for c in range(componentsCount, 3): initialCoordinates.append(0.0) pointattr = self._editGraphics.getGraphicspointattributes() editVectorField = vectorField = pointattr.getOrientationScaleField( ) pointBaseSize = pointattr.getBaseSize(3)[1][0] pointScaleFactor = pointattr.getScaleFactors(3)[1][0] if editVectorField.isValid() and (vectorField.getNumberOfComponents() == componentsCount) \ and (pointBaseSize == 0.0) and (pointScaleFactor != 0.0): if vectorField.getCoordinateSystemType( ) != Field.COORDINATE_SYSTEM_TYPE_RECTANGULAR_CARTESIAN: editVectorField = fieldmodule.createFieldCoordinateTransformation( vectorField, coordinateField) editVectorField.setCoordinateSystemType( Field. COORDINATE_SYSTEM_TYPE_RECTANGULAR_CARTESIAN) result, initialVector = editVectorField.evaluateReal( fieldcache, componentsCount) for c in range(componentsCount, 3): initialVector.append(0.0) initialTipCoordinates = [ (initialCoordinates[c] + initialVector[c] * pointScaleFactor) for c in range(3) ] windowCoordinates = self.projectLocal( initialTipCoordinates[0], initialTipCoordinates[1], initialTipCoordinates[2], localScene) finalTipCoordinates = self.unprojectLocal( mousePos[0], -mousePos[1], windowCoordinates[2], localScene) finalVector = [ (finalTipCoordinates[c] - initialCoordinates[c]) / pointScaleFactor for c in range(3) ] result = editVectorField.assignReal( fieldcache, finalVector) else: windowCoordinates = self.projectLocal( initialCoordinates[0], initialCoordinates[1], initialCoordinates[2], localScene) xa = self.unprojectLocal(self._lastMousePos[0], -self._lastMousePos[1], windowCoordinates[2], localScene) xb = self.unprojectLocal(mousePos[0], -mousePos[1], windowCoordinates[2], localScene) finalCoordinates = [ (initialCoordinates[c] + xb[c] - xa[c]) for c in range(3) ] result = editCoordinateField.assignReal( fieldcache, finalCoordinates) del editVectorField del editCoordinateField del fieldcache self._lastMousePos = mousePos event.accept() return if self._alignMode != self.AlignMode.NONE: mousePos = [event.x(), event.y()] delta = [ mousePos[0] - self._lastMousePos[0], mousePos[1] - self._lastMousePos[1] ] result, eye = self._sceneviewer.getEyePosition() result, lookat = self._sceneviewer.getLookatPosition() result, up = self._sceneviewer.getUpVector() lookatToEye = sub(eye, lookat) eyeDistance = magnitude(lookatToEye) front = div(lookatToEye, eyeDistance) right = cross(up, front) if self._alignMode == self.AlignMode.ROTATION: mag = magnitude(delta) prop = div(delta, mag) axis = add(mult(up, prop[0]), mult(right, prop[1])) angle = mag * 0.002 # print('delta', delta, 'axis', axis, 'angle', angle) self._model.interactionRotate(axis, angle) elif self._alignMode == self.AlignMode.SCALE: factor = 1.0 + delta[1] * 0.0005 if factor < 0.9: factor = 0.9 self._model.interactionScale(factor) elif self._alignMode == self.AlignMode.TRANSLATION: result, l, r, b, t, near, far = self._sceneviewer.getViewingVolume( ) viewportWidth = self.width() viewportHeight = self.height() if viewportWidth > viewportHeight: eyeScale = (t - b) / viewportHeight else: eyeScale = (r - l) / viewportWidth offset = add(mult(right, eyeScale * delta[0]), mult(up, -eyeScale * delta[1])) self._model.interactionTranslate(offset) self._lastMousePos = mousePos event.accept() return else: super(NodeEditorSceneviewerWidget, self).mouseMoveEvent(event)